Contract 0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa1 3

 
 
Txn Hash
Method
Block
From
To
Value [Txn Fee]
0xe3e48f092dc6d4ae5fd24e60ef5909b8e0b11a71d2d99cf74c0d441d77f0ad89Zap Into382546192023-01-19 2:59:34248 days 13 hrs ago0xabae1d588942f41304cf718ab8d34877b11f18db IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.038327589311 40.574697191
0x86e1487f82c29b271b49849e199e06537670288eb2ae6d9d7a9abdddfa94fdf2Zap Out Lp382506292023-01-19 0:35:53248 days 16 hrs ago0xabae1d588942f41304cf718ab8d34877b11f18db IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.103163936326 51.402342677
0x68118568b7ffac4dda6a063bbaba4225cf0208e0a1d233ce1cafb97776b480d4Zap Out382505992023-01-19 0:34:49248 days 16 hrs ago0xabae1d588942f41304cf718ab8d34877b11f18db IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.054076676472 57.554584931
0x9c6b8145f11767320c3854a7921a33e72acc307acc241482663b0e0581fd8414Zap Out382050032023-01-17 20:28:14249 days 20 hrs ago0x7564b369e4138f6f7d9a3786368ecb125bb07fbb IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.069979581036 57.760087884
0x7fe64a4230620f32f27aa9e4f5ba5e12364214ff01eda6829cc5780fabd7d1e4Zap Out381634032023-01-16 19:47:13250 days 20 hrs ago0x791b2f2ae169b5d5143d73b0c4b723b884335ebc IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.040541761356 41.928244547
0xbf00b99b05c86680ef7ded99fd50ca2540104896719a2bc40e5338cfd2b115a8Zap Out Lp381209712023-01-15 19:13:55251 days 21 hrs ago0x3351b913d9b37abbbfc057224aa38547f485cbed IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.05303797239
0x3f7cd3eec6fbbdcb16d9ef4faef7c331cc8c994e0a0f6063ba6ae5233941af71Zap Into381197042023-01-15 18:30:13251 days 22 hrs ago0x7e7f686264adde643a296c7649452752c102afff IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.050930353457 41.799948834
0x0fe639ee3cc10c2f590b4cbc0f0c6e1364562fbba4183b0243c2832894650935Zap Out380258372023-01-13 12:21:28254 days 4 hrs ago0xdfde5804789e1b4170e22442a9cf2ca40527eb97 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.071366082732 42.757864525
0x0b8dae0b05af7474198e8a5cfd418b1e6f7498eb7d1ef207f6e87dba158afbd9Zap Out Lp380246872023-01-13 11:41:56254 days 4 hrs ago0xdfde5804789e1b4170e22442a9cf2ca40527eb97 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.060920068806 44.795881024
0x2556996ee57245413b7003ec2746c65bdf4afc8cc471987827cfeecd33a54f97Zap Out380245462023-01-13 11:37:06254 days 4 hrs ago0xa74fb268a35ddf30e0b987fec3ca068930e88697 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.069277004365 44.478332482
0x08eb7887289a9e3bf51a5075b8d496c4f5ebc96a3d1b56189edb5ef8e0bf043bZap Out Lp380243632023-01-13 11:30:48254 days 5 hrs ago0xa74fb268a35ddf30e0b987fec3ca068930e88697 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.053687612028 39.412777112
0xb56ad3874fa5e25ae34544d19d44bdbbfc824ed85f3c4215a5d2482618c2b4ebZap Into380140502023-01-13 5:33:39254 days 11 hrs ago0x571a8c4c608911f0dd21f55e95c455310b4bfa5d IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.0435252 50
0x2ea2f2801220a7de51a268c9c9f64400936835f732bab930a8df5e0c35b83550Zap Out Lp378906022023-01-10 6:00:50257 days 10 hrs ago0xcb6af959f7e0b2b9e93b47687799db519cb45ed0 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.091610193373 44.315326208
0x173e5deabf5010d64e99a305525ff6ad297047d336d06a637c11783f99d90d12Zap Out378518912023-01-09 5:56:21258 days 10 hrs ago0xa47dd60513fe6bbda88935429273627b3dafabf9 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.038007121597 40.837354448
0x6fda3081c0cb18be09119f0d328ce279848704c2a4cdd9ffb7fee148f07be6b1Zap Into Lp377568142023-01-06 21:22:44260 days 19 hrs ago0xcb6af959f7e0b2b9e93b47687799db519cb45ed0 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.1219803872 49.949791242
0xd8083c1e73d96e78772f1b1a54bf09d55acde9d0469c69235ac15966e699ec7cZap Into Lp376477112023-01-04 3:50:48263 days 12 hrs ago0xcb6af959f7e0b2b9e93b47687799db519cb45ed0 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.168389807137 73.592601458
0x6c3d7f421788ec69bb96c30d546ec0f90d10363595c7611f5485e99b62b3ffd1Zap Into Lp376407042023-01-03 23:32:45263 days 17 hrs ago0xa52101d957d28b531a9ec374fd674c482cfc7a19 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.075585928656 41.73290532
0x852359f7bf662fdfd04c9752a85a9b545ce620f22e711d6433354730a574e39fZap Into Lp376360202023-01-03 20:47:21263 days 19 hrs ago0x76c8a1c74fdc88072f4582830ddbe588388c055b IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.087637887986 36.058386034
0x2dd99a363550435dd6f228b5795c535d0db19c1ca1a034412aafe1ee5bf2c0b9Zap Into Lp376347852023-01-03 20:02:47263 days 20 hrs ago0xc1c473d653a60836d4037300a0d3bc4898eb2a55 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.077811795853 36.840630596
0x018c7d7ca3ff2962716bdf9fc37cf235ec28109831e04a89ea2393357e78e290Zap Into Lp376081922023-01-03 4:12:29264 days 12 hrs ago0x2969610a02e5120e0947aa9241f1dd5840f2ccf6 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.068466500535 40.809666869
0x55d42dd1c5d66d647f7b3e7609ffeb11a9e852f144636cc38b3a579802013972Zap Into Lp376074482023-01-03 3:46:53264 days 12 hrs ago0x2969610a02e5120e0947aa9241f1dd5840f2ccf6 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.100406889755 40.852276974
0xd72188db8a57d5c149ae79aa1f63af9b77c8300e965a231e15ad239d68b5ef54Zap Out375811762023-01-02 12:19:57265 days 4 hrs ago0x8b9928379c26dd872af1e2ef73536194877a3f88 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.042765679386 47.887539009
0x850949616efd725969eeb94001b8ebf671e7ffb1f62ea31ca97611729522c190Zap Out Lp375722262023-01-02 6:50:44265 days 9 hrs ago0xc1c473d653a60836d4037300a0d3bc4898eb2a55 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.031577105064 34.472332887
0xf12285005548adb38923da0730ccb40695b8876d2342eb05bef7c16e4ff68f44Zap Out Lp375721032023-01-02 6:46:30265 days 9 hrs ago0xc1c473d653a60836d4037300a0d3bc4898eb2a55 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.008202725454 48.367693185
0x597ac34019b09d0993803a65e6c0cd889c0658330444539bfc5d87fc1ae106f7Zap Into Lp375630082023-01-02 1:18:09265 days 15 hrs ago0xcb6af959f7e0b2b9e93b47687799db519cb45ed0 IN  0x8e365e2f1cc56d9cd0eb3b0a00705d089ca1dfa10 MATIC0.088818833533 37.617629073
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ZapContract

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : ZapContract.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/
pragma solidity 0.8.4;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../../base/governance/Controllable.sol";
import "../../base/interface/ISmartVault.sol";
import "../../base/interface/IStrategy.sol";
import "../../base/interface/IController.sol";
import "../../third_party/uniswap/IUniswapV2Pair.sol";
import "../../third_party/uniswap/IUniswapV2Router02.sol";
import "../price/IPriceCalculator.sol";
import "./IMultiSwap.sol";

