ETH Price: $1,861.82 (-5.58%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap ETH For Ass...160785172022-11-29 22:06:231181 days ago1669759583IN
Nexus Mutual: Swap Operator
0 ETH0.0049972226.45418142
Swap ETH For Ass...160784632022-11-29 21:55:351181 days ago1669758935IN
Nexus Mutual: Swap Operator
0 ETH0.0047280325.02916016
Swap ETH For Ass...160784112022-11-29 21:44:591181 days ago1669758299IN
Nexus Mutual: Swap Operator
0 ETH0.0047132224.95077062
Swap ETH For Ass...160783592022-11-29 21:34:351181 days ago1669757675IN
Nexus Mutual: Swap Operator
0 ETH0.0047773225.29011121
Swap ETH For Ass...160783072022-11-29 21:23:471181 days ago1669757027IN
Nexus Mutual: Swap Operator
0 ETH0.0050102626.52323726
Swap ETH For Ass...160782552022-11-29 21:13:231181 days ago1669756403IN
Nexus Mutual: Swap Operator
0 ETH0.0055480629.37021213
Swap ETH For Ass...160782032022-11-29 21:02:471181 days ago1669755767IN
Nexus Mutual: Swap Operator
0 ETH0.0046718824.73194473
Swap ETH For Ass...160781512022-11-29 20:52:111181 days ago1669755131IN
Nexus Mutual: Swap Operator
0 ETH0.004761125.20420921
Swap ETH For Ass...160780992022-11-29 20:41:351181 days ago1669754495IN
Nexus Mutual: Swap Operator
0 ETH0.004918526.03746775
Swap ETH For Ass...160780472022-11-29 20:31:111181 days ago1669753871IN
Nexus Mutual: Swap Operator
0 ETH0.004634824.53565555
Swap ETH For Ass...160778692022-11-29 19:55:111181 days ago1669751711IN
Nexus Mutual: Swap Operator
0 ETH0.0045280923.97072654
Swap ETH For Ass...160778172022-11-29 19:44:471181 days ago1669751087IN
Nexus Mutual: Swap Operator
0 ETH0.0047816925.31320653
Swap ETH For Ass...160777642022-11-29 19:33:591181 days ago1669750439IN
Nexus Mutual: Swap Operator
0 ETH0.0046002624.35276227
Swap ETH For Ass...160777062022-11-29 19:22:231181 days ago1669749743IN
Nexus Mutual: Swap Operator
0 ETH0.0046522824.62818541
Swap ETH For Ass...160776532022-11-29 19:11:471181 days ago1669749107IN
Nexus Mutual: Swap Operator
0 ETH0.0058224830.82291916
Swap ETH For Ass...160775992022-11-29 19:00:591181 days ago1669748459IN
Nexus Mutual: Swap Operator
0 ETH0.0051915127.48274542
Swap ETH For Ass...160775452022-11-29 18:50:111181 days ago1669747811IN
Nexus Mutual: Swap Operator
0 ETH0.0052974828.0437202
Swap ETH For Ass...160774932022-11-29 18:39:471181 days ago1669747187IN
Nexus Mutual: Swap Operator
0 ETH0.0055380429.31716626
Swap ETH For Ass...160774392022-11-29 18:28:591181 days ago1669746539IN
Nexus Mutual: Swap Operator
0 ETH0.0053709828.43280441
Swap ETH For Ass...160773862022-11-29 18:18:111181 days ago1669745891IN
Nexus Mutual: Swap Operator
0 ETH0.0055034929.13425614
Swap ETH For Ass...160773312022-11-29 18:06:591181 days ago1669745219IN
Nexus Mutual: Swap Operator
0 ETH0.0058723231.08679238
Swap ETH For Ass...160772282022-11-29 17:46:231181 days ago1669743983IN
Nexus Mutual: Swap Operator
0 ETH0.0049008425.9439989
Swap ETH For Ass...160771752022-11-29 17:35:471181 days ago1669743347IN
Nexus Mutual: Swap Operator
0 ETH0.0046253524.485582
Swap ETH For Ass...160771192022-11-29 17:24:351181 days ago1669742675IN
Nexus Mutual: Swap Operator
0 ETH0.005028426.61925801
Swap ETH For Ass...160770662022-11-29 17:13:591181 days ago1669742039IN
Nexus Mutual: Swap Operator
0 ETH0.0048135125.48167888
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Swap Exact ETH F...160785172022-11-29 22:06:231181 days ago1669759583
Nexus Mutual: Swap Operator
10 ETH
Transfer160785172022-11-29 22:06:231181 days ago1669759583
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160784632022-11-29 21:55:351181 days ago1669758935
Nexus Mutual: Swap Operator
10 ETH
Transfer160784632022-11-29 21:55:351181 days ago1669758935
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160784112022-11-29 21:44:591181 days ago1669758299
Nexus Mutual: Swap Operator
10 ETH
Transfer160784112022-11-29 21:44:591181 days ago1669758299
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160783592022-11-29 21:34:351181 days ago1669757675
Nexus Mutual: Swap Operator
10 ETH
Transfer160783592022-11-29 21:34:351181 days ago1669757675
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160783072022-11-29 21:23:471181 days ago1669757027
Nexus Mutual: Swap Operator
10 ETH
Transfer160783072022-11-29 21:23:471181 days ago1669757027
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160782552022-11-29 21:13:231181 days ago1669756403
Nexus Mutual: Swap Operator
10 ETH
Transfer160782552022-11-29 21:13:231181 days ago1669756403
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160782032022-11-29 21:02:471181 days ago1669755767
Nexus Mutual: Swap Operator
10 ETH
Transfer160782032022-11-29 21:02:471181 days ago1669755767
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160781512022-11-29 20:52:111181 days ago1669755131
Nexus Mutual: Swap Operator
10 ETH
Transfer160781512022-11-29 20:52:111181 days ago1669755131
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160780992022-11-29 20:41:351181 days ago1669754495
Nexus Mutual: Swap Operator
10 ETH
Transfer160780992022-11-29 20:41:351181 days ago1669754495
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160780472022-11-29 20:31:111181 days ago1669753871
Nexus Mutual: Swap Operator
10 ETH
Transfer160780472022-11-29 20:31:111181 days ago1669753871
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160778692022-11-29 19:55:111181 days ago1669751711
Nexus Mutual: Swap Operator
10 ETH
Transfer160778692022-11-29 19:55:111181 days ago1669751711
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160778172022-11-29 19:44:471181 days ago1669751087
Nexus Mutual: Swap Operator
10 ETH
Transfer160778172022-11-29 19:44:471181 days ago1669751087
Nexus Mutual: Swap Operator
10 ETH
Swap Exact ETH F...160777642022-11-29 19:33:591181 days ago1669750439
Nexus Mutual: Swap Operator
10 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SwapOperator

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity ^0.8.0;

import "@openzeppelin/contracts-v4/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts-v4/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol";
import "../../external/enzyme/IEnzymeV4Comptroller.sol";
import "../../external/enzyme/IEnzymeV4DepositWrapper.sol";
import "../../external/enzyme/IEnzymeV4Vault.sol";
import "../../external/enzyme/IWETH.sol";
import "../../external/uniswap/IUniswapV2Pair.sol";
import "../../external/uniswap/IUniswapV2Router02.sol";
import "../../interfaces/INXMMaster.sol";
import "../../interfaces/IPool.sol";
import "../../interfaces/ITwapOracle.sol";
import "../../interfaces/IERC20Detailed.sol";

import "../../external/enzyme/IEnzymeFundValueCalculatorRouter.sol";

contract SwapOperator is ReentrancyGuard {
  using SafeERC20 for IERC20;

  struct AssetData {
    uint112 minAmount;
    uint112 maxAmount;
    uint32 lastSwapTime;
    // 18 decimals of precision. 0.01% -> 0.0001 -> 1e14
    uint maxSlippageRatio;
  }

  /* storage */
  bool public communityFundTransferExecuted;

  /* immutables */
  ITwapOracle immutable public twapOracle;
  address immutable public swapController;
  INXMMaster immutable master;
  address immutable public stETH;
  IWETH immutable public weth;

  /* constants */
  address constant public ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
  IUniswapV2Router02 constant public router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
  uint constant public MAX_LIQUIDITY_RATIO = 0.015 ether;
  uint constant public MIN_TIME_BETWEEN_SWAPS = 10 minutes;

  address public immutable enzymeV4VaultProxyAddress;
  IEnzymeFundValueCalculatorRouter public immutable enzymeFundValueCalculatorRouter;

  /* events */
  event Swapped(address indexed fromAsset, address indexed toAsset, uint amountIn, uint amountOut);

  /* logic */
  modifier onlySwapController {
    require(msg.sender == swapController, "SwapOperator: not swapController");
    _;
  }

  constructor(
    address payable _master,
    address _twapOracle,
    address _swapController,
    address _stETH,
    address _enzymeV4VaultProxyAddress,
    IEnzymeFundValueCalculatorRouter _enzymeFundValueCalculatorRouter,
    address _weth
  ) {
    master = INXMMaster(_master);
    twapOracle = ITwapOracle(_twapOracle);
    swapController = _swapController;
    stETH = _stETH;
    enzymeV4VaultProxyAddress = _enzymeV4VaultProxyAddress;
    enzymeFundValueCalculatorRouter = _enzymeFundValueCalculatorRouter;
    weth = IWETH(_weth);
  }

  function swapETHForAsset(
    address toTokenAddress,
    uint amountIn,
    uint amountOutMin
  ) external onlySwapController {

    IPool pool = _pool();
    (
    uint112 min,
    uint112 max,
    uint32 lastAssetSwapTime,
    uint maxSlippageRatio
    ) = pool.getAssetDetails(toTokenAddress);

    AssetData memory assetDetails = AssetData(min, max, lastAssetSwapTime, maxSlippageRatio);
    require(assetIsEnabled(assetDetails), "SwapOperator: asset is not enabled");

    pool.transferAssetToSwapOperator(ETH, amountIn);
    pool.setAssetDataLastSwapTime(toTokenAddress, uint32(block.timestamp));
    uint amountOut = _swapETHForAsset(
      assetDetails,
      toTokenAddress,
      amountIn,
      amountOutMin,
      pool.minPoolEth()
    );
    transferAssetTo(toTokenAddress, address(pool), amountOut);

    emit Swapped(ETH, toTokenAddress, amountIn, amountOut);
  }

  function swapAssetForETH(
    address fromTokenAddress,
    uint amountIn,
    uint amountOutMin
  ) external onlySwapController {

    IPool pool = _pool();
    (
    uint112 min,
    uint112 max,
    uint32 lastAssetSwapTime,
    uint maxSlippageRatio
    ) = pool.getAssetDetails(fromTokenAddress);

    AssetData memory assetDetails = AssetData(min, max, lastAssetSwapTime, maxSlippageRatio);
    require(assetIsEnabled(assetDetails), "SwapOperator: asset is not enabled");

    pool.transferAssetToSwapOperator(fromTokenAddress, amountIn);
    pool.setAssetDataLastSwapTime(fromTokenAddress, uint32(block.timestamp));
    uint amountOut = _swapAssetForETH(
      assetDetails,
      fromTokenAddress,
      amountIn,
      amountOutMin
    );
    transferAssetTo(ETH, address(pool), amountOut);
    emit Swapped(fromTokenAddress, ETH, amountIn, amountOut);
  }

  function getSwapQuote(
    uint tokenAmountIn,
    IERC20 fromToken,
    IERC20 toToken
  ) public view returns (uint tokenAmountOut) {

    address[] memory path = new address[](2);
    path[0] = address(fromToken);
    path[1] = address(toToken);
    uint[] memory amountsOut = router.getAmountsOut(tokenAmountIn, path);

    return amountsOut[1];
  }

  function _swapETHForAsset(
    AssetData memory assetData,
    address toTokenAddress,
    uint amountIn,
    uint amountOutMin,
    uint minLeftETH
  ) internal returns (uint) {

    IPool pool = _pool();
    uint balanceBefore = IERC20(toTokenAddress).balanceOf(address(pool));
    address WETH = address(weth);

    {
      // scope for swap frequency check
      uint timeSinceLastTrade = block.timestamp - uint(assetData.lastSwapTime);
      require(timeSinceLastTrade > MIN_TIME_BETWEEN_SWAPS, "SwapOperator: too fast");
    }

    {
      // scope for liquidity check
      address pairAddress = twapOracle.pairFor(WETH, toTokenAddress);
      IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);
      (uint112 reserve0, uint112 reserve1, /* time */) = pair.getReserves();

      uint ethReserve = WETH < toTokenAddress ? reserve0 : reserve1;
      uint maxTradable = ethReserve * MAX_LIQUIDITY_RATIO / 1e18;

      require(amountIn <= maxTradable, "SwapOperator: exceeds max tradable amount");
    }

    {
      // scope for ether checks
      uint ethBalanceAfter = address(pool).balance;
      require(ethBalanceAfter >= minLeftETH, "SwapOperator: insufficient ether left");
    }

    {
      // scope for token checks
      uint avgAmountOut = twapOracle.consult(WETH, amountIn, toTokenAddress);
      uint maxSlippageAmount = avgAmountOut * assetData.maxSlippageRatio / 1e18;
      uint minOutOnMaxSlippage = avgAmountOut - maxSlippageAmount;

      // gas optimisation: reads both values using a single SLOAD
      (uint minAssetAmount, uint maxAssetAmount) = (assetData.minAmount, assetData.maxAmount);

      require(amountOutMin >= minOutOnMaxSlippage, "SwapOperator: amountOutMin < minOutOnMaxSlippage");
      require(balanceBefore < minAssetAmount, "SwapOperator: balanceBefore >= min");
      require(balanceBefore + amountOutMin <= maxAssetAmount, "SwapOperator: balanceAfter > max");
    }

    address[] memory path = new address[](2);
    path[0] = WETH;
    path[1] = toTokenAddress;
    router.swapExactETHForTokens{ value: amountIn }(amountOutMin, path, address(this), block.timestamp);

    uint amountOut = IERC20(toTokenAddress).balanceOf(address(this));

    return amountOut;
  }

  function _swapAssetForETH(
    AssetData memory assetData,
    address fromTokenAddress,
    uint amountIn,
    uint amountOutMin
  ) internal returns (uint) {

    IPool pool = _pool();
    uint tokenBalanceBefore = IERC20(fromTokenAddress).balanceOf(address(pool)) + amountIn;
    address WETH = address(weth);

    {
      // scope for swap frequency check
      uint timeSinceLastTrade = block.timestamp - uint(assetData.lastSwapTime);
      require(timeSinceLastTrade > MIN_TIME_BETWEEN_SWAPS, "SwapOperator: too fast");
    }

    {
      // scope for liquidity check
      address pairAddress = twapOracle.pairFor(fromTokenAddress, WETH);
      IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);
      (uint112 reserve0, uint112 reserve1, /* time */) = pair.getReserves();

      uint tokenReserve = fromTokenAddress < WETH ? reserve0 : reserve1;
      uint maxTradable = tokenReserve * MAX_LIQUIDITY_RATIO / 1e18;

      require(amountIn <= maxTradable, "SwapOperator: exceeds max tradable amount");
    }

    {
      // scope for token checks
      uint avgAmountOut = twapOracle.consult(fromTokenAddress, amountIn, WETH);
      uint maxSlippageAmount = avgAmountOut * assetData.maxSlippageRatio / 1e18;
      uint minOutOnMaxSlippage = avgAmountOut - maxSlippageAmount;

      // gas optimisation: reads both values using a single SLOAD
      (uint minAssetAmount, uint maxAssetAmount) = (assetData.minAmount, assetData.maxAmount);

      require(amountOutMin >= minOutOnMaxSlippage, "SwapOperator: amountOutMin < minOutOnMaxSlippage");
      require(tokenBalanceBefore > maxAssetAmount, "SwapOperator: tokenBalanceBefore <= max");
      require(tokenBalanceBefore - amountIn >= minAssetAmount, "SwapOperator: tokenBalanceAfter < min");
    }

    address[] memory path = new address[](2);
    path[0] = fromTokenAddress;
    path[1] = address(weth);
    IERC20(fromTokenAddress).approve(address(router), amountIn);
    router.swapExactTokensForETH(amountIn, amountOutMin, path, address(this), block.timestamp);

    uint amountOut = address(this).balance;

    return amountOut;
  }

  function transferAssetTo (address asset, address to, uint amount) internal {

    if (asset == ETH) {
      (bool ok, /* data */) = to.call{ value: amount }("");
      require(ok, "SwapOperator: Eth transfer failed");
      return;
    }

    IERC20 token = IERC20(asset);
    token.safeTransfer(to, amount);
  }

  function swapETHForStETH(uint amountIn) external onlySwapController {
    IPool pool = _pool();
    address toTokenAddress = stETH;
    (
    uint112 minAmount,
    uint112 maxAmount,
    /* uint32 lastAssetSwapTime */,
    /* uint maxSlippageRatio */
    ) = pool.getAssetDetails(toTokenAddress);

    require(!(minAmount == 0 && maxAmount == 0), "SwapOperator: asset is not enabled");

    uint amountOutMin;
    if (amountIn > 10000) {
      amountOutMin = amountIn - 10000; // allow for precision error
    }

    uint balanceBefore = IERC20(toTokenAddress).balanceOf(address(pool));

    pool.transferAssetToSwapOperator(ETH, amountIn);

    (bool ok, /* data */) = toTokenAddress.call{ value: amountIn }("");
    require(ok, "SwapOperator: stEth transfer failed");

    pool.setAssetDataLastSwapTime(toTokenAddress, uint32(block.timestamp));

    uint amountOut = IERC20(toTokenAddress).balanceOf(address(this));

    require(amountOut >= amountOutMin, "SwapOperator: amountOut < amountOutMin");

    require(balanceBefore < minAmount, "SwapOperator: balanceBefore >= min");
    require(balanceBefore + amountOutMin <= maxAmount, "SwapOperator: balanceAfter > max");
    {
      uint ethBalanceAfter = address(pool).balance;
      require(ethBalanceAfter >= pool.minPoolEth(), "SwapOperator: insufficient ether left");
    }

    transferAssetTo(stETH, address(pool), amountOut);

    emit Swapped(ETH, stETH, amountIn, amountOut);
  }

  function swapETHForEnzymeVaultShare(uint amountIn, uint amountOutMin) external onlySwapController {
    IPool pool = _pool();
    IEnzymeV4Comptroller comptrollerProxy = IEnzymeV4Comptroller(IEnzymeV4Vault(enzymeV4VaultProxyAddress).getAccessor());
    IERC20Detailed toToken = IERC20Detailed(enzymeV4VaultProxyAddress);

    (
    uint112 minAmount,
    uint112 maxAmount,
    uint32 lastAssetSwapTime,
    uint maxSlippageRatio
    ) = pool.getAssetDetails(address(toToken));

    require(!(minAmount == 0 && maxAmount == 0), "SwapOperator: asset is not enabled");

    {
      // scope for swap frequency check
      uint timeSinceLastTrade = block.timestamp - uint(lastAssetSwapTime);
      require(timeSinceLastTrade > MIN_TIME_BETWEEN_SWAPS, "SwapOperator: too fast");
    }

    {
      // check slippage
      (, uint netShareValue) = enzymeFundValueCalculatorRouter.calcNetShareValue(enzymeV4VaultProxyAddress);

      uint avgAmountOut = amountIn * 1e18 / netShareValue;
      uint maxSlippageAmount = avgAmountOut * maxSlippageRatio / 1e18;
      uint minOutOnMaxSlippage = avgAmountOut - maxSlippageAmount;

      require(amountOutMin >= minOutOnMaxSlippage, "SwapOperator: amountOutMin < minOutOnMaxSlippage");
    }

    uint balanceBefore = toToken.balanceOf(address(pool));
    pool.transferAssetToSwapOperator(ETH, amountIn);

    require(comptrollerProxy.getDenominationAsset() == address(weth), "SwapOperator: invalid denomination asset");

    weth.deposit{ value: amountIn }();
    weth.approve(address(comptrollerProxy), amountIn);
    comptrollerProxy.buyShares(amountIn, amountOutMin);

    pool.setAssetDataLastSwapTime(address(toToken), uint32(block.timestamp));

    uint amountOut = toToken.balanceOf(address(this));

    require(amountOut >= amountOutMin, "SwapOperator: amountOut < amountOutMin");
    require(balanceBefore < minAmount, "SwapOperator: balanceBefore >= min");
    require(balanceBefore + amountOutMin <= maxAmount, "SwapOperator: balanceAfter > max");

    {
      uint ethBalanceAfter = address(pool).balance;
      require(ethBalanceAfter >= pool.minPoolEth(), "SwapOperator: insufficient ether left");
    }

    transferAssetTo(enzymeV4VaultProxyAddress, address(pool), amountOut);

    emit Swapped(ETH, enzymeV4VaultProxyAddress, amountIn, amountOut);
  }

  function swapEnzymeVaultShareForETH(
    uint amountIn,
    uint amountOutMin
  ) external onlySwapController {

    IPool pool = _pool();
    IERC20Detailed fromToken = IERC20Detailed(enzymeV4VaultProxyAddress);

    uint balanceBefore = fromToken.balanceOf(address(pool));
    {
      (
      uint112 minAmount,
      uint112 maxAmount,
      uint32 lastAssetSwapTime,
      uint maxSlippageRatio
      ) = pool.getAssetDetails(address(fromToken));

      require(!(minAmount == 0 && maxAmount == 0), "SwapOperator: asset is not enabled");

      // swap frequency check
      uint timeSinceLastTrade = block.timestamp - uint(lastAssetSwapTime);
      require(timeSinceLastTrade > MIN_TIME_BETWEEN_SWAPS, "SwapOperator: too fast");

      uint netShareValue;
      {
        address denominationAsset;
        (denominationAsset, netShareValue) =
        enzymeFundValueCalculatorRouter.calcNetShareValue(enzymeV4VaultProxyAddress);

        require(denominationAsset ==  address(weth), "SwapOperator: invalid denomination asset");
      }

      // avgAmountOut in ETH
      uint avgAmountOut = amountIn * netShareValue / (10 ** fromToken.decimals());
      uint maxSlippageAmount = avgAmountOut * maxSlippageRatio / 1e18;
      uint minOutOnMaxSlippage = avgAmountOut - maxSlippageAmount;

      // slippage check
      require(amountOutMin >= minOutOnMaxSlippage, "SwapOperator: amountOutMin < minOutOnMaxSlippage");
      require(balanceBefore > maxAmount, "SwapOperator: balanceBefore <= max");
      require(balanceBefore - amountIn >= minAmount, "SwapOperator: tokenBalanceAfter < min");
    }

    pool.transferAssetToSwapOperator(address(fromToken), amountIn);

    IEnzymeV4Comptroller comptrollerProxy = IEnzymeV4Comptroller(IEnzymeV4Vault(enzymeV4VaultProxyAddress).getAccessor());
    fromToken.approve(address(comptrollerProxy), amountIn);

    address[] memory payoutAssets = new address[](1);
    uint[] memory payoutAssetsPercentages = new uint[](1);

    payoutAssets[0] = address(weth);
    payoutAssetsPercentages[0] = 10000;

    comptrollerProxy.redeemSharesForSpecificAssets(address(this), amountIn, payoutAssets, payoutAssetsPercentages);

    uint amountOut = weth.balanceOf(address(this));
    weth.withdraw(amountOut);

    pool.setAssetDataLastSwapTime(address(fromToken), uint32(block.timestamp));

    require(amountOut >= amountOutMin, "SwapOperator: amountOut < amountOutMin");

    transferAssetTo(ETH, address(pool), amountOut);

    emit Swapped(enzymeV4VaultProxyAddress, ETH, amountIn, amountOut);
  }

  function transferToCommunityFund() external onlySwapController {

    // amount, destination, deadline
    uint amount = 8000 ether;
    address communityFund = 0x586b9b2F8010b284A0197f392156f1A7Eb5e86e9;
    uint deadline = 1638057600; // Sun Nov 28 2021 00:00:00 GMT+0000

    // perform checks and mark as paid
    require(block.timestamp < deadline, "SwapOperator: the deadline has passed");
    require(!communityFundTransferExecuted, "SwapOperator: already executed");
    communityFundTransferExecuted = true;

    // transfer
    _pool().transferAssetToSwapOperator(ETH, amount);
    (bool ok, /* data */) = communityFund.call{ value: amount }("");
    require(ok, "SwapOperator: transfer failed");
  }

  function assetIsEnabled(AssetData memory assetData) internal pure returns (bool) {
    return !(assetData.minAmount == 0 && assetData.maxAmount == 0);
  }

  function _pool() internal view returns (IPool) {
    return IPool(master.getLatestAddress('P1'));
  }


  function recoverAsset(address assetAddress, address receiver) public onlySwapController {

    IERC20 asset = IERC20(assetAddress);

    uint balance = asset.balanceOf(address(this));
    require(balance > 0, "SwapOperator: Balance = 0");

    IPool pool = _pool();
    (
    uint112 min,
    uint112 max,
    /* uint32 lastAssetSwapTime */,
    /* uint maxSlippageRatio */
    ) = pool.getAssetDetails(assetAddress);

    if (min == 0 && max == 0) {
      // asset is not supported
      asset.transfer(receiver, balance);
      return;
    }

    asset.transfer(address(pool), balance);
  }

  receive() external payable {}
}

