Contract 0x1c7f7210a7acc13d26824a8267cf9ca5d4020bc1

Tetu 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x9b61e983dfb7e576091be92ec3e52ab51141975bf428e0a9869e66e21dae96c7Swap Exact Token...387250242022-05-21 9:47:028 hrs 21 mins ago0xdb19d3186ea32001f6f16867d5d31a39bba139be IN  Tetu: TetuSwap Router0 FTM0.013880958
0x255883f235be9fbb24f9e57c8542a893d505716584eeae4a2dc14711a8fbf7b1Swap Exact Token...386814402022-05-20 19:55:0822 hrs 13 mins ago0xa41c5504464989b219c14301e785d29961b5a719 IN  Tetu: TetuSwap Router0 FTM0.039016906962
0x8806d4dfdc7334541c43d82baf6def151e7f682ad4dd2ef1c4a94e1a9567fcf0Swap Exact Token...386755012022-05-20 18:05:501 day 2 mins ago0x6129aeaf582dd8b748772e19fb7a80af26d4c2d3 IN  Tetu: TetuSwap Router0 FTM0.251358960854
0xc89a46b0af73a59169e962ddc536485c203f4279a94eb2465b5181dfb9c90d88Swap Exact Token...386470182022-05-20 8:35:301 day 9 hrs ago0xd11bcc0e7d44169a572da39ca6297d0dfa5c17fa IN  Tetu: TetuSwap Router0 FTM0.059296436332
0x7b324847235d423a628c4ddf7a9a0255e1db6e6423571de0945510d21235f4dcAdd Liquidity386442462022-05-20 7:42:371 day 10 hrs ago0x30044b7c080a6e456386d5b9c370dc7c259ae2cd IN  Tetu: TetuSwap Router0 FTM0.06652292268
0x8f134f803c6d715eba6a45a6ce9163cdb1895890798f9ccc02bc90adc3dd2472Add Liquidity386387902022-05-20 6:00:411 day 12 hrs ago0x9efc70ad55a304959fcf9791754da08ecc322ed2 IN  Tetu: TetuSwap Router0 FTM0.125333299299
0xd856fc049978e51909f06370babcbf27417397c3586bfb2ce799d46f9953a1c1Remove Liquidity...386177412022-05-19 23:11:261 day 18 hrs ago0x1fe3feb0ce0905862444e43d241a3624f66987e1 IN  Tetu: TetuSwap Router0 FTM0.193683773954
0x3f4311a10d1fc6684219bfec3a232e3407e71b9981faa5f2af005ef46212d78fRemove Liquidity...386094532022-05-19 20:27:001 day 21 hrs ago0x129cb2eef85c3edaae8cd649b45b7ffce836cd6f IN  Tetu: TetuSwap Router0 FTM0.062718101175
0x9b0c40be1f4e17e04d8ca4357db6561173ad2f660f08c2b3897ac61749e8dfe8Swap Exact ETH F...385661122022-05-19 6:40:282 days 11 hrs ago0x8330d58cc6458a1579f11f68e466829f1d19c78c IN  Tetu: TetuSwap Router60 FTM0.526624695
0xed43a0e9dab168bcd536048c1ad21b155cac727779a21c9e403ba7c013f08932Swap Exact Token...385271082022-05-18 17:34:593 days 33 mins ago0xb70204e0143856bb3e0f31a71d677a38c0514d57 IN  Tetu: TetuSwap Router0 FTM0.45196075826
0x0fc9a54c05774058bc3e6bbe63a3f5c3b5f19db1546e698220c2d97a4dc307f4Swap Exact Token...384503442022-05-17 15:24:184 days 2 hrs ago0x396932cf21d7a37eb8db923d669fcd5bc0c751d2 IN  Tetu: TetuSwap Router0 FTM0.3976296
0x5d17b88b7b2752e6b48a42ff074b25ad6ec3234ac939b9fcea22342294172918Swap Exact Token...384429642022-05-17 12:57:064 days 5 hrs ago0xe2e3fce1b7712c0faba08e72990b5094c666ef5c IN  Tetu: TetuSwap Router0 FTM0.28632279036
0x082a0732ca54565712cc5f1bcece3cfdacd5795c7f272142e2e530a31e84321fSwap Exact Token...384397082022-05-17 11:52:514 days 6 hrs ago0xba94a228765ffe3fdd63e28edd05409ea9f3e24b IN  Tetu: TetuSwap Router0 FTM0.174182711604
0x9ceadc15f096bc14ce64643c458764052ec775a08925210b3a230039a86f8909Swap Exact Token...384320732022-05-17 9:35:084 days 8 hrs ago0x4ca8ad3a20848ac6f5dbb14cc02fce8c037d11da IN  Tetu: TetuSwap Router0 FTM0.297433768553
0x408b67dd19bffbce6f52db38609afa3f497eb198adec703745e32361296ba6c8Swap Exact Token...383999632022-05-16 23:26:244 days 18 hrs ago0x05679df1e0f5719dabb8cbbfd46d9513c93907d0 IN  Tetu: TetuSwap Router0 FTM0.335174167425
0xde38b8ab300467ba0c1df0fcdae08b7106ff0ce968be83791692a547c21686caSwap Exact Token...383988932022-05-16 23:07:434 days 19 hrs ago0xb3c8dae61fc42a488eb0233f1990e8531382714d IN  Tetu: TetuSwap Router0 FTM1.318064107039
0xf829bed366b2c26adff98f2f0cbc6e975889a865763eae96bed439d4a6753b98Swap Exact Token...383658772022-05-16 12:51:245 days 5 hrs ago0xe2e3fce1b7712c0faba08e72990b5094c666ef5c IN  Tetu: TetuSwap Router0 FTM2.086801159779
0xe067fffc22ae7027459496d8c1a03b597b95f81bafe1495336e4ccbb990df694Swap ETH For Exa...383541292022-05-16 8:51:375 days 9 hrs ago0x8330d58cc6458a1579f11f68e466829f1d19c78c IN  Tetu: TetuSwap Router201.635251172109275 FTM1.72931565
0xbe61a0b5aea497bee759d1fb3c235d02576919275b37f9caf6c1cdaac3aee316Swap Exact Token...383497632022-05-16 7:21:285 days 10 hrs ago0x8330d58cc6458a1579f11f68e466829f1d19c78c IN  Tetu: TetuSwap Router0 FTM1.088616
0xa9a4d84cba965ed89ca444119d2391c67a3b93f779dc8e66119783636ace4696Swap Exact Token...383191982022-05-15 21:16:175 days 20 hrs ago0xe2e3fce1b7712c0faba08e72990b5094c666ef5c IN  Tetu: TetuSwap Router0 FTM0.851025847305
0xf65cbf5e83ab0f7f686037dba11791e3db095278e4e7b2b343ccf5a5970d2824Swap Exact Token...383157012022-05-15 19:59:535 days 22 hrs ago0x3a6601d001e866060d8006b96ed4bf0ae067b9cb IN  Tetu: TetuSwap Router0 FTM0.954670085978
0x242b4df55c44542470f284c86a6665ab2f9eb0df2df160e321276a8d27cfb2daSwap Exact Token...382989052022-05-15 13:56:056 days 4 hrs ago0x5abb9ed9073e147066eabc32df59f8c31a37d61e IN  Tetu: TetuSwap Router0 FTM0.552701681112
0xfa3a6e6889d4c87939f2c95ee875e2e02cd85eebdc74eb871c50b5478ec6e1cfSwap Exact Token...382898262022-05-15 10:47:556 days 7 hrs ago0x941eaaf5f9f8463bec0cc22da1dada6f0d30e28a IN  Tetu: TetuSwap Router0 FTM0.517099717713
0xf0126aef73fc3bf918ed0b624234083b023abdbd1b8eab6ebb40bb67ce272d9bSwap Exact Token...382886512022-05-15 10:26:306 days 7 hrs ago0x941eaaf5f9f8463bec0cc22da1dada6f0d30e28a IN  Tetu: TetuSwap Router0 FTM0.271538413945
0x17493df6d78522cf83cbf5d521f99437ce2aab5018bb98ae3e01ca673f486aa4Swap Exact Token...382860842022-05-15 9:40:396 days 8 hrs ago0xa9ba157770045cffe977601fd46b9cc3c4429604 IN  Tetu: TetuSwap Router0 FTM0.43880252085
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x9b0c40be1f4e17e04d8ca4357db6561173ad2f660f08c2b3897ac61749e8dfe8385661122022-05-19 6:40:282 days 11 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token60 FTM
0xde38b8ab300467ba0c1df0fcdae08b7106ff0ce968be83791692a547c21686ca383988932022-05-16 23:07:434 days 19 hrs ago Tetu: TetuSwap Router0xb3c8dae61fc42a488eb0233f1990e8531382714d3.964730654407893365 FTM
0xde38b8ab300467ba0c1df0fcdae08b7106ff0ce968be83791692a547c21686ca383988932022-05-16 23:07:434 days 19 hrs ago Fantom Finance: Wrapped Fantom Token Tetu: TetuSwap Router3.964730654407893365 FTM
0xe067fffc22ae7027459496d8c1a03b597b95f81bafe1495336e4ccbb990df694383541292022-05-16 8:51:375 days 9 hrs ago Tetu: TetuSwap Router0x8330d58cc6458a1579f11f68e466829f1d19c78c0.16734868913590697 FTM
0xe067fffc22ae7027459496d8c1a03b597b95f81bafe1495336e4ccbb990df694383541292022-05-16 8:51:375 days 9 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token201.46790248297336878 FTM
0xfa3a6e6889d4c87939f2c95ee875e2e02cd85eebdc74eb871c50b5478ec6e1cf382898262022-05-15 10:47:556 days 7 hrs ago Tetu: TetuSwap Router0x941eaaf5f9f8463bec0cc22da1dada6f0d30e28a23.575156517122227102 FTM
0xfa3a6e6889d4c87939f2c95ee875e2e02cd85eebdc74eb871c50b5478ec6e1cf382898262022-05-15 10:47:556 days 7 hrs ago Fantom Finance: Wrapped Fantom Token Tetu: TetuSwap Router23.575156517122227102 FTM
0x7ad250d9c6274019b09695bc5c2ffe605318968182e911dd26ed61a08532a743382173282022-05-14 10:33:437 days 7 hrs ago Tetu: TetuSwap Router0x3c5aac016ef2f178e8699d6208796a2d67557fe20.954915738869454134 FTM
0x7ad250d9c6274019b09695bc5c2ffe605318968182e911dd26ed61a08532a743382173282022-05-14 10:33:437 days 7 hrs ago Fantom Finance: Wrapped Fantom Token Tetu: TetuSwap Router0.954915738869454134 FTM
0xe96aac7c282a8da94a69a19cdbe1d222f3c19d11059e5879527f65aa0400ae00382091562022-05-14 7:57:597 days 10 hrs ago Tetu: TetuSwap Router0x8330d58cc6458a1579f11f68e466829f1d19c78c0.221449971975902674 FTM
0xe96aac7c282a8da94a69a19cdbe1d222f3c19d11059e5879527f65aa0400ae00382091562022-05-14 7:57:597 days 10 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token118.165577204229419933 FTM
0x97cea266d4c85999af1081b178327c8e8982f1c2c82861308f0b5ed6536502fb381702312022-05-13 19:16:397 days 22 hrs ago Tetu: TetuSwap Router0x8330d58cc6458a1579f11f68e466829f1d19c78c0.271102085970011315 FTM
0x97cea266d4c85999af1081b178327c8e8982f1c2c82861308f0b5ed6536502fb381702312022-05-13 19:16:397 days 22 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token134.919815879479169054 FTM
0x2293b0f26425c2c4c76d1444ef6fb5718f5ecc10b75f9b231fec92d72e67213a381147472022-05-12 20:42:348 days 21 hrs ago Tetu: TetuSwap Router0x941eaaf5f9f8463bec0cc22da1dada6f0d30e28a3,112.46655063245551206 FTM
0x2293b0f26425c2c4c76d1444ef6fb5718f5ecc10b75f9b231fec92d72e67213a381147472022-05-12 20:42:348 days 21 hrs ago Fantom Finance: Wrapped Fantom Token Tetu: TetuSwap Router3,112.46655063245551206 FTM
0x55d417105c3900ec94c0e8bc10a23924fa8dd9d64ef465fd66903a9e09111194380859482022-05-12 7:54:389 days 10 hrs ago Tetu: TetuSwap Router0x8330d58cc6458a1579f11f68e466829f1d19c78c0.679732978546175629 FTM
0x55d417105c3900ec94c0e8bc10a23924fa8dd9d64ef465fd66903a9e09111194380859482022-05-12 7:54:389 days 10 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token221.645966551348019835 FTM
0x405536dba9f3bea797cb98f811ec0313840e521c77e5694033ac40fa70263d24380619262022-05-11 21:24:559 days 20 hrs ago Tetu: TetuSwap Router0x8330d58cc6458a1579f11f68e466829f1d19c78c1.072543452640936535 FTM
0x405536dba9f3bea797cb98f811ec0313840e521c77e5694033ac40fa70263d24380619262022-05-11 21:24:559 days 20 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token539.015450137452943556 FTM
0x4d9203dbeb5125e5026e55a148550d6a712bd41159a3f68e8422654ff0cf9520380543742022-05-11 18:12:379 days 23 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token660 FTM
0xb04548cff81bdb6b2f3a9ab73dff9ac9c74349407a7f8323f9f4eb78c6806102380542292022-05-11 18:08:569 days 23 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token500 FTM
0xec4515d71cc7ccd85294c89415034965d6d98b10f1f453864089f783ff40cdd1380324802022-05-11 8:54:2110 days 9 hrs ago Tetu: TetuSwap Router0x8330d58cc6458a1579f11f68e466829f1d19c78c0.15769163958782784 FTM
0xec4515d71cc7ccd85294c89415034965d6d98b10f1f453864089f783ff40cdd1380324802022-05-11 8:54:2110 days 9 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token241.182348333149268265 FTM
0x003868d5606a4b0dba617a247110f6b030f0ff0806cff59b0143835539e603c4379998342022-05-10 20:39:2610 days 21 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token148 FTM
0x042a36e9c6639f33b129c00c614639e61fa279073a66ffcfc6727c5325552427379595632022-05-10 7:21:3811 days 10 hrs ago Tetu: TetuSwap Router Fantom Finance: Wrapped Fantom Token163 FTM
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TetuSwapRouter

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 150 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 10 : TetuSwapRouter.sol
// SPDX-License-Identifier: UNLICENSED
/**
* 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/IERC20.sol";
import "./libraries/TransferHelper.sol";
import "./libraries/TetuSwapLibrary.sol";
import "./interfaces/ITetuSwapERC20.sol";
import "./interfaces/ITetuSwapPair.sol";
import "./interfaces/ITetuSwapRouter.sol";
import "./interfaces/ITetuSwapFactory.sol";
import "./interfaces/IWETH.sol";

/// @title UniswapV2Router02 https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol
/// @dev Few changes for compatability with Tetu Swap
contract TetuSwapRouter is ITetuSwapRouter {

  address public immutable override factory;
  address public immutable override WETH;
  string public constant VERSION = "1.1.0";

  event EthReceived(address sender);

  modifier ensure(uint deadline) {
    require(deadline >= block.timestamp, "TSR: EXPIRED");
    _;
  }

  constructor(address _factory, address _WETH) {
    require(_factory != address(0), "TSR: Zero factory");
    require(_WETH != address(0), "TSR: Zero WETH");
    factory = _factory;
    WETH = _WETH;
  }

  receive() external payable {
    require(msg.sender == WETH, "TSR: ETH sender is not WETH contract");
    // only accept ETH via fallback from the WETH contract
    emit EthReceived(msg.sender);
  }

  // **** ADD LIQUIDITY ****
  function _addLiquidity(
    address tokenA,
    address tokenB,
    uint amountADesired,
    uint amountBDesired,
    uint amountAMin,
    uint amountBMin
  ) internal virtual returns (uint amountA, uint amountB) {
    require(ITetuSwapFactory(factory).getPair(tokenA, tokenB) != address(0), "TSR: Pair not exist");
    (uint reserveA, uint reserveB) = TetuSwapLibrary.getReserves(factory, tokenA, tokenB);
    if (reserveA == 0 && reserveB == 0) {
      (amountA, amountB) = (amountADesired, amountBDesired);
    } else {
      uint amountBOptimal = TetuSwapLibrary.quote(amountADesired, reserveA, reserveB);
      if (amountBOptimal <= amountBDesired) {
        require(amountBOptimal >= amountBMin, "TSR: INSUFFICIENT_B_AMOUNT");
        (amountA, amountB) = (amountADesired, amountBOptimal);
      } else {
        uint amountAOptimal = TetuSwapLibrary.quote(amountBDesired, reserveB, reserveA);
        assert(amountAOptimal <= amountADesired);
        require(amountAOptimal >= amountAMin, "TSR: INSUFFICIENT_A_AMOUNT");
        (amountA, amountB) = (amountAOptimal, amountBDesired);
      }
    }
  }

  function addLiquidity(
    address tokenA,
    address tokenB,
    uint amountADesired,
    uint amountBDesired,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
  ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
    (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
    address pair = TetuSwapLibrary.pairFor(factory, tokenA, tokenB);
    TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
    TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
    liquidity = ITetuSwapPair(pair).mint(to);
  }

  function addLiquidityETH(
    address token,
    uint amountTokenDesired,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
  ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
    (amountToken, amountETH) = _addLiquidity(
      token,
      WETH,
      amountTokenDesired,
      msg.value,
      amountTokenMin,
      amountETHMin
    );
    address pair = TetuSwapLibrary.pairFor(factory, token, WETH);
    TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
    IWETH(WETH).deposit{value : amountETH}();
    assert(IWETH(WETH).transfer(pair, amountETH));
    liquidity = ITetuSwapPair(pair).mint(to);
    // refund dust eth, if any
    if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
  }

  // **** REMOVE LIQUIDITY ****
  function removeLiquidity(
    address tokenA,
    address tokenB,
    uint liquidity,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
  ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
    address pair = TetuSwapLibrary.pairFor(factory, tokenA, tokenB);
    ITetuSwapERC20(pair).transferFrom(msg.sender, pair, liquidity);
    // send liquidity to pair
    (uint amount0, uint amount1) = ITetuSwapPair(pair).burn(to);
    (address token0,) = TetuSwapLibrary.sortTokens(tokenA, tokenB);
    (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
    require(amountA >= amountAMin, "TSR: INSUFFICIENT_A_AMOUNT");
    require(amountB >= amountBMin, "TSR: INSUFFICIENT_B_AMOUNT");
  }

  function removeLiquidityETH(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
  ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
    (amountToken, amountETH) = removeLiquidity(
      token,
      WETH,
      liquidity,
      amountTokenMin,
      amountETHMin,
      address(this),
      deadline
    );
    TransferHelper.safeTransfer(token, to, amountToken);
    IWETH(WETH).withdraw(amountETH);
    TransferHelper.safeTransferETH(to, 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 virtual override returns (uint amountA, uint amountB) {
    address pair = TetuSwapLibrary.pairFor(factory, tokenA, tokenB);
    uint value = approveMax ? type(uint).max : liquidity;
    ITetuSwapERC20(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
    (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
  }

  function removeLiquidityETHWithPermit(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline,
    bool approveMax, uint8 v, bytes32 r, bytes32 s
  ) external virtual override returns (uint amountToken, uint amountETH) {
    address pair = TetuSwapLibrary.pairFor(factory, token, WETH);
    uint value = approveMax ? type(uint).max : liquidity;
    ITetuSwapERC20(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
    (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
  }

  // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
  function removeLiquidityETHSupportingFeeOnTransferTokens(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
  ) public virtual override ensure(deadline) returns (uint amountETH) {
    (, amountETH) = removeLiquidity(
      token,
      WETH,
      liquidity,
      amountTokenMin,
      amountETHMin,
      address(this),
      deadline
    );
    TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
    IWETH(WETH).withdraw(amountETH);
    TransferHelper.safeTransferETH(to, amountETH);
  }

  function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline,
    bool approveMax, uint8 v, bytes32 r, bytes32 s
  ) external virtual override returns (uint amountETH) {
    address pair = TetuSwapLibrary.pairFor(factory, token, WETH);
    uint value = approveMax ? type(uint).max : liquidity;
    ITetuSwapERC20(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
    amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
      token, liquidity, amountTokenMin, amountETHMin, to, deadline
    );
  }

  // **** SWAP ****
  // requires the initial amount to have already been sent to the first pair
  function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
    for (uint i; i < path.length - 1; i++) {
      (address input, address output) = (path[i], path[i + 1]);
      (address token0,) = TetuSwapLibrary.sortTokens(input, output);
      uint amountOut = amounts[i + 1];
      (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
      address to = i < path.length - 2 ? TetuSwapLibrary.pairFor(factory, output, path[i + 2]) : _to;
      ITetuSwapPair(TetuSwapLibrary.pairFor(factory, input, output)).swap(
        amount0Out, amount1Out, to, new bytes(0)
      );
    }
  }

  function swapExactTokensForTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  ) external virtual override ensure(deadline) returns (uint[] memory amounts) {
    callSync(path);
    amounts = TetuSwapLibrary.getAmountsOut(factory, amountIn, path);
    require(amounts[amounts.length - 1] >= amountOutMin, "TSR: INSUFFICIENT_OUTPUT_AMOUNT");
    TransferHelper.safeTransferFrom(
      path[0], msg.sender, TetuSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0]
    );
    _swap(amounts, path, to);
  }

  function swapTokensForExactTokens(
    uint amountOut,
    uint amountInMax,
    address[] calldata path,
    address to,
    uint deadline
  ) external virtual override ensure(deadline) returns (uint[] memory amounts) {
    callSync(path);
    amounts = TetuSwapLibrary.getAmountsIn(factory, amountOut, path);
    require(amounts[0] <= amountInMax, "TSR: EXCESSIVE_INPUT_AMOUNT");
    TransferHelper.safeTransferFrom(
      path[0], msg.sender, TetuSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0]
    );
    _swap(amounts, path, to);
  }

  function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
  external
  virtual
  override
  payable
  ensure(deadline)
  returns (uint[] memory amounts)
  {
    require(path[0] == WETH, "TSR: INVALID_PATH");
    callSync(path);
    amounts = TetuSwapLibrary.getAmountsOut(factory, msg.value, path);
    require(amounts[amounts.length - 1] >= amountOutMin, "TSR: INSUFFICIENT_OUTPUT_AMOUNT");
    IWETH(WETH).deposit{value : amounts[0]}();
    assert(IWETH(WETH).transfer(TetuSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
    _swap(amounts, path, to);
  }

  function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
  external
  virtual
  override
  ensure(deadline)
  returns (uint[] memory amounts)
  {
    require(path[path.length - 1] == WETH, "TSR: INVALID_PATH");
    callSync(path);
    amounts = TetuSwapLibrary.getAmountsIn(factory, amountOut, path);
    require(amounts[0] <= amountInMax, "TSR: EXCESSIVE_INPUT_AMOUNT");
    TransferHelper.safeTransferFrom(
      path[0], msg.sender, TetuSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0]
    );
    _swap(amounts, path, address(this));
    IWETH(WETH).withdraw(amounts[amounts.length - 1]);
    TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
  }

  function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
  external
  virtual
  override
  ensure(deadline)
  returns (uint[] memory amounts)
  {
    require(path[path.length - 1] == WETH, "TSR: INVALID_PATH");
    callSync(path);
    amounts = TetuSwapLibrary.getAmountsOut(factory, amountIn, path);
    require(amounts[amounts.length - 1] >= amountOutMin, "TSR: INSUFFICIENT_OUTPUT_AMOUNT");
    TransferHelper.safeTransferFrom(
      path[0], msg.sender, TetuSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0]
    );
    _swap(amounts, path, address(this));
    IWETH(WETH).withdraw(amounts[amounts.length - 1]);
    TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
  }

  function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
  external
  virtual
  override
  payable
  ensure(deadline)
  returns (uint[] memory amounts)
  {
    require(path[0] == WETH, "TSR: INVALID_PATH");
    callSync(path);
    amounts = TetuSwapLibrary.getAmountsIn(factory, amountOut, path);
    require(amounts[0] <= msg.value, "TSR: EXCESSIVE_INPUT_AMOUNT");
    IWETH(WETH).deposit{value : amounts[0]}();
    assert(IWETH(WETH).transfer(TetuSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
    _swap(amounts, path, to);
    // refund dust eth, if any
    if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
  }

  // **** SWAP (supporting fee-on-transfer tokens) ****
  // requires the initial amount to have already been sent to the first pair
  function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
    callSync(path);
    for (uint i; i < path.length - 1; i++) {
      (address input, address output) = (path[i], path[i + 1]);
      (address token0,) = TetuSwapLibrary.sortTokens(input, output);
      ITetuSwapPair pair = ITetuSwapPair(TetuSwapLibrary.pairFor(factory, input, output));
      uint amountInput;
      uint amountOutput;
      {// scope to avoid stack too deep errors
        (uint reserve0, uint reserve1,) = pair.getReserves();
        (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
        amountInput = pair.balanceOfVaultUnderlying(input) - reserveInput;
        amountOutput = TetuSwapLibrary.getAmountOut(
          amountInput,
          reserveInput,
          reserveOutput,
          pair.fee()
        );
      }
      (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
      address to = i < path.length - 2 ? TetuSwapLibrary.pairFor(factory, output, path[i + 2]) : _to;
      pair.swap(amount0Out, amount1Out, to, new bytes(0));
    }
  }

  function swapExactTokensForTokensSupportingFeeOnTransferTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  ) external virtual override ensure(deadline) {
    callSync(path);
    TransferHelper.safeTransferFrom(
      path[0], msg.sender, TetuSwapLibrary.pairFor(factory, path[0], path[1]), amountIn
    );
    uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
    _swapSupportingFeeOnTransferTokens(path, to);
    require(
      IERC20(path[path.length - 1]).balanceOf(to) - balanceBefore >= amountOutMin,
      "TSR: INSUFFICIENT_OUTPUT_AMOUNT"
    );
  }

  function swapExactETHForTokensSupportingFeeOnTransferTokens(
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  )
  external
  virtual
  override
  payable
  ensure(deadline)
  {
    require(path[0] == WETH, "TSR: INVALID_PATH");
    callSync(path);
    uint amountIn = msg.value;
    IWETH(WETH).deposit{value : amountIn}();
    assert(IWETH(WETH).transfer(TetuSwapLibrary.pairFor(factory, path[0], path[1]), amountIn));
    uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
    _swapSupportingFeeOnTransferTokens(path, to);
    require(
      IERC20(path[path.length - 1]).balanceOf(to) - balanceBefore >= amountOutMin,
      "TSR: INSUFFICIENT_OUTPUT_AMOUNT"
    );
  }

  function swapExactTokensForETHSupportingFeeOnTransferTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
  )
  external
  virtual
  override
  ensure(deadline)
  {
    require(path[path.length - 1] == WETH, "TSR: INVALID_PATH");
    callSync(path);
    TransferHelper.safeTransferFrom(
      path[0], msg.sender, TetuSwapLibrary.pairFor(factory, path[0], path[1]), amountIn
    );
    _swapSupportingFeeOnTransferTokens(path, address(this));
    uint amountOut = IERC20(WETH).balanceOf(address(this));
    require(amountOut >= amountOutMin, "TSR: INSUFFICIENT_OUTPUT_AMOUNT");
    IWETH(WETH).withdraw(amountOut);
    TransferHelper.safeTransferETH(to, amountOut);
  }

  function callSync(address[] memory path) private {
    require(path.length >= 2, "TSR: INVALID_PATH");
    for (uint i; i < path.length - 1; i++) {
      ITetuSwapPair(TetuSwapLibrary.pairFor(factory, path[i], path[i + 1])).sync();
    }
  }

  // **** LIBRARY FUNCTIONS ****
  function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {
    return TetuSwapLibrary.quote(amountA, reserveA, reserveB);
  }

  function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut, uint fee)
  public
  pure
  virtual
  override
  returns (uint amountOut)
  {
    return TetuSwapLibrary.getAmountOut(amountIn, reserveIn, reserveOut, fee);
  }

  function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut, uint fee)
  public
  pure
  virtual
  override
  returns (uint amountIn)
  {
    return TetuSwapLibrary.getAmountIn(amountOut, reserveIn, reserveOut, fee);
  }

  function getAmountsOut(uint amountIn, address[] memory path)
  public
  view
  virtual
  override
  returns (uint[] memory amounts)
  {
    return TetuSwapLibrary.getAmountsOut(factory, amountIn, path);
  }

  function getAmountsIn(uint amountOut, address[] memory path)
  public
  view
  virtual
  override
  returns (uint[] memory amounts)
  {
    return TetuSwapLibrary.getAmountsIn(factory, amountOut, path);
  }
}

File 2 of 10 : 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 10 : TransferHelper.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.4;

/// @title helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {

  function safeApprove(
    address token,
    address to,
    uint256 value
  ) internal {
    // bytes4(keccak256(bytes('approve(address,uint256)')));
    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
    require(
      success && (data.length == 0 || abi.decode(data, (bool))),
      "TransferHelper::safeApprove: approve failed"
    );
  }

  function safeTransfer(
    address token,
    address to,
    uint256 value
  ) internal {
    // bytes4(keccak256(bytes('transfer(address,uint256)')));
    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
    require(
      success && (data.length == 0 || abi.decode(data, (bool))),
      "TransferHelper::safeTransfer: transfer failed"
    );
  }

  function safeTransferFrom(
    address token,
    address from,
    address to,
    uint256 value
  ) internal {
    // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
    require(
      success && (data.length == 0 || abi.decode(data, (bool))),
      "TransferHelper::transferFrom: transferFrom failed"
    );
  }

  function safeTransferETH(address to, uint256 value) internal {
    (bool success,) = to.call{value : value}(new bytes(0));
    require(success, "TransferHelper::safeTransferETH: ETH transfer failed");
  }
}

File 4 of 10 : TetuSwapLibrary.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/utils/math/SafeMath.sol";
import "../interfaces/ITetuSwapPair.sol";
import "../interfaces/ITetuSwapFactory.sol";

/// @title UniswapV2Library https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol
library TetuSwapLibrary {
  using SafeMath for uint;

  uint constant private _PRECISION = 10000;
  uint constant private _FEE = 2;

  /// @dev returns sorted token addresses, used to handle return values from pairs sorted in this order
  function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
    require(tokenA != tokenB, "TSL: IDENTICAL_ADDRESSES");
    (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
    require(token0 != address(0), "TSL: ZERO_ADDRESS");
  }

  /// @dev use stored in factory pairs instead on the flay calculation
  ///      we have more flexible system and can't use old function
  function pairFor(address factory, address tokenA, address tokenB) internal view returns (address pair) {
    return ITetuSwapFactory(factory).getPair(tokenA, tokenB);
  }

  /// @dev fetches and sorts the reserves for a pair
  function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
    (address token0,) = sortTokens(tokenA, tokenB);
    (uint reserve0, uint reserve1,) = ITetuSwapPair(pairFor(factory, tokenA, tokenB)).getReserves();
    (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
  }

  /// @dev given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
  function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
    require(amountA > 0, "TSL: INSUFFICIENT_AMOUNT");
    require(reserveA > 0 && reserveB > 0, "TSL: INSUFFICIENT_LIQUIDITY");
    amountB = amountA.mul(reserveB) / reserveA;
  }

  /// @dev given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
  function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut, uint fee) internal pure returns (uint amountOut) {
    require(amountIn > 0, "TSL: INSUFFICIENT_INPUT_AMOUNT");
    require(reserveIn > 0 && reserveOut > 0, "TSL: INSUFFICIENT_LIQUIDITY");
    uint amountInWithFee = amountIn.mul(_PRECISION - fee);
    uint numerator = amountInWithFee.mul(reserveOut);
    uint denominator = reserveIn.mul(_PRECISION).add(amountInWithFee);
    amountOut = numerator / denominator;
  }

  /// @dev given an output amount of an asset and pair reserves, returns a required input amount of the other asset
  function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut, uint fee) internal pure returns (uint amountIn) {
    require(amountOut > 0, "TSL: INSUFFICIENT_OUTPUT_AMOUNT");
    require(reserveIn > 0 && reserveOut > 0, "TSL: INSUFFICIENT_LIQUIDITY");
    uint numerator = reserveIn.mul(amountOut).mul(_PRECISION);
    uint denominator = reserveOut.sub(amountOut).mul(_PRECISION - fee);
    amountIn = (numerator / denominator).add(1);
  }

  /// @dev performs chained getAmountOut calculations on any number of pairs
  function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
    require(path.length >= 2, "TSL: INVALID_PATH");
    amounts = new uint[](path.length);
    amounts[0] = amountIn;
    for (uint i; i < path.length - 1; i++) {
      (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
      amounts[i + 1] = getAmountOut(
        amounts[i],
        reserveIn,
        reserveOut,
        ITetuSwapPair(pairFor(factory, path[i], path[i + 1])).fee()
      );
    }
  }

  /// @dev performs chained getAmountIn calculations on any number of pairs
  function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) {
    require(path.length >= 2, "TSL: INVALID_PATH");
    amounts = new uint[](path.length);
    amounts[amounts.length - 1] = amountOut;
    for (uint i = path.length - 1; i > 0; i--) {
      (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]);
      amounts[i - 1] = getAmountIn(
        amounts[i],
        reserveIn,
        reserveOut,
        ITetuSwapPair(pairFor(factory, path[i - 1], path[i])).fee()
      );
    }
  }
}

File 5 of 10 : ITetuSwapERC20.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 ITetuSwapERC20 {

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

File 6 of 10 : ITetuSwapPair.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 ITetuSwapPair {

  function balanceOfVaultUnderlying(address _token) external view returns (uint);

  function setFee(uint _fee) external;

  function setVaults(address _vault0, address _vault1) external;

  function setRewardRecipient(address _recipient) external;

  function claimAll() external;

  function MINIMUM_LIQUIDITY() external pure returns (uint);

  function factory() external view returns (address);

  function rewardRecipient() external view returns (address);

  function fee() external view returns (uint);

  function token0() external view returns (address);

  function token1() external view returns (address);

  function vault0() external view returns (address);

  function vault1() 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 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 sync() external;

  function initialize(
    address _token0,
    address _token1,
    uint _fee
  ) external;

}

File 7 of 10 : ITetuSwapRouter.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 ITetuSwapRouter {

  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, uint fee) external pure returns (uint amountOut);

  function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut, uint fee) 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 8 of 10 : ITetuSwapFactory.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 ITetuSwapFactory {

  function getPair(address tokenA, address tokenB) external view returns (address pair);

  function allPairs(uint) external view returns (address pair);

  function allPairsLength() external view returns (uint);

  function createPair(address tokenA, address tokenB) external returns (address pair);

  function validPairs(address _pair) external view returns (bool);

}

File 9 of 10 : IWETH.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.4;

interface IWETH {
  function deposit() external payable;

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

  function withdraw(uint) external;
}

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

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"EthReceived","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b5060405162004c2138038062004c21833981016040819052620000349162000109565b6001600160a01b038216620000845760405162461bcd60e51b81526020600482015260116024820152705453523a205a65726f20666163746f727960781b60448201526064015b60405180910390fd5b6001600160a01b038116620000cd5760405162461bcd60e51b815260206004820152600e60248201526d0a8a6a47440b4cae4de40ae8aa8960931b60448201526064016200007b565b6001600160601b0319606092831b8116608052911b1660a05262000140565b80516001600160a01b03811681146200010457600080fd5b919050565b600080604083850312156200011c578182fd5b6200012783620000ec565b91506200013760208401620000ec565b90509250929050565b60805160601c60a05160601c614949620002d86000396000818161016a01528181610402015281816105e101528181610630015281816106d70152818161098a01528181610d3501528181610eed015281816112dd0152818161141a015281816114d70152818161156a015281816116e00152818161177c01528181611a2e01528181611afa01528181611b8b01528181611c5201528181611cc6015281816121c4015281816123c70152818161241d01528181612451015281816124d70152818161264b015281816127b501526128510152600081816104b60152818161079d0152818161088b01528181610a8c01528181610ac301528181610bf601528181610dfb01528181610ecb0152818161104c0152818161162f015281816117ae0152818161194d01528181611cf801528181611f5501528181612172015281816121a2015281816122cb015281816123fb015281816127100152818161288301528181612c6d015281816132a3015281816132d60152818161387901528181613a7401528181613cc40152613d9501526149496000f3fe60806040526004361061015a5760003560e01c80638803dbee116100c1578063c45a01551161007a578063c45a0155146104a4578063d06ca61f146104d8578063ded9382a146104f8578063e8e3370014610518578063f305d71914610553578063fb3bdb4114610566578063ffa1ad741461057957600080fd5b80638803dbee146103d0578063ad5c4648146103f0578063ad615dec14610431578063af2979eb14610451578063b6f9de9514610471578063baa2abde1461048457600080fd5b806352707d8c1161011357806352707d8c1461030d578063571fd0121461033b5780635b0d59841461035b5780635c11d7951461037b578063791ac9471461039d5780637ff36ab5146103bd57600080fd5b806302751cec1461022657806318cbafe5146102605780631f00ca741461028d5780632195995c146102ad57806338ed1739146102cd5780634a25d94a146102ed57600080fd5b3661022157336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101e85760405162461bcd60e51b8152602060048201526024808201527f5453523a204554482073656e646572206973206e6f74205745544820636f6e746044820152631c9858dd60e21b60648201526084015b60405180910390fd5b7f43d9b737f57bab095d7084cbd3c577bc42c225e75b71031ad697545794e3984a336040516102179190614603565b60405180910390a1005b600080fd5b34801561023257600080fd5b5061024661024136600461421f565b6105b7565b604080519283526020830191909152015b60405180910390f35b34801561026c57600080fd5b5061028061027b3660046144ee565b6106aa565b6040516102579190614671565b34801561029957600080fd5b506102806102a83660046143f8565b610a85565b3480156102b957600080fd5b506102466102c83660046140fb565b610ab9565b3480156102d957600080fd5b506102806102e83660046144ee565b610b92565b3480156102f957600080fd5b506102806103083660046144ee565b610d08565b34801561031957600080fd5b5061032d61032836600461458a565b610e9e565b604051908152602001610257565b34801561034757600080fd5b5061032d61035636600461458a565b610eb5565b34801561036757600080fd5b5061032d61037636600461427c565b610ec3565b34801561038757600080fd5b5061039b6103963660046144ee565b610fb0565b005b3480156103a957600080fd5b5061039b6103b83660046144ee565b6112b2565b6102806103cb366004614393565b611545565b3480156103dc57600080fd5b506102806103eb3660046144ee565b6118e9565b3480156103fc57600080fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b6040516102579190614603565b34801561043d57600080fd5b5061032d61044c36600461455f565b6119f0565b34801561045d57600080fd5b5061032d61046c36600461421f565b611a05565b61039b61047f366004614393565b611b68565b34801561049057600080fd5b5061024661049f36600461408a565b611f2a565b3480156104b057600080fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e457600080fd5b506102806104f33660046143f8565b61216b565b34801561050457600080fd5b5061024661051336600461427c565b612198565b34801561052457600080fd5b506105386105333660046141a4565b61228b565b60408051938452602084019290925290820152606001610257565b61053861056136600461421f565b61239b565b610280610574366004614393565b612626565b34801561058557600080fd5b506105aa604051806040016040528060058152602001640312e312e360dc1b81525081565b60405161025791906146b5565b60008082428110156105db5760405162461bcd60e51b81526004016101df9061472a565b61060a897f00000000000000000000000000000000000000000000000000000000000000008a8a8a308a611f2a565b909350915061061a898685612a1c565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561067c57600080fd5b505af1158015610690573d6000803e3d6000fd5b5050505061069e8583612b4f565b50965096945050505050565b606081428110156106cd5760405162461bcd60e51b81526004016101df9061472a565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016868661070460018261484c565b81811061072157634e487b7160e01b600052603260045260246000fd5b90506020020160208101906107369190614052565b6001600160a01b03161461075c5760405162461bcd60e51b81526004016101df906146ff565b610798868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b6107f67f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612d5692505050565b9150868260018451610808919061484c565b8151811061082657634e487b7160e01b600052603260045260246000fd5b6020026020010151101561084c5760405162461bcd60e51b81526004016101df90614787565b6109498686600081811061087057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906108859190614052565b3361091b7f00000000000000000000000000000000000000000000000000000000000000008a8a60008181106108cb57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906108e09190614052565b8b8b600181811061090157634e487b7160e01b600052603260045260246000fd5b90506020020160208101906109169190614052565b612fd3565b8560008151811061093c57634e487b7160e01b600052603260045260246000fd5b6020026020010151613058565b61098882878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250613196915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d83600185516109c6919061484c565b815181106109e457634e487b7160e01b600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b8152600401610a0a91815260200190565b600060405180830381600087803b158015610a2457600080fd5b505af1158015610a38573d6000803e3d6000fd5b50505050610a7a848360018551610a4f919061484c565b81518110610a6d57634e487b7160e01b600052603260045260246000fd5b6020026020010151612b4f565b509695505050505050565b6060610ab27f000000000000000000000000000000000000000000000000000000000000000084846133ab565b9392505050565b6000806000610ae97f00000000000000000000000000000000000000000000000000000000000000008f8f612fd3565b9050600087610af8578c610afc565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610b37903390309086908f908e908e908e90600401614617565b600060405180830381600087803b158015610b5157600080fd5b505af1158015610b65573d6000803e3d6000fd5b50505050610b788f8f8f8f8f8f8f611f2a565b809450819550505050509b509b9950505050505050505050565b60608142811015610bb55760405162461bcd60e51b81526004016101df9061472a565b610bf1868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b610c4f7f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612d5692505050565b9150868260018451610c61919061484c565b81518110610c7f57634e487b7160e01b600052603260045260246000fd5b60200260200101511015610ca55760405162461bcd60e51b81526004016101df90614787565b610cc98686600081811061087057634e487b7160e01b600052603260045260246000fd5b610a7a82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250613196915050565b60608142811015610d2b5760405162461bcd60e51b81526004016101df9061472a565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168686610d6260018261484c565b818110610d7f57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610d949190614052565b6001600160a01b031614610dba5760405162461bcd60e51b81526004016101df906146ff565b610df6868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b610e547f0000000000000000000000000000000000000000000000000000000000000000898888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506133ab92505050565b91508682600081518110610e7857634e487b7160e01b600052603260045260246000fd5b6020026020010151111561084c5760405162461bcd60e51b81526004016101df90614750565b6000610eac8585858561363c565b95945050505050565b6000610eac85858585613711565b600080610f117f00000000000000000000000000000000000000000000000000000000000000008d7f0000000000000000000000000000000000000000000000000000000000000000612fd3565b9050600086610f20578b610f24565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610f5f903390309086908e908d908d908d90600401614617565b600060405180830381600087803b158015610f7957600080fd5b505af1158015610f8d573d6000803e3d6000fd5b50505050610f9f8d8d8d8d8d8d611a05565b9d9c50505050505050505050505050565b8042811015610fd15760405162461bcd60e51b81526004016101df9061472a565b61100d858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b6110c88585600081811061103157634e487b7160e01b600052603260045260246000fd5b90506020020160208101906110469190614052565b336110c27f00000000000000000000000000000000000000000000000000000000000000008989600081811061108c57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906110a19190614052565b8a8a600181811061090157634e487b7160e01b600052603260045260246000fd5b8a613058565b600085856110d760018261484c565b8181106110f457634e487b7160e01b600052603260045260246000fd5b90506020020160208101906111099190614052565b6001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016111349190614603565b60206040518083038186803b15801561114c57600080fd5b505afa158015611160573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611184919061437b565b90506111c48686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892506137df915050565b868187876111d360018261484c565b8181106111f057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906112059190614052565b6001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016112309190614603565b60206040518083038186803b15801561124857600080fd5b505afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611280919061437b565b61128a919061484c565b10156112a85760405162461bcd60e51b81526004016101df90614787565b5050505050505050565b80428110156112d35760405162461bcd60e51b81526004016101df9061472a565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016858561130a60018261484c565b81811061132757634e487b7160e01b600052603260045260246000fd5b905060200201602081019061133c9190614052565b6001600160a01b0316146113625760405162461bcd60e51b81526004016101df906146ff565b61139e858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b6113c28585600081811061103157634e487b7160e01b600052603260045260246000fd5b6114008585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152503092506137df915050565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319061144f903090600401614603565b60206040518083038186803b15801561146757600080fd5b505afa15801561147b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149f919061437b565b9050868110156114c15760405162461bcd60e51b81526004016101df90614787565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561152357600080fd5b505af1158015611537573d6000803e3d6000fd5b505050506112a88482612b4f565b606081428110156115685760405162461bcd60e51b81526004016101df9061472a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316868660008181106115b357634e487b7160e01b600052603260045260246000fd5b90506020020160208101906115c89190614052565b6001600160a01b0316146115ee5760405162461bcd60e51b81526004016101df906146ff565b61162a868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b6116887f000000000000000000000000000000000000000000000000000000000000000034888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612d5692505050565b915086826001845161169a919061484c565b815181106116b857634e487b7160e01b600052603260045260246000fd5b602002602001015110156116de5760405162461bcd60e51b81526004016101df90614787565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08360008151811061172e57634e487b7160e01b600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561176157600080fd5b505af1158015611775573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6117ee7f00000000000000000000000000000000000000000000000000000000000000008989600081811061108c57634e487b7160e01b600052603260045260246000fd5b8460008151811061180f57634e487b7160e01b600052603260045260246000fd5b60200260200101516040518363ffffffff1660e01b8152600401611834929190614658565b602060405180830381600087803b15801561184e57600080fd5b505af1158015611862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118869190614311565b6118a057634e487b7160e01b600052600160045260246000fd5b6118df82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250613196915050565b5095945050505050565b6060814281101561190c5760405162461bcd60e51b81526004016101df9061472a565b611948868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b6119a67f0000000000000000000000000000000000000000000000000000000000000000898888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506133ab92505050565b915086826000815181106119ca57634e487b7160e01b600052603260045260246000fd5b60200260200101511115610ca55760405162461bcd60e51b81526004016101df90614750565b60006119fd848484613b30565b949350505050565b60008142811015611a285760405162461bcd60e51b81526004016101df9061472a565b611a57887f00000000000000000000000000000000000000000000000000000000000000008989893089611f2a565b6040516370a0823160e01b8152909350611ae49150899086906001600160a01b038316906370a0823190611a8f903090600401614603565b60206040518083038186803b158015611aa757600080fd5b505afa158015611abb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adf919061437b565b612a1c565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611b4657600080fd5b505af1158015611b5a573d6000803e3d6000fd5b50505050610a7a8483612b4f565b8042811015611b895760405162461bcd60e51b81526004016101df9061472a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031685856000818110611bd457634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611be99190614052565b6001600160a01b031614611c0f5760405162461bcd60e51b81526004016101df906146ff565b611c4b858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b60003490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611cab57600080fd5b505af1158015611cbf573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb611d387f00000000000000000000000000000000000000000000000000000000000000008989600081811061108c57634e487b7160e01b600052603260045260246000fd5b836040518363ffffffff1660e01b8152600401611d56929190614658565b602060405180830381600087803b158015611d7057600080fd5b505af1158015611d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da89190614311565b611dc257634e487b7160e01b600052600160045260246000fd5b60008686611dd160018261484c565b818110611dee57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611e039190614052565b6001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401611e2e9190614603565b60206040518083038186803b158015611e4657600080fd5b505afa158015611e5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7e919061437b565b9050611ebe8787808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508992506137df915050565b87818888611ecd60018261484c565b818110611eea57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611eff9190614052565b6001600160a01b03166370a08231886040518263ffffffff1660e01b81526004016112309190614603565b6000808242811015611f4e5760405162461bcd60e51b81526004016101df9061472a565b6000611f7b7f00000000000000000000000000000000000000000000000000000000000000008c8c612fd3565b6040516323b872dd60e01b81523360048201526001600160a01b03821660248201819052604482018c90529192506323b872dd90606401602060405180830381600087803b158015611fcc57600080fd5b505af1158015611fe0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120049190614311565b50600080826001600160a01b03166389afcb44896040518263ffffffff1660e01b81526004016120349190614603565b6040805180830381600087803b15801561204d57600080fd5b505af1158015612061573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208591906144cb565b9150915060006120958e8e613bbd565b509050806001600160a01b03168e6001600160a01b0316146120b85781836120bb565b82825b90975095508a87101561210d5760405162461bcd60e51b815260206004820152601a6024820152791514d48e88125394d551919250d251539517d057d05353d5539560321b60448201526064016101df565b8986101561215a5760405162461bcd60e51b815260206004820152601a6024820152791514d48e88125394d551919250d251539517d097d05353d5539560321b60448201526064016101df565b505050505097509795505050505050565b6060610ab27f00000000000000000000000000000000000000000000000000000000000000008484612d56565b60008060006121e87f00000000000000000000000000000000000000000000000000000000000000008e7f0000000000000000000000000000000000000000000000000000000000000000612fd3565b90506000876121f7578c6121fb565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90612236903390309086908f908e908e908e90600401614617565b600060405180830381600087803b15801561225057600080fd5b505af1158015612264573d6000803e3d6000fd5b505050506122768e8e8e8e8e8e6105b7565b909f909e509c50505050505050505050505050565b600080600083428110156122b15760405162461bcd60e51b81526004016101df9061472a565b6122bf8c8c8c8c8c8c613c96565b909450925060006122f17f00000000000000000000000000000000000000000000000000000000000000008e8e612fd3565b90506122ff8d338388613058565b61230b8c338387613058565b6040516335313c2160e11b81526001600160a01b03821690636a62784290612337908a90600401614603565b602060405180830381600087803b15801561235157600080fd5b505af1158015612365573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612389919061437b565b92505050985098509895505050505050565b600080600083428110156123c15760405162461bcd60e51b81526004016101df9061472a565b6123ef8a7f00000000000000000000000000000000000000000000000000000000000000008b348c8c613c96565b909450925060006124417f00000000000000000000000000000000000000000000000000000000000000008c7f0000000000000000000000000000000000000000000000000000000000000000612fd3565b905061244f8b338388613058565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb9250612511915084908890600401614658565b602060405180830381600087803b15801561252b57600080fd5b505af115801561253f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125639190614311565b61257d57634e487b7160e01b600052600160045260246000fd5b6040516335313c2160e11b81526001600160a01b03821690636a627842906125a9908a90600401614603565b602060405180830381600087803b1580156125c357600080fd5b505af11580156125d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125fb919061437b565b9250833411156126185761261833612613863461484c565b612b4f565b505096509650969350505050565b606081428110156126495760405162461bcd60e51b81526004016101df9061472a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168686600081811061269457634e487b7160e01b600052603260045260246000fd5b90506020020160208101906126a99190614052565b6001600160a01b0316146126cf5760405162461bcd60e51b81526004016101df906146ff565b61270b868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c2e92505050565b6127697f0000000000000000000000000000000000000000000000000000000000000000888888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506133ab92505050565b9150348260008151811061278d57634e487b7160e01b600052603260045260246000fd5b602002602001015111156127b35760405162461bcd60e51b81526004016101df90614750565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08360008151811061280357634e487b7160e01b600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561283657600080fd5b505af115801561284a573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6128c37f00000000000000000000000000000000000000000000000000000000000000008989600081811061108c57634e487b7160e01b600052603260045260246000fd5b846000815181106128e457634e487b7160e01b600052603260045260246000fd5b60200260200101516040518363ffffffff1660e01b8152600401612909929190614658565b602060405180830381600087803b15801561292357600080fd5b505af1158015612937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061295b9190614311565b61297557634e487b7160e01b600052600160045260246000fd5b6129b482878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250613196915050565b816000815181106129d557634e487b7160e01b600052603260045260246000fd5b60200260200101513411156118df576118df3383600081518110612a0957634e487b7160e01b600052603260045260246000fd5b602002602001015134612613919061484c565b600080846001600160a01b031663a9059cbb8585604051602401612a41929190614658565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612a7a91906145e7565b6000604051808303816000865af19150503d8060008114612ab7576040519150601f19603f3d011682016040523d82523d6000602084013e612abc565b606091505b5091509150818015612ae6575080511580612ae6575080806020019051810190612ae69190614311565b612b485760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201526c185b9cd9995c8819985a5b1959609a1b60648201526084016101df565b5050505050565b604080516000808252602082019092526001600160a01b038416908390604051612b7991906145e7565b60006040518083038185875af1925050503d8060008114612bb6576040519150601f19603f3d011682016040523d82523d6000602084013e612bbb565b606091505b5050905080612c295760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527308115512081d1c985b9cd9995c8819985a5b195960621b60648201526084016101df565b505050565b600281511015612c505760405162461bcd60e51b81526004016101df906146ff565b60005b60018251612c61919061484c565b811015612d5257612ced7f0000000000000000000000000000000000000000000000000000000000000000838381518110612cac57634e487b7160e01b600052603260045260246000fd5b602002602001015184846001612cc291906147f5565b81518110612ce057634e487b7160e01b600052603260045260246000fd5b6020026020010151612fd3565b6001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d2757600080fd5b505af1158015612d3b573d6000803e3d6000fd5b505050508080612d4a906148a6565b915050612c53565b5050565b6060600282511015612d9e5760405162461bcd60e51b81526020600482015260116024820152700a8a6987440929cac82989288bea082a89607b1b60448201526064016101df565b815167ffffffffffffffff811115612dc657634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612def578160200160208202803683370190505b5090508281600081518110612e1457634e487b7160e01b600052603260045260246000fd5b60200260200101818152505060005b60018351612e31919061484c565b811015612fcb57600080612ea087868581518110612e5f57634e487b7160e01b600052603260045260246000fd5b602002602001015187866001612e7591906147f5565b81518110612e9357634e487b7160e01b600052603260045260246000fd5b6020026020010151613eda565b91509150612f80848481518110612ec757634e487b7160e01b600052603260045260246000fd5b60200260200101518383612f0b8b8a8981518110612ef557634e487b7160e01b600052603260045260246000fd5b60200260200101518b8a6001612cc291906147f5565b6001600160a01b031663ddca3f436040518163ffffffff1660e01b815260040160206040518083038186803b158015612f4357600080fd5b505afa158015612f57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f7b919061437b565b61363c565b84612f8c8560016147f5565b81518110612faa57634e487b7160e01b600052603260045260246000fd5b60200260200101818152505050508080612fc3906148a6565b915050612e23565b509392505050565b60405163e6a4390560e01b81526001600160a01b03838116600483015282811660248301526000919085169063e6a439059060440160206040518083038186803b15801561302057600080fd5b505afa158015613034573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119fd919061406e565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916130bc91906145e7565b6000604051808303816000865af19150503d80600081146130f9576040519150601f19603f3d011682016040523d82523d6000602084013e6130fe565b606091505b50915091508180156131285750805115806131285750808060200190518101906131289190614311565b61318e5760405162461bcd60e51b815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472604482015270185b9cd9995c919c9bdb4819985a5b1959607a1b60648201526084016101df565b505050505050565b60005b600183516131a7919061484c565b8110156133a5576000808483815181106131d157634e487b7160e01b600052603260045260246000fd5b6020026020010151858460016131e791906147f5565b8151811061320557634e487b7160e01b600052603260045260246000fd5b602002602001015191509150600061321d8383613bbd565b50905060008761322e8660016147f5565b8151811061324c57634e487b7160e01b600052603260045260246000fd5b60200260200101519050600080836001600160a01b0316866001600160a01b03161461327a5782600061327e565b6000835b91509150600060028a51613292919061484c565b881061329e57886132cf565b6132cf7f0000000000000000000000000000000000000000000000000000000000000000878c612cc28c60026147f5565b90506132fc7f00000000000000000000000000000000000000000000000000000000000000008888612fd3565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015613339576020820181803683370190505b506040518563ffffffff1660e01b815260040161335994939291906147be565b600060405180830381600087803b15801561337357600080fd5b505af1158015613387573d6000803e3d6000fd5b5050505050505050505050808061339d906148a6565b915050613199565b50505050565b60606002825110156133f35760405162461bcd60e51b81526020600482015260116024820152700a8a6987440929cac82989288bea082a89607b1b60448201526064016101df565b815167ffffffffffffffff81111561341b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613444578160200160208202803683370190505b509050828160018351613457919061484c565b8151811061347557634e487b7160e01b600052603260045260246000fd5b602002602001018181525050600060018351613491919061484c565b90505b8015612fcb576000806134f387866134ad60018761484c565b815181106134cb57634e487b7160e01b600052603260045260246000fd5b6020026020010151878681518110612e9357634e487b7160e01b600052603260045260246000fd5b915091506135f184848151811061351a57634e487b7160e01b600052603260045260246000fd5b6020026020010151838361357c8b8a60018a613536919061484c565b8151811061355457634e487b7160e01b600052603260045260246000fd5b60200260200101518b8a81518110612ce057634e487b7160e01b600052603260045260246000fd5b6001600160a01b031663ddca3f436040518163ffffffff1660e01b815260040160206040518083038186803b1580156135b457600080fd5b505afa1580156135c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ec919061437b565b613711565b846135fd60018661484c565b8151811061361b57634e487b7160e01b600052603260045260246000fd5b602002602001018181525050505080806136349061488f565b915050613494565b600080851161368d5760405162461bcd60e51b815260206004820152601e60248201527f54534c3a20494e53554646494349454e545f494e5055545f414d4f554e54000060448201526064016101df565b60008411801561369d5750600083115b6136b95760405162461bcd60e51b81526004016101df906146c8565b60006136d16136ca8461271061484c565b8790613fb3565b905060006136df8286613fb3565b905060006136f9836136f389612710613fb3565b90613fbf565b9050613705818361480d565b98975050505050505050565b60008085116137625760405162461bcd60e51b815260206004820152601f60248201527f54534c3a20494e53554646494349454e545f4f55545055545f414d4f554e540060448201526064016101df565b6000841180156137725750600083115b61378e5760405162461bcd60e51b81526004016101df906146c8565b60006137a66127106137a08789613fb3565b90613fb3565b905060006137c36137b98561271061484c565b6137a0878a613fcb565b90506137d460016136f3838561480d565b979650505050505050565b6137e882612c2e565b60005b600183516137f9919061484c565b811015612c295760008084838151811061382357634e487b7160e01b600052603260045260246000fd5b60200260200101518584600161383991906147f5565b8151811061385757634e487b7160e01b600052603260045260246000fd5b602002602001015191509150600061386f8383613bbd565b509050600061389f7f00000000000000000000000000000000000000000000000000000000000000008585612fd3565b9050600080600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156138e057600080fd5b505afa1580156138f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613918919061432d565b506001600160701b031691506001600160701b03169150600080876001600160a01b03168a6001600160a01b031614613952578284613955565b83835b9150915081876001600160a01b031663a7af47968c6040518263ffffffff1660e01b81526004016139869190614603565b60206040518083038186803b15801561399e57600080fd5b505afa1580156139b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139d6919061437b565b6139e0919061484c565b9550613a218683838a6001600160a01b031663ddca3f436040518163ffffffff1660e01b815260040160206040518083038186803b158015612f4357600080fd5b945050505050600080856001600160a01b0316886001600160a01b031614613a4b57826000613a4f565b6000835b91509150600060028c51613a63919061484c565b8a10613a6f578a613aa0565b613aa07f0000000000000000000000000000000000000000000000000000000000000000898e612cc28e60026147f5565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f90613ae290869086908690602481016147be565b600060405180830381600087803b158015613afc57600080fd5b505af1158015613b10573d6000803e3d6000fd5b505050505050505050505050508080613b28906148a6565b9150506137eb565b6000808411613b7c5760405162461bcd60e51b81526020600482015260186024820152771514d30e88125394d551919250d251539517d05353d5539560421b60448201526064016101df565b600083118015613b8c5750600082115b613ba85760405162461bcd60e51b81526004016101df906146c8565b82613bb38584613fb3565b6119fd919061480d565b600080826001600160a01b0316846001600160a01b03161415613c1d5760405162461bcd60e51b815260206004820152601860248201527754534c3a204944454e544943414c5f41444452455353455360401b60448201526064016101df565b826001600160a01b0316846001600160a01b031610613c3d578284613c40565b83835b90925090506001600160a01b038216613c8f5760405162461bcd60e51b815260206004820152601160248201527054534c3a205a45524f5f4144445245535360781b60448201526064016101df565b9250929050565b60405163e6a4390560e01b81526001600160a01b0387811660048301528681166024830152600091829182917f00000000000000000000000000000000000000000000000000000000000000009091169063e6a439059060440160206040518083038186803b158015613d0857600080fd5b505afa158015613d1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d40919061406e565b6001600160a01b03161415613d8d5760405162461bcd60e51b81526020600482015260136024820152721514d48e8814185a5c881b9bdd08195e1a5cdd606a1b60448201526064016101df565b600080613dbb7f00000000000000000000000000000000000000000000000000000000000000008b8b613eda565b91509150816000148015613dcd575080155b15613ddd57879350869250613ecd565b6000613dea898484613b30565b9050878111613e4b5785811015613e405760405162461bcd60e51b815260206004820152601a6024820152791514d48e88125394d551919250d251539517d097d05353d5539560321b60448201526064016101df565b889450925082613ecb565b6000613e58898486613b30565b905089811115613e7857634e487b7160e01b600052600160045260246000fd5b87811015613ec55760405162461bcd60e51b815260206004820152601a6024820152791514d48e88125394d551919250d251539517d057d05353d5539560321b60448201526064016101df565b94508793505b505b5050965096945050505050565b6000806000613ee98585613bbd565b509050600080613efa888888612fd3565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015613f3257600080fd5b505afa158015613f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f6a919061432d565b506001600160701b031691506001600160701b03169150826001600160a01b0316876001600160a01b031614613fa1578082613fa4565b81815b90999098509650505050505050565b6000610ab2828461482d565b6000610ab282846147f5565b6000610ab2828461484c565b8035613fe2816148ed565b919050565b60008083601f840112613ff8578081fd5b50813567ffffffffffffffff81111561400f578182fd5b6020830191508360208260051b8501011115613c8f57600080fd5b80516001600160701b0381168114613fe257600080fd5b803560ff81168114613fe257600080fd5b600060208284031215614063578081fd5b8135610ab2816148ed565b60006020828403121561407f578081fd5b8151610ab2816148ed565b600080600080600080600060e0888a0312156140a4578283fd5b87356140af816148ed565b965060208801356140bf816148ed565b955060408801359450606088013593506080880135925060a08801356140e4816148ed565b8092505060c0880135905092959891949750929550565b60008060008060008060008060008060006101608c8e03121561411c578384fd5b8b35614127816148ed565b9a5060208c0135614137816148ed565b995060408c0135985060608c0135975060808c0135965060a08c013561415c816148ed565b955060c08c0135945060e08c013561417381614905565b93506141826101008d01614041565b92506101208c013591506101408c013590509295989b509295989b9093969950565b600080600080600080600080610100898b0312156141c0578384fd5b88356141cb816148ed565b975060208901356141db816148ed565b965060408901359550606089013594506080890135935060a0890135925060c0890135614207816148ed565b8092505060e089013590509295985092959890939650565b60008060008060008060c08789031215614237578182fd5b8635614242816148ed565b95506020870135945060408701359350606087013592506080870135614267816148ed565b8092505060a087013590509295509295509295565b6000806000806000806000806000806101408b8d03121561429b578384fd5b8a356142a6816148ed565b995060208b0135985060408b0135975060608b0135965060808b01356142cb816148ed565b955060a08b0135945060c08b01356142e281614905565b93506142f060e08c01614041565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600060208284031215614322578081fd5b8151610ab281614905565b600080600060608486031215614341578081fd5b61434a8461402a565b92506143586020850161402a565b9150604084015163ffffffff81168114614370578182fd5b809150509250925092565b60006020828403121561438c578081fd5b5051919050565b6000806000806000608086880312156143aa578283fd5b85359450602086013567ffffffffffffffff8111156143c7578384fd5b6143d388828901613fe7565b90955093505060408601356143e7816148ed565b949793965091946060013592915050565b6000806040838503121561440a578182fd5b8235915060208084013567ffffffffffffffff80821115614429578384fd5b818601915086601f83011261443c578384fd5b81358181111561444e5761444e6148d7565b8060051b604051601f19603f83011681018181108582111715614473576144736148d7565b604052828152858101935084860182860187018b1015614491578788fd5b8795505b838610156144ba576144a681613fd7565b855260019590950194938601938601614495565b508096505050505050509250929050565b600080604083850312156144dd578182fd5b505080516020909101519092909150565b60008060008060008060a08789031215614506578384fd5b8635955060208701359450604087013567ffffffffffffffff81111561452a578485fd5b61453689828a01613fe7565b909550935050606087013561454a816148ed565b80925050608087013590509295509295509295565b600080600060608486031215614573578081fd5b505081359360208301359350604090920135919050565b6000806000806080858703121561459f578182fd5b5050823594602084013594506040840135936060013592509050565b600081518084526145d3816020860160208601614863565b601f01601f19169290920160200192915050565b600082516145f9818460208701614863565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156146a95783518352928401929184019160010161468d565b50909695505050505050565b602081526000610ab260208301846145bb565b6020808252601b908201527f54534c3a20494e53554646494349454e545f4c49515549444954590000000000604082015260600190565b6020808252601190820152700a8a6a47440929cac82989288bea082a89607b1b604082015260600190565b6020808252600c908201526b1514d48e881156141254915160a21b604082015260600190565b6020808252601b908201527f5453523a204558434553534956455f494e5055545f414d4f554e540000000000604082015260600190565b6020808252601f908201527f5453523a20494e53554646494349454e545f4f55545055545f414d4f554e5400604082015260600190565b84815283602082015260018060a01b03831660408201526080606082015260006147eb60808301846145bb565b9695505050505050565b60008219821115614808576148086148c1565b500190565b60008261482857634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615614847576148476148c1565b500290565b60008282101561485e5761485e6148c1565b500390565b60005b8381101561487e578181015183820152602001614866565b838111156133a55750506000910152565b60008161489e5761489e6148c1565b506000190190565b60006000198214156148ba576148ba6148c1565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461490257600080fd5b50565b801515811461490257600080fdfea264697066735822122076b7d417e22e5132690a90fcf2e4884f3c0ccdae5b587f2a1fdd5aea5109882964736f6c63430008040033000000000000000000000000fb6a440af0bbbad0cc5f24323c7df9d400084a1200000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83

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

000000000000000000000000fb6a440af0bbbad0cc5f24323c7df9d400084a1200000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83

-----Decoded View---------------
Arg [0] : _factory (address): 0xfb6a440af0bbbad0cc5f24323c7df9d400084a12
Arg [1] : _WETH (address): 0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000fb6a440af0bbbad0cc5f24323c7df9d400084a12
Arg [1] : 00000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Validator ID :
0 FTM

Amount Staked
0

Amount Delegated
0

Staking Total
0

Staking Start Epoch
0

Staking Start Time
0

Proof of Importance
0

Origination Score
0

Validation Score
0

Active
0

Online
0

Downtime
0 s
Address Amount claimed Rewards Created On Epoch Created On
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.