/// @title Dedicated solution for interacting with Tetu vaults.
///        Able to zap in/out assets to vaults
/// @author belbix
contract ZapContract is Controllable, ReentrancyGuard {
  using SafeMath for uint256;
  using SafeERC20 for IERC20;

  string public constant VERSION = "1.1.1";

  IMultiSwap public multiSwap;
  mapping(address => uint256) calls;

  struct ZapInfo {
    address lp;
    address tokenIn;
    address asset0;
    address[] asset0Route;
    address asset1;
    address[] asset1Route;
    uint256 tokenInAmount;
    uint256 slippageTolerance;
  }

  constructor(address _controller, address _multiSwap) {
    require(_multiSwap != address(0), "ZC: zero multiSwap address");
    Controllable.initializeControllable(_controller);
    multiSwap = IMultiSwap(_multiSwap);
  }

  modifier onlyOneCallPerBlock() {
    require(calls[msg.sender] < block.number, "ZC: call in the same block forbidden");
    _;
    calls[msg.sender] = block.number;
  }

  // ******************** USERS ACTIONS *********************

  /// @notice Approval for token is assumed.
  ///      Buy token and deposit to given vault
  ///      TokenIn should be declared as a keyToken in the PriceCalculator
  /// @param _vault A target vault for deposit
  /// @param _tokenIn This token will be swapped to required token for adding liquidity
  /// @param _asset Token address required for adding liquidity
  /// @param _assetRoute Pair addresses for buying asset0
  /// @param _tokenInAmount Amount of token for deposit
  /// @param slippageTolerance A number in 0-100 range that reflect is a percent of acceptable slippage
  function zapInto(
    address _vault,
    address _tokenIn,
    address _asset,
    address[] memory _assetRoute,
    uint256 _tokenInAmount,
    uint256 slippageTolerance
  ) external nonReentrant onlyOneCallPerBlock {
    require(_tokenInAmount > 1, "ZC: not enough amount");
    require(_asset == ISmartVault(_vault).underlying(), "ZC: asset is not underlying");

    IERC20(_tokenIn).safeTransferFrom(msg.sender, address(this), _tokenInAmount);

    // asset multi-swap
    callMultiSwap(
      _tokenIn,
      _tokenInAmount,
      _assetRoute,
      _asset,
      slippageTolerance
    );
    // assume that final outcome amount was checked on the multiSwap contract side

    uint256 assetAmount = IERC20(_asset).balanceOf(address(this));

    depositToVault(_vault, assetAmount, _asset);
  }

  /// @notice Approval for token is assumed.
  ///      Add liquidity and deposit to given vault with Uin pair underlying
  ///      TokenIn should be declared as a keyToken in the PriceCalculator
  /// @param _vault A target vault for deposit
  /// @param _tokenIn This token will be swapped to required token for adding liquidity
  /// @param _asset0 Token address required for adding liquidity
  /// @param _asset0Route Pair addresses for buying asset0
  /// @param _asset1 Token address required for adding liquidity
  /// @param _asset1Route Pair addresses for buying asset1
  /// @param _tokenInAmount Amount of token for deposit
  /// @param slippageTolerance A number in 0-100 range that reflect is a percent of acceptable slippage
  function zapIntoLp(
    address _vault,
    address _tokenIn,
    address _asset0,
    address[] memory _asset0Route,
    address _asset1,
    address[] memory _asset1Route,
    uint256 _tokenInAmount,
    uint256 slippageTolerance
  ) external nonReentrant onlyOneCallPerBlock {
    require(_tokenInAmount > 1, "ZC: not enough amount");

    IUniswapV2Pair lp = IUniswapV2Pair(ISmartVault(_vault).underlying());
    require(_asset0 == lp.token0() || _asset0 == lp.token1(), "ZC: asset 0 not exist in lp tokens");
    require(_asset1 == lp.token0() || _asset1 == lp.token1(), "ZC: asset 1 not exist in lp tokens");

    // transfer only require amount
    IERC20(_tokenIn).safeTransferFrom(msg.sender, address(this), _tokenInAmount.div(2).mul(2));

    // asset0 multi-swap
    callMultiSwap(
      _tokenIn,
      _tokenInAmount.div(2),
      _asset0Route,
      _asset0,
      slippageTolerance
    );

    // asset0 multi-swap
    callMultiSwap(
      _tokenIn,
      _tokenInAmount.div(2),
      _asset1Route,
      _asset1,
      slippageTolerance
    );
    // assume that final outcome amounts was checked on the multiSwap contract side

    uint256 liquidity = addLiquidity(
      ZapInfo(
        address(lp),
        _tokenIn,
        _asset0,
        _asset0Route,
        _asset1,
        _asset1Route,
        _tokenInAmount,
        slippageTolerance
      )
    );

    require(liquidity != 0, "ZC: zero liq");
    depositToVault(_vault, liquidity, address(lp));
  }

  /// @notice Approval for share token is assumed.
  ///         Withdraw from given vault underlying and sell tokens for given tokenOut
  /// @param _vault A target vault for withdraw
  /// @param _tokenOut This token will be a target for swaps
  /// @param _asset Token address required selling removed assets
  /// @param _assetRoute Pair addresses for selling asset0
  /// @param _shareTokenAmount Amount of share token for withdraw
  /// @param slippageTolerance A number in 0-100 range that reflect is a percent of acceptable slippage
  function zapOut(
    address _vault,
    address _tokenOut,
    address _asset,
    address[] memory _assetRoute,
    uint256 _shareTokenAmount,
    uint256 slippageTolerance
  ) external nonReentrant onlyOneCallPerBlock {
    require(_shareTokenAmount != 0, "ZC: zero amount");
    require(_asset == ISmartVault(_vault).underlying(), "ZC: asset is not underlying");

    IERC20(_vault).safeTransferFrom(msg.sender, address(this), _shareTokenAmount);

    uint256 assetBalance = withdrawFromVault(_vault, _asset, _shareTokenAmount);

    // asset multi-swap
    callMultiSwap(
      _asset,
      assetBalance,
      _assetRoute,
      _tokenOut,
      slippageTolerance
    );

    uint256 tokenOutBalance = IERC20(_tokenOut).balanceOf(address(this));
    require(tokenOutBalance != 0, "zero token out balance");
    IERC20(_tokenOut).safeTransfer(msg.sender, tokenOutBalance);
  }

  /// @notice Approval for share token is assumed.
  ///      Withdraw from given vault underlying, remove liquidity and sell tokens for given tokenOut
  /// @param _vault A target vault for withdraw
  /// @param _tokenOut This token will be a target for swaps
  /// @param _asset0 Token address required selling removed assets
  /// @param _asset0Route Pair addresses for selling asset0
  /// @param _asset1 Token address required selling removed assets
  /// @param _asset1Route Pair addresses for selling asset1
  /// @param _shareTokenAmount Amount of share token for withdraw
  /// @param slippageTolerance A number in 0-100 range that reflect is a percent of acceptable slippage
  function zapOutLp(
    address _vault,
    address _tokenOut,
    address _asset0,
    address[] memory _asset0Route,
    address _asset1,
    address[] memory _asset1Route,
    uint256 _shareTokenAmount,
    uint256 slippageTolerance
  ) external nonReentrant onlyOneCallPerBlock {
    require(_shareTokenAmount != 0, "ZC: zero amount");

    IUniswapV2Pair lp = IUniswapV2Pair(ISmartVault(_vault).underlying());
    require(_asset0 == lp.token0() || _asset0 == lp.token1(), "ZC: asset 0 not exist in lp token");
    require(_asset1 == lp.token0() || _asset1 == lp.token1(), "ZC: asset 1 not exist in lp token");

    IERC20(_vault).safeTransferFrom(msg.sender, address(this), _shareTokenAmount);

    uint256 lpBalance = withdrawFromVault(_vault, address(lp), _shareTokenAmount);

    IUniswapV2Router02 router = IUniswapV2Router02(multiSwap.routerForPair(address(lp)));

    IERC20(address(lp)).safeApprove(address(router), 0);
    IERC20(address(lp)).safeApprove(address(router), lpBalance);
    // without care about slippage
    router.removeLiquidity(
      _asset0,
      _asset1,
      lpBalance,
      1,
      1,
      address(this),
      block.timestamp
    );

    // asset0 multi-swap
    callMultiSwap(
      _asset0,
      IERC20(_asset0).balanceOf(address(this)),
      _asset0Route,
      _tokenOut,
      slippageTolerance
    );

    // asset1 multi-swap
    callMultiSwap(
      _asset1,
      IERC20(_asset1).balanceOf(address(this)),
      _asset1Route,
      _tokenOut,
      slippageTolerance
    );

    uint256 tokenOutBalance = IERC20(_tokenOut).balanceOf(address(this));
    require(tokenOutBalance != 0, "zero token out balance");
    IERC20(_tokenOut).safeTransfer(msg.sender, tokenOutBalance);
  }

  // ************************* INTERNAL *******************

  function addLiquidity(ZapInfo memory zapInfo) internal returns (uint256){
    uint256 asset0Amount = IERC20(zapInfo.asset0).balanceOf(address(this));
    uint256 asset1Amount = IERC20(zapInfo.asset1).balanceOf(address(this));

    IUniswapV2Router02 router = IUniswapV2Router02(multiSwap.routerForPair(zapInfo.lp));

    IERC20(zapInfo.asset0).safeApprove(address(router), 0);
    IERC20(zapInfo.asset0).safeApprove(address(router), asset0Amount);
    IERC20(zapInfo.asset1).safeApprove(address(router), 0);
    IERC20(zapInfo.asset1).safeApprove(address(router), asset1Amount);
    // without care about min amounts
    (,, uint256 liquidity) = router.addLiquidity(
      zapInfo.asset0,
      zapInfo.asset1,
      asset0Amount,
      asset1Amount,
      1,
      1,
      address(this),
      block.timestamp
    );
    // send back change if exist
    sendBackChange(zapInfo);
    return liquidity;
  }

  function sendBackChange(ZapInfo memory zapInfo) internal {
    uint256 bal0 = IERC20(zapInfo.asset0).balanceOf(address(this));
    uint256 bal1 = IERC20(zapInfo.asset1).balanceOf(address(this));
    if (bal0 != 0) {
      address[] memory reverseRoute = new address[](zapInfo.asset0Route.length);

      for (uint256 i = zapInfo.asset0Route.length; i > 0; i--) {
        reverseRoute[zapInfo.asset0Route.length - i] = zapInfo.asset0Route[i - 1];
      }

      callMultiSwap(
        zapInfo.asset0,
        bal0,
        reverseRoute,
        zapInfo.tokenIn,
        zapInfo.slippageTolerance
      );
    }
    if (bal1 != 0) {
      address[] memory reverseRoute = new address[](zapInfo.asset1Route.length);

      for (uint256 i = zapInfo.asset1Route.length; i > 0; i--) {
        reverseRoute[zapInfo.asset1Route.length - i] = zapInfo.asset1Route[i - 1];
      }

      callMultiSwap(
        zapInfo.asset1,
        bal1,
        reverseRoute,
        zapInfo.tokenIn,
        zapInfo.slippageTolerance
      );
    }

    uint256 tokenBal = IERC20(zapInfo.tokenIn).balanceOf(address(this));
    if (tokenBal != 0) {
      IERC20(zapInfo.tokenIn).safeTransfer(msg.sender, tokenBal);
    }
  }

  function callMultiSwap(
    address _tokenIn,
    uint256 _tokenInAmount,
    address[] memory _lpRoute,
    address _tokenOut,
    uint256 slippageTolerance
  ) internal {
    if (_tokenIn == _tokenOut) {
      // no actions if we already have required token
      return;
    }
    require(_tokenInAmount <= IERC20(_tokenIn).balanceOf(address(this)), "ZC: not enough balance for multi-swap");
    IERC20(_tokenIn).safeApprove(address(multiSwap), 0);
    IERC20(_tokenIn).safeApprove(address(multiSwap), _tokenInAmount);
    multiSwap.multiSwap(_lpRoute, _tokenIn, _tokenOut, _tokenInAmount, slippageTolerance);
  }

  /// @dev Deposit into the vault, check the result and send share token to msg.sender
  function depositToVault(address _vault, uint256 _amount, address _underlying) internal {
    require(ISmartVault(_vault).underlying() == _underlying, "ZC: wrong lp for vault");

    IERC20(_underlying).safeApprove(_vault, 0);
    IERC20(_underlying).safeApprove(_vault, _amount);
    ISmartVault(_vault).depositAndInvest(_amount);

    uint256 shareBalance = IERC20(_vault).balanceOf(address(this));
    require(shareBalance != 0, "ZC: zero shareBalance");

    IERC20(_vault).safeTransfer(msg.sender, shareBalance);
  }

  /// @dev Withdraw from vault and check the result
  function withdrawFromVault(address _vault, address _underlying, uint256 _amount) internal returns (uint256){
    ISmartVault(_vault).withdraw(_amount);

    uint256 underlyingBalance = IERC20(_underlying).balanceOf(address(this));
    require(underlyingBalance != 0, "ZC: zero underlying balance");
    return underlyingBalance;
  }

  // ************************* GOV ACTIONS *******************

  /// @notice Controller or Governance can claim coins that are somehow transferred into the contract
  /// @param _token Token address
  /// @param _amount Token amount
  function salvage(address _token, uint256 _amount) external onlyControllerOrGovernance {
    IERC20(_token).safeTransfer(msg.sender, _amount);
  }

}