File 2 of 21 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _approve(sender, _msgSender(), currentAllowance - amount);
        }

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

        _afterTokenTransfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IEnzymeV4Comptroller {
    function getDenominationAsset() external view returns (address denominationAsset_);
    function redeemSharesForSpecificAssets(
        address _recipient,
        uint256 _sharesQuantity,
        address[] calldata _payoutAssets,
        uint256[] calldata _payoutAssetPercentages
    ) external returns (uint256[] memory payoutAmounts_);

  function vaultCallOnContract(
    address _contract,
    bytes4 _selector,
    bytes calldata _encodedArgs
  ) external;

  function buyShares(uint _investmentAmount, uint _minSharesQuantity) external;
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IEnzymeV4DepositWrapper {
  function exchangeEthAndBuyShares(
    address  comptrollerProxy,
    address denominationAsset,
    uint256 minSharesQuantity,
    address exchange,
    address exchangeApproveTarget,
    bytes calldata exchangeData,
    uint256 minInvestmentAmount) external payable returns (uint256 sharesReceived_);
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IEnzymeV4Vault {
  function getAccessor() external view returns (address);

  function getOwner() external view returns (address);
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IWETH {
  function withdraw(uint256) external;
  function deposit() external payable;

  function approve(address spender, uint256 value) external;

  function balanceOf(address account) external view returns (uint256);

  function transfer(address recipient, uint256 amount) external returns (bool);
}

File 9 of 21 : IUniswapV2Pair.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IUniswapV2Pair {
  function getReserves() external view returns (uint112, uint112, uint32);
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

import './IUniswapV2Router01.sol';

interface IUniswapV2Router02 is IUniswapV2Router01 {

  function removeLiquidityETHSupportingFeeOnTransferTokens(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
  ) external returns (uint amountETH);

  function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline,
    bool approveMax, uint8 v, bytes32 r, bytes32 s
  ) external returns (uint amountETH);

  function swapExactTokensForTokensSupportingFeeOnTransferTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  ) external;

  function swapExactETHForTokensSupportingFeeOnTransferTokens(
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  ) external payable;

  function swapExactTokensForETHSupportingFeeOnTransferTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  ) external;
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface INXMMaster {

  function tokenAddress() external view returns (address);

  function owner() external view returns (address);

  function masterInitialized() external view returns (bool);

  function isInternal(address _add) external view returns (bool);

  function isPause() external view returns (bool check);

  function isOwner(address _add) external view returns (bool);

  function isMember(address _add) external view returns (bool);

  function checkIsAuthToGoverned(address _add) external view returns (bool);

  function dAppLocker() external view returns (address _add);

  function getLatestAddress(bytes2 _contractName) external view returns (address payable contractAddress);

  function upgradeMultipleContracts(
    bytes2[] calldata _contractCodes,
    address payable[] calldata newAddresses
  ) external;

  function removeContracts(bytes2[] calldata contractCodesToRemove) external;

  function addNewInternalContracts(
    bytes2[] calldata _contractCodes,
    address payable[] calldata newAddresses,
    uint[] calldata _types
  ) external;

  function updateOwnerParameters(bytes8 code, address payable val) external;
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

import "./IPriceFeedOracle.sol";

interface IPool {
  function sellNXM(uint tokenAmount, uint minEthOut) external;

  function sellNXMTokens(uint tokenAmount) external returns (bool);

  function minPoolEth() external returns (uint);

  function transferAssetToSwapOperator(address asset, uint amount) external;

  function setAssetDataLastSwapTime(address asset, uint32 lastSwapTime) external;

  function getAssetDetails(address _asset) external view returns (
    uint112 min,
    uint112 max,
    uint32 lastAssetSwapTime,
    uint maxSlippageRatio
  );

  function sendClaimPayout (
    address asset,
    address payable payoutAddress,
    uint amount
  ) external returns (bool success);

  function transferAsset(
    address asset,
    address payable destination,
    uint amount
  ) external;

  function upgradeCapitalPool(address payable newPoolAddress) external;

  function priceFeedOracle() external view returns (IPriceFeedOracle);

  function getPoolValueInEth() external view returns (uint);


  function transferAssetFrom(address asset, address from, uint amount) external;

  function getEthForNXM(uint nxmAmount) external view returns (uint ethAmount);

  function calculateEthForNXM(
    uint nxmAmount,
    uint currentTotalAssetValue,
    uint mcrEth
  ) external pure returns (uint);

  function calculateMCRRatio(uint totalAssetValue, uint mcrEth) external pure returns (uint);

  function calculateTokenSpotPrice(uint totalAssetValue, uint mcrEth) external pure returns (uint tokenPrice);

  function getTokenPrice(address asset) external view returns (uint tokenPrice);

  function getMCRRatio() external view returns (uint);
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface ITwapOracle {
  function pairFor(address tokenA, address tokenB) external view returns (address);
  function consult(address tokenIn, uint amountIn, address tokenOut) external view returns (uint);
  function periodSize() external view returns (uint);
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IERC20Detailed {

  function totalSupply() external view returns (uint256);

  function balanceOf(address account) external view returns (uint256);

  function transfer(address recipient, uint256 amount) external returns (bool);

  function allowance(address owner, address spender) external view returns (uint256);

  function approve(address spender, uint256 amount) external returns (bool);

  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

  event Transfer(address indexed from, address indexed to, uint256 value);

  event Approval(address indexed owner, address indexed spender, uint256 value);

  function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IEnzymeFundValueCalculatorRouter {
  function calcGrossShareValue(address _vaultProxy)
  external
  returns (address denominationAsset_, uint256 grossShareValue_);

  function calcNetShareValue(address _vaultProxy)
  external
  returns (address denominationAsset_, uint256 netShareValue_);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IUniswapV2Router01 {

  function factory() external pure returns (address);

  function WETH() external pure returns (address);

  function addLiquidity(
    address tokenA,
    address tokenB,
    uint amountADesired,
    uint amountBDesired,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
  ) external returns (uint amountA, uint amountB, uint liquidity);

  function addLiquidityETH(
    address token,
    uint amountTokenDesired,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
  ) external payable returns (uint amountToken, uint amountETH, uint liquidity);

  function removeLiquidity(
    address tokenA,
    address tokenB,
    uint liquidity,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
  ) external returns (uint amountA, uint amountB);

  function removeLiquidityETH(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
  ) external returns (uint amountToken, uint amountETH);

  function removeLiquidityWithPermit(
    address tokenA,
    address tokenB,
    uint liquidity,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline,
    bool approveMax, uint8 v, bytes32 r, bytes32 s
  ) external returns (uint amountA, uint amountB);

  function removeLiquidityETHWithPermit(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline,
    bool approveMax, uint8 v, bytes32 r, bytes32 s
  ) external returns (uint amountToken, uint amountETH);

  function swapExactTokensForTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  ) external returns (uint[] memory amounts);

  function swapTokensForExactTokens(
    uint amountOut,
    uint amountInMax,
    address[] calldata path,
    address to,
    uint deadline
  ) external returns (uint[] memory amounts);

  function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
  external
  payable
  returns (uint[] memory amounts);

  function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
  external
  returns (uint[] memory amounts);

  function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
  external
  returns (uint[] memory amounts);

  function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
  external
  payable
  returns (uint[] memory amounts);

  function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);

  function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);

  function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);

  function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);

  function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity >=0.5.0;

interface IPriceFeedOracle {

  function daiAddress() external view returns (address);
  function ETH() external view returns (address);

  function getAssetToEthRate(address asset) external view returns (uint);
  function getAssetForEth(address asset, uint ethIn) external view returns (uint);

}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address payable","name":"_master","type":"address"},{"internalType":"address","name":"_twapOracle","type":"address"},{"internalType":"address","name":"_swapController","type":"address"},{"internalType":"address","name":"_stETH","type":"address"},{"internalType":"address","name":"_enzymeV4VaultProxyAddress","type":"address"},{"internalType":"contract IEnzymeFundValueCalculatorRouter","name":"_enzymeFundValueCalculatorRouter","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromAsset","type":"address"},{"indexed":true,"internalType":"address","name":"toAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swapped","type":"event"},{"inputs":[],"name":"ETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_LIQUIDITY_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_TIME_BETWEEN_SWAPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"communityFundTransferExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enzymeFundValueCalculatorRouter","outputs":[{"internalType":"contract IEnzymeFundValueCalculatorRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enzymeV4VaultProxyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"toToken","type":"address"}],"name":"getSwapQuote","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"recoverAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromTokenAddress","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapAssetForETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"toTokenAddress","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapETHForAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapETHForEnzymeVaultShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"swapETHForStETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapEnzymeVaultShareForETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferToCommunityFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"twapOracle","outputs":[{"internalType":"contract ITwapOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101606040523480156200001257600080fd5b506040516200448038038062004480833981016040819052620000359162000083565b60016000556001600160601b0319606097881b811660c05295871b861660805293861b851660a05291851b841660e052841b831661012052831b82166101405290911b166101005262000146565b600080600080600080600060e0888a0312156200009e578283fd5b8751620000ab816200012d565b6020890151909750620000be816200012d565b6040890151909650620000d1816200012d565b6060890151909550620000e4816200012d565b6080890151909450620000f7816200012d565b60a08901519093506200010a816200012d565b60c08901519092506200011d816200012d565b8091505092959891949750929550565b6001600160a01b03811681146200014357600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6141d5620002ab60003960008181610399015281816114920152611e0e0152600081816102b8015281816112ce015281816114650152818161174301528181611b8501528181611c1c01528181611cc201528181611de30152818161240301526124410152600081816101a1015281816115130152818161189d015281816119cd01528181611a6801528181611ff2015281816120b301528181612139015281816128e601528181612d000152612ffd0152600081816102ec0152818161099401528181610e170152610e55015260006127910152600081816103650152818161042e015281816106bc015281816109360152818161101e0152818161126501528181611bcf01526124a30152600081816102840152818161296701528181612b0d0152818161307e015261325401526141d56000f3fe6080604052600436106101185760003560e01c80639043292a116100a0578063ddf403aa11610064578063ddf403aa14610353578063e0dc77c214610387578063f2030f34146103bb578063f887ea40146103db578063ffa6de3a1461040357600080fd5b80639043292a14610272578063b01a86ab146102a6578063c1fe3e48146102da578063d77b2a7c1461030e578063d8ecf9e11461033857600080fd5b8063468c5300116100e7578063468c5300146101db57806349386d87146101fb578063616c756a1461021b578063644595f0146102305780638322fff21461025057600080fd5b806309053ac414610124578063112677841461014657806311a9992e146101665780633fc8cef31461018f57600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b5061014461013f36600461384d565b610423565b005b34801561015257600080fd5b506101446101613660046138b2565b6106b1565b34801561017257600080fd5b5061017c61025881565b6040519081526020015b60405180910390f35b34801561019b57600080fd5b506101c37f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610186565b3480156101e757600080fd5b506101446101f6366004613a52565b61092b565b34801561020757600080fd5b5061017c610216366004613a82565b610eab565b34801561022757600080fd5b50610144611013565b34801561023c57600080fd5b5061014461024b366004613ac3565b61125a565b34801561025c57600080fd5b506101c360008051602061418083398151915281565b34801561027e57600080fd5b506101c37f000000000000000000000000000000000000000000000000000000000000000081565b3480156102b257600080fd5b506101c37f000000000000000000000000000000000000000000000000000000000000000081565b3480156102e657600080fd5b506101c37f000000000000000000000000000000000000000000000000000000000000000081565b34801561031a57600080fd5b506001546103289060ff1681565b6040519015158152602001610186565b34801561034457600080fd5b5061017c66354a6ba7a1800081565b34801561035f57600080fd5b506101c37f000000000000000000000000000000000000000000000000000000000000000081565b34801561039357600080fd5b506101c37f000000000000000000000000000000000000000000000000000000000000000081565b3480156103c757600080fd5b506101446103d6366004613ac3565b611bc4565b3480156103e757600080fd5b506101c3737a250d5630b4cf539739df2c5dacb4c659f2488d81565b34801561040f57600080fd5b5061014461041e3660046138b2565b612498565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104745760405162461bcd60e51b815260040161046b90613d4a565b60405180910390fd5b6040516370a0823160e01b815230600482015282906000906001600160a01b038316906370a082319060240160206040518083038186803b1580156104b857600080fd5b505afa1580156104cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f09190613a6a565b9050600081116105425760405162461bcd60e51b815260206004820152601960248201527f537761704f70657261746f723a2042616c616e6365203d203000000000000000604482015260640161046b565b600061054c612775565b604051639c9b645160e01b81526001600160a01b038781166004830152919250600091829190841690639c9b64519060240160806040518083038186803b15801561059657600080fd5b505afa1580156105aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ce9190613a08565b505091509150816001600160701b031660001480156105f457506001600160701b038116155b156106835760405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb906106279089908890600401613b64565b602060405180830381600087803b15801561064157600080fd5b505af1158015610655573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067991906139a6565b5050505050505050565b60405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb906106279086908890600401613b64565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106f95760405162461bcd60e51b815260040161046b90613d4a565b6000610703612775565b604051639c9b645160e01b81526001600160a01b03868116600483015291925060009182918291829190861690639c9b64519060240160806040518083038186803b15801561075157600080fd5b505afa158015610765573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107899190613a08565b935093509350935060006040518060800160405280866001600160701b03168152602001856001600160701b031681526020018463ffffffff1681526020018381525090506107d781612818565b6107f35760405162461bcd60e51b815260040161046b90613c38565b60405163013ea14360e21b81526001600160a01b038716906304fa850c90610821908c908c90600401613b64565b600060405180830381600087803b15801561083b57600080fd5b505af115801561084f573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b0389169250637ad32bee9150610881908c904290600401613be6565b600060405180830381600087803b15801561089b57600080fd5b505af11580156108af573d6000803e3d6000fd5b5050505060006108c1828b8b8b612845565b90506108dc6000805160206141808339815191528883612e88565b604080518a815260208101839052600080516020614180833981519152916001600160a01b038d169160008051602061416083398151915291015b60405180910390a350505050505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109735760405162461bcd60e51b815260040161046b90613d4a565b600061097d612775565b604051639c9b645160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081811660048401529293506000918291851690639c9b64519060240160806040518083038186803b1580156109e757600080fd5b505afa1580156109fb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1f9190613a08565b505091509150816001600160701b03166000148015610a4557506001600160701b038116155b15610a625760405162461bcd60e51b815260040161046b90613c38565b6000612710861115610a7d57610a7a612710876140d8565b90505b6040516370a0823160e01b81526001600160a01b038681166004830152600091908616906370a082319060240160206040518083038186803b158015610ac257600080fd5b505afa158015610ad6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afa9190613a6a565b60405163013ea14360e21b81529091506001600160a01b038716906304fa850c90610b3990600080516020614180833981519152908b90600401613b64565b600060405180830381600087803b158015610b5357600080fd5b505af1158015610b67573d6000803e3d6000fd5b505050506000856001600160a01b03168860405160006040518083038185875af1925050503d8060008114610bb8576040519150601f19603f3d011682016040523d82523d6000602084013e610bbd565b606091505b5050905080610c1a5760405162461bcd60e51b815260206004820152602360248201527f537761704f70657261746f723a207374457468207472616e73666572206661696044820152621b195960ea1b606482015260840161046b565b604051633d6995f760e11b81526001600160a01b03881690637ad32bee90610c489089904290600401613be6565b600060405180830381600087803b158015610c6257600080fd5b505af1158015610c76573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03891691506370a082319060240160206040518083038186803b158015610cbc57600080fd5b505afa158015610cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf49190613a6a565b905083811015610d165760405162461bcd60e51b815260040161046b90613d7f565b856001600160701b03168310610d3e5760405162461bcd60e51b815260040161046b90613c7a565b6001600160701b038516610d528585613f91565b1115610d705760405162461bcd60e51b815260040161046b90613dc5565b6000886001600160a01b0316319050886001600160a01b0316630bb76fff6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610dba57600080fd5b505af1158015610dce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df29190613a6a565b811015610e115760405162461bcd60e51b815260040161046b90613cbc565b50610e3d7f00000000000000000000000000000000000000000000000000000000000000008983612e88565b604080518a8152602081018390526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916000805160206141808339815191529160008051602061416083398151915291015b60405180910390a3505050505050505050565b604080516002808252606082018352600092839291906020830190803683370190505090508381600081518110610ef257634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250508281600181518110610f3457634e487b7160e01b600052603260045260246000fd5b6001600160a01b039092166020928302919091019091015260405163d06ca61f60e01b8152600090737a250d5630b4cf539739df2c5dacb4c659f2488d9063d06ca61f90610f889089908690600401613f07565b60006040518083038186803b158015610fa057600080fd5b505afa158015610fb4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fdc91908101906138e6565b905080600181518110610fff57634e487b7160e01b600052603260045260246000fd5b6020026020010151925050505b9392505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461105b5760405162461bcd60e51b815260040161046b90613d4a565b6901b1ae4d6e2ef500000073586b9b2f8010b284a0197f392156f1a7eb5e86e96361a2c6804281116110dd5760405162461bcd60e51b815260206004820152602560248201527f537761704f70657261746f723a2074686520646561646c696e65206861732070604482015264185cdcd95960da1b606482015260840161046b565b60015460ff16156111305760405162461bcd60e51b815260206004820152601e60248201527f537761704f70657261746f723a20616c72656164792065786563757465640000604482015260640161046b565b6001805460ff191681179055611144612775565b6001600160a01b03166304fa850c600080516020614180833981519152856040518363ffffffff1660e01b815260040161117f929190613b64565b600060405180830381600087803b15801561119957600080fd5b505af11580156111ad573d6000803e3d6000fd5b505050506000826001600160a01b03168460405160006040518083038185875af1925050503d80600081146111fe576040519150601f19603f3d011682016040523d82523d6000602084013e611203565b606091505b50509050806112545760405162461bcd60e51b815260206004820152601d60248201527f537761704f70657261746f723a207472616e73666572206661696c6564000000604482015260640161046b565b50505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112a25760405162461bcd60e51b815260040161046b90613d4a565b60006112ac612775565b6040516370a0823160e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000091600091908316906370a082319060240160206040518083038186803b15801561131657600080fd5b505afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e9190613a6a565b604051639c9b645160e01b81526001600160a01b03848116600483015291925060009182918291829190881690639c9b64519060240160806040518083038186803b15801561139c57600080fd5b505afa1580156113b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d49190613a08565b9350935093509350836001600160701b031660001480156113fc57506001600160701b038316155b156114195760405162461bcd60e51b815260040161046b90613c38565b600061142b63ffffffff8416426140d8565b9050610258811161144e5760405162461bcd60e51b815260040161046b90613e92565b604051633ba6b85160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690633ba6b851906024016040805180830381600087803b1580156114d557600080fd5b505af11580156114e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150d9190613885565b925090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169082161461155d5760405162461bcd60e51b815260040161046b90613e4a565b506000886001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d19190613ae4565b6115dc90600a61400c565b6115e6838e6140b9565b6115f09190613fa9565b90506000670de0b6b3a764000061160786846140b9565b6116119190613fa9565b9050600061161f82846140d8565b9050808d10156116415760405162461bcd60e51b815260040161046b90613dfa565b876001600160701b03168a116116a45760405162461bcd60e51b815260206004820152602260248201527f537761704f70657261746f723a2062616c616e63654265666f7265203c3d206d6044820152610c2f60f31b606482015260840161046b565b6001600160701b0389166116b88f8c6140d8565b10156116d65760405162461bcd60e51b815260040161046b90613ec2565b505050505050505050826001600160a01b03166304fa850c83876040518363ffffffff1660e01b815260040161170d929190613b64565b600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635a53e3486040518163ffffffff1660e01b815260040160206040518083038186803b15801561179a57600080fd5b505afa1580156117ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d29190613831565b60405163095ea7b360e01b81529091506001600160a01b0384169063095ea7b3906118039084908a90600401613b64565b602060405180830381600087803b15801561181d57600080fd5b505af1158015611831573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185591906139a6565b506040805160018082528183019092526000916020808301908036833750506040805160018082528183019092529293506000929150602080830190803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000826000815181106118dd57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250506127108160008151811061192157634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051633462fcc160e01b81526001600160a01b03841690633462fcc19061195e9030908c9087908790600401613b7d565b600060405180830381600087803b15801561197857600080fd5b505af115801561198c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119b491908101906138e6565b506040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015611a1757600080fd5b505afa158015611a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4f9190613a6a565b604051632e1a7d4d60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611ab457600080fd5b505af1158015611ac8573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b038a169250637ad32bee9150611afa9089904290600401613be6565b600060405180830381600087803b158015611b1457600080fd5b505af1158015611b28573d6000803e3d6000fd5b5050505087811015611b4c5760405162461bcd60e51b815260040161046b90613d7f565b611b656000805160206141808339815191528883612e88565b604080518a815260208101839052600080516020614180833981519152917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916000805160206141608339815191529101610e98565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611c0c5760405162461bcd60e51b815260040161046b90613d4a565b6000611c16612775565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635a53e3486040518163ffffffff1660e01b815260040160206040518083038186803b158015611c7357600080fd5b505afa158015611c87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cab9190613831565b604051639c9b645160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008181166004840152929350600091829182918291881690639c9b64519060240160806040518083038186803b158015611d1957600080fd5b505afa158015611d2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d519190613a08565b9350935093509350836001600160701b03166000148015611d7957506001600160701b038316155b15611d965760405162461bcd60e51b815260040161046b90613c38565b6000611da863ffffffff8416426140d8565b90506102588111611dcb5760405162461bcd60e51b815260040161046b90613e92565b50604051633ba6b85160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690633ba6b851906024016040805180830381600087803b158015611e5357600080fd5b505af1158015611e67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8b9190613885565b91506000905081611ea48c670de0b6b3a76400006140b9565b611eae9190613fa9565b90506000670de0b6b3a7640000611ec585846140b9565b611ecf9190613fa9565b90506000611edd82846140d8565b9050808c1015611eff5760405162461bcd60e51b815260040161046b90613dfa565b50506040516370a0823160e01b81526001600160a01b038a8116600483015260009350881691506370a082319060240160206040518083038186803b158015611f4757600080fd5b505afa158015611f5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7f9190613a6a565b60405163013ea14360e21b81529091506001600160a01b038916906304fa850c90611fbe90600080516020614180833981519152908e90600401613b64565b600060405180830381600087803b158015611fd857600080fd5b505af1158015611fec573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b031663e269c3d66040518163ffffffff1660e01b815260040160206040518083038186803b15801561205357600080fd5b505afa158015612067573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208b9190613831565b6001600160a01b0316146120b15760405162461bcd60e51b815260040161046b90613e4a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561210c57600080fd5b505af1158015612120573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063095ea7b3925061217391508a908e90600401613b64565b600060405180830381600087803b15801561218d57600080fd5b505af11580156121a1573d6000803e3d6000fd5b5050604051635f75e2ed60e11b8152600481018d9052602481018c90526001600160a01b038a16925063beebc5da9150604401600060405180830381600087803b1580156121ee57600080fd5b505af1158015612202573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b038b169250637ad32bee91506122349089904290600401613be6565b600060405180830381600087803b15801561224e57600080fd5b505af1158015612262573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03891691506370a082319060240160206040518083038186803b1580156122a857600080fd5b505afa1580156122bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e09190613a6a565b9050898110156123025760405162461bcd60e51b815260040161046b90613d7f565b856001600160701b0316821061232a5760405162461bcd60e51b815260040161046b90613c7a565b6001600160701b03851661233e8b84613f91565b111561235c5760405162461bcd60e51b815260040161046b90613dc5565b6000896001600160a01b0316319050896001600160a01b0316630bb76fff6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123de9190613a6a565b8110156123fd5760405162461bcd60e51b815260040161046b90613cbc565b506124297f00000000000000000000000000000000000000000000000000000000000000008a83612e88565b604080518c8152602081018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169160008051602061418083398151915291600080516020614160833981519152910160405180910390a35050505050505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146124e05760405162461bcd60e51b815260040161046b90613d4a565b60006124ea612775565b604051639c9b645160e01b81526001600160a01b03868116600483015291925060009182918291829190861690639c9b64519060240160806040518083038186803b15801561253857600080fd5b505afa15801561254c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125709190613a08565b935093509350935060006040518060800160405280866001600160701b03168152602001856001600160701b031681526020018463ffffffff1681526020018381525090506125be81612818565b6125da5760405162461bcd60e51b815260040161046b90613c38565b60405163013ea14360e21b81526001600160a01b038716906304fa850c9061261690600080516020614180833981519152908c90600401613b64565b600060405180830381600087803b15801561263057600080fd5b505af1158015612644573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b0389169250637ad32bee9150612676908c904290600401613be6565b600060405180830381600087803b15801561269057600080fd5b505af11580156126a4573d6000803e3d6000fd5b505050506000612729828b8b8b8b6001600160a01b0316630bb76fff6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156126ec57600080fd5b505af1158015612700573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127249190613a6a565b612f69565b90506127368a8883612e88565b604080518a8152602081018390526001600160a01b038c1691600080516020614180833981519152916000805160206141608339815191529101610917565b6040516227050b60e31b815261503160f01b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063013828589060240160206040518083038186803b1580156127db57600080fd5b505afa1580156127ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128139190613831565b905090565b80516000906001600160701b031615801561283e575060208201516001600160701b0316155b1592915050565b600080612850612775565b6040516370a0823160e01b81526001600160a01b0380831660048301529192506000918691908816906370a082319060240160206040518083038186803b15801561289a57600080fd5b505afa1580156128ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d29190613a6a565b6128dc9190613f91565b60408801519091507f0000000000000000000000000000000000000000000000000000000000000000906000906129199063ffffffff16426140d8565b9050610258811161293c5760405162461bcd60e51b815260040161046b90613e92565b506040516396ed28f960e01b81526001600160a01b03888116600483015282811660248301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906396ed28f99060440160206040518083038186803b1580156129ab57600080fd5b505afa1580156129bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e39190613831565b90506000819050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612a2657600080fd5b505afa158015612a3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a5e91906139c6565b50915091506000856001600160a01b03168c6001600160a01b031610612a845781612a86565b825b6001600160701b031690506000670de0b6b3a7640000612aad66354a6ba7a18000846140b9565b612ab79190613fa9565b9050808c1115612ad95760405162461bcd60e51b815260040161046b90613d01565b5050604051632321bc7960e21b81526001600160a01b038c81166004830152602482018c90528681166044830152600095507f0000000000000000000000000000000000000000000000000000000000000000169350638c86f1e49250606401905060206040518083038186803b158015612b5357600080fd5b505afa158015612b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8b9190613a6a565b90506000670de0b6b3a76400008a6060015183612ba891906140b9565b612bb29190613fa9565b90506000612bc082846140d8565b8b5160208d01519192506001600160701b039081169116828a1015612bf75760405162461bcd60e51b815260040161046b90613dfa565b808711612c565760405162461bcd60e51b815260206004820152602760248201527f537761704f70657261746f723a20746f6b656e42616c616e63654265666f7265604482015266040787a40dac2f60cb1b606482015260840161046b565b81612c618c896140d8565b1015612c7f5760405162461bcd60e51b815260040161046b90613ec2565b506000935060029250612c90915050565b604051908082528060200260200182016040528015612cb9578160200160208202803683370190505b5090508781600081518110612cde57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600181518110612d4057634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201015260405163095ea7b360e01b81529089169063095ea7b390612d9190737a250d5630b4cf539739df2c5dacb4c659f2488d908b90600401613b64565b602060405180830381600087803b158015612dab57600080fd5b505af1158015612dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de391906139a6565b506040516318cbafe560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d906318cbafe590612e23908a908a90869030904290600401613f55565b600060405180830381600087803b158015612e3d57600080fd5b505af1158015612e51573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7991908101906138e6565b50479998505050505050505050565b6001600160a01b0383166000805160206141808339815191521415612f54576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612ef4576040519150601f19603f3d011682016040523d82523d6000602084013e612ef9565b606091505b50509050806112545760405162461bcd60e51b815260206004820152602160248201527f537761704f70657261746f723a20457468207472616e73666572206661696c656044820152601960fa1b606482015260840161046b565b826112546001600160a01b038216848461355c565b600080612f74612775565b6040516370a0823160e01b81526001600160a01b0380831660048301529192506000918816906370a082319060240160206040518083038186803b158015612fbb57600080fd5b505afa158015612fcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff39190613a6a565b60408901519091507f0000000000000000000000000000000000000000000000000000000000000000906000906130309063ffffffff16426140d8565b905061025881116130535760405162461bcd60e51b815260040161046b90613e92565b506040516396ed28f960e01b81526001600160a01b03828116600483015289811660248301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906396ed28f99060440160206040518083038186803b1580156130c257600080fd5b505afa1580156130d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130fa9190613831565b90506000819050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561313d57600080fd5b505afa158015613151573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317591906139c6565b509150915060008c6001600160a01b0316866001600160a01b03161061319b578161319d565b825b6001600160701b031690506000670de0b6b3a76400006131c466354a6ba7a18000846140b9565b6131ce9190613fa9565b9050808d11156131f05760405162461bcd60e51b815260040161046b90613d01565b5050506001600160a01b0386163192505050858110156132225760405162461bcd60e51b815260040161046b90613cbc565b50604051632321bc7960e21b81526001600160a01b0382811660048301526024820189905289811660448301526000917f000000000000000000000000000000000000000000000000000000000000000090911690638c86f1e49060640160206040518083038186803b15801561329857600080fd5b505afa1580156132ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d09190613a6a565b90506000670de0b6b3a76400008b60600151836132ed91906140b9565b6132f79190613fa9565b9050600061330582846140d8565b8c5160208e01519192506001600160701b039081169116828b101561333c5760405162461bcd60e51b815260040161046b90613dfa565b81871061335b5760405162461bcd60e51b815260040161046b90613c7a565b806133668c89613f91565b11156133845760405162461bcd60e51b815260040161046b90613dc5565b506000935060029250613395915050565b6040519080825280602002602001820160405280156133be578160200160208202803683370190505b50905081816000815181106133e357634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b031681525050888160018151811061342557634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390921660209283029190910190910152604051637ff36ab560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d90637ff36ab5908a9061347c908b90869030904290600401613f20565b6000604051808303818588803b15801561349557600080fd5b505af11580156134a9573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526134d291908101906138e6565b506040516370a0823160e01b81523060048201526000906001600160a01b038b16906370a082319060240160206040518083038186803b15801561351557600080fd5b505afa158015613529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354d9190613a6a565b9b9a5050505050505050505050565b6135b28363a9059cbb60e01b848460405160240161357b929190613b64565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526135b7565b505050565b600061360c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166136899092919063ffffffff16565b8051909150156135b2578080602001905181019061362a91906139a6565b6135b25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161046b565b606061369884846000856136a0565b949350505050565b6060824710156137015760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161046b565b843b61374f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161046b565b600080866001600160a01b0316858760405161376b9190613b48565b60006040518083038185875af1925050503d80600081146137a8576040519150601f19603f3d011682016040523d82523d6000602084013e6137ad565b606091505b50915091506137bd8282866137c8565b979650505050505050565b606083156137d757508161100c565b8251156137e75782518084602001fd5b8160405162461bcd60e51b815260040161046b9190613c05565b80516001600160701b038116811461381857600080fd5b919050565b805163ffffffff8116811461381857600080fd5b600060208284031215613842578081fd5b815161100c81614147565b6000806040838503121561385f578081fd5b823561386a81614147565b9150602083013561387a81614147565b809150509250929050565b60008060408385031215613897578182fd5b82516138a281614147565b6020939093015192949293505050565b6000806000606084860312156138c6578081fd5b83356138d181614147565b95602085013595506040909401359392505050565b600060208083850312156138f8578182fd5b825167ffffffffffffffff8082111561390f578384fd5b818501915085601f830112613922578384fd5b81518181111561393457613934614131565b8060051b604051601f19603f8301168101818110858211171561395957613959614131565b604052828152858101935084860182860187018a1015613977578788fd5b8795505b8386101561399957805185526001959095019493860193860161397b565b5098975050505050505050565b6000602082840312156139b7578081fd5b8151801515811461100c578182fd5b6000806000606084860312156139da578283fd5b6139e384613801565b92506139f160208501613801565b91506139ff6040850161381d565b90509250925092565b60008060008060808587031215613a1d578081fd5b613a2685613801565b9350613a3460208601613801565b9250613a426040860161381d565b6060959095015193969295505050565b600060208284031215613a63578081fd5b5035919050565b600060208284031215613a7b578081fd5b5051919050565b600080600060608486031215613a96578283fd5b833592506020840135613aa881614147565b91506040840135613ab881614147565b809150509250925092565b60008060408385031215613ad5578182fd5b50508035926020909101359150565b600060208284031215613af5578081fd5b815160ff8116811461100c578182fd5b6000815180845260208085019450808401835b83811015613b3d5781516001600160a01b031687529582019590820190600101613b18565b509495945050505050565b60008251613b5a8184602087016140ef565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b60018060a01b038516815260006020858184015260806040840152613ba56080840186613b05565b8381036060850152845180825282860191830190845b81811015613bd757835183529284019291840191600101613bbb565b50909998505050505050505050565b6001600160a01b0392909216825263ffffffff16602082015260400190565b6020815260008251806020840152613c248160408501602087016140ef565b601f01601f19169190910160400192915050565b60208082526022908201527f537761704f70657261746f723a206173736574206973206e6f7420656e61626c604082015261195960f21b606082015260800190565b60208082526022908201527f537761704f70657261746f723a2062616c616e63654265666f7265203e3d206d60408201526134b760f11b606082015260800190565b60208082526025908201527f537761704f70657261746f723a20696e73756666696369656e74206574686572604082015264081b19599d60da1b606082015260800190565b60208082526029908201527f537761704f70657261746f723a2065786365656473206d6178207472616461626040820152681b1948185b5bdd5b9d60ba1b606082015260800190565b6020808252818101527f537761704f70657261746f723a206e6f742073776170436f6e74726f6c6c6572604082015260600190565b60208082526026908201527f537761704f70657261746f723a20616d6f756e744f7574203c20616d6f756e7460408201526527baba26b4b760d11b606082015260800190565b6020808252818101527f537761704f70657261746f723a2062616c616e63654166746572203e206d6178604082015260600190565b60208082526030908201527f537761704f70657261746f723a20616d6f756e744f75744d696e203c206d696e60408201526f4f75744f6e4d6178536c69707061676560801b606082015260800190565b60208082526028908201527f537761704f70657261746f723a20696e76616c69642064656e6f6d696e6174696040820152671bdb88185cdcd95d60c21b606082015260800190565b60208082526016908201527514ddd85c13dc195c985d1bdc8e881d1bdbc819985cdd60521b604082015260600190565b60208082526025908201527f537761704f70657261746f723a20746f6b656e42616c616e63654166746572206040820152641e1036b4b760d91b606082015260800190565b8281526040602082015260006136986040830184613b05565b848152608060208201526000613f396080830186613b05565b6001600160a01b03949094166040830152506060015292915050565b85815284602082015260a060408201526000613f7460a0830186613b05565b6001600160a01b0394909416606083015250608001529392505050565b60008219821115613fa457613fa461411b565b500190565b600082613fc457634e487b7160e01b81526012600452602481fd5b500490565b600181815b80851115614004578160001904821115613fea57613fea61411b565b80851615613ff757918102915b93841c9390800290613fce565b509250929050565b600061100c60ff841683600082614025575060016140b3565b81614032575060006140b3565b816001811461404857600281146140525761406e565b60019150506140b3565b60ff8411156140635761406361411b565b50506001821b6140b3565b5060208310610133831016604e8410600b8410161715614091575081810a6140b3565b61409b8383613fc9565b80600019048211156140af576140af61411b565b0290505b92915050565b60008160001904831182151516156140d3576140d361411b565b500290565b6000828210156140ea576140ea61411b565b500390565b60005b8381101561410a5781810151838201526020016140f2565b838111156112545750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461415c57600080fd5b5056fea078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeea264697066735822122055f8ad6a13693c899520837aa6e8db0f48a30947289e17f1a6873ccb30dff88e64736f6c6343000804003300000000000000000000000001bfd82675dbcc7762c84019ca518e701c0cd07e000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8400000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd0000000000000000000000007c728cd0cfa92401e01a4849a01b57ee53f5b2b9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x6080604052600436106101185760003560e01c80639043292a116100a0578063ddf403aa11610064578063ddf403aa14610353578063e0dc77c214610387578063f2030f34146103bb578063f887ea40146103db578063ffa6de3a1461040357600080fd5b80639043292a14610272578063b01a86ab146102a6578063c1fe3e48146102da578063d77b2a7c1461030e578063d8ecf9e11461033857600080fd5b8063468c5300116100e7578063468c5300146101db57806349386d87146101fb578063616c756a1461021b578063644595f0146102305780638322fff21461025057600080fd5b806309053ac414610124578063112677841461014657806311a9992e146101665780633fc8cef31461018f57600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b5061014461013f36600461384d565b610423565b005b34801561015257600080fd5b506101446101613660046138b2565b6106b1565b34801561017257600080fd5b5061017c61025881565b6040519081526020015b60405180910390f35b34801561019b57600080fd5b506101c37f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b039091168152602001610186565b3480156101e757600080fd5b506101446101f6366004613a52565b61092b565b34801561020757600080fd5b5061017c610216366004613a82565b610eab565b34801561022757600080fd5b50610144611013565b34801561023c57600080fd5b5061014461024b366004613ac3565b61125a565b34801561025c57600080fd5b506101c360008051602061418083398151915281565b34801561027e57600080fd5b506101c37f000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c81565b3480156102b257600080fd5b506101c37f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd81565b3480156102e657600080fd5b506101c37f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b34801561031a57600080fd5b506001546103289060ff1681565b6040519015158152602001610186565b34801561034457600080fd5b5061017c66354a6ba7a1800081565b34801561035f57600080fd5b506101c37f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f81565b34801561039357600080fd5b506101c37f0000000000000000000000007c728cd0cfa92401e01a4849a01b57ee53f5b2b981565b3480156103c757600080fd5b506101446103d6366004613ac3565b611bc4565b3480156103e757600080fd5b506101c3737a250d5630b4cf539739df2c5dacb4c659f2488d81565b34801561040f57600080fd5b5061014461041e3660046138b2565b612498565b336001600160a01b037f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f16146104745760405162461bcd60e51b815260040161046b90613d4a565b60405180910390fd5b6040516370a0823160e01b815230600482015282906000906001600160a01b038316906370a082319060240160206040518083038186803b1580156104b857600080fd5b505afa1580156104cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f09190613a6a565b9050600081116105425760405162461bcd60e51b815260206004820152601960248201527f537761704f70657261746f723a2042616c616e6365203d203000000000000000604482015260640161046b565b600061054c612775565b604051639c9b645160e01b81526001600160a01b038781166004830152919250600091829190841690639c9b64519060240160806040518083038186803b15801561059657600080fd5b505afa1580156105aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ce9190613a08565b505091509150816001600160701b031660001480156105f457506001600160701b038116155b156106835760405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb906106279089908890600401613b64565b602060405180830381600087803b15801561064157600080fd5b505af1158015610655573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067991906139a6565b5050505050505050565b60405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb906106279086908890600401613b64565b336001600160a01b037f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f16146106f95760405162461bcd60e51b815260040161046b90613d4a565b6000610703612775565b604051639c9b645160e01b81526001600160a01b03868116600483015291925060009182918291829190861690639c9b64519060240160806040518083038186803b15801561075157600080fd5b505afa158015610765573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107899190613a08565b935093509350935060006040518060800160405280866001600160701b03168152602001856001600160701b031681526020018463ffffffff1681526020018381525090506107d781612818565b6107f35760405162461bcd60e51b815260040161046b90613c38565b60405163013ea14360e21b81526001600160a01b038716906304fa850c90610821908c908c90600401613b64565b600060405180830381600087803b15801561083b57600080fd5b505af115801561084f573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b0389169250637ad32bee9150610881908c904290600401613be6565b600060405180830381600087803b15801561089b57600080fd5b505af11580156108af573d6000803e3d6000fd5b5050505060006108c1828b8b8b612845565b90506108dc6000805160206141808339815191528883612e88565b604080518a815260208101839052600080516020614180833981519152916001600160a01b038d169160008051602061416083398151915291015b60405180910390a350505050505050505050565b336001600160a01b037f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f16146109735760405162461bcd60e51b815260040161046b90613d4a565b600061097d612775565b604051639c9b645160e01b81526001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8481811660048401529293506000918291851690639c9b64519060240160806040518083038186803b1580156109e757600080fd5b505afa1580156109fb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1f9190613a08565b505091509150816001600160701b03166000148015610a4557506001600160701b038116155b15610a625760405162461bcd60e51b815260040161046b90613c38565b6000612710861115610a7d57610a7a612710876140d8565b90505b6040516370a0823160e01b81526001600160a01b038681166004830152600091908616906370a082319060240160206040518083038186803b158015610ac257600080fd5b505afa158015610ad6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afa9190613a6a565b60405163013ea14360e21b81529091506001600160a01b038716906304fa850c90610b3990600080516020614180833981519152908b90600401613b64565b600060405180830381600087803b158015610b5357600080fd5b505af1158015610b67573d6000803e3d6000fd5b505050506000856001600160a01b03168860405160006040518083038185875af1925050503d8060008114610bb8576040519150601f19603f3d011682016040523d82523d6000602084013e610bbd565b606091505b5050905080610c1a5760405162461bcd60e51b815260206004820152602360248201527f537761704f70657261746f723a207374457468207472616e73666572206661696044820152621b195960ea1b606482015260840161046b565b604051633d6995f760e11b81526001600160a01b03881690637ad32bee90610c489089904290600401613be6565b600060405180830381600087803b158015610c6257600080fd5b505af1158015610c76573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03891691506370a082319060240160206040518083038186803b158015610cbc57600080fd5b505afa158015610cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf49190613a6a565b905083811015610d165760405162461bcd60e51b815260040161046b90613d7f565b856001600160701b03168310610d3e5760405162461bcd60e51b815260040161046b90613c7a565b6001600160701b038516610d528585613f91565b1115610d705760405162461bcd60e51b815260040161046b90613dc5565b6000886001600160a01b0316319050886001600160a01b0316630bb76fff6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610dba57600080fd5b505af1158015610dce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df29190613a6a565b811015610e115760405162461bcd60e51b815260040161046b90613cbc565b50610e3d7f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe848983612e88565b604080518a8152602081018390526001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8416916000805160206141808339815191529160008051602061416083398151915291015b60405180910390a3505050505050505050565b604080516002808252606082018352600092839291906020830190803683370190505090508381600081518110610ef257634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250508281600181518110610f3457634e487b7160e01b600052603260045260246000fd5b6001600160a01b039092166020928302919091019091015260405163d06ca61f60e01b8152600090737a250d5630b4cf539739df2c5dacb4c659f2488d9063d06ca61f90610f889089908690600401613f07565b60006040518083038186803b158015610fa057600080fd5b505afa158015610fb4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fdc91908101906138e6565b905080600181518110610fff57634e487b7160e01b600052603260045260246000fd5b6020026020010151925050505b9392505050565b336001600160a01b037f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f161461105b5760405162461bcd60e51b815260040161046b90613d4a565b6901b1ae4d6e2ef500000073586b9b2f8010b284a0197f392156f1a7eb5e86e96361a2c6804281116110dd5760405162461bcd60e51b815260206004820152602560248201527f537761704f70657261746f723a2074686520646561646c696e65206861732070604482015264185cdcd95960da1b606482015260840161046b565b60015460ff16156111305760405162461bcd60e51b815260206004820152601e60248201527f537761704f70657261746f723a20616c72656164792065786563757465640000604482015260640161046b565b6001805460ff191681179055611144612775565b6001600160a01b03166304fa850c600080516020614180833981519152856040518363ffffffff1660e01b815260040161117f929190613b64565b600060405180830381600087803b15801561119957600080fd5b505af11580156111ad573d6000803e3d6000fd5b505050506000826001600160a01b03168460405160006040518083038185875af1925050503d80600081146111fe576040519150601f19603f3d011682016040523d82523d6000602084013e611203565b606091505b50509050806112545760405162461bcd60e51b815260206004820152601d60248201527f537761704f70657261746f723a207472616e73666572206661696c6564000000604482015260640161046b565b50505050565b336001600160a01b037f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f16146112a25760405162461bcd60e51b815260040161046b90613d4a565b60006112ac612775565b6040516370a0823160e01b81526001600160a01b0380831660048301529192507f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd91600091908316906370a082319060240160206040518083038186803b15801561131657600080fd5b505afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e9190613a6a565b604051639c9b645160e01b81526001600160a01b03848116600483015291925060009182918291829190881690639c9b64519060240160806040518083038186803b15801561139c57600080fd5b505afa1580156113b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d49190613a08565b9350935093509350836001600160701b031660001480156113fc57506001600160701b038316155b156114195760405162461bcd60e51b815260040161046b90613c38565b600061142b63ffffffff8416426140d8565b9050610258811161144e5760405162461bcd60e51b815260040161046b90613e92565b604051633ba6b85160e01b81526001600160a01b037f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd8116600483015260009182917f0000000000000000000000007c728cd0cfa92401e01a4849a01b57ee53f5b2b91690633ba6b851906024016040805180830381600087803b1580156114d557600080fd5b505af11580156114e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150d9190613885565b925090507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b039081169082161461155d5760405162461bcd60e51b815260040161046b90613e4a565b506000886001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d19190613ae4565b6115dc90600a61400c565b6115e6838e6140b9565b6115f09190613fa9565b90506000670de0b6b3a764000061160786846140b9565b6116119190613fa9565b9050600061161f82846140d8565b9050808d10156116415760405162461bcd60e51b815260040161046b90613dfa565b876001600160701b03168a116116a45760405162461bcd60e51b815260206004820152602260248201527f537761704f70657261746f723a2062616c616e63654265666f7265203c3d206d6044820152610c2f60f31b606482015260840161046b565b6001600160701b0389166116b88f8c6140d8565b10156116d65760405162461bcd60e51b815260040161046b90613ec2565b505050505050505050826001600160a01b03166304fa850c83876040518363ffffffff1660e01b815260040161170d929190613b64565b600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b5050505060007f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd6001600160a01b0316635a53e3486040518163ffffffff1660e01b815260040160206040518083038186803b15801561179a57600080fd5b505afa1580156117ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d29190613831565b60405163095ea7b360e01b81529091506001600160a01b0384169063095ea7b3906118039084908a90600401613b64565b602060405180830381600087803b15801561181d57600080fd5b505af1158015611831573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185591906139a6565b506040805160018082528183019092526000916020808301908036833750506040805160018082528183019092529293506000929150602080830190803683370190505090507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2826000815181106118dd57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250506127108160008151811061192157634e487b7160e01b600052603260045260246000fd5b6020908102919091010152604051633462fcc160e01b81526001600160a01b03841690633462fcc19061195e9030908c9087908790600401613b7d565b600060405180830381600087803b15801561197857600080fd5b505af115801561198c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119b491908101906138e6565b506040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a082319060240160206040518083038186803b158015611a1757600080fd5b505afa158015611a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4f9190613a6a565b604051632e1a7d4d60e01b8152600481018290529091507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611ab457600080fd5b505af1158015611ac8573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b038a169250637ad32bee9150611afa9089904290600401613be6565b600060405180830381600087803b158015611b1457600080fd5b505af1158015611b28573d6000803e3d6000fd5b5050505087811015611b4c5760405162461bcd60e51b815260040161046b90613d7f565b611b656000805160206141808339815191528883612e88565b604080518a815260208101839052600080516020614180833981519152917f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd6001600160a01b0316916000805160206141608339815191529101610e98565b336001600160a01b037f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f1614611c0c5760405162461bcd60e51b815260040161046b90613d4a565b6000611c16612775565b905060007f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd6001600160a01b0316635a53e3486040518163ffffffff1660e01b815260040160206040518083038186803b158015611c7357600080fd5b505afa158015611c87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cab9190613831565b604051639c9b645160e01b81526001600160a01b037f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd8181166004840152929350600091829182918291881690639c9b64519060240160806040518083038186803b158015611d1957600080fd5b505afa158015611d2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d519190613a08565b9350935093509350836001600160701b03166000148015611d7957506001600160701b038316155b15611d965760405162461bcd60e51b815260040161046b90613c38565b6000611da863ffffffff8416426140d8565b90506102588111611dcb5760405162461bcd60e51b815260040161046b90613e92565b50604051633ba6b85160e01b81526001600160a01b037f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd811660048301526000917f0000000000000000000000007c728cd0cfa92401e01a4849a01b57ee53f5b2b990911690633ba6b851906024016040805180830381600087803b158015611e5357600080fd5b505af1158015611e67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8b9190613885565b91506000905081611ea48c670de0b6b3a76400006140b9565b611eae9190613fa9565b90506000670de0b6b3a7640000611ec585846140b9565b611ecf9190613fa9565b90506000611edd82846140d8565b9050808c1015611eff5760405162461bcd60e51b815260040161046b90613dfa565b50506040516370a0823160e01b81526001600160a01b038a8116600483015260009350881691506370a082319060240160206040518083038186803b158015611f4757600080fd5b505afa158015611f5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7f9190613a6a565b60405163013ea14360e21b81529091506001600160a01b038916906304fa850c90611fbe90600080516020614180833981519152908e90600401613b64565b600060405180830381600087803b158015611fd857600080fd5b505af1158015611fec573d6000803e3d6000fd5b505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316876001600160a01b031663e269c3d66040518163ffffffff1660e01b815260040160206040518083038186803b15801561205357600080fd5b505afa158015612067573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208b9190613831565b6001600160a01b0316146120b15760405162461bcd60e51b815260040161046b90613e4a565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db08b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561210c57600080fd5b505af1158015612120573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063095ea7b3925061217391508a908e90600401613b64565b600060405180830381600087803b15801561218d57600080fd5b505af11580156121a1573d6000803e3d6000fd5b5050604051635f75e2ed60e11b8152600481018d9052602481018c90526001600160a01b038a16925063beebc5da9150604401600060405180830381600087803b1580156121ee57600080fd5b505af1158015612202573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b038b169250637ad32bee91506122349089904290600401613be6565b600060405180830381600087803b15801561224e57600080fd5b505af1158015612262573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03891691506370a082319060240160206040518083038186803b1580156122a857600080fd5b505afa1580156122bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e09190613a6a565b9050898110156123025760405162461bcd60e51b815260040161046b90613d7f565b856001600160701b0316821061232a5760405162461bcd60e51b815260040161046b90613c7a565b6001600160701b03851661233e8b84613f91565b111561235c5760405162461bcd60e51b815260040161046b90613dc5565b6000896001600160a01b0316319050896001600160a01b0316630bb76fff6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123de9190613a6a565b8110156123fd5760405162461bcd60e51b815260040161046b90613cbc565b506124297f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd8a83612e88565b604080518c8152602081018390526001600160a01b037f00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd169160008051602061418083398151915291600080516020614160833981519152910160405180910390a35050505050505050505050565b336001600160a01b037f000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f16146124e05760405162461bcd60e51b815260040161046b90613d4a565b60006124ea612775565b604051639c9b645160e01b81526001600160a01b03868116600483015291925060009182918291829190861690639c9b64519060240160806040518083038186803b15801561253857600080fd5b505afa15801561254c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125709190613a08565b935093509350935060006040518060800160405280866001600160701b03168152602001856001600160701b031681526020018463ffffffff1681526020018381525090506125be81612818565b6125da5760405162461bcd60e51b815260040161046b90613c38565b60405163013ea14360e21b81526001600160a01b038716906304fa850c9061261690600080516020614180833981519152908c90600401613b64565b600060405180830381600087803b15801561263057600080fd5b505af1158015612644573d6000803e3d6000fd5b5050604051633d6995f760e11b81526001600160a01b0389169250637ad32bee9150612676908c904290600401613be6565b600060405180830381600087803b15801561269057600080fd5b505af11580156126a4573d6000803e3d6000fd5b505050506000612729828b8b8b8b6001600160a01b0316630bb76fff6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156126ec57600080fd5b505af1158015612700573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127249190613a6a565b612f69565b90506127368a8883612e88565b604080518a8152602081018390526001600160a01b038c1691600080516020614180833981519152916000805160206141608339815191529101610917565b6040516227050b60e31b815261503160f01b60048201526000907f00000000000000000000000001bfd82675dbcc7762c84019ca518e701c0cd07e6001600160a01b03169063013828589060240160206040518083038186803b1580156127db57600080fd5b505afa1580156127ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128139190613831565b905090565b80516000906001600160701b031615801561283e575060208201516001600160701b0316155b1592915050565b600080612850612775565b6040516370a0823160e01b81526001600160a01b0380831660048301529192506000918691908816906370a082319060240160206040518083038186803b15801561289a57600080fd5b505afa1580156128ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d29190613a6a565b6128dc9190613f91565b60408801519091507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2906000906129199063ffffffff16426140d8565b9050610258811161293c5760405162461bcd60e51b815260040161046b90613e92565b506040516396ed28f960e01b81526001600160a01b03888116600483015282811660248301526000917f000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c909116906396ed28f99060440160206040518083038186803b1580156129ab57600080fd5b505afa1580156129bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e39190613831565b90506000819050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612a2657600080fd5b505afa158015612a3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a5e91906139c6565b50915091506000856001600160a01b03168c6001600160a01b031610612a845781612a86565b825b6001600160701b031690506000670de0b6b3a7640000612aad66354a6ba7a18000846140b9565b612ab79190613fa9565b9050808c1115612ad95760405162461bcd60e51b815260040161046b90613d01565b5050604051632321bc7960e21b81526001600160a01b038c81166004830152602482018c90528681166044830152600095507f000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c169350638c86f1e49250606401905060206040518083038186803b158015612b5357600080fd5b505afa158015612b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8b9190613a6a565b90506000670de0b6b3a76400008a6060015183612ba891906140b9565b612bb29190613fa9565b90506000612bc082846140d8565b8b5160208d01519192506001600160701b039081169116828a1015612bf75760405162461bcd60e51b815260040161046b90613dfa565b808711612c565760405162461bcd60e51b815260206004820152602760248201527f537761704f70657261746f723a20746f6b656e42616c616e63654265666f7265604482015266040787a40dac2f60cb1b606482015260840161046b565b81612c618c896140d8565b1015612c7f5760405162461bcd60e51b815260040161046b90613ec2565b506000935060029250612c90915050565b604051908082528060200260200182016040528015612cb9578160200160208202803683370190505b5090508781600081518110612cde57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110612d4057634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201015260405163095ea7b360e01b81529089169063095ea7b390612d9190737a250d5630b4cf539739df2c5dacb4c659f2488d908b90600401613b64565b602060405180830381600087803b158015612dab57600080fd5b505af1158015612dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de391906139a6565b506040516318cbafe560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d906318cbafe590612e23908a908a90869030904290600401613f55565b600060405180830381600087803b158015612e3d57600080fd5b505af1158015612e51573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7991908101906138e6565b50479998505050505050505050565b6001600160a01b0383166000805160206141808339815191521415612f54576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612ef4576040519150601f19603f3d011682016040523d82523d6000602084013e612ef9565b606091505b50509050806112545760405162461bcd60e51b815260206004820152602160248201527f537761704f70657261746f723a20457468207472616e73666572206661696c656044820152601960fa1b606482015260840161046b565b826112546001600160a01b038216848461355c565b600080612f74612775565b6040516370a0823160e01b81526001600160a01b0380831660048301529192506000918816906370a082319060240160206040518083038186803b158015612fbb57600080fd5b505afa158015612fcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff39190613a6a565b60408901519091507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2906000906130309063ffffffff16426140d8565b905061025881116130535760405162461bcd60e51b815260040161046b90613e92565b506040516396ed28f960e01b81526001600160a01b03828116600483015289811660248301526000917f000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c909116906396ed28f99060440160206040518083038186803b1580156130c257600080fd5b505afa1580156130d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130fa9190613831565b90506000819050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561313d57600080fd5b505afa158015613151573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317591906139c6565b509150915060008c6001600160a01b0316866001600160a01b03161061319b578161319d565b825b6001600160701b031690506000670de0b6b3a76400006131c466354a6ba7a18000846140b9565b6131ce9190613fa9565b9050808d11156131f05760405162461bcd60e51b815260040161046b90613d01565b5050506001600160a01b0386163192505050858110156132225760405162461bcd60e51b815260040161046b90613cbc565b50604051632321bc7960e21b81526001600160a01b0382811660048301526024820189905289811660448301526000917f000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c90911690638c86f1e49060640160206040518083038186803b15801561329857600080fd5b505afa1580156132ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d09190613a6a565b90506000670de0b6b3a76400008b60600151836132ed91906140b9565b6132f79190613fa9565b9050600061330582846140d8565b8c5160208e01519192506001600160701b039081169116828b101561333c5760405162461bcd60e51b815260040161046b90613dfa565b81871061335b5760405162461bcd60e51b815260040161046b90613c7a565b806133668c89613f91565b11156133845760405162461bcd60e51b815260040161046b90613dc5565b506000935060029250613395915050565b6040519080825280602002602001820160405280156133be578160200160208202803683370190505b50905081816000815181106133e357634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b031681525050888160018151811061342557634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390921660209283029190910190910152604051637ff36ab560e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d90637ff36ab5908a9061347c908b90869030904290600401613f20565b6000604051808303818588803b15801561349557600080fd5b505af11580156134a9573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526134d291908101906138e6565b506040516370a0823160e01b81523060048201526000906001600160a01b038b16906370a082319060240160206040518083038186803b15801561351557600080fd5b505afa158015613529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354d9190613a6a565b9b9a5050505050505050505050565b6135b28363a9059cbb60e01b848460405160240161357b929190613b64565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526135b7565b505050565b600061360c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166136899092919063ffffffff16565b8051909150156135b2578080602001905181019061362a91906139a6565b6135b25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161046b565b606061369884846000856136a0565b949350505050565b6060824710156137015760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161046b565b843b61374f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161046b565b600080866001600160a01b0316858760405161376b9190613b48565b60006040518083038185875af1925050503d80600081146137a8576040519150601f19603f3d011682016040523d82523d6000602084013e6137ad565b606091505b50915091506137bd8282866137c8565b979650505050505050565b606083156137d757508161100c565b8251156137e75782518084602001fd5b8160405162461bcd60e51b815260040161046b9190613c05565b80516001600160701b038116811461381857600080fd5b919050565b805163ffffffff8116811461381857600080fd5b600060208284031215613842578081fd5b815161100c81614147565b6000806040838503121561385f578081fd5b823561386a81614147565b9150602083013561387a81614147565b809150509250929050565b60008060408385031215613897578182fd5b82516138a281614147565b6020939093015192949293505050565b6000806000606084860312156138c6578081fd5b83356138d181614147565b95602085013595506040909401359392505050565b600060208083850312156138f8578182fd5b825167ffffffffffffffff8082111561390f578384fd5b818501915085601f830112613922578384fd5b81518181111561393457613934614131565b8060051b604051601f19603f8301168101818110858211171561395957613959614131565b604052828152858101935084860182860187018a1015613977578788fd5b8795505b8386101561399957805185526001959095019493860193860161397b565b5098975050505050505050565b6000602082840312156139b7578081fd5b8151801515811461100c578182fd5b6000806000606084860312156139da578283fd5b6139e384613801565b92506139f160208501613801565b91506139ff6040850161381d565b90509250925092565b60008060008060808587031215613a1d578081fd5b613a2685613801565b9350613a3460208601613801565b9250613a426040860161381d565b6060959095015193969295505050565b600060208284031215613a63578081fd5b5035919050565b600060208284031215613a7b578081fd5b5051919050565b600080600060608486031215613a96578283fd5b833592506020840135613aa881614147565b91506040840135613ab881614147565b809150509250925092565b60008060408385031215613ad5578182fd5b50508035926020909101359150565b600060208284031215613af5578081fd5b815160ff8116811461100c578182fd5b6000815180845260208085019450808401835b83811015613b3d5781516001600160a01b031687529582019590820190600101613b18565b509495945050505050565b60008251613b5a8184602087016140ef565b9190910192915050565b6001600160a01b03929092168252602082015260400190565b60018060a01b038516815260006020858184015260806040840152613ba56080840186613b05565b8381036060850152845180825282860191830190845b81811015613bd757835183529284019291840191600101613bbb565b50909998505050505050505050565b6001600160a01b0392909216825263ffffffff16602082015260400190565b6020815260008251806020840152613c248160408501602087016140ef565b601f01601f19169190910160400192915050565b60208082526022908201527f537761704f70657261746f723a206173736574206973206e6f7420656e61626c604082015261195960f21b606082015260800190565b60208082526022908201527f537761704f70657261746f723a2062616c616e63654265666f7265203e3d206d60408201526134b760f11b606082015260800190565b60208082526025908201527f537761704f70657261746f723a20696e73756666696369656e74206574686572604082015264081b19599d60da1b606082015260800190565b60208082526029908201527f537761704f70657261746f723a2065786365656473206d6178207472616461626040820152681b1948185b5bdd5b9d60ba1b606082015260800190565b6020808252818101527f537761704f70657261746f723a206e6f742073776170436f6e74726f6c6c6572604082015260600190565b60208082526026908201527f537761704f70657261746f723a20616d6f756e744f7574203c20616d6f756e7460408201526527baba26b4b760d11b606082015260800190565b6020808252818101527f537761704f70657261746f723a2062616c616e63654166746572203e206d6178604082015260600190565b60208082526030908201527f537761704f70657261746f723a20616d6f756e744f75744d696e203c206d696e60408201526f4f75744f6e4d6178536c69707061676560801b606082015260800190565b60208082526028908201527f537761704f70657261746f723a20696e76616c69642064656e6f6d696e6174696040820152671bdb88185cdcd95d60c21b606082015260800190565b60208082526016908201527514ddd85c13dc195c985d1bdc8e881d1bdbc819985cdd60521b604082015260600190565b60208082526025908201527f537761704f70657261746f723a20746f6b656e42616c616e63654166746572206040820152641e1036b4b760d91b606082015260800190565b8281526040602082015260006136986040830184613b05565b848152608060208201526000613f396080830186613b05565b6001600160a01b03949094166040830152506060015292915050565b85815284602082015260a060408201526000613f7460a0830186613b05565b6001600160a01b0394909416606083015250608001529392505050565b60008219821115613fa457613fa461411b565b500190565b600082613fc457634e487b7160e01b81526012600452602481fd5b500490565b600181815b80851115614004578160001904821115613fea57613fea61411b565b80851615613ff757918102915b93841c9390800290613fce565b509250929050565b600061100c60ff841683600082614025575060016140b3565b81614032575060006140b3565b816001811461404857600281146140525761406e565b60019150506140b3565b60ff8411156140635761406361411b565b50506001821b6140b3565b5060208310610133831016604e8410600b8410161715614091575081810a6140b3565b61409b8383613fc9565b80600019048211156140af576140af61411b565b0290505b92915050565b60008160001904831182151516156140d3576140d361411b565b500290565b6000828210156140ea576140ea61411b565b500390565b60005b8381101561410a5781810151838201526020016140f2565b838111156112545750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461415c57600080fd5b5056fea078c4190abe07940190effc1846be0ccf03ad6007bc9e93f9697d0b460befbb000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeea264697066735822122055f8ad6a13693c899520837aa6e8db0f48a30947289e17f1a6873ccb30dff88e64736f6c63430008040033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000001bfd82675dbcc7762c84019ca518e701c0cd07e000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8400000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd0000000000000000000000007c728cd0cfa92401e01a4849a01b57ee53f5b2b9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : _master (address): 0x01BFd82675DBCc7762C84019cA518e701C0cD07e
Arg [1] : _twapOracle (address): 0xcafea1C9f94e077DF44D95c4A1ad5a5747a18b5C
Arg [2] : _swapController (address): 0x551D5500F613a4beC77BA8B834b5eEd52ad5764f
Arg [3] : _stETH (address): 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84
Arg [4] : _enzymeV4VaultProxyAddress (address): 0x27F23c710dD3d878FE9393d93465FeD1302f2EbD
Arg [5] : _enzymeFundValueCalculatorRouter (address): 0x7c728cd0CfA92401E01A4849a01b57EE53F5b2b9
Arg [6] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 00000000000000000000000001bfd82675dbcc7762c84019ca518e701c0cd07e
Arg [1] : 000000000000000000000000cafea1c9f94e077df44d95c4a1ad5a5747a18b5c
Arg [2] : 000000000000000000000000551d5500f613a4bec77ba8b834b5eed52ad5764f
Arg [3] : 000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84
Arg [4] : 00000000000000000000000027f23c710dd3d878fe9393d93465fed1302f2ebd
Arg [5] : 0000000000000000000000007c728cd0cfa92401e01a4849a01b57ee53f5b2b9
Arg [6] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.