File 2 of 16 : IERC20.sol
// 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);
}

File 3 of 16 : SafeERC20.sol
// 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");
        }
    }
}

File 4 of 16 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 5 of 16 : 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;
    }
}

File 6 of 16 : Controllable.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/

pragma solidity 0.8.4;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../interface/IController.sol";
import "../interface/IControllable.sol";

/// @title Implement basic functionality for any contract that require strict control
/// @dev Can be used with upgradeable pattern.
///      Require call initializeControllable() in any case.
/// @author belbix
abstract contract Controllable is Initializable, IControllable {
  bytes32 internal constant _CONTROLLER_SLOT = 0x5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c3617;
  bytes32 internal constant _CREATED_SLOT = 0x6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8a;

  /// @notice Controller address changed
  event UpdateController(address oldValue, address newValue);

  constructor() {
    assert(_CONTROLLER_SLOT == bytes32(uint256(keccak256("eip1967.controllable.controller")) - 1));
    assert(_CREATED_SLOT == bytes32(uint256(keccak256("eip1967.controllable.created")) - 1));
  }

  /// @notice Initialize contract after setup it as proxy implementation
  ///         Save block.timestamp in the "created" variable
  /// @dev Use it only once after first logic setup
  /// @param _controller Controller address
  function initializeControllable(address _controller) public initializer {
    setController(_controller);
    setCreated(block.timestamp);
  }

  function isController(address _adr) public override view returns (bool) {
    return _adr == controller();
  }

  /// @notice Return true is given address is setup as governance in Controller
  /// @param _adr Address for check
  /// @return true if given address is governance
  function isGovernance(address _adr) public override view returns (bool) {
    return IController(controller()).governance() == _adr;
  }

  // ************ MODIFIERS **********************

  /// @dev Allow operation only for Controller
  modifier onlyController() {
    require(controller() == msg.sender, "not controller");
    _;
  }

  /// @dev Allow operation only for Controller or Governance
  modifier onlyControllerOrGovernance() {
    require(isController(msg.sender) || isGovernance(msg.sender), "not controller or gov");
    _;
  }

  /// @dev Only smart contracts will be affected by this modifier
  ///      If it is a contract it should be whitelisted
  modifier onlyAllowedUsers() {
    require(IController(controller()).isAllowedUser(msg.sender), "not allowed");
    _;
  }

  /// @dev Only Reward Distributor allowed. Governance is Reward Distributor by default.
  modifier onlyRewardDistribution() {
    require(IController(controller()).isRewardDistributor(msg.sender), "only distr");
    _;
  }

  // ************* SETTERS/GETTERS *******************

  /// @notice Return controller address saved in the contract slot
  /// @return adr Controller address
  function controller() public view returns (address adr) {
    bytes32 slot = _CONTROLLER_SLOT;
    assembly {
      adr := sload(slot)
    }
  }

  /// @dev Set a controller address to contract slot
  /// @param _newController Controller address
  function setController(address _newController) internal {
    require(_newController != address(0), "zero address");
    emit UpdateController(controller(), _newController);
    bytes32 slot = _CONTROLLER_SLOT;
    assembly {
      sstore(slot, _newController)
    }
  }

  /// @notice Return creation timestamp
  /// @return ts Creation timestamp
  function created() external view returns (uint256 ts) {
    bytes32 slot = _CREATED_SLOT;
    assembly {
      ts := sload(slot)
    }
  }

  /// @dev Filled only once when contract initialized
  /// @param _created block.timestamp
  function setCreated(uint256 _created) private {
    bytes32 slot = _CREATED_SLOT;
    assembly {
      sstore(slot, _created)
    }
  }

}

File 7 of 16 : ISmartVault.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/

pragma solidity 0.8.4;

interface ISmartVault {

  function setStrategy(address _strategy) external;

  function changeActivityStatus(bool _active) external;

  function changePpfsDecreaseAllowed(bool _value) external;

  function setLockPeriod(uint256 _value) external;

  function setLockPenalty(uint256 _value) external;

  function doHardWork() external;

  function notifyTargetRewardAmount(address _rewardToken, uint256 reward) external;

  function notifyRewardWithoutPeriodChange(address _rewardToken, uint256 reward) external;

  function deposit(uint256 amount) external;

  function depositAndInvest(uint256 amount) external;

  function depositFor(uint256 amount, address holder) external;

  function withdraw(uint256 numberOfShares) external;

  function exit() external;

  function getAllRewards() external;

  function getReward(address rt) external;

  function underlying() external view returns (address);

  function strategy() external view returns (address);

  function getRewardTokenIndex(address rt) external view returns (uint256);

  function getPricePerFullShare() external view returns (uint256);

  function underlyingUnit() external view returns (uint256);

  function duration() external view returns (uint256);

  function underlyingBalanceInVault() external view returns (uint256);

  function underlyingBalanceWithInvestment() external view returns (uint256);

  function underlyingBalanceWithInvestmentForHolder(address holder) external view returns (uint256);

  function availableToInvestOut() external view returns (uint256);

  function earned(address rt, address account) external view returns (uint256);

  function earnedWithBoost(address rt, address account) external view returns (uint256);

  function rewardPerToken(address rt) external view returns (uint256);

  function lastTimeRewardApplicable(address rt) external view returns (uint256);

  function rewardTokensLength() external view returns (uint256);

  function active() external view returns (bool);

  function rewardTokens() external view returns (address[] memory);

  function periodFinishForToken(address _rt) external view returns (uint256);

  function rewardRateForToken(address _rt) external view returns (uint256);

  function lastUpdateTimeForToken(address _rt) external view returns (uint256);

  function rewardPerTokenStoredForToken(address _rt) external view returns (uint256);

  function userRewardPerTokenPaidForToken(address _rt, address account) external view returns (uint256);

  function rewardsForToken(address _rt, address account) external view returns (uint256);

  function userLastWithdrawTs(address _user) external returns (uint256);

  function userLastDepositTs(address _user) external returns (uint256);

  function userBoostTs(address _user) external returns (uint256);

  function userLockTs(address _user) external returns (uint256);

  function addRewardToken(address rt) external;

  function removeRewardToken(address rt) external;

  function stop() external;

  function ppfsDecreaseAllowed() external view returns (bool);

  function lockPeriod() external view returns (uint256);

  function lockPenalty() external view returns (uint256);

  function lockAllowed() external view returns (bool);
}

File 8 of 16 : IStrategy.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/

pragma solidity 0.8.4;

interface IStrategy {

  enum Platform {
    UNKNOWN, // 0
    TETU, // 1
    QUICK, // 2
    SUSHI, // 3
    WAULT, // 4
    IRON, // 5
    COSMIC, // 6
    CURVE, // 7
    DINO, // 8
    IRON_LEND, // 9
    HERMES, // 10
    CAFE, // 11
    TETU_SWAP // 12
  }

  // *************** GOVERNANCE ACTIONS **************
  function STRATEGY_NAME() external view returns (string memory);

  function withdrawAllToVault() external;

  function withdrawToVault(uint256 amount) external;

  function salvage(address recipient, address token, uint256 amount) external;

  function doHardWork() external;

  function investAllUnderlying() external;

  function emergencyExit() external;

  function continueInvesting() external;

  // **************** VIEWS ***************
  function rewardTokens() external view returns (address[] memory);

  function underlying() external view returns (address);

  function underlyingBalance() external view returns (uint256);

  function rewardPoolBalance() external view returns (uint256);

  function buyBackRatio() external view returns (uint256);

  function unsalvageableTokens(address token) external view returns (bool);

  function vault() external view returns (address);

  function investedUnderlyingBalance() external view returns (uint256);

  function platform() external view returns (Platform);

  function assets() external view returns (address[] memory);

  function pausedInvesting() external view returns (bool);

  function readyToClaim() external view returns (uint256[] memory);

  function poolTotalAmount() external view returns (uint256);
}

File 9 of 16 : IController.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/

pragma solidity 0.8.4;

interface IController {

  function addVaultAndStrategy(address _vault, address _strategy) external;

  function addStrategy(address _strategy) external;

  function governance() external view returns (address);

  function dao() external view returns (address);

  function bookkeeper() external view returns (address);

  function feeRewardForwarder() external view returns (address);

  function mintHelper() external view returns (address);

  function rewardToken() external view returns (address);

  function fundToken() external view returns (address);

  function psVault() external view returns (address);

  function fund() external view returns (address);

  function announcer() external view returns (address);

  function vaultController() external view returns (address);

  function whiteList(address _target) external view returns (bool);

  function vaults(address _target) external view returns (bool);

  function strategies(address _target) external view returns (bool);

  function psNumerator() external view returns (uint256);

  function psDenominator() external view returns (uint256);

  function fundNumerator() external view returns (uint256);

  function fundDenominator() external view returns (uint256);

  function isAllowedUser(address _adr) external view returns (bool);

  function isDao(address _adr) external view returns (bool);

  function isHardWorker(address _adr) external view returns (bool);

  function isRewardDistributor(address _adr) external view returns (bool);

  function isPoorRewardConsumer(address _adr) external view returns (bool);

  function isValidVault(address _vault) external view returns (bool);

  function isValidStrategy(address _strategy) external view returns (bool);

  // ************ DAO ACTIONS *************
  function setPSNumeratorDenominator(uint256 numerator, uint256 denominator) external;

  function setFundNumeratorDenominator(uint256 numerator, uint256 denominator) external;

  function addToWhiteListMulti(address[] calldata _targets) external;

  function addToWhiteList(address _target) external;

  function removeFromWhiteListMulti(address[] calldata _targets) external;

  function removeFromWhiteList(address _target) external;
}

File 10 of 16 : IUniswapV2Pair.sol
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.4;

interface IUniswapV2Pair {
  event Approval(address indexed owner, address indexed spender, uint value);
  event Transfer(address indexed from, address indexed to, uint value);

  function name() external pure returns (string memory);

  function symbol() external pure returns (string memory);

  function decimals() external pure returns (uint8);

  function totalSupply() external view returns (uint);

  function balanceOf(address owner) external view returns (uint);

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

  function approve(address spender, uint value) external returns (bool);

  function transfer(address to, uint value) external returns (bool);

  function transferFrom(address from, address to, uint value) external returns (bool);

  function DOMAIN_SEPARATOR() external view returns (bytes32);

  function PERMIT_TYPEHASH() external pure returns (bytes32);

  function nonces(address owner) external view returns (uint);

  function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

  event Mint(address indexed sender, uint amount0, uint amount1);
  event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
  event Swap(
    address indexed sender,
    uint amount0In,
    uint amount1In,
    uint amount0Out,
    uint amount1Out,
    address indexed to
  );
  event Sync(uint112 reserve0, uint112 reserve1);

  function MINIMUM_LIQUIDITY() external pure returns (uint);

  function factory() external view returns (address);

  function token0() external view returns (address);

  function token1() external view returns (address);

  function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

  function price0CumulativeLast() external view returns (uint);

  function price1CumulativeLast() external view returns (uint);

  function kLast() external view returns (uint);

  function mint(address to) external returns (uint liquidity);

  function burn(address to) external returns (uint amount0, uint amount1);

  function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;

  function skim(address to) external;

  function sync() external;

  function initialize(address, address) external;
}

File 11 of 16 : IUniswapV2Router02.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.4;

interface IUniswapV2Router02 {
  function factory() external view returns (address);

  function WETH() external view 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);

  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;
}

File 12 of 16 : IPriceCalculator.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/

pragma solidity 0.8.4;

interface IPriceCalculator {

  function getPrice(address token, address outputToken) external view returns (uint256);

  function getPriceWithDefaultOutput(address token) external view returns (uint256);

  function getLargestPool(address token, address[] memory usedLps) external view returns (address, uint256, address);

  function getPriceFromLp(address lpAddress, address token) external view returns (uint256);

}

File 13 of 16 : IMultiSwap.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/

pragma solidity 0.8.4;

interface IMultiSwap {

  function findLpsForSwaps(address _tokenIn, address _tokenOut) external view returns (address[] memory);

  function routerForPair(address pair) external view returns (address);

  function multiSwap(address[] memory lps, address tokenIn, address tokenOut, uint256 amount, uint256 slippageTolerance) external;

}

File 14 of 16 : Address.sol
// 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);
            }
        }
    }
}

File 15 of 16 : Initializable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

File 16 of 16 : IControllable.sol
// SPDX-License-Identifier: ISC
/**
* By using this software, you understand, acknowledge and accept that Tetu
* and/or the underlying software are provided “as is” and “as available”
* basis and without warranties or representations of any kind either expressed
* or implied. Any use of this open source software released under the ISC
* Internet Systems Consortium license is done at your own risk to the fullest
* extent permissible pursuant to applicable law any and all liability as well
* as all warranties, including any fitness for a particular purpose with respect
* to Tetu and/or the underlying software and the use thereof are disclaimed.
*/

pragma solidity 0.8.4;

interface IControllable {

  function isController(address _contract) external view returns (bool);

  function isGovernance(address _contract) external view returns (bool);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_multiSwap","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValue","type":"address"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"UpdateController","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"adr","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"created","outputs":[{"internalType":"uint256","name":"ts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"initializeControllable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_adr","type":"address"}],"name":"isController","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_adr","type":"address"}],"name":"isGovernance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiSwap","outputs":[{"internalType":"contract IMultiSwap","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"salvage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address[]","name":"_assetRoute","type":"address[]"},{"internalType":"uint256","name":"_tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"slippageTolerance","type":"uint256"}],"name":"zapInto","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_asset0","type":"address"},{"internalType":"address[]","name":"_asset0Route","type":"address[]"},{"internalType":"address","name":"_asset1","type":"address"},{"internalType":"address[]","name":"_asset1Route","type":"address[]"},{"internalType":"uint256","name":"_tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"slippageTolerance","type":"uint256"}],"name":"zapIntoLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address[]","name":"_assetRoute","type":"address[]"},{"internalType":"uint256","name":"_shareTokenAmount","type":"uint256"},{"internalType":"uint256","name":"slippageTolerance","type":"uint256"}],"name":"zapOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"address","name":"_asset0","type":"address"},{"internalType":"address[]","name":"_asset0Route","type":"address[]"},{"internalType":"address","name":"_asset1","type":"address"},{"internalType":"address[]","name":"_asset1Route","type":"address[]"},{"internalType":"uint256","name":"_shareTokenAmount","type":"uint256"},{"internalType":"uint256","name":"slippageTolerance","type":"uint256"}],"name":"zapOutLp","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060405162002e8a38038062002e8a833981016040819052620000349162000331565b6200006160017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c361862000368565b60008051602062002e4a833981519152146200008d57634e487b7160e01b600052600160045260246000fd5b620000ba60017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b62000368565b60008051602062002e6a83398151915214620000e657634e487b7160e01b600052600160045260246000fd5b600180556001600160a01b038116620001465760405162461bcd60e51b815260206004820152601a60248201527f5a433a207a65726f206d756c746953776170206164647265737300000000000060448201526064015b60405180910390fd5b6200015c826200018360201b6200147c1760201c565b600280546001600160a01b0319166001600160a01b0392909216919091179055506200038c565b600054610100900460ff16806200019d575060005460ff16155b620002025760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016200013d565b600054610100900460ff1615801562000225576000805461ffff19166101011790555b62000230826200025f565b620002484260008051602062002e6a83398151915255565b80156200025b576000805461ff00191690555b5050565b6001600160a01b038116620002a65760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b60448201526064016200013d565b7f19b7d592cea0dfda222f6a4ea5c5a8d018ee9c6b1d0a917483a405de94eb26cd620002df60008051602062002e4a8339815191525490565b604080516001600160a01b03928316815291841660208301520160405180910390a160008051602062002e4a83398151915255565b80516001600160a01b03811681146200032c57600080fd5b919050565b6000806040838503121562000344578182fd5b6200034f8362000314565b91506200035f6020840162000314565b90509250929050565b6000828210156200038757634e487b7160e01b81526011600452602481fd5b500390565b612aae806200039c6000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063d1a13fb611610071578063d1a13fb61461015f578063dee1f0e414610172578063e945cdcd14610185578063f77c479114610198578063fd164f08146101c1578063ffa1ad74146101d457600080fd5b8063129a3f4d146100b957806330c701b8146100ce578063325a19f1146100e15780633e3309cc146101165780636f29911114610129578063b429afeb1461013c575b600080fd5b6100cc6100c7366004612644565b610205565b005b6100cc6100dc366004612705565b61071e565b7f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8a546040519081526020015b60405180910390f35b6100cc61012436600461278a565b6109ab565b6100cc610137366004612705565b610a1f565b61014f61014a36600461260c565b610c56565b604051901515815260200161010d565b6100cc61016d366004612644565b610c89565b61014f61018036600461260c565b6113da565b6100cc61019336600461260c565b61147c565b600080516020612a59833981519152545b6040516001600160a01b03909116815260200161010d565b6002546101a9906001600160a01b031681565b6101f860405180604001604052806005815260200164312e312e3160d81b81525081565b60405161010d91906128cd565b600260015414156102315760405162461bcd60e51b815260040161022890612944565b60405180910390fd5b60026001553360009081526003602052604090205443116102645760405162461bcd60e51b815260040161022890612900565b600182116102ac5760405162461bcd60e51b81526020600482015260156024820152741690ce881b9bdd08195b9bdd59da08185b5bdd5b9d605a1b6044820152606401610228565b6000886001600160a01b0316636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b1580156102e757600080fd5b505afa1580156102fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061031f9190612628565b9050806001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561035a57600080fd5b505afa15801561036e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103929190612628565b6001600160a01b0316876001600160a01b031614806104325750806001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b1580156103e557600080fd5b505afa1580156103f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041d9190612628565b6001600160a01b0316876001600160a01b0316145b6104895760405162461bcd60e51b815260206004820152602260248201527f5a433a2061737365742030206e6f7420657869737420696e206c7020746f6b656044820152616e7360f01b6064820152608401610228565b806001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b1580156104c257600080fd5b505afa1580156104d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fa9190612628565b6001600160a01b0316856001600160a01b0316148061059a5750806001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561054d57600080fd5b505afa158015610561573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105859190612628565b6001600160a01b0316856001600160a01b0316145b6105f15760405162461bcd60e51b815260206004820152602260248201527f5a433a2061737365742031206e6f7420657869737420696e206c7020746f6b656044820152616e7360f01b6064820152608401610228565b61061d333061060b60026106058882611560565b90611573565b6001600160a01b038c1692919061157f565b6106348861062c856002611560565b888a866115f0565b61064b88610643856002611560565b8688866115f0565b60006106b3604051806101000160405280846001600160a01b031681526020018b6001600160a01b031681526020018a6001600160a01b03168152602001898152602001886001600160a01b031681526020018781526020018681526020018581525061178a565b9050806106f15760405162461bcd60e51b815260206004820152600c60248201526b5a433a207a65726f206c697160a01b6044820152606401610228565b6106fc8a8284611a4b565b5050336000908152600360205260409020439055505060018055505050505050565b600260015414156107415760405162461bcd60e51b815260040161022890612944565b60026001553360009081526003602052604090205443116107745760405162461bcd60e51b815260040161022890612900565b816107b35760405162461bcd60e51b815260206004820152600f60248201526e1690ce881e995c9bc8185b5bdd5b9d608a1b6044820152606401610228565b856001600160a01b0316636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b1580156107ec57600080fd5b505afa158015610800573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108249190612628565b6001600160a01b0316846001600160a01b0316146108845760405162461bcd60e51b815260206004820152601b60248201527f5a433a206173736574206973206e6f7420756e6465726c79696e6700000000006044820152606401610228565b6108996001600160a01b03871633308561157f565b60006108a6878685611c6d565b90506108b585828689866115f0565b6040516370a0823160e01b81523060048201526000906001600160a01b038816906370a082319060240160206040518083038186803b1580156108f757600080fd5b505afa15801561090b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092f91906127d5565b9050806109775760405162461bcd60e51b81526020600482015260166024820152757a65726f20746f6b656e206f75742062616c616e636560501b6044820152606401610228565b61098b6001600160a01b0388163383611d9b565b505033600090815260036020526040902043905550506001805550505050565b6109b433610c56565b806109c357506109c3336113da565b610a075760405162461bcd60e51b81526020600482015260156024820152743737ba1031b7b73a3937b63632b91037b91033b7bb60591b6044820152606401610228565b610a1b6001600160a01b0383163383611d9b565b5050565b60026001541415610a425760405162461bcd60e51b815260040161022890612944565b6002600155336000908152600360205260409020544311610a755760405162461bcd60e51b815260040161022890612900565b60018211610abd5760405162461bcd60e51b81526020600482015260156024820152741690ce881b9bdd08195b9bdd59da08185b5bdd5b9d605a1b6044820152606401610228565b856001600160a01b0316636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b158015610af657600080fd5b505afa158015610b0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2e9190612628565b6001600160a01b0316846001600160a01b031614610b8e5760405162461bcd60e51b815260206004820152601b60248201527f5a433a206173736574206973206e6f7420756e6465726c79696e6700000000006044820152606401610228565b610ba36001600160a01b03861633308561157f565b610bb085838587856115f0565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a082319060240160206040518083038186803b158015610bf257600080fd5b505afa158015610c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2a91906127d5565b9050610c37878287611a4b565b5050336000908152600360205260409020439055505060018055505050565b6000610c6e600080516020612a598339815191525490565b6001600160a01b0316826001600160a01b0316149050919050565b60026001541415610cac5760405162461bcd60e51b815260040161022890612944565b6002600155336000908152600360205260409020544311610cdf5760405162461bcd60e51b815260040161022890612900565b81610d1e5760405162461bcd60e51b815260206004820152600f60248201526e1690ce881e995c9bc8185b5bdd5b9d608a1b6044820152606401610228565b6000886001600160a01b0316636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b158015610d5957600080fd5b505afa158015610d6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d919190612628565b9050806001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015610dcc57600080fd5b505afa158015610de0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e049190612628565b6001600160a01b0316876001600160a01b03161480610ea45750806001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5757600080fd5b505afa158015610e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8f9190612628565b6001600160a01b0316876001600160a01b0316145b610efa5760405162461bcd60e51b815260206004820152602160248201527f5a433a2061737365742030206e6f7420657869737420696e206c7020746f6b656044820152603760f91b6064820152608401610228565b806001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015610f3357600080fd5b505afa158015610f47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6b9190612628565b6001600160a01b0316856001600160a01b0316148061100b5750806001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610fbe57600080fd5b505afa158015610fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff69190612628565b6001600160a01b0316856001600160a01b0316145b6110615760405162461bcd60e51b815260206004820152602160248201527f5a433a2061737365742031206e6f7420657869737420696e206c7020746f6b656044820152603760f91b6064820152608401610228565b6110766001600160a01b038a1633308661157f565b60006110838a8386611c6d565b600254604051637a0c1c3f60e01b81526001600160a01b03858116600483015292935060009290911690637a0c1c3f9060240160206040518083038186803b1580156110ce57600080fd5b505afa1580156110e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111069190612628565b905061111d6001600160a01b038416826000611dd0565b6111316001600160a01b0384168284611dd0565b604051635d5155ef60e11b81526001600160a01b038a8116600483015288811660248301526044820184905260016064830181905260848301523060a48301524260c483015282169063baa2abde9060e4016040805180830381600087803b15801561119c57600080fd5b505af11580156111b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d491906127ed565b50506040516370a0823160e01b815230600482015261125b908a906001600160a01b038216906370a082319060240160206040518083038186803b15801561121b57600080fd5b505afa15801561122f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125391906127d5565b8a8d886115f0565b6040516370a0823160e01b81523060048201526112e09088906001600160a01b038216906370a082319060240160206040518083038186803b1580156112a057600080fd5b505afa1580156112b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d891906127d5565b888d886115f0565b6040516370a0823160e01b81523060048201526000906001600160a01b038c16906370a082319060240160206040518083038186803b15801561132257600080fd5b505afa158015611336573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135a91906127d5565b9050806113a25760405162461bcd60e51b81526020600482015260166024820152757a65726f20746f6b656e206f75742062616c616e636560501b6044820152606401610228565b6113b66001600160a01b038c163383611d9b565b50503360009081526003602052604090204390555050600180555050505050505050565b6000816001600160a01b03166113fc600080516020612a598339815191525490565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561143457600080fd5b505afa158015611448573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146c9190612628565b6001600160a01b03161492915050565b600054610100900460ff1680611495575060005460ff16155b6114f85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610228565b600054610100900460ff1615801561151a576000805461ffff19166101011790555b61152382611ef4565b61154b427f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8a55565b8015610a1b576000805461ff00191690555050565b600061156c828461297b565b9392505050565b600061156c828461299b565b6040516001600160a01b03808516602483015283166044820152606481018290526115ea9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611fa4565b50505050565b816001600160a01b0316856001600160a01b0316141561160f57611783565b6040516370a0823160e01b81523060048201526001600160a01b038616906370a082319060240160206040518083038186803b15801561164e57600080fd5b505afa158015611662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168691906127d5565b8411156116e35760405162461bcd60e51b815260206004820152602560248201527f5a433a206e6f7420656e6f7567682062616c616e636520666f72206d756c746960448201526402d737761760dc1b6064820152608401610228565b6002546116fe906001600160a01b0387811691166000611dd0565b600254611718906001600160a01b03878116911686611dd0565b600254604051636c63a1f160e11b81526001600160a01b039091169063d8c743e290611750908690899087908a908890600401612859565b600060405180830381600087803b15801561176a57600080fd5b505af115801561177e573d6000803e3d6000fd5b505050505b5050505050565b60408082015190516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a082319060240160206040518083038186803b1580156117d457600080fd5b505afa1580156117e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180c91906127d5565b60808401516040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a082319060240160206040518083038186803b15801561185757600080fd5b505afa15801561186b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188f91906127d5565b6002548551604051637a0c1c3f60e01b81526001600160a01b039182166004820152929350600092911690637a0c1c3f9060240160206040518083038186803b1580156118db57600080fd5b505afa1580156118ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119139190612628565b6040860151909150611930906001600160a01b0316826000611dd0565b6040850151611949906001600160a01b03168285611dd0565b6080850151611963906001600160a01b0316826000611dd0565b608085015161197c906001600160a01b03168284611dd0565b6040858101516080870151915162e8e33760e81b81526001600160a01b0391821660048201529181166024830152604482018590526064820184905260016084830181905260a48301523060c48301524260e48301526000919083169063e8e337009061010401606060405180830381600087803b1580156119fd57600080fd5b505af1158015611a11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a359190612810565b92505050611a4286612076565b95945050505050565b806001600160a01b0316836001600160a01b0316636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b158015611a8e57600080fd5b505afa158015611aa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac69190612628565b6001600160a01b031614611b155760405162461bcd60e51b81526020600482015260166024820152751690ce881ddc9bdb99c81b1c08199bdc881d985d5b1d60521b6044820152606401610228565b611b2a6001600160a01b038216846000611dd0565b611b3e6001600160a01b0382168484611dd0565b6040516332e2261360e21b8152600481018390526001600160a01b0384169063cb88984c90602401600060405180830381600087803b158015611b8057600080fd5b505af1158015611b94573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03861691506370a082319060240160206040518083038186803b158015611bda57600080fd5b505afa158015611bee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1291906127d5565b905080611c595760405162461bcd60e51b81526020600482015260156024820152745a433a207a65726f20736861726542616c616e636560581b6044820152606401610228565b6115ea6001600160a01b0385163383611d9b565b604051632e1a7d4d60e01b8152600481018290526000906001600160a01b03851690632e1a7d4d90602401600060405180830381600087803b158015611cb257600080fd5b505af1158015611cc6573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03861691506370a082319060240160206040518083038186803b158015611d0c57600080fd5b505afa158015611d20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4491906127d5565b905080611d935760405162461bcd60e51b815260206004820152601b60248201527f5a433a207a65726f20756e6465726c79696e672062616c616e636500000000006044820152606401610228565b949350505050565b6040516001600160a01b038316602482015260448101829052611dcb90849063a9059cbb60e01b906064016115b3565b505050565b801580611e595750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015611e1f57600080fd5b505afa158015611e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5791906127d5565b155b611ec45760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610228565b6040516001600160a01b038316602482015260448101829052611dcb90849063095ea7b360e01b906064016115b3565b6001600160a01b038116611f395760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b6044820152606401610228565b7f19b7d592cea0dfda222f6a4ea5c5a8d018ee9c6b1d0a917483a405de94eb26cd611f70600080516020612a598339815191525490565b604080516001600160a01b03928316815291841660208301520160405180910390a1600080516020612a5983398151915255565b6000611ff9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661244c9092919063ffffffff16565b805190915015611dcb578080602001905181019061201791906127b5565b611dcb5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610228565b60408082015190516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b1580156120bc57600080fd5b505afa1580156120d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f491906127d5565b60808301516040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a082319060240160206040518083038186803b15801561213f57600080fd5b505afa158015612153573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217791906127d5565b9050811561229357600083606001515167ffffffffffffffff8111156121ad57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156121d6578160200160208202803683370190505b506060850151519091505b80156122775760608501516121f76001836129ba565b8151811061221557634e487b7160e01b600052603260045260246000fd5b6020026020010151828287606001515161222f91906129ba565b8151811061224d57634e487b7160e01b600052603260045260246000fd5b6001600160a01b03909216602092830291909101909101528061226f816129fd565b9150506121e1565b506122918460400151848387602001518860e001516115f0565b505b80156123ad5760008360a001515167ffffffffffffffff8111156122c757634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156122f0578160200160208202803683370190505b5060a0850151519091505b80156123915760a08501516123116001836129ba565b8151811061232f57634e487b7160e01b600052603260045260246000fd5b602002602001015182828760a001515161234991906129ba565b8151811061236757634e487b7160e01b600052603260045260246000fd5b6001600160a01b039092166020928302919091019091015280612389816129fd565b9150506122fb565b506123ab8460800151838387602001518860e001516115f0565b505b60208301516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b1580156123f357600080fd5b505afa158015612407573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242b91906127d5565b905080156115ea5760208401516115ea906001600160a01b03163383611d9b565b6060611d93848460008585843b6124a55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610228565b600080866001600160a01b031685876040516124c1919061283d565b60006040518083038185875af1925050503d80600081146124fe576040519150601f19603f3d011682016040523d82523d6000602084013e612503565b606091505b509150915061251382828661251e565b979650505050505050565b6060831561252d57508161156c565b82511561253d5782518084602001fd5b8160405162461bcd60e51b815260040161022891906128cd565b803561256281612a40565b919050565b600082601f830112612577578081fd5b8135602067ffffffffffffffff8083111561259457612594612a2a565b8260051b604051601f19603f830116810181811084821117156125b9576125b9612a2a565b604052848152838101925086840182880185018910156125d7578687fd5b8692505b85831015612600576125ec81612557565b8452928401926001929092019184016125db565b50979650505050505050565b60006020828403121561261d578081fd5b813561156c81612a40565b600060208284031215612639578081fd5b815161156c81612a40565b600080600080600080600080610100898b031215612660578384fd5b883561266b81612a40565b9750602089013561267b81612a40565b9650604089013561268b81612a40565b9550606089013567ffffffffffffffff808211156126a7578586fd5b6126b38c838d01612567565b965060808b013591506126c582612a40565b90945060a08a013590808211156126da578485fd5b506126e78b828c01612567565b93505060c0890135915060e089013590509295985092959890939650565b60008060008060008060c0878903121561271d578182fd5b863561272881612a40565b9550602087013561273881612a40565b9450604087013561274881612a40565b9350606087013567ffffffffffffffff811115612763578283fd5b61276f89828a01612567565b9350506080870135915060a087013590509295509295509295565b6000806040838503121561279c578182fd5b82356127a781612a40565b946020939093013593505050565b6000602082840312156127c6578081fd5b8151801515811461156c578182fd5b6000602082840312156127e6578081fd5b5051919050565b600080604083850312156127ff578182fd5b505080516020909101519092909150565b600080600060608486031215612824578283fd5b8351925060208401519150604084015190509250925092565b6000825161284f8184602087016129d1565b9190910192915050565b60a0808252865190820181905260009060209060c0840190828a01845b8281101561289b5781516001600160a01b031684529284019290840190600101612876565b5050506001600160a01b0397881691840191909152949095166040820152606081019290925260809091015292915050565b60208152600082518060208401526128ec8160408501602087016129d1565b601f01601f19169190910160400192915050565b60208082526024908201527f5a433a2063616c6c20696e207468652073616d6520626c6f636b20666f726269604082015263323232b760e11b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008261299657634e487b7160e01b81526012600452602481fd5b500490565b60008160001904831182151516156129b5576129b5612a14565b500290565b6000828210156129cc576129cc612a14565b500390565b60005b838110156129ec5781810151838201526020016129d4565b838111156115ea5750506000910152565b600081612a0c57612a0c612a14565b506000190190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114612a5557600080fd5b5056fe5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c3617a2646970667358221220fbcee558c5955eaf4ed82f68d86f6fb83a62ec758944ccfea8b6c336f87b384464736f6c634300080400335165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c36176f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8a0000000000000000000000006678814c273d5088114b6e40cc49c8db04f9bc29000000000000000000000000cde742ee6fd35f3045afa6b4eaf2d9e867c82fdf

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

0000000000000000000000006678814c273d5088114b6e40cc49c8db04f9bc29000000000000000000000000cde742ee6fd35f3045afa6b4eaf2d9e867c82fdf

-----Decoded View---------------
Arg [0] : _controller (address): 0x6678814c273d5088114b6e40cc49c8db04f9bc29
Arg [1] : _multiSwap (address): 0xcde742ee6fd35f3045afa6b4eaf2d9e867c82fdf

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000006678814c273d5088114b6e40cc49c8db04f9bc29
Arg [1] : 000000000000000000000000cde742ee6fd35f3045afa6b4eaf2d9e867c82fdf


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.