CRO Price: $0.19 (+4.60%)

Contract

0xfc4d9543b08Ac8c6F883755e83bf673d533B5DCE

Overview

CRO Balance

Cronos Chain LogoCronos Chain LogoCronos Chain Logo0 CRO

CRO Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap And Repay171601432024-12-12 15:33:591 hr ago1734017639IN
0xfc4d9543...d533B5DCE
0 CRO9.330253755,050
Swap And Repay171601302024-12-12 15:32:441 hr ago1734017564IN
0xfc4d9543...d533B5DCE
0 CRO5.32479075,050
Swap And Repay171600552024-12-12 15:25:402 hrs ago1734017140IN
0xfc4d9543...d533B5DCE
0 CRO8.89360425,048.5
Swap And Deposit171594252024-12-12 14:26:113 hrs ago1734013571IN
0xfc4d9543...d533B5DCE
0 CRO8.66615975,100
Swap And Repay171592792024-12-12 14:12:253 hrs ago1734012745IN
0xfc4d9543...d533B5DCE
0 CRO9.30710965,050
Swap And Deposit171589452024-12-12 13:40:533 hrs ago1734010853IN
0xfc4d9543...d533B5DCE
0 CRO8.470938735,048.5
Swap And Repay171582902024-12-12 12:39:104 hrs ago1734007150IN
0xfc4d9543...d533B5DCE
0 CRO8.94294445,200
Swap And Repay171577122024-12-12 11:44:385 hrs ago1734003878IN
0xfc4d9543...d533B5DCE
0 CRO8.301356655,050
Swap And Repay171554972024-12-12 8:14:199 hrs ago1733991259IN
0xfc4d9543...d533B5DCE
0 CRO9.468280355,050
Swap And Repay171540452024-12-12 5:45:2111 hrs ago1733982321IN
0xfc4d9543...d533B5DCE
0 CRO9.428597455,050
Swap And Deposit171533512024-12-12 4:37:5212 hrs ago1733978272IN
0xfc4d9543...d533B5DCE
0 CRO9.58290025,050
Swap And Deposit171533202024-12-12 4:34:5112 hrs ago1733978091IN
0xfc4d9543...d533B5DCE
0 CRO9.069966655,050
Swap And Repay171529032024-12-12 3:54:0413 hrs ago1733975644IN
0xfc4d9543...d533B5DCE
0 CRO7.834913555,048.5
Swap And Repay171528982024-12-12 3:53:3713 hrs ago1733975617IN
0xfc4d9543...d533B5DCE
0 CRO7.473107755,048.5
Swap And Deposit171524042024-12-12 3:05:3814 hrs ago1733972738IN
0xfc4d9543...d533B5DCE
0 CRO8.743605355,050
Swap And Deposit171523032024-12-12 2:55:5314 hrs ago1733972153IN
0xfc4d9543...d533B5DCE
0 CRO9.58290025,050
Swap And Repay171516802024-12-12 1:55:1915 hrs ago1733968519IN
0xfc4d9543...d533B5DCE
0 CRO8.87495085,050
Swap And Repay171516692024-12-12 1:54:0915 hrs ago1733968449IN
0xfc4d9543...d533B5DCE
0 CRO8.8217445,050
Swap And Repay171516652024-12-12 1:53:4715 hrs ago1733968427IN
0xfc4d9543...d533B5DCE
0 CRO8.8217445,050
Swap And Deposit171502682024-12-11 23:38:2717 hrs ago1733960307IN
0xfc4d9543...d533B5DCE
0 CRO7.980436565,048.5
Swap And Repay171500862024-12-11 23:20:4818 hrs ago1733959248IN
0xfc4d9543...d533B5DCE
0 CRO9.327405555,050
Swap And Repay171498202024-12-11 22:55:0718 hrs ago1733957707IN
0xfc4d9543...d533B5DCE
0 CRO8.50519285,048.5
Swap And Repay171495592024-12-11 22:29:5418 hrs ago1733956194IN
0xfc4d9543...d533B5DCE
0 CRO8.908598245,048.5
Swap And Repay171495452024-12-11 22:28:3519 hrs ago1733956115IN
0xfc4d9543...d533B5DCE
0 CRO8.906159825,048.5
Swap And Repay171492482024-12-11 21:59:5619 hrs ago1733954396IN
0xfc4d9543...d533B5DCE
0 CRO8.83478315,050
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
171594252024-12-12 14:26:113 hrs ago1734013571
0xfc4d9543...d533B5DCE
2,397.00015565 CRO
171594252024-12-12 14:26:113 hrs ago1734013571
0xfc4d9543...d533B5DCE
2,397.00015565 CRO
171589452024-12-12 13:40:533 hrs ago1734010853
0xfc4d9543...d533B5DCE
49.7155871 CRO
171589452024-12-12 13:40:533 hrs ago1734010853
0xfc4d9543...d533B5DCE
49.7155871 CRO
171577122024-12-12 11:44:385 hrs ago1734003878
0xfc4d9543...d533B5DCE
13.72445203 CRO
171577122024-12-12 11:44:385 hrs ago1734003878
0xfc4d9543...d533B5DCE
13.45340131 CRO
171577122024-12-12 11:44:385 hrs ago1734003878
0xfc4d9543...d533B5DCE
2,704.13366367 CRO
171577122024-12-12 11:44:385 hrs ago1734003878
0xfc4d9543...d533B5DCE
2,704.40471439 CRO
171533512024-12-12 4:37:5212 hrs ago1733978272
0xfc4d9543...d533B5DCE
10,000.00007507 CRO
171533512024-12-12 4:37:5212 hrs ago1733978272
0xfc4d9543...d533B5DCE
10,000.00007507 CRO
171533202024-12-12 4:34:5112 hrs ago1733978091
0xfc4d9543...d533B5DCE
8,000.00033629 CRO
171533202024-12-12 4:34:5112 hrs ago1733978091
0xfc4d9543...d533B5DCE
8,000.00033629 CRO
171529032024-12-12 3:54:0413 hrs ago1733975644
0xfc4d9543...d533B5DCE
9.09333843 CRO
171529032024-12-12 3:54:0413 hrs ago1733975644
0xfc4d9543...d533B5DCE
8.05364515 CRO
171529032024-12-12 3:54:0413 hrs ago1733975644
0xfc4d9543...d533B5DCE
10,396.38438298 CRO
171529032024-12-12 3:54:0413 hrs ago1733975644
0xfc4d9543...d533B5DCE
10,397.42407626 CRO
171528982024-12-12 3:53:3713 hrs ago1733975617
0xfc4d9543...d533B5DCE
5.71000747 CRO
171528982024-12-12 3:53:3713 hrs ago1733975617
0xfc4d9543...d533B5DCE
5.19010236 CRO
171528982024-12-12 3:53:3713 hrs ago1733975617
0xfc4d9543...d533B5DCE
5,195.29247016 CRO
171528982024-12-12 3:53:3713 hrs ago1733975617
0xfc4d9543...d533B5DCE
5,195.81237527 CRO
171524042024-12-12 3:05:3814 hrs ago1733972738
0xfc4d9543...d533B5DCE
18,000.00016309 CRO
171524042024-12-12 3:05:3814 hrs ago1733972738
0xfc4d9543...d533B5DCE
18,000.00016309 CRO
171523032024-12-12 2:55:5314 hrs ago1733972153
0xfc4d9543...d533B5DCE
33,000.01006578 CRO
171523032024-12-12 2:55:5314 hrs ago1733972153
0xfc4d9543...d533B5DCE
33,000.01006578 CRO
171502682024-12-11 23:38:2717 hrs ago1733960307
0xfc4d9543...d533B5DCE
7,323.17246286 CRO
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DeferLiquidityCheckAdapter

Compiler Version
v0.8.3+commit.8d00100c

Optimization Enabled:
Yes with 10 runs

Other Settings:
default evmVersion
File 1 of 10 : DeferLiquidityCheckAdapter.sol
pragma solidity ^0.8.0;

import "./DeferLiquidityCheckAdapterV7.sol";

/**
 * @title Tectonic's DeferLiquidityCheckAdapter Contract
 * @author Tectonic
 * @notice Adapter to leverage deferLiquidityCheck feature to implement strategies. No tokens should be left on this contract.
 */
contract DeferLiquidityCheckAdapter is DeferLiquidityCheckAdapterV7 {
    constructor(address _WETH, address _vvs, address _wowmaxRouter) public DeferLiquidityCheckAdapterV7(_WETH, _vvs, _wowmaxRouter) {}
}

File 2 of 10 : DeferLiquidityCheckAdapterV7.sol
pragma solidity ^0.8.0;

import "./Interface.sol";
import "./DeferLiquidityCheckAdapterStorage.sol";
import "../Interfaces/IVVSRouter02.sol";
import "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-solidity/contracts/access/Ownable.sol";
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
//import "hardhat/console.sol";

/**
 * @title Tectonic's DeferLiquidityCheckAdapterV7 Contract
 * @author Tectonic
 * @notice Adapter to help with the deferLiquidityCheck related features. No tokens should be left on this contract.
 */
contract DeferLiquidityCheckAdapterV7 is Ownable, DeferLiquidityCheckAdapterStorageV5 {
    using SafeERC20 for IERC20;

    // @notice Emitted when set underlying token to tToken mapping
    event SetErc20AndTTokenMapping(address tectonicSocketAddress, address[] erc20Addresses, address[] tTokenAddresses);

    // @notice Emitted when set tectonicSocketAddress
    event AddOrRemoveTectonicSocket(address tectonicSocketAddress, bool isTCore);

    /**
     * @notice Event emitted when swapAndRepay
     */
    event SwapAndRepay(address indexed user, address tTokenFrom, uint swapFromAmount, address tTokenTo, uint actualRepayAmount);

    /**
     * @notice Event emitted when swapAndDeposit
     */
    event SwapAndDeposit(address indexed user, address tTokenFrom, uint swapFromAmount, address tTokenTo, uint swapToAmount);

    /**
     * @notice Event emitted when CreateLongNShortPosition
     */
    event CreateLongNShortPosition(address indexed user, address tTokenToShort, uint shortAmount, address tTokenToLong, uint longAmount, uint finalLongAmount);

    uint256 constant SLIPPAGE_BASE = 10 ** 18;

    uint256 constant PRECISION = 10 ** 18;

    uint256 constant DOUBLE_PRECISION = 10 ** 36;

    uint256 constant MAX_VALUE = 2 ** 256 - 1;

    address public immutable WETH;
    IVVSRouter02 public immutable vvs;
    address public immutable wowmaxRouter;

    constructor(address _WETH, address _vvs, address _wowmaxRouter) public {
        WETH = _WETH;
        vvs = IVVSRouter02(_vvs);
        wowmaxRouter = _wowmaxRouter;
    }

    /**
     * Only tectonic core can access
     */
    modifier onlyTectonicCore() virtual {
        require(isTectonicCores[msg.sender], "only tectonicCore can access this function");
        _;
    }

    /** External Functions **/

    function adapterVersion() external pure virtual returns (uint8) {
        return 7;
    }

    /**
     * @notice Repay debt with collateral
     * @param tectonicSocketAddress       Address of tectonic socket
     * @param account                     Address of user
     * @param tTokenAmount                Amount of tToken to redeem
     * @param repayAmount                 Amount of debt token to repay, as borrows accrue every block, we usually set a larger value for this field on FE
     * @param amountInMax                 Max amountIn while token swap
     * @param path                        Path to swap token on VVS finance
     */
    function swapAndRepay(
        address tectonicSocketAddress,
        address account,
        uint tTokenAmount,
        uint repayAmount,
        uint amountInMax,
        address[] calldata path
    ) external {
        //packing data
        bytes memory data = abi.encode(msg.sender, repayAmount, tTokenAmount, amountInMax, path);
        ITectonicCore(tectonicSocketAddress).deferLiquidityCheck(msg.sender, abi.encodeWithSignature("swapAndRepayCallback(bytes)", data));
    }

    /**
     * @dev Local vars for avoiding stack-depth limits in swapAndRepayCallback function.
     */
    struct SwapAndRepayLocalVars {
        address account;
    }

    /**
         * @dev Suppose user is using tToken A to pay token B's debt:
     *          0. Transfer tToken A to Adapter
     *          1. Redeem tToken A to token A
     *          2. Swap token A to token B
     *          3. Repay token B and clear the debt for user
     *          4. deposit remaining token A to get tToken A
     *          5. Transfer tToken A to user
     *
     * @param data      Callback data from TectonicCore
     */
    function swapAndRepayCallback(bytes memory data) external onlyTectonicCore {
        // unpacking data
        (address account, uint repayAmount, uint tTokenAmount, uint amountInMax, address[] memory path) =
        abi.decode(data, (address, uint, uint, uint, address[]));
        address underlyingFrom = path[0];
        address underlyingTo = path[path.length - 1];
        address tTokenFrom = erc20TokenToTTokenMap[msg.sender][underlyingFrom];
        address tTokenTo = erc20TokenToTTokenMap[msg.sender][underlyingTo];

        SwapAndRepayLocalVars memory vars;
        vars.account = account;

        require(tTokenFrom != tTokenTo, "same markets");

        require(ITToken(tTokenFrom).transferFrom(vars.account, address(this), tTokenAmount), "tToken insufficient fund");

        // Notice that for tCRO market, get CRO after redeem
        require(ITToken(tTokenFrom).redeem(tTokenAmount) == 0, "redeem tToken failed");
        uint redeemFromAmount = _balanceOf(underlyingFrom);

        uint borrows = ITToken(tTokenTo).borrowBalanceCurrent(vars.account);
        // get actual repay amount by comparing to account's current borrow
        uint actualRepayAmount = repayAmount > borrows ? borrows : repayAmount;

        _performSwapAnyForExactAny(amountInMax, actualRepayAmount, path);

        // repay borrow
        _repayBorrowBehalf(underlyingTo, tTokenTo, vars.account, actualRepayAmount);

        // send back remaining token A to account
        uint remainingFromAmount = _balanceOf(underlyingFrom);
        if (remainingFromAmount > 0) {
            _mint(underlyingFrom, tTokenFrom, remainingFromAmount);
            require(ITToken(tTokenFrom).transfer(vars.account, ITToken(tTokenFrom).balanceOf(address(this))), "transfer remaining tToken failed");
        }

        emit SwapAndRepay(vars.account, tTokenFrom, redeemFromAmount - remainingFromAmount, tTokenTo, actualRepayAmount);
    }

    /**
     * @notice Swap collateral
     * @param tectonicSocketAddress       Address of tectonic socket
     * @param account                     Address of user
     * @param tTokenAmount                Amount of tToken to redeem
     * @param amountOutMin                Min amountOut while token swap
     * @param path                        Path to swap token on VVS finance
     */
    function swapAndDeposit(
        address tectonicSocketAddress,
        address account,
        uint tTokenAmount,
        uint amountOutMin,
        address[] calldata path
    ) external {
        //packing data
        bytes memory data = abi.encode(msg.sender, tTokenAmount, amountOutMin, path);
        ITectonicCore(tectonicSocketAddress).deferLiquidityCheck(msg.sender, abi.encodeWithSignature("swapAndDepositCallback(bytes)", data));
    }

    /**
     * @dev Suppose user swap tToken A to tToken B:
     *          0. Transfer tToken A to Adapter
     *          1. Redeem tToken A to token A
     *          2. Swap token A to token B
     *          4. deposit token B to get tToken B
     *          5. Transfer tToken B to user
     *
     * @param data      Callback data from TectonicCore
     */
    function swapAndDepositCallback(bytes memory data) external onlyTectonicCore {
        // unpacking data
        (address account, uint tTokenAmount, uint amountOutMin, address[] memory path) = abi.decode(data, (address, uint, uint, address[]));
        address underlyingFrom = path[0];
        address underlyingTo = path[path.length - 1];
        address tTokenFrom = erc20TokenToTTokenMap[msg.sender][underlyingFrom];
        address tTokenTo = erc20TokenToTTokenMap[msg.sender][underlyingTo];

        require(tTokenFrom != tTokenTo, "same markets");

        require(ITToken(tTokenFrom).transferFrom(account, address(this), tTokenAmount), "insufficient tToken to transfer");
        require(ITToken(tTokenFrom).redeem(tTokenAmount) == 0, "redeem tToken failed");

        uint swapFromAmount = _balanceOf(underlyingFrom);
        _performSwapExactAnyForAny(swapFromAmount, amountOutMin, path);

        uint swapToAmount = _balanceOf(underlyingTo);
        _mint(underlyingTo, tTokenTo, swapToAmount);
        require(ITToken(tTokenTo).transfer(account, ITToken(tTokenTo).balanceOf(address(this))), "transfer remaining tToken failed");

        emit SwapAndDeposit(account, tTokenFrom, swapFromAmount, tTokenTo, swapToAmount);
    }

    /**
     * @notice Flash loan and liquidate
     * @param tectonicSocketAddress       Address of tectonic socket
     * @param borrower                    Address of borrower
     * @param repayTToken                 Address of debt tToken
     * @param seizeTToken                 Address of collateral tToken
     * @param repayAmount                 Amount of debt token to repay
     * @param dexes                       DEXes to perform swaps
     * @param paths                       Paths to swap token on DEXes
     */
    function flashLoanAndLiquidate(
        address tectonicSocketAddress,
        address borrower,
        address repayTToken,
        address seizeTToken,
        uint repayAmount,
        address[] calldata dexes,
        address[][] calldata paths
    ) external {
        //packing data
        bytes memory data = abi.encode(msg.sender, borrower, repayTToken, seizeTToken, repayAmount, dexes, paths);
        ITectonicCore(tectonicSocketAddress).deferLiquidityCheck(address(this), abi.encodeWithSignature("flashLoanAndLiquidateCallback(bytes)", data));
    }

    /**
     * @dev Suppose the borrower supplied token A and borrowed token B:
     *          0. Adapter Borrow token B from Tectonic
     *          1. Adapter do liquidation for borrower and get tToken A
     *          2. Adapter Redeem tToken A and get Token A
     *          3. Swap token A to token B
     *          4. Adapter Repay token B and clear self debt
     *          5. Transfer remaining token A to caller
     *
     * @param data      Callback data from TectonicCore
     */
    function flashLoanAndLiquidateCallback(bytes memory data) external onlyTectonicCore {
        // unpacking data
        (address caller, address borrower, address repayTToken, address seizeTToken, uint repayAmount, address[] memory dexes, address[][] memory paths) =
        abi.decode(data, (address, address, address, address, uint, address[], address[][]));

        // Adapter Borrow token B from Tectonic
        require(ITToken(repayTToken).borrow(repayAmount) == 0, "borrow failed");

        address repayErc20Token = tTokenToErc20TokenMap[msg.sender][repayTToken];
        address seizeErc20Token = tTokenToErc20TokenMap[msg.sender][seizeTToken];

        // Adapter do liquidation for borrower and get tToken A
        _liquidateBorrow(repayErc20Token, repayTToken, seizeTToken, borrower, repayAmount);

        // Notice that for tCRO market, get CRO after redeem
        require(ITToken(seizeTToken).redeem(ITToken(seizeTToken).balanceOf(address(this))) == 0, "redeem failed");

        // if we need a swap
        if (repayTToken != seizeTToken) {
            // if get CRO after redeem, then deposit all CRO to WCRO, WCRO will be used for the following swaps
            if (seizeErc20Token == WETH) {
                IWETH(WETH).deposit{value : address(this).balance}();
            }

            // perform swaps according to paths via selected DEXs
            _performSwapOnMultiDex(dexes, paths);

            // if need to repay in CRO
            if (repayErc20Token == WETH) {
                IWETH(WETH).withdraw(IERC20(WETH).balanceOf(address(this)));
            }
        }

        require(_balanceOf(repayErc20Token) >= repayAmount, "insufficient balance to repayBorrow");
        // adapter repay its borrows
        _repayBorrow(repayErc20Token, repayTToken, repayAmount);

        // transfer remaining token to caller
        uint remainingRepayErc20TokenAmount = _balanceOf(repayErc20Token);
        if (remainingRepayErc20TokenAmount > 0) {
            _transfer(repayErc20Token, caller, remainingRepayErc20TokenAmount);
        }
    }

    /**
     * @notice Create a long and short position. Suppose long token A and short token B.
     * @param tectonicSocketAddress       Address of tectonic socket
     * @param longAmount                  Amount of token A to long
     * @param shortAmount                 Amount of token B to short
     * @param expectAmount                Expect amount of target token after swap
     * @param dexes                       DEXes to perform swaps
     * @param paths                       Paths to swap token on DEXes, underlyingTokenToShort swap to underlyingTokenToLong
     */
    function createLongNShortPosition(
        address tectonicSocketAddress,
        uint longAmount,
        uint shortAmount,
        uint expectAmount,
        address[] calldata dexes,
        address[][] calldata paths
    ) external payable {
        uint pathLength = paths.length;
        uint lastPathLength = paths[pathLength - 1].length;
        address underlyingTokenToLong = paths[pathLength - 1][lastPathLength - 1];
        if (underlyingTokenToLong == WETH) {
            require(msg.value == longAmount, "msg.value must be equal longAmount");
        }

        //packing data
        bytes memory data = abi.encode(msg.sender, longAmount, shortAmount, expectAmount, dexes, paths);
        // msg.sender is marked to defer liquidity check
        ITectonicCore(tectonicSocketAddress).deferLiquidityCheck(msg.sender, abi.encodeWithSignature("createLongNShortPositionCallback(bytes)", data));
    }

    /**
     * @dev Local vars for avoiding stack-depth limits in createLongNShortPositionCallback function.
     */
    struct LongNShortLocalVars {
        address account;
        uint shortAmount;
        uint longAmount;
    }

    /**
     * @dev Suppose user long $X worth of token A and short $Y worth of token B:
     *          Prepare: user should approve token A and token B to adapter
     *          0. Transfer $X worth of token A to Adapter
     *          1. adapter borrow $Y token B on behalf of user, adapter get token B, user is in debt for $Y token B now
     *          2. swap $Y token B to $Y token A
     *          3. adapter mint ($X + $Y) token A to tToken A
     *          4. adapter transfer ($X + $Y) tToken A to user
     *          5. adapter should not have any tToken A, token A and token B at this stage (check this in unit test is enough)
     *          6. lava bar check for user, lava bar should < 90%
     *
     * @param data      Callback data from TectonicCore
     */
    function createLongNShortPositionCallback(bytes memory data) external onlyTectonicCore {
        // unpacking data
        (address account, uint longAmount, uint shortAmount, uint expectAmount, address[] memory dexes, address[][] memory paths) =
        abi.decode(data, (address, uint, uint, uint, address[], address[][]));

        // get underlying tokens and tTokens
        uint pathLength = paths.length;
        uint lastPathLength = paths[pathLength - 1].length;
        address underlyingTokenToLong = paths[pathLength - 1][lastPathLength - 1];
        address underlyingTokenToShort = paths[0][0];
        address tTokenToLong = erc20TokenToTTokenMap[msg.sender][underlyingTokenToLong];
        address tTokenToShort = erc20TokenToTTokenMap[msg.sender][underlyingTokenToShort];

        require(underlyingTokenToShort != WETH, "unsupported short CRO");
        require(tTokenToLong != tTokenToShort, "same markets");

        LongNShortLocalVars memory vars;
        vars.account = account;
        vars.shortAmount = shortAmount;
        vars.longAmount = longAmount;

        // if not long CRO, transfer $X worth of token A from user to Adapter
        if (underlyingTokenToLong != WETH) {
            IERC20(underlyingTokenToLong).safeTransferFrom(vars.account, address(this), vars.longAmount);
        }

        // borrow $Y token B on behalf of user, token B are sent to adapter, user will be in debt
        require(ITToken(tTokenToShort).borrowOnBehalf(payable(vars.account), payable(address(this)), vars.shortAmount) == 0, "borrowOnBehalf failed");

        // swap $Y token B to $Y token A
        // perform swaps according to paths via selected DEXs
        _performSwapOnMultiDex(dexes, paths);

        // if long CRO
        if (underlyingTokenToLong == WETH) {
            IWETH(WETH).withdraw(IERC20(WETH).balanceOf(address(this)));
        }

        // adapter mint ($X + $Y) token A to tToken A
        uint underlyingTokenToLongBalance = _balanceOf(underlyingTokenToLong);
        require((underlyingTokenToLongBalance - vars.longAmount) >= expectAmount, "insufficient output amount");
        _mint(underlyingTokenToLong, tTokenToLong, underlyingTokenToLongBalance);

        // adapter transfer ($X + $Y) tToken A to user
        uint tTokenToLongBalance = ITToken(tTokenToLong).balanceOf(address(this));
        require(ITToken(tTokenToLong).transfer(vars.account, tTokenToLongBalance), "transfer tToken A failed");

        emit CreateLongNShortPosition(vars.account, tTokenToShort, vars.shortAmount, tTokenToLong, vars.longAmount, underlyingTokenToLongBalance);
    }

    /**
     * @notice Create a long and short position. Suppose long token A and short token B.
     * @param tectonicSocketAddress       Address of tectonic socket
     * @param longAmount                  Amount of token A to long
     * @param shortAmount                 Amount of token B to short
     * @param longToken                   Token to long
     * @param shortToken                  Token to short
     * @param swapData                    Txn data of WOWMAX
     */
    function createLongNShortPositionByWowmax(
        address tectonicSocketAddress,
        uint longAmount,
        uint shortAmount,
        address longToken,
        address shortToken,
        bytes calldata swapData
    ) external payable {
        require(longToken != shortToken, "same markets");
        if (longToken == WETH) {
            require(msg.value == longAmount, "msg.value must be equal longAmount");
        }

        //packing data
        bytes memory data = abi.encode(msg.sender, longAmount, shortAmount, longToken, shortToken, swapData);
        // msg.sender is marked to defer liquidity check
        ITectonicCore(tectonicSocketAddress).deferLiquidityCheck(msg.sender, abi.encodeWithSignature("createLongNShortPositionByWowmaxCallback(bytes)", data));
    }

    /**
     * @dev Suppose user long $X worth of token A and short $Y worth of token B:
     *          Prepare: user should approve token A and token B to adapter
     *          0. Transfer $X worth of token A to Adapter
     *          1. adapter borrow $Y token B on behalf of user, adapter get token B, user is in debt for $Y token B now
     *          2. swap $Y token B to $Y token A
     *          3. adapter mint ($X + $Y) token A to tToken A
     *          4. adapter transfer ($X + $Y) tToken A to user
     *          5. adapter should not have any tToken A, token A and token B at this stage (check this in unit test is enough)
     *          6. lava bar check for user, lava bar should < 90%
     *
     * @param data      Callback data from TectonicCore
     */
    function createLongNShortPositionByWowmaxCallback(bytes memory data) external onlyTectonicCore {
        // unpacking data
        (address account, uint longAmount, uint shortAmount, address longToken, address shortToken, bytes memory swapData) =
        abi.decode(data, (address, uint, uint, address, address, bytes));

        // get tTokens according to underlying tokens
        address tTokenToLong = erc20TokenToTTokenMap[msg.sender][longToken];
        address tTokenToShort = erc20TokenToTTokenMap[msg.sender][shortToken];

        require(shortToken != WETH, "unsupported short CRO");

        LongNShortLocalVars memory vars;
        vars.account = account;
        vars.shortAmount = shortAmount;
        vars.longAmount = longAmount;

        // if not long CRO, transfer $X worth of token A from user to Adapter
        if (longToken != WETH) {
            IERC20(longToken).safeTransferFrom(vars.account, address(this), vars.longAmount);
        }

        // borrow $Y token B on behalf of user, token B are sent to adapter, user will be in debt
        require(ITToken(tTokenToShort).borrowOnBehalf(payable(vars.account), payable(address(this)), vars.shortAmount) == 0, "borrowOnBehalf failed");

        // swap $Y token B to $Y token A
        // perform swaps by WOWMAX
        (bool success, bytes memory returndata) = address(wowmaxRouter).call(swapData);
        assembly {
            let returndata_size := mload(returndata)

            switch success
            case 0 {revert(add(32, returndata), returndata_size)}
        }

        // adapter mint ($X + $Y) token A to tToken A
        uint underlyingTokenToLongBalance = _balanceOf(longToken);
        _mint(longToken, tTokenToLong, underlyingTokenToLongBalance);

        // adapter transfer ($X + $Y) tToken A to user
        uint tTokenToLongBalance = ITToken(tTokenToLong).balanceOf(address(this));
        require(ITToken(tTokenToLong).transfer(vars.account, tTokenToLongBalance), "transfer tToken A failed");

        emit CreateLongNShortPosition(vars.account, tTokenToShort, vars.shortAmount, tTokenToLong, vars.longAmount, underlyingTokenToLongBalance);
    }

    /** Admin Functions **/

    function setErc20AndTTokenMap(address tectonicSocketAddress, address[] calldata erc20, address[] calldata tToken) external onlyOwner {
        uint length = erc20.length;
        for (uint i = 0; i < length;) {
            erc20TokenToTTokenMap[tectonicSocketAddress][erc20[i]] = tToken[i];
            tTokenToErc20TokenMap[tectonicSocketAddress][tToken[i]] = erc20[i];
            unchecked {i++;}
        }
        emit SetErc20AndTTokenMapping(tectonicSocketAddress, erc20, tToken);
    }

    function addOrRemoveTectonicSocketAddress(address tectonicSocketAddress, bool isTCore) external onlyOwner {
        isTectonicCores[tectonicSocketAddress] = isTCore;
        emit AddOrRemoveTectonicSocket(tectonicSocketAddress, isTCore);
    }

    function approveTTokenAndVVSAndWowmax(address[] calldata erc20, address[] calldata tToken) external onlyOwner {
        uint length = erc20.length;
        for (uint i = 0; i < length;) {
            IERC20(erc20[i]).approve(tToken[i], MAX_VALUE);
            IERC20(erc20[i]).approve(address(vvs), MAX_VALUE);
            IERC20(erc20[i]).approve(wowmaxRouter, MAX_VALUE);
            unchecked {i++;}
        }
    }

    function approveFerroSwap(address _ferroSwap, address[] calldata erc20) external onlyOwner {
        uint length = erc20.length;
        for (uint i = 0; i < length;) {
            IERC20(erc20[i]).approve(_ferroSwap, MAX_VALUE);
            unchecked {i++;}
        }
    }

    function setAllowedDexes(address[] calldata dexes, bool[] calldata flags) external onlyOwner {
        uint length = dexes.length;
        require(length == flags.length, "length not matched");
        for (uint i = 0; i < length;) {
            allowedDex[dexes[i]] = flags[i];
            unchecked {i++;}
        }
    }

    /** Internal Functions **/

    function _mint(address underlyingToken, address tToken, uint mintAmount) internal {
        if (underlyingToken == WETH) {
            ITEther(tToken).mint{value : mintAmount}();
        } else {
            require(ITToken(tToken).mint(mintAmount) == 0, "mint tToken failed");
        }
    }

    function _repayBorrowBehalf(address underlyingToken, address tToken, address account, uint actualRepayAmount) internal {
        if (underlyingToken == WETH) {
            ITEther(tToken).repayBorrowBehalf{value : actualRepayAmount}(account);
        } else {
            require(ITToken(tToken).repayBorrowBehalf(account, actualRepayAmount) == 0, "repay borrow failed");
        }
    }

    /**
     * @notice Tectonic liquidate borrow
     * @param repayErc20Token             Address of debt token
     * @param repayTToken                 Address of debt tToken
     * @param seizeTToken                 Address of collateral tToken
     * @param borrower                    Address of borrower
     * @param repayAmount                 Amount of debt token to repay
     */
    function _liquidateBorrow(address repayErc20Token, address repayTToken, address seizeTToken, address borrower, uint repayAmount) internal {
        if (repayErc20Token == WETH) {
            ITEther(repayTToken).liquidateBorrow{value : repayAmount}(borrower, seizeTToken);
        } else {
            require(ITToken(repayTToken).liquidateBorrow(borrower, repayAmount, seizeTToken) == 0, "liquidateBorrow failed");
        }
    }

    /**
     * @notice Tectonic repay borrow
     * @param repayErc20Token             Address of debt token
     * @param repayTToken                 Address of debt tToken
     * @param repayAmount                 Amount of debt token to repay
     */
    function _repayBorrow(address repayErc20Token, address repayTToken, uint repayAmount) internal {
        if (repayErc20Token == WETH) {
            ITEther(repayTToken).repayBorrow{value : repayAmount}();
        } else {
            require(ITToken(repayTToken).repayBorrow(repayAmount) == 0, "repayBorrow failed");
        }
    }

    /**
     * @notice transfer CRO or ERC20 tokens
     * @param underlyingToken       Asset tokens to transfer
     * @param receiver              Address to receive tokens
     * @param amount                Transfer amount
     */
    function _transfer(address underlyingToken, address receiver, uint amount) internal {
        if (underlyingToken == WETH) {
            (bool success,) = address(receiver).call{value : amount}("");
            require(success, "_transfer failed");
        } else {
            IERC20(underlyingToken).safeTransfer(receiver, amount);
        }
    }

    function _balanceOf(address erc20) internal view returns (uint) {
        if (erc20 == WETH) {
            return address(this).balance;
        } else {
            return IERC20(erc20).balanceOf(address(this));
        }
    }

    function _balanceOfERC20(address erc20) internal view returns (uint) {
        return IERC20(erc20).balanceOf(address(this));
    }

    /**
     * @notice Swap on VVS finance
     * @param amountInMax       Max amount in
     * @param amountOut         Exact amount out
     * @param path              Path for swap
     */
    function _performSwapAnyForExactAny(
        uint amountInMax,
        uint amountOut,
        address[] memory path
    ) internal {
        if (path[0] == WETH) {
            vvs.swapETHForExactTokens{value : amountInMax}(amountOut, path, address(this), block.timestamp);
        } else if (path[path.length - 1] == WETH) {
            vvs.swapTokensForExactETH(amountOut, amountInMax, path, address(this), block.timestamp);
        } else {
            vvs.swapTokensForExactTokens(amountOut, amountInMax, path, address(this), block.timestamp);
        }
    }

    /**
     * @notice Swap on VVS finance
     * @param amountIn          Exact amount in
     * @param amountOutMin      Min amount out
     * @param path              Path for swap
     */
    function _performSwapExactAnyForAny(
        uint amountIn,
        uint amountOutMin,
        address[] memory path
    ) internal {
        if (path[0] == WETH) {
            vvs.swapExactETHForTokensSupportingFeeOnTransferTokens{value : amountIn}(amountOutMin, path, address(this), block.timestamp);
        } else if (path[path.length - 1] == WETH) {
            vvs.swapExactTokensForETHSupportingFeeOnTransferTokens(amountIn, amountOutMin, path, address(this), block.timestamp);
        } else {
            vvs.swapExactTokensForTokensSupportingFeeOnTransferTokens(amountIn, amountOutMin, path, address(this), block.timestamp);
        }
    }

    /**
     * @notice Swap erc20 token on Multi DEXes
     * @param dexes                       DEXes to perform swaps
     * @param paths                       Paths to swap token on DEXes
     */
    function _performSwapOnMultiDex(
        address[] memory dexes,
        address[][] memory paths
    ) internal {
        uint pathCount = paths.length;
        for (uint i = 0; i < pathCount;) {
            address dex = dexes[i];
            require(allowedDex[dex], "unsupported dex");
            address[] memory path = paths[i];
            uint amountIn = _balanceOfERC20(path[0]);

            if (dex == address(vvs)) {
                // if use vvs to swap
                vvs.swapExactTokensForTokensSupportingFeeOnTransferTokens(amountIn, 0, path, address(this), block.timestamp);
            } else {
                // if use ferro to swap
                IFerroSwap ferro = IFerroSwap(dex);
                uint8 tokenIndex0 = ferro.getTokenIndex(path[0]);
                uint8 tokenIndex1 = ferro.getTokenIndex(path[path.length - 1]);
                ferro.swap(tokenIndex0, tokenIndex1, amountIn, 0, block.timestamp);
            }
            unchecked {i++;}
        }
    }

    /** External View Functions **/

    /**
     * @notice get max tToken amount in for swap and repay, this function is for FE only, dont use it in smart contract
     * @param tectonicSocketAddress       Tectonic socket address
     * @param repayAmount                 AmountOut
     * @param slippageTolerance           Slippage tolerance selected by user
     * @param path                        Swap path
     */
    function getTTokenAmountIn(
        address tectonicSocketAddress,
        uint repayAmount,
        uint slippageTolerance,
        address[] calldata path
    ) external view returns (uint tTokenAmount, uint amountInMax) {
        address tTokenFrom = erc20TokenToTTokenMap[tectonicSocketAddress][path[0]];

        uint[] memory amounts = vvs.getAmountsIn(repayAmount, path);

        amountInMax = amounts[0] * (SLIPPAGE_BASE + slippageTolerance) / SLIPPAGE_BASE;

        uint exchangeRateMantissa = ITToken(tTokenFrom).exchangeRateStored();

        // the effect of slippageTolerance is very likely to lost here when amountInMax is small
        tTokenAmount = amountInMax * DOUBLE_PRECISION / exchangeRateMantissa / PRECISION;
    }

    /**
     * @notice get min token amount out for swap and deposit, this function is for FE only, dont use it in smart contract
     * @param tectonicSocketAddress       Tectonic socket address
     * @param fromAmount                  AmountIn
     * @param slippageTolerance           Slippage tolerance selected by user
     * @param path                        Swap path
     */
    function getTTokenAmountOut(
        address tectonicSocketAddress,
        uint fromAmount,
        uint slippageTolerance,
        address[] calldata path
    ) external view returns (uint tTokenAmount, uint amountOutMin) {
        address tTokenFrom = erc20TokenToTTokenMap[tectonicSocketAddress][path[0]];

        uint exchangeRateStored = ITToken(tTokenFrom).exchangeRateStored();

        tTokenAmount = fromAmount * DOUBLE_PRECISION / exchangeRateStored / PRECISION;

        uint[] memory amounts = vvs.getAmountsOut(fromAmount, path);

        amountOutMin = amounts[amounts.length - 1] * (SLIPPAGE_BASE - slippageTolerance) / SLIPPAGE_BASE;
    }

    receive() external payable {
        // TODO: Check if any checks regarding the sender are needed
    }
}

File 3 of 10 : Interface.sol
pragma solidity ^0.8.0;

interface ITToken {
    function balanceOf(address owner) external view returns (uint256);
    function transfer(address dst, uint256 amount) external returns (bool);
    function transferFrom(address src, address dst, uint256 amount) external returns (bool);
    function mint(uint mintAmount) external returns (uint);
    function redeem(uint redeemTokens) external returns (uint);
    function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint);
    function exchangeRateStored() external view returns (uint);
    function borrowBalanceCurrent(address account) external returns (uint);
    function borrow(uint borrowAmount) external returns (uint);
    function liquidateBorrow(address borrower, uint repayAmount, address tTokenCollateral) external returns (uint);
    function repayBorrow(uint repayAmount) external returns (uint);
    function borrowOnBehalf(address payable borrower, address payable receiver, uint borrowAmount) external returns (uint);
}

interface ITEther {
    function mint() external payable;
    function repayBorrowBehalf(address borrower) external payable;
    function liquidateBorrow(address borrower, address tTokenCollateral) external payable;
    function repayBorrow() external payable;
}

interface ITectonicCore {
    function deferLiquidityCheck(address account, bytes memory data) external;
    function getAccountLiquidityAndTotalBorrow(address account) external view returns (uint, uint, uint, uint);
}

interface IPriceOracle {
    function getUnderlyingPrice(address tToken) external view returns (uint);
}

interface IFerroSwap {
    function swap(
        uint8 tokenIndexFrom,
        uint8 tokenIndexTo,
        uint256 dx,
        uint256 minDy,
        uint256 deadline
    ) external returns (uint256);

    function getTokenIndex(address tokenAddress) external returns (uint8);
}

interface IWETH {
    function deposit() external payable;
    function withdraw(uint wad) external;
}

/*
interface IWowmaxRouter {
    struct Swap {
        // target token address
        address to;
        // part of owned tokens to be swapped
        uint256 part;
        // contract address that performs the swap
        address addr;
        // contract DEX family
        bytes32 family;
        // additional data that is required for a specific DEX protocol
        bytes data;
    }

    struct ExchangeRoute {
        // source token address
        address from;
        // total parts of owned token
        uint256 parts;
        // array of swaps for a specified token
        Swap[] swaps;
    }

    struct ExchangeRequest {
        // source token address
        address from;
        // source token amount to swap
        uint256 amountIn;
        // target token addresses
        address[] to;
        // exchange routes
        ExchangeRoute[] exchangeRoutes;
        // slippage tolerance for each target token
        uint256[] slippage;
        // expected amount for each target token
        uint256[] amountOutExpected;
    }

    // @notice Executes a token swap
    // @param request - swap request
    // @return amountsOut - array of amounts that were received for each target token
    // @dev if from token is address(0) and amountIn is 0,
    // then chain native token is used as a source token, and value is used as amountIn
    function swap(ExchangeRequest calldata request) external payable returns (uint256[] memory amountsOut);
}*/

File 4 of 10 : DeferLiquidityCheckAdapterStorage.sol
pragma solidity ^0.8.0;

import "./Interface.sol";
import "../Interfaces/IVVSRouter02.sol";

contract DeferLiquidityCheckAdapterStorageV1 {
    address public WETH;
    IVVSRouter02 public vvs;

    //tectonicSocket address => oracleAdapter address
    mapping(address => IPriceOracle) public oracles;

    //tectonicSocket address => erc20 address => tToken address
    mapping(address => mapping(address => address)) public erc20TokenToTTokenMap;
}

contract DeferLiquidityCheckAdapterStorageV2 is DeferLiquidityCheckAdapterStorageV1 {
    uint256 public flashLoanAndLiquidateSlippageTolerance;

    // tectonicSocket address => tToken address => erc20 address
    mapping(address => mapping(address => address)) public tTokenToErc20TokenMap;
}

contract DeferLiquidityCheckAdapterStorageV3 is DeferLiquidityCheckAdapterStorageV2 {
    uint public lavaBarLimit;

    mapping(address => bool) public allowedDex;
}

contract DeferLiquidityCheckAdapterStorageV4 is DeferLiquidityCheckAdapterStorageV3 {
    address public wowmaxRouter;
}

contract DeferLiquidityCheckAdapterStorageV5 {
    // if address is tectonicCore
    mapping(address => bool) public isTectonicCores;

    mapping(address => bool) public allowedDex;

    //tectonicSocket address => erc20 address => tToken address
    mapping(address => mapping(address => address)) public erc20TokenToTTokenMap;

    // tectonicSocket address => tToken address => erc20 address
    mapping(address => mapping(address => address)) public tTokenToErc20TokenMap;
}

File 5 of 10 : IVVSRouter02.sol
pragma solidity ^0.8.0;

interface IVVSRouter02 {
    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;

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

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

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

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

File 6 of 10 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

File 7 of 10 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _setOwner(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 8 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 9 of 10 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

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

File 10 of 10 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_WETH","type":"address"},{"internalType":"address","name":"_vvs","type":"address"},{"internalType":"address","name":"_wowmaxRouter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"isTCore","type":"bool"}],"name":"AddOrRemoveTectonicSocket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"tTokenToShort","type":"address"},{"indexed":false,"internalType":"uint256","name":"shortAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tTokenToLong","type":"address"},{"indexed":false,"internalType":"uint256","name":"longAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalLongAmount","type":"uint256"}],"name":"CreateLongNShortPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"indexed":false,"internalType":"address[]","name":"erc20Addresses","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"tTokenAddresses","type":"address[]"}],"name":"SetErc20AndTTokenMapping","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"tTokenFrom","type":"address"},{"indexed":false,"internalType":"uint256","name":"swapFromAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tTokenTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"swapToAmount","type":"uint256"}],"name":"SwapAndDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"tTokenFrom","type":"address"},{"indexed":false,"internalType":"uint256","name":"swapFromAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tTokenTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"SwapAndRepay","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adapterVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"bool","name":"isTCore","type":"bool"}],"name":"addOrRemoveTectonicSocketAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedDex","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ferroSwap","type":"address"},{"internalType":"address[]","name":"erc20","type":"address[]"}],"name":"approveFerroSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"erc20","type":"address[]"},{"internalType":"address[]","name":"tToken","type":"address[]"}],"name":"approveTTokenAndVVSAndWowmax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"uint256","name":"longAmount","type":"uint256"},{"internalType":"uint256","name":"shortAmount","type":"uint256"},{"internalType":"uint256","name":"expectAmount","type":"uint256"},{"internalType":"address[]","name":"dexes","type":"address[]"},{"internalType":"address[][]","name":"paths","type":"address[][]"}],"name":"createLongNShortPosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"uint256","name":"longAmount","type":"uint256"},{"internalType":"uint256","name":"shortAmount","type":"uint256"},{"internalType":"address","name":"longToken","type":"address"},{"internalType":"address","name":"shortToken","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"name":"createLongNShortPositionByWowmax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"createLongNShortPositionByWowmaxCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"createLongNShortPositionCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"erc20TokenToTTokenMap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"repayTToken","type":"address"},{"internalType":"address","name":"seizeTToken","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"address[]","name":"dexes","type":"address[]"},{"internalType":"address[][]","name":"paths","type":"address[][]"}],"name":"flashLoanAndLiquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoanAndLiquidateCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"slippageTolerance","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getTTokenAmountIn","outputs":[{"internalType":"uint256","name":"tTokenAmount","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"slippageTolerance","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getTTokenAmountOut","outputs":[{"internalType":"uint256","name":"tTokenAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTectonicCores","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"dexes","type":"address[]"},{"internalType":"bool[]","name":"flags","type":"bool[]"}],"name":"setAllowedDexes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"address[]","name":"erc20","type":"address[]"},{"internalType":"address[]","name":"tToken","type":"address[]"}],"name":"setErc20AndTTokenMap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tTokenAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"swapAndDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swapAndDepositCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tectonicSocketAddress","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tTokenAmount","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"swapAndRepay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swapAndRepayCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"tTokenToErc20TokenMap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vvs","outputs":[{"internalType":"contract IVVSRouter02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wowmaxRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b50604051620057d0380380620057d08339810160408190526200003491620000db565b82828262000042336200006e565b6001600160601b0319606093841b811660805291831b821660a05290911b1660c0525062000124915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000d657600080fd5b919050565b600080600060608486031215620000f0578283fd5b620000fb84620000be565b92506200010b60208501620000be565b91506200011b60408501620000be565b90509250925092565b60805160601c60a05160601c60c05160601c61557e62000252600039600081816101f5015281816112650152612e0101526000818161018b01528181610e880152818161118e01528181612a6a01528181613290015281816132df01528181613abf01528181613b9a01528181613c2501528181613e7401528181613f360152613f8a01526000818161043b01528181610b9101528181610bcb01528181610c4a01528181610c99015281816113fc0152818161156401528181611932015281816119c701528181611abc01528181611b0b01528181612cae01528181612d13015281816130220152818161356c01528181613631015281816137850152818161391701528181613a4801528181613b1701528181613c9b01528181613dfd0152613eb3015261557e6000f3fe60806040526004361061014b5760003560e01c806301ebfe781461015757806308e77344146101795780631676c720146101c35780632a2c372e146101e35780632fdb7309146102175780633395635d14610237578063444c55581461027757806348180e231461029757806356194f56146102b7578063587261d9146102e7578063620f0b151461031c578063715018a61461033c57806377aabbbe146103515780637b3fb21b1461036457806383975275146103775780638a70e439146103975780638da5cb5b146103d8578063a76385b8146103ed578063a77ec9e01461040d578063ad5c464814610429578063c0c28da21461045d578063c7fb1c721461047d578063ce9095e4146104be578063db03c117146104de578063e1faf5d2146104fe578063e5dc168d1461051e578063f2fde38b1461053e578063f85278e31461055e57610152565b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004614b32565b61057e565b005b34801561018557600080fd5b506101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6040516101ba9190614e65565b60405180910390f35b3480156101cf57600080fd5b506101776101de36600461495c565b6106ac565b3480156101ef57600080fd5b506101ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561022357600080fd5b506101776102323660046146cd565b61073e565b34801561024357600080fd5b506102676102523660046143a1565b60026020526000908152604090205460ff1681565b60405190151581526020016101ba565b34801561028357600080fd5b5061017761029236600461478f565b61081b565b3480156102a357600080fd5b506101776102b2366004614c64565b6108ed565b3480156102c357600080fd5b506102676102d23660046143a1565b60016020526000908152604090205460ff1681565b3480156102f357600080fd5b50610307610302366004614a41565b610e04565b604080519283526020830191909152016101ba565b34801561032857600080fd5b50610177610337366004614b32565b611023565b34801561034857600080fd5b506101776112ff565b61017761035f366004614a97565b61133a565b610177610372366004614989565b611530565b34801561038357600080fd5b5061017761039236600461488b565b611692565b3480156103a357600080fd5b506101ad6103b2366004614695565b60036020908152600092835260408084209091529082529020546001600160a01b031681565b3480156103e457600080fd5b506101ad611793565b3480156103f957600080fd5b50610177610408366004614c64565b6117a2565b34801561041957600080fd5b50604051600781526020016101ba565b34801561043557600080fd5b506101ad7f000000000000000000000000000000000000000000000000000000000000000081565b34801561046957600080fd5b50610177610478366004614808565b611dd0565b34801561048957600080fd5b506101ad610498366004614695565b60046020908152600092835260408084209091529082529020546001600160a01b031681565b3480156104ca57600080fd5b506101776104d93660046148dd565b611e69565b3480156104ea57600080fd5b506101776104f9366004614c64565b61205c565b34801561050a57600080fd5b50610177610519366004614c64565b61252f565b34801561052a57600080fd5b50610307610539366004614a41565b612933565b34801561054a57600080fd5b506101776105593660046143a1565b612b79565b34801561056a57600080fd5b50610177610579366004614c64565b612c19565b33610587611793565b6001600160a01b0316146105b65760405162461bcd60e51b81526004016105ad906151fb565b60405180910390fd5b828181146105fb5760405162461bcd60e51b81526020600482015260126024820152711b195b99dd1a081b9bdd081b585d18da195960721b60448201526064016105ad565b60005b818110156106a45783838281811061062657634e487b7160e01b600052603260045260246000fd5b905060200201602081019061063b9190614c2c565b6002600088888581811061065f57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061067491906143a1565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790556001016105fe565b505050505050565b336106b5611793565b6001600160a01b0316146106db5760405162461bcd60e51b81526004016105ad906151fb565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527fa22ebc7a07361801b1b3f0d83d8155491878f37ca47db690d89f35828a49df9b910160405180910390a15050565b600033898989898989898960405160200161076199989796959493929190614e9d565b6040516020818303038152906040529050896001600160a01b03166389b7b7a6308360405160240161079391906150fd565b60408051601f198184030181529181526020820180516001600160e01b03166348180e2360e01b1790525160e084901b6001600160e01b03191681526107dd929190600401614f48565b600060405180830381600087803b1580156107f757600080fd5b505af115801561080b573d6000803e3d6000fd5b5050505050505050505050505050565b60003385858585604051602001610836959493929190615045565b6040516020818303038152906040529050866001600160a01b03166389b7b7a6338360405160240161086891906150fd565b60408051601f198184030181529181526020820180516001600160e01b03166370fd7ae960e11b1790525160e084901b6001600160e01b03191681526108b2929190600401614f48565b600060405180830381600087803b1580156108cc57600080fd5b505af11580156108e0573d6000803e3d6000fd5b5050505050505050505050565b3360009081526001602052604090205460ff1661091c5760405162461bcd60e51b81526004016105ad90615230565b60008060008060008060008780602001905181019061093b91906143bd565b9650965096509650965096509650846001600160a01b031663c5ebeaec846040518263ffffffff1660e01b815260040161097791815260200190565b602060405180830381600087803b15801561099157600080fd5b505af11580156109a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c99190614cd7565b15610a065760405162461bcd60e51b815260206004820152600d60248201526c189bdc9c9bddc819985a5b1959609a1b60448201526064016105ad565b3360009081526004602090815260408083206001600160a01b03898116855292528083205487831684529220549181169116610a458288888b89613020565b6040516370a0823160e01b81526001600160a01b0387169063db006a759082906370a0823190610a79903090600401614e65565b60206040518083038186803b158015610a9157600080fd5b505afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac99190614cd7565b6040518263ffffffff1660e01b8152600401610ae791815260200190565b602060405180830381600087803b158015610b0157600080fd5b505af1158015610b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b399190614cd7565b15610b765760405162461bcd60e51b815260206004820152600d60248201526c1c995919595b4819985a5b1959609a1b60448201526064016105ad565b856001600160a01b0316876001600160a01b031614610d77577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03161415610c3e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015610c2457600080fd5b505af1158015610c38573d6000803e3d6000fd5b50505050505b610c488484613194565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415610d77576040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d9082906370a0823190610cd6903090600401614e65565b60206040518083038186803b158015610cee57600080fd5b505afa158015610d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d269190614cd7565b6040518263ffffffff1660e01b8152600401610d4491815260200190565b600060405180830381600087803b158015610d5e57600080fd5b505af1158015610d72573d6000803e3d6000fd5b505050505b84610d8183613568565b1015610ddb5760405162461bcd60e51b815260206004820152602360248201527f696e73756666696369656e742062616c616e636520746f207265706179426f72604482015262726f7760e81b60648201526084016105ad565b610de682888761362f565b6000610df183613568565b905080156108e0576108e0838b83613783565b6001600160a01b0385166000908152600360205260408120819081908186868281610e3f57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610e5491906143a1565b6001600160a01b0390811682526020820192909252604090810160009081205491516307c0329d60e21b81529183169350917f00000000000000000000000000000000000000000000000000000000000000001690631f00ca7490610ec1908b908a908a906004016152ea565b60006040518083038186803b158015610ed957600080fd5b505afa158015610eed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f159190810190614b9a565b9050670de0b6b3a7640000610f2a888261543f565b82600081518110610f4b57634e487b7160e01b600052603260045260246000fd5b6020026020010151610f5d9190615477565b610f679190615457565b92506000826001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610fa457600080fd5b505afa158015610fb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdc9190614cd7565b9050670de0b6b3a7640000816110006a0c097ce7bc90715b34b9f160241b87615477565b61100a9190615457565b6110149190615457565b94505050509550959350505050565b3361102c611793565b6001600160a01b0316146110525760405162461bcd60e51b81526004016105ad906151fb565b8260005b818110156106a45785858281811061107e57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061109391906143a1565b6001600160a01b031663095ea7b38585848181106110c157634e487b7160e01b600052603260045260246000fd5b90506020020160208101906110d691906143a1565b6000196040518363ffffffff1660e01b81526004016110f6929190614f6c565b602060405180830381600087803b15801561111057600080fd5b505af1158015611124573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111489190614c48565b5085858281811061116957634e487b7160e01b600052603260045260246000fd5b905060200201602081019061117e91906143a1565b6001600160a01b031663095ea7b37f00000000000000000000000000000000000000000000000000000000000000006000196040518363ffffffff1660e01b81526004016111cd929190614f6c565b602060405180830381600087803b1580156111e757600080fd5b505af11580156111fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121f9190614c48565b5085858281811061124057634e487b7160e01b600052603260045260246000fd5b905060200201602081019061125591906143a1565b6001600160a01b031663095ea7b37f00000000000000000000000000000000000000000000000000000000000000006000196040518363ffffffff1660e01b81526004016112a4929190614f6c565b602060405180830381600087803b1580156112be57600080fd5b505af11580156112d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f69190614c48565b50600101611056565b33611308611793565b6001600160a01b03161461132e5760405162461bcd60e51b81526004016105ad906151fb565b611338600061386d565b565b806000838261134a600182615496565b81811061136757634e487b7160e01b600052603260045260246000fd5b9050602002810190611379919061537e565b915060009050848461138c600186615496565b8181106113a957634e487b7160e01b600052603260045260246000fd5b90506020028101906113bb919061537e565b6113c6600185615496565b8181106113e357634e487b7160e01b600052603260045260246000fd5b90506020020160208101906113f891906143a1565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03161415611453578934146114535760405162461bcd60e51b81526004016105ad9061527a565b6000338b8b8b8b8b8b8b6040516020016114749897969594939291906150a7565b60405160208183030381529060405290508b6001600160a01b03166389b7b7a633836040516024016114a691906150fd565b60408051601f198184030181529181526020820180516001600160e01b03166314ec70b760e31b1790525160e084901b6001600160e01b03191681526114f0929190600401614f48565b600060405180830381600087803b15801561150a57600080fd5b505af115801561151e573d6000803e3d6000fd5b50505050505050505050505050505050565b826001600160a01b0316846001600160a01b031614156115625760405162461bcd60e51b81526004016105ad906151a6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614156115bb578534146115bb5760405162461bcd60e51b81526004016105ad9061527a565b6000338787878787876040516020016115da9796959493929190614fe3565b6040516020818303038152906040529050876001600160a01b03166389b7b7a6338360405160240161160c91906150fd565b60408051601f198184030181529181526020820180516001600160e01b031663f85278e360e01b1790525160e084901b6001600160e01b0319168152611656929190600401614f48565b600060405180830381600087803b15801561167057600080fd5b505af1158015611684573d6000803e3d6000fd5b505050505050505050505050565b3361169b611793565b6001600160a01b0316146116c15760405162461bcd60e51b81526004016105ad906151fb565b8060005b8181101561178c578383828181106116ed57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061170291906143a1565b6001600160a01b031663095ea7b3866000196040518363ffffffff1660e01b8152600401611731929190614f6c565b602060405180830381600087803b15801561174b57600080fd5b505af115801561175f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117839190614c48565b506001016116c5565b5050505050565b6000546001600160a01b031690565b3360009081526001602052604090205460ff166117d15760405162461bcd60e51b81526004016105ad90615230565b600080600080600080868060200190518101906117ee9190614605565b8051959b5093995091975095509350915060008261180d600184615496565b8151811061182b57634e487b7160e01b600052603260045260246000fd5b60200260200101515190506000836001846118469190615496565b8151811061186457634e487b7160e01b600052603260045260246000fd5b60200260200101516001836118799190615496565b8151811061189757634e487b7160e01b600052603260045260246000fd5b602002602001015190506000846000815181106118c457634e487b7160e01b600052603260045260246000fd5b60200260200101516000815181106118ec57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101513360009081526003835260408082206001600160a01b038781168452945280822054848416808452919092205492945090831692918216917f00000000000000000000000000000000000000000000000000000000000000001614156119705760405162461bcd60e51b81526004016105ad90615177565b806001600160a01b0316826001600160a01b031614156119a25760405162461bcd60e51b81526004016105ad906151a6565b6119aa614261565b6001600160a01b038d81168252602082018c9052604082018d90527f0000000000000000000000000000000000000000000000000000000000000000811690861614611a0d5780516040820151611a0d916001600160a01b0388169130906138bd565b8051602082015160405163654c3dcf60e01b81526001600160a01b0385169263654c3dcf92611a4192309190600401614e79565b602060405180830381600087803b158015611a5b57600080fd5b505af1158015611a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a939190614cd7565b15611ab05760405162461bcd60e51b81526004016105ad906151cc565b611aba8989613194565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b03161415611be9576040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d9082906370a0823190611b48903090600401614e65565b60206040518083038186803b158015611b6057600080fd5b505afa158015611b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b989190614cd7565b6040518263ffffffff1660e01b8152600401611bb691815260200190565b600060405180830381600087803b158015611bd057600080fd5b505af1158015611be4573d6000803e3d6000fd5b505050505b6000611bf486613568565b90508a826040015182611c079190615496565b1015611c525760405162461bcd60e51b815260206004820152601a6024820152791a5b9cdd59999a58da595b9d081bdd5d1c1d5d08185b5bdd5b9d60321b60448201526064016105ad565b611c5d868583613915565b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190611c8c903090600401614e65565b60206040518083038186803b158015611ca457600080fd5b505afa158015611cb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdc9190614cd7565b835160405163a9059cbb60e01b81529192506001600160a01b0387169163a9059cbb91611d0d918590600401614f6c565b602060405180830381600087803b158015611d2757600080fd5b505af1158015611d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5f9190614c48565b611d7b5760405162461bcd60e51b81526004016105ad90615145565b82600001516001600160a01b031660008051602061552983398151915285856020015188876040015187604051611db6959493929190614faf565b60405180910390a250505050505050505050505050505050565b6000338587868686604051602001611ded96959493929190615073565b6040516020818303038152906040529050876001600160a01b03166389b7b7a63383604051602401611e1f91906150fd565b60408051601f198184030181529181526020820180516001600160e01b031663db03c11760e01b1790525160e084901b6001600160e01b0319168152611656929190600401614f48565b33611e72611793565b6001600160a01b031614611e985760405162461bcd60e51b81526004016105ad906151fb565b8260005b8181101561201457838382818110611ec457634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611ed991906143a1565b6001600160a01b038816600090815260036020526040812090888885818110611f1257634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611f2791906143a1565b6001600160a01b039081168252602082019290925260400160002080546001600160a01b03191692909116919091179055858582818110611f7857634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611f8d91906143a1565b6001600160a01b038816600090815260046020526040812090868685818110611fc657634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611fdb91906143a1565b6001600160a01b039081168252602082019290925260400160002080546001600160a01b03191692909116919091179055600101611e9c565b507fd7fe33c445d86c4d4c370d1211518954fdfd403eaeb5f74ebc9f2a0a2f1a73be868686868660405161204c959493929190614f04565b60405180910390a1505050505050565b3360009081526001602052604090205460ff1661208b5760405162461bcd60e51b81526004016105ad90615230565b6000806000806000858060200190518101906120a79190614599565b945094509450945094506000816000815181106120d457634e487b7160e01b600052603260045260246000fd5b60200260200101519050600082600184516120ef9190615496565b8151811061210d57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101513360009081526003835260408082206001600160a01b038781168452908552818320548185168452928290205482519586019092528b81168552929450908216929116908183141561217d5760405162461bcd60e51b81526004016105ad906151a6565b80516040516323b872dd60e01b81526001600160a01b038516916323b872dd916121ae919030908d90600401614e79565b602060405180830381600087803b1580156121c857600080fd5b505af11580156121dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122009190614c48565b6122475760405162461bcd60e51b81526020600482015260186024820152771d151bdad95b881a5b9cdd59999a58da595b9d08199d5b9960421b60448201526064016105ad565b60405163db006a7560e01b8152600481018990526001600160a01b0384169063db006a7590602401602060405180830381600087803b15801561228957600080fd5b505af115801561229d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c19190614cd7565b156122de5760405162461bcd60e51b81526004016105ad906152bc565b60006122e986613568565b82516040516305eff7ef60e21b81529192506000916001600160a01b038616916317bfdfbc9161231c9190600401614e65565b602060405180830381600087803b15801561233657600080fd5b505af115801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e9190614cd7565b90506000818c1161237f578b612381565b815b905061238e8a828b613a46565b61239e8786866000015184613c99565b60006123a989613568565b905080156124cd576123bc898883613915565b84516040516370a0823160e01b81526001600160a01b0389169163a9059cbb9183906370a08231906123f2903090600401614e65565b60206040518083038186803b15801561240a57600080fd5b505afa15801561241e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124429190614cd7565b6040518363ffffffff1660e01b815260040161245f929190614f6c565b602060405180830381600087803b15801561247957600080fd5b505af115801561248d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124b19190614c48565b6124cd5760405162461bcd60e51b81526004016105ad90615110565b84516001600160a01b03167f7f5cab282a9e1113c00984f503d22a59104d70bf6eebfcb7e1528648f8a54a71886125048488615496565b89866040516125169493929190614f85565b60405180910390a2505050505050505050505050505050565b3360009081526001602052604090205460ff1661255e5760405162461bcd60e51b81526004016105ad90615230565b600080600080848060200190518101906125789190614537565b93509350935093506000816000815181106125a357634e487b7160e01b600052603260045260246000fd5b60200260200101519050600082600184516125be9190615496565b815181106125dc57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101513360009081526003835260408082206001600160a01b038781168452945280822054848416835291205491935082169116808214156126395760405162461bcd60e51b81526004016105ad906151a6565b6040516323b872dd60e01b81526001600160a01b038316906323b872dd90612669908b9030908c90600401614e79565b602060405180830381600087803b15801561268357600080fd5b505af1158015612697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bb9190614c48565b6127075760405162461bcd60e51b815260206004820152601f60248201527f696e73756666696369656e742074546f6b656e20746f207472616e736665720060448201526064016105ad565b60405163db006a7560e01b8152600481018890526001600160a01b0383169063db006a7590602401602060405180830381600087803b15801561274957600080fd5b505af115801561275d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127819190614cd7565b1561279e5760405162461bcd60e51b81526004016105ad906152bc565b60006127a985613568565b90506127b6818888613dfb565b60006127c185613568565b90506127ce858483613915565b6040516370a0823160e01b81526001600160a01b0384169063a9059cbb908c9083906370a0823190612804903090600401614e65565b60206040518083038186803b15801561281c57600080fd5b505afa158015612830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128549190614cd7565b6040518363ffffffff1660e01b8152600401612871929190614f6c565b602060405180830381600087803b15801561288b57600080fd5b505af115801561289f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c39190614c48565b6128df5760405162461bcd60e51b81526004016105ad90615110565b896001600160a01b03167f3dad173153e728b4c08a837601fdd63f2cc18161a56b3d9e4cb56f624cf24c4a8584868560405161291e9493929190614f85565b60405180910390a25050505050505050505050565b6001600160a01b038516600090815260036020526040812081908190818686828161296e57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061298391906143a1565b6001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a90046001600160a01b031690506000816001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b1580156129f457600080fd5b505afa158015612a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a2c9190614cd7565b9050670de0b6b3a764000081612a506a0c097ce7bc90715b34b9f160241b8b615477565b612a5a9190615457565b612a649190615457565b935060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d06ca61f8a89896040518463ffffffff1660e01b8152600401612ab8939291906152ea565b60006040518083038186803b158015612ad057600080fd5b505afa158015612ae4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b0c9190810190614b9a565b9050670de0b6b3a7640000612b218982615496565b8260018451612b309190615496565b81518110612b4e57634e487b7160e01b600052603260045260246000fd5b6020026020010151612b609190615477565b612b6a9190615457565b93505050509550959350505050565b33612b82611793565b6001600160a01b031614612ba85760405162461bcd60e51b81526004016105ad906151fb565b6001600160a01b038116612c0d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105ad565b612c168161386d565b50565b3360009081526001602052604090205460ff16612c485760405162461bcd60e51b81526004016105ad90615230565b60008060008060008086806020019051810190612c659190614475565b3360009081526003602090815260408083206001600160a01b0387811685529252808320548583168085529190932054989e50969c50949a5092985090965094508116928116917f00000000000000000000000000000000000000000000000000000000000000009091161415612cee5760405162461bcd60e51b81526004016105ad90615177565b612cf6614261565b6001600160a01b03898116825260208201889052604082018990527f0000000000000000000000000000000000000000000000000000000000000000811690871614612d595780516040820151612d59916001600160a01b0389169130906138bd565b8051602082015160405163654c3dcf60e01b81526001600160a01b0385169263654c3dcf92612d8d92309190600401614e79565b602060405180830381600087803b158015612da757600080fd5b505af1158015612dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddf9190614cd7565b15612dfc5760405162461bcd60e51b81526004016105ad906151cc565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686604051612e379190614e49565b6000604051808303816000865af19150503d8060008114612e74576040519150601f19603f3d011682016040523d82523d6000602084013e612e79565b606091505b509150915080518260008114612e8e57612e95565b8183602001fd5b50506000612ea289613568565b9050612eaf898783613915565b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190612ede903090600401614e65565b60206040518083038186803b158015612ef657600080fd5b505afa158015612f0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2e9190614cd7565b855160405163a9059cbb60e01b81529192506001600160a01b0389169163a9059cbb91612f5f918590600401614f6c565b602060405180830381600087803b158015612f7957600080fd5b505af1158015612f8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb19190614c48565b612fcd5760405162461bcd60e51b81526004016105ad90615145565b84600001516001600160a01b03166000805160206155298339815191528787602001518a896040015187604051613008959493929190614faf565b60405180910390a25050505050505050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031614156130c457604051635572051560e11b81526001600160a01b038381166004830152848116602483015285169063aae40a2a9083906044016000604051808303818588803b1580156130a657600080fd5b505af11580156130ba573d6000803e3d6000fd5b505050505061178c565b604051637af1e23160e11b81526001600160a01b03838116600483015260248201839052848116604483015285169063f5e3c46290606401602060405180830381600087803b15801561311657600080fd5b505af115801561312a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061314e9190614cd7565b1561178c5760405162461bcd60e51b81526020600482015260166024820152751b1a5c5d5a59185d19509bdc9c9bddc819985a5b195960521b60448201526064016105ad565b805160005b818110156135625760008482815181106131c357634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b0381166000908152600290925260409091205490915060ff1661322d5760405162461bcd60e51b815260206004820152600f60248201526e0eadce6eae0e0dee4e8cac840c8caf608b1b60448201526064016105ad565b600084838151811061324f57634e487b7160e01b600052603260045260246000fd5b60200260200101519050600061328c8260008151811061327f57634e487b7160e01b600052603260045260246000fd5b6020026020010151613fc7565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316141561335457604051635c11d79560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635c11d7959061331d908490600090879030904290600401615342565b600060405180830381600087803b15801561333757600080fd5b505af115801561334b573d6000803e3d6000fd5b50505050613557565b60008390506000816001600160a01b03166366c0bd248560008151811061338b57634e487b7160e01b600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b81526004016133af9190614e65565b602060405180830381600087803b1580156133c957600080fd5b505af11580156133dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134019190614cef565b90506000826001600160a01b03166366c0bd2486600188516134239190615496565b8151811061344157634e487b7160e01b600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b81526004016134659190614e65565b602060405180830381600087803b15801561347f57600080fd5b505af1158015613493573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134b79190614cef565b6040516348b4aac360e11b815260ff80851660048301528216602482015260448101869052600060648201524260848201529091506001600160a01b0384169063916955869060a401602060405180830381600087803b15801561351a57600080fd5b505af115801561352e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135529190614cd7565b505050505b505050600101613199565b50505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156135ab57504761362a565b6040516370a0823160e01b81526001600160a01b038316906370a08231906135d7903090600401614e65565b60206040518083038186803b1580156135ef57600080fd5b505afa158015613603573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136279190614cd7565b90505b919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614156136c257816001600160a01b0316634e4d9fea826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156136a457600080fd5b505af11580156136b8573d6000803e3d6000fd5b505050505061377e565b60405163073a938160e11b8152600481018290526001600160a01b03831690630e75270290602401602060405180830381600087803b15801561370457600080fd5b505af1158015613718573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373c9190614cd7565b1561377e5760405162461bcd60e51b81526020600482015260126024820152711c995c185e509bdc9c9bddc819985a5b195960721b60448201526064016105ad565b505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161415613859576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461380a576040519150601f19603f3d011682016040523d82523d6000602084013e61380f565b606091505b50509050806138535760405162461bcd60e51b815260206004820152601060248201526f17dd1c985b9cd9995c8819985a5b195960821b60448201526064016105ad565b5061377e565b61377e6001600160a01b0384168383613ff6565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b613562846323b872dd60e01b8585856040516024016138de93929190614e79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614015565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316141561398a57816001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156136a457600080fd5b60405163140e25ad60e31b8152600481018290526001600160a01b0383169063a0712d6890602401602060405180830381600087803b1580156139cc57600080fd5b505af11580156139e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a049190614cd7565b1561377e5760405162461bcd60e51b81526020600482015260126024820152711b5a5b9d081d151bdad95b8819985a5b195960721b60448201526064016105ad565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681600081518110613a9157634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613b155760405163fb3bdb4160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fb3bdb41908590613afc90869086903090429060040161530d565b6000604051808303818588803b1580156136a457600080fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168160018351613b4e9190615496565b81518110613b6c57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613c0e57604051632512eca560e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690634a25d94a90613bd79085908790869030904290600401615342565b600060405180830381600087803b158015613bf157600080fd5b505af1158015613c05573d6000803e3d6000fd5b5050505061377e565b604051634401edf760e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638803dbee90613c629085908790869030904290600401615342565b600060405180830381600087803b158015613c7c57600080fd5b505af1158015613c90573d6000803e3d6000fd5b50505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161415613d385760405163e597461960e01b81526001600160a01b0384169063e5974619908390613d01908690600401614e65565b6000604051808303818588803b158015613d1a57600080fd5b505af1158015613d2e573d6000803e3d6000fd5b5050505050613562565b6040516304c11f0360e31b81526001600160a01b03841690632608f81890613d669085908590600401614f6c565b602060405180830381600087803b158015613d8057600080fd5b505af1158015613d94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db89190614cd7565b156135625760405162461bcd60e51b81526020600482015260136024820152721c995c185e48189bdc9c9bddc819985a5b1959606a1b60448201526064016105ad565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681600081518110613e4657634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613eb15760405163b6f9de9560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b6f9de95908590613afc90869086903090429060040161530d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168160018351613eea9190615496565b81518110613f0857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613f735760405163791ac94760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063791ac94790613bd79086908690869030904290600401615342565b604051635c11d79560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635c11d79590613c629086908690869030904290600401615342565b6040516370a0823160e01b81526000906001600160a01b038316906370a08231906135d7903090600401614e65565b61377e8363a9059cbb60e01b84846040516024016138de929190614f6c565b600061406a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166140e79092919063ffffffff16565b80519091501561377e57808060200190518101906140889190614c48565b61377e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105ad565b60606140f68484600085614100565b90505b9392505050565b6060824710156141615760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105ad565b843b6141af5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105ad565b600080866001600160a01b031685876040516141cb9190614e49565b60006040518083038185875af1925050503d8060008114614208576040519150601f19603f3d011682016040523d82523d6000602084013e61420d565b606091505b509150915061421d828286614228565b979650505050505050565b606083156142375750816140f9565b8251156142475782518084602001fd5b8160405162461bcd60e51b81526004016105ad91906150fd565b604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b60008083601f84011261429c578182fd5b5081356001600160401b038111156142b2578182fd5b6020830191508360208260051b85010111156142cd57600080fd5b9250929050565b600082601f8301126142e4578081fd5b815160206142f96142f4836153f5565b6153c5565b80838252828201915082860187848660051b8901011115614318578586fd5b855b8581101561433f57815161432d81615505565b8452928401929084019060010161431a565b5090979650505050505050565b600082601f83011261435c578081fd5b8151602061436c6142f4836153f5565b82815281810190858301855b8581101561433f5761438f898684518b01016142d4565b84529284019290840190600101614378565b6000602082840312156143b2578081fd5b81356140f981615505565b600080600080600080600060e0888a0312156143d7578283fd5b87516143e281615505565b60208901519097506143f381615505565b604089015190965061440481615505565b606089015190955061441581615505565b608089015160a08a015191955093506001600160401b0380821115614438578384fd5b6144448b838c016142d4565b935060c08a0151915080821115614459578283fd5b506144668a828b0161434c565b91505092959891949750929550565b60008060008060008060c0878903121561448d578384fd5b865161449881615505565b80965050602087015194506040870151935060608701516144b881615505565b60808801519093506144c981615505565b60a08801519092506001600160401b038111156144e4578182fd5b8701601f810189136144f4578182fd5b80516145026142f482615418565b8181528a6020838501011115614516578384fd5b6145278260208301602086016154ad565b8093505050509295509295509295565b6000806000806080858703121561454c578182fd5b845161455781615505565b60208601516040870151606088015192965090945092506001600160401b03811115614581578182fd5b61458d878288016142d4565b91505092959194509250565b600080600080600060a086880312156145b0578283fd5b85516145bb81615505565b60208701516040880151606089015160808a0151939850919650945092506001600160401b038111156145ec578182fd5b6145f8888289016142d4565b9150509295509295909350565b60008060008060008060c0878903121561461d578384fd5b865161462881615505565b6020880151604089015160608a015160808b0151939950919750955093506001600160401b038082111561465a578384fd5b6146668a838b016142d4565b935060a089015191508082111561467b578283fd5b5061468889828a0161434c565b9150509295509295509295565b600080604083850312156146a7578182fd5b82356146b281615505565b915060208301356146c281615505565b809150509250929050565b600080600080600080600080600060e08a8c0312156146ea578283fd5b89356146f581615505565b985060208a013561470581615505565b975060408a013561471581615505565b965060608a013561472581615505565b955060808a0135945060a08a01356001600160401b0380821115614747578485fd5b6147538d838e0161428b565b909650945060c08c013591508082111561476b578384fd5b506147788c828d0161428b565b915080935050809150509295985092959850929598565b60008060008060008060a087890312156147a7578384fd5b86356147b281615505565b955060208701356147c281615505565b9450604087013593506060870135925060808701356001600160401b038111156147ea578283fd5b6147f689828a0161428b565b979a9699509497509295939492505050565b600080600080600080600060c0888a031215614822578081fd5b873561482d81615505565b9650602088013561483d81615505565b955060408801359450606088013593506080880135925060a08801356001600160401b0381111561486c578182fd5b6148788a828b0161428b565b989b979a50959850939692959293505050565b60008060006040848603121561489f578081fd5b83356148aa81615505565b925060208401356001600160401b038111156148c4578182fd5b6148d08682870161428b565b9497909650939450505050565b6000806000806000606086880312156148f4578283fd5b85356148ff81615505565b945060208601356001600160401b038082111561491a578485fd5b61492689838a0161428b565b9096509450604088013591508082111561493e578283fd5b5061494b8882890161428b565b969995985093965092949392505050565b6000806040838503121561496e578182fd5b823561497981615505565b915060208301356146c28161551a565b600080600080600080600060c0888a0312156149a3578081fd5b87356149ae81615505565b9650602088013595506040880135945060608801356149cc81615505565b935060808801356149dc81615505565b925060a08801356001600160401b03808211156149f7578283fd5b818a0191508a601f830112614a0a578283fd5b813581811115614a18578384fd5b8b6020828501011115614a29578384fd5b60208301945080935050505092959891949750929550565b600080600080600060808688031215614a58578283fd5b8535614a6381615505565b9450602086013593506040860135925060608601356001600160401b03811115614a8b578182fd5b61494b8882890161428b565b60008060008060008060008060c0898b031215614ab2578182fd5b8835614abd81615505565b975060208901359650604089013595506060890135945060808901356001600160401b0380821115614aed578384fd5b614af98c838d0161428b565b909650945060a08b0135915080821115614b11578384fd5b50614b1e8b828c0161428b565b999c989b5096995094979396929594505050565b60008060008060408587031215614b47578182fd5b84356001600160401b0380821115614b5d578384fd5b614b698883890161428b565b90965094506020870135915080821115614b81578384fd5b50614b8e8782880161428b565b95989497509550505050565b60006020808385031215614bac578182fd5b82516001600160401b03811115614bc1578283fd5b8301601f81018513614bd1578283fd5b8051614bdf6142f4826153f5565b80828252848201915084840188868560051b8701011115614bfe578687fd5b8694505b83851015614c20578051835260019490940193918501918501614c02565b50979650505050505050565b600060208284031215614c3d578081fd5b81356140f98161551a565b600060208284031215614c59578081fd5b81516140f98161551a565b600060208284031215614c75578081fd5b81356001600160401b03811115614c8a578182fd5b8201601f81018413614c9a578182fd5b8035614ca86142f482615418565b818152856020838501011115614cbc578384fd5b81602084016020830137908101602001929092525092915050565b600060208284031215614ce8578081fd5b5051919050565b600060208284031215614d00578081fd5b815160ff811681146140f9578182fd5b60008284526020808501945082825b85811015614d4d578135614d3281615505565b6001600160a01b031687529582019590820190600101614d1f565b509495945050505050565b6000815180845260208085019450808401835b83811015614d4d5781516001600160a01b031687529582019590820190600101614d6b565b60008284526020808501945084600585811b870185855b88811015614e0f578483038a528135601e19893603018112614dc7578788fd5b880180356001600160401b03811115614dde578889fd5b80861b36038a1315614dee578889fd5b614dfb85828a8501614d10565b9b88019b9450505090850190600101614da7565b509098975050505050505050565b60008151808452614e358160208601602086016154ad565b601f01601f19169290920160200192915050565b60008251614e5b8184602087016154ad565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038a8116825289811660208301528881166040830152871660608201526080810186905260e060a08201819052600090614ee19083018688614d10565b82810360c0840152614ef4818587614d90565b9c9b505050505050505050505050565b6001600160a01b0386168152606060208201819052600090614f299083018688614d10565b8281036040840152614f3c818587614d10565b98975050505050505050565b6001600160a01b03831681526040602082018190526000906140f690830184614e1d565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b038881168252602082018890526040820187905285811660608301528416608082015260c060a0820181905281018290526000828460e084013781830160e090810191909152601f909201601f191601019695505050505050565b600060018060a01b03871682528560208301528460408301526080606083015261421d608083018486614d10565b600060018060a01b038816825286602083015285604083015284606083015260a06080830152614f3c60a083018486614d10565b600060018060a01b038a16825288602083015287604083015286606083015260c060808301526150db60c083018688614d10565b82810360a08401526150ee818587614d90565b9b9a5050505050505050505050565b6000602082526140f96020830184614e1d565b6020808252818101527f7472616e736665722072656d61696e696e672074546f6b656e206661696c6564604082015260600190565b6020808252601890820152771d1c985b9cd9995c881d151bdad95b88104819985a5b195960421b604082015260600190565b602080825260159082015274756e737570706f727465642073686f72742043524f60581b604082015260600190565b6020808252600c908201526b73616d65206d61726b65747360a01b604082015260600190565b602080825260159082015274189bdc9c9bddd3db90995a185b198819985a5b1959605a1b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602a908201527f6f6e6c7920746563746f6e6963436f72652063616e20616363657373207468696040820152693990333ab731ba34b7b760b11b606082015260800190565b60208082526022908201527f6d73672e76616c7565206d75737420626520657175616c206c6f6e67416d6f756040820152611b9d60f21b606082015260800190565b6020808252601490820152731c995919595b481d151bdad95b8819985a5b195960621b604082015260600190565b600084825260406020830152615304604083018486614d10565b95945050505050565b6000858252608060208301526153266080830186614d58565b6001600160a01b03949094166040830152506060015292915050565b600086825285602083015260a0604083015261536160a0830186614d58565b6001600160a01b0394909416606083015250608001529392505050565b6000808335601e19843603018112615394578283fd5b8301803591506001600160401b038211156153ad578283fd5b6020019150600581901b36038213156142cd57600080fd5b604051601f8201601f191681016001600160401b03811182821017156153ed576153ed6154ef565b604052919050565b60006001600160401b0382111561540e5761540e6154ef565b5060051b60200190565b60006001600160401b03821115615431576154316154ef565b50601f01601f191660200190565b60008219821115615452576154526154d9565b500190565b60008261547257634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615491576154916154d9565b500290565b6000828210156154a8576154a86154d9565b500390565b60005b838110156154c85781810151838201526020016154b0565b838111156135625750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114612c1657600080fd5b8015158114612c1657600080fdfe255bc41afe8d8409fb085d5e9c36bf9917671efdb2f3d452e9d65271da35480da2646970667358221220835c404ee10eb99e583b7af1a58bb3e4ab872098a0f31bdfa83f89715948b8ab64736f6c634300080300330000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae23000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae000000000000000000000000db37a3132eb2df17fd17135ed780ed2d0385cdb6

Deployed Bytecode

0x60806040526004361061014b5760003560e01c806301ebfe781461015757806308e77344146101795780631676c720146101c35780632a2c372e146101e35780632fdb7309146102175780633395635d14610237578063444c55581461027757806348180e231461029757806356194f56146102b7578063587261d9146102e7578063620f0b151461031c578063715018a61461033c57806377aabbbe146103515780637b3fb21b1461036457806383975275146103775780638a70e439146103975780638da5cb5b146103d8578063a76385b8146103ed578063a77ec9e01461040d578063ad5c464814610429578063c0c28da21461045d578063c7fb1c721461047d578063ce9095e4146104be578063db03c117146104de578063e1faf5d2146104fe578063e5dc168d1461051e578063f2fde38b1461053e578063f85278e31461055e57610152565b3661015257005b600080fd5b34801561016357600080fd5b50610177610172366004614b32565b61057e565b005b34801561018557600080fd5b506101ad7f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae81565b6040516101ba9190614e65565b60405180910390f35b3480156101cf57600080fd5b506101776101de36600461495c565b6106ac565b3480156101ef57600080fd5b506101ad7f000000000000000000000000db37a3132eb2df17fd17135ed780ed2d0385cdb681565b34801561022357600080fd5b506101776102323660046146cd565b61073e565b34801561024357600080fd5b506102676102523660046143a1565b60026020526000908152604090205460ff1681565b60405190151581526020016101ba565b34801561028357600080fd5b5061017761029236600461478f565b61081b565b3480156102a357600080fd5b506101776102b2366004614c64565b6108ed565b3480156102c357600080fd5b506102676102d23660046143a1565b60016020526000908152604090205460ff1681565b3480156102f357600080fd5b50610307610302366004614a41565b610e04565b604080519283526020830191909152016101ba565b34801561032857600080fd5b50610177610337366004614b32565b611023565b34801561034857600080fd5b506101776112ff565b61017761035f366004614a97565b61133a565b610177610372366004614989565b611530565b34801561038357600080fd5b5061017761039236600461488b565b611692565b3480156103a357600080fd5b506101ad6103b2366004614695565b60036020908152600092835260408084209091529082529020546001600160a01b031681565b3480156103e457600080fd5b506101ad611793565b3480156103f957600080fd5b50610177610408366004614c64565b6117a2565b34801561041957600080fd5b50604051600781526020016101ba565b34801561043557600080fd5b506101ad7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae2381565b34801561046957600080fd5b50610177610478366004614808565b611dd0565b34801561048957600080fd5b506101ad610498366004614695565b60046020908152600092835260408084209091529082529020546001600160a01b031681565b3480156104ca57600080fd5b506101776104d93660046148dd565b611e69565b3480156104ea57600080fd5b506101776104f9366004614c64565b61205c565b34801561050a57600080fd5b50610177610519366004614c64565b61252f565b34801561052a57600080fd5b50610307610539366004614a41565b612933565b34801561054a57600080fd5b506101776105593660046143a1565b612b79565b34801561056a57600080fd5b50610177610579366004614c64565b612c19565b33610587611793565b6001600160a01b0316146105b65760405162461bcd60e51b81526004016105ad906151fb565b60405180910390fd5b828181146105fb5760405162461bcd60e51b81526020600482015260126024820152711b195b99dd1a081b9bdd081b585d18da195960721b60448201526064016105ad565b60005b818110156106a45783838281811061062657634e487b7160e01b600052603260045260246000fd5b905060200201602081019061063b9190614c2c565b6002600088888581811061065f57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061067491906143a1565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790556001016105fe565b505050505050565b336106b5611793565b6001600160a01b0316146106db5760405162461bcd60e51b81526004016105ad906151fb565b6001600160a01b038216600081815260016020908152604091829020805460ff19168515159081179091558251938452908301527fa22ebc7a07361801b1b3f0d83d8155491878f37ca47db690d89f35828a49df9b910160405180910390a15050565b600033898989898989898960405160200161076199989796959493929190614e9d565b6040516020818303038152906040529050896001600160a01b03166389b7b7a6308360405160240161079391906150fd565b60408051601f198184030181529181526020820180516001600160e01b03166348180e2360e01b1790525160e084901b6001600160e01b03191681526107dd929190600401614f48565b600060405180830381600087803b1580156107f757600080fd5b505af115801561080b573d6000803e3d6000fd5b5050505050505050505050505050565b60003385858585604051602001610836959493929190615045565b6040516020818303038152906040529050866001600160a01b03166389b7b7a6338360405160240161086891906150fd565b60408051601f198184030181529181526020820180516001600160e01b03166370fd7ae960e11b1790525160e084901b6001600160e01b03191681526108b2929190600401614f48565b600060405180830381600087803b1580156108cc57600080fd5b505af11580156108e0573d6000803e3d6000fd5b5050505050505050505050565b3360009081526001602052604090205460ff1661091c5760405162461bcd60e51b81526004016105ad90615230565b60008060008060008060008780602001905181019061093b91906143bd565b9650965096509650965096509650846001600160a01b031663c5ebeaec846040518263ffffffff1660e01b815260040161097791815260200190565b602060405180830381600087803b15801561099157600080fd5b505af11580156109a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c99190614cd7565b15610a065760405162461bcd60e51b815260206004820152600d60248201526c189bdc9c9bddc819985a5b1959609a1b60448201526064016105ad565b3360009081526004602090815260408083206001600160a01b03898116855292528083205487831684529220549181169116610a458288888b89613020565b6040516370a0823160e01b81526001600160a01b0387169063db006a759082906370a0823190610a79903090600401614e65565b60206040518083038186803b158015610a9157600080fd5b505afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac99190614cd7565b6040518263ffffffff1660e01b8152600401610ae791815260200190565b602060405180830381600087803b158015610b0157600080fd5b505af1158015610b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b399190614cd7565b15610b765760405162461bcd60e51b815260206004820152600d60248201526c1c995919595b4819985a5b1959609a1b60448201526064016105ad565b856001600160a01b0316876001600160a01b031614610d77577f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316816001600160a01b03161415610c3e577f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015610c2457600080fd5b505af1158015610c38573d6000803e3d6000fd5b50505050505b610c488484613194565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316826001600160a01b03161415610d77576040516370a0823160e01b81526001600160a01b037f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae231690632e1a7d4d9082906370a0823190610cd6903090600401614e65565b60206040518083038186803b158015610cee57600080fd5b505afa158015610d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d269190614cd7565b6040518263ffffffff1660e01b8152600401610d4491815260200190565b600060405180830381600087803b158015610d5e57600080fd5b505af1158015610d72573d6000803e3d6000fd5b505050505b84610d8183613568565b1015610ddb5760405162461bcd60e51b815260206004820152602360248201527f696e73756666696369656e742062616c616e636520746f207265706179426f72604482015262726f7760e81b60648201526084016105ad565b610de682888761362f565b6000610df183613568565b905080156108e0576108e0838b83613783565b6001600160a01b0385166000908152600360205260408120819081908186868281610e3f57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610e5491906143a1565b6001600160a01b0390811682526020820192909252604090810160009081205491516307c0329d60e21b81529183169350917f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae1690631f00ca7490610ec1908b908a908a906004016152ea565b60006040518083038186803b158015610ed957600080fd5b505afa158015610eed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f159190810190614b9a565b9050670de0b6b3a7640000610f2a888261543f565b82600081518110610f4b57634e487b7160e01b600052603260045260246000fd5b6020026020010151610f5d9190615477565b610f679190615457565b92506000826001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610fa457600080fd5b505afa158015610fb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdc9190614cd7565b9050670de0b6b3a7640000816110006a0c097ce7bc90715b34b9f160241b87615477565b61100a9190615457565b6110149190615457565b94505050509550959350505050565b3361102c611793565b6001600160a01b0316146110525760405162461bcd60e51b81526004016105ad906151fb565b8260005b818110156106a45785858281811061107e57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061109391906143a1565b6001600160a01b031663095ea7b38585848181106110c157634e487b7160e01b600052603260045260246000fd5b90506020020160208101906110d691906143a1565b6000196040518363ffffffff1660e01b81526004016110f6929190614f6c565b602060405180830381600087803b15801561111057600080fd5b505af1158015611124573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111489190614c48565b5085858281811061116957634e487b7160e01b600052603260045260246000fd5b905060200201602081019061117e91906143a1565b6001600160a01b031663095ea7b37f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae6000196040518363ffffffff1660e01b81526004016111cd929190614f6c565b602060405180830381600087803b1580156111e757600080fd5b505af11580156111fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121f9190614c48565b5085858281811061124057634e487b7160e01b600052603260045260246000fd5b905060200201602081019061125591906143a1565b6001600160a01b031663095ea7b37f000000000000000000000000db37a3132eb2df17fd17135ed780ed2d0385cdb66000196040518363ffffffff1660e01b81526004016112a4929190614f6c565b602060405180830381600087803b1580156112be57600080fd5b505af11580156112d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f69190614c48565b50600101611056565b33611308611793565b6001600160a01b03161461132e5760405162461bcd60e51b81526004016105ad906151fb565b611338600061386d565b565b806000838261134a600182615496565b81811061136757634e487b7160e01b600052603260045260246000fd5b9050602002810190611379919061537e565b915060009050848461138c600186615496565b8181106113a957634e487b7160e01b600052603260045260246000fd5b90506020028101906113bb919061537e565b6113c6600185615496565b8181106113e357634e487b7160e01b600052603260045260246000fd5b90506020020160208101906113f891906143a1565b90507f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316816001600160a01b03161415611453578934146114535760405162461bcd60e51b81526004016105ad9061527a565b6000338b8b8b8b8b8b8b6040516020016114749897969594939291906150a7565b60405160208183030381529060405290508b6001600160a01b03166389b7b7a633836040516024016114a691906150fd565b60408051601f198184030181529181526020820180516001600160e01b03166314ec70b760e31b1790525160e084901b6001600160e01b03191681526114f0929190600401614f48565b600060405180830381600087803b15801561150a57600080fd5b505af115801561151e573d6000803e3d6000fd5b50505050505050505050505050505050565b826001600160a01b0316846001600160a01b031614156115625760405162461bcd60e51b81526004016105ad906151a6565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316846001600160a01b031614156115bb578534146115bb5760405162461bcd60e51b81526004016105ad9061527a565b6000338787878787876040516020016115da9796959493929190614fe3565b6040516020818303038152906040529050876001600160a01b03166389b7b7a6338360405160240161160c91906150fd565b60408051601f198184030181529181526020820180516001600160e01b031663f85278e360e01b1790525160e084901b6001600160e01b0319168152611656929190600401614f48565b600060405180830381600087803b15801561167057600080fd5b505af1158015611684573d6000803e3d6000fd5b505050505050505050505050565b3361169b611793565b6001600160a01b0316146116c15760405162461bcd60e51b81526004016105ad906151fb565b8060005b8181101561178c578383828181106116ed57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061170291906143a1565b6001600160a01b031663095ea7b3866000196040518363ffffffff1660e01b8152600401611731929190614f6c565b602060405180830381600087803b15801561174b57600080fd5b505af115801561175f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117839190614c48565b506001016116c5565b5050505050565b6000546001600160a01b031690565b3360009081526001602052604090205460ff166117d15760405162461bcd60e51b81526004016105ad90615230565b600080600080600080868060200190518101906117ee9190614605565b8051959b5093995091975095509350915060008261180d600184615496565b8151811061182b57634e487b7160e01b600052603260045260246000fd5b60200260200101515190506000836001846118469190615496565b8151811061186457634e487b7160e01b600052603260045260246000fd5b60200260200101516001836118799190615496565b8151811061189757634e487b7160e01b600052603260045260246000fd5b602002602001015190506000846000815181106118c457634e487b7160e01b600052603260045260246000fd5b60200260200101516000815181106118ec57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101513360009081526003835260408082206001600160a01b038781168452945280822054848416808452919092205492945090831692918216917f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae231614156119705760405162461bcd60e51b81526004016105ad90615177565b806001600160a01b0316826001600160a01b031614156119a25760405162461bcd60e51b81526004016105ad906151a6565b6119aa614261565b6001600160a01b038d81168252602082018c9052604082018d90527f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae23811690861614611a0d5780516040820151611a0d916001600160a01b0388169130906138bd565b8051602082015160405163654c3dcf60e01b81526001600160a01b0385169263654c3dcf92611a4192309190600401614e79565b602060405180830381600087803b158015611a5b57600080fd5b505af1158015611a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a939190614cd7565b15611ab05760405162461bcd60e51b81526004016105ad906151cc565b611aba8989613194565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316856001600160a01b03161415611be9576040516370a0823160e01b81526001600160a01b037f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae231690632e1a7d4d9082906370a0823190611b48903090600401614e65565b60206040518083038186803b158015611b6057600080fd5b505afa158015611b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b989190614cd7565b6040518263ffffffff1660e01b8152600401611bb691815260200190565b600060405180830381600087803b158015611bd057600080fd5b505af1158015611be4573d6000803e3d6000fd5b505050505b6000611bf486613568565b90508a826040015182611c079190615496565b1015611c525760405162461bcd60e51b815260206004820152601a6024820152791a5b9cdd59999a58da595b9d081bdd5d1c1d5d08185b5bdd5b9d60321b60448201526064016105ad565b611c5d868583613915565b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190611c8c903090600401614e65565b60206040518083038186803b158015611ca457600080fd5b505afa158015611cb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdc9190614cd7565b835160405163a9059cbb60e01b81529192506001600160a01b0387169163a9059cbb91611d0d918590600401614f6c565b602060405180830381600087803b158015611d2757600080fd5b505af1158015611d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5f9190614c48565b611d7b5760405162461bcd60e51b81526004016105ad90615145565b82600001516001600160a01b031660008051602061552983398151915285856020015188876040015187604051611db6959493929190614faf565b60405180910390a250505050505050505050505050505050565b6000338587868686604051602001611ded96959493929190615073565b6040516020818303038152906040529050876001600160a01b03166389b7b7a63383604051602401611e1f91906150fd565b60408051601f198184030181529181526020820180516001600160e01b031663db03c11760e01b1790525160e084901b6001600160e01b0319168152611656929190600401614f48565b33611e72611793565b6001600160a01b031614611e985760405162461bcd60e51b81526004016105ad906151fb565b8260005b8181101561201457838382818110611ec457634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611ed991906143a1565b6001600160a01b038816600090815260036020526040812090888885818110611f1257634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611f2791906143a1565b6001600160a01b039081168252602082019290925260400160002080546001600160a01b03191692909116919091179055858582818110611f7857634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611f8d91906143a1565b6001600160a01b038816600090815260046020526040812090868685818110611fc657634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611fdb91906143a1565b6001600160a01b039081168252602082019290925260400160002080546001600160a01b03191692909116919091179055600101611e9c565b507fd7fe33c445d86c4d4c370d1211518954fdfd403eaeb5f74ebc9f2a0a2f1a73be868686868660405161204c959493929190614f04565b60405180910390a1505050505050565b3360009081526001602052604090205460ff1661208b5760405162461bcd60e51b81526004016105ad90615230565b6000806000806000858060200190518101906120a79190614599565b945094509450945094506000816000815181106120d457634e487b7160e01b600052603260045260246000fd5b60200260200101519050600082600184516120ef9190615496565b8151811061210d57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101513360009081526003835260408082206001600160a01b038781168452908552818320548185168452928290205482519586019092528b81168552929450908216929116908183141561217d5760405162461bcd60e51b81526004016105ad906151a6565b80516040516323b872dd60e01b81526001600160a01b038516916323b872dd916121ae919030908d90600401614e79565b602060405180830381600087803b1580156121c857600080fd5b505af11580156121dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122009190614c48565b6122475760405162461bcd60e51b81526020600482015260186024820152771d151bdad95b881a5b9cdd59999a58da595b9d08199d5b9960421b60448201526064016105ad565b60405163db006a7560e01b8152600481018990526001600160a01b0384169063db006a7590602401602060405180830381600087803b15801561228957600080fd5b505af115801561229d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c19190614cd7565b156122de5760405162461bcd60e51b81526004016105ad906152bc565b60006122e986613568565b82516040516305eff7ef60e21b81529192506000916001600160a01b038616916317bfdfbc9161231c9190600401614e65565b602060405180830381600087803b15801561233657600080fd5b505af115801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e9190614cd7565b90506000818c1161237f578b612381565b815b905061238e8a828b613a46565b61239e8786866000015184613c99565b60006123a989613568565b905080156124cd576123bc898883613915565b84516040516370a0823160e01b81526001600160a01b0389169163a9059cbb9183906370a08231906123f2903090600401614e65565b60206040518083038186803b15801561240a57600080fd5b505afa15801561241e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124429190614cd7565b6040518363ffffffff1660e01b815260040161245f929190614f6c565b602060405180830381600087803b15801561247957600080fd5b505af115801561248d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124b19190614c48565b6124cd5760405162461bcd60e51b81526004016105ad90615110565b84516001600160a01b03167f7f5cab282a9e1113c00984f503d22a59104d70bf6eebfcb7e1528648f8a54a71886125048488615496565b89866040516125169493929190614f85565b60405180910390a2505050505050505050505050505050565b3360009081526001602052604090205460ff1661255e5760405162461bcd60e51b81526004016105ad90615230565b600080600080848060200190518101906125789190614537565b93509350935093506000816000815181106125a357634e487b7160e01b600052603260045260246000fd5b60200260200101519050600082600184516125be9190615496565b815181106125dc57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101513360009081526003835260408082206001600160a01b038781168452945280822054848416835291205491935082169116808214156126395760405162461bcd60e51b81526004016105ad906151a6565b6040516323b872dd60e01b81526001600160a01b038316906323b872dd90612669908b9030908c90600401614e79565b602060405180830381600087803b15801561268357600080fd5b505af1158015612697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bb9190614c48565b6127075760405162461bcd60e51b815260206004820152601f60248201527f696e73756666696369656e742074546f6b656e20746f207472616e736665720060448201526064016105ad565b60405163db006a7560e01b8152600481018890526001600160a01b0383169063db006a7590602401602060405180830381600087803b15801561274957600080fd5b505af115801561275d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127819190614cd7565b1561279e5760405162461bcd60e51b81526004016105ad906152bc565b60006127a985613568565b90506127b6818888613dfb565b60006127c185613568565b90506127ce858483613915565b6040516370a0823160e01b81526001600160a01b0384169063a9059cbb908c9083906370a0823190612804903090600401614e65565b60206040518083038186803b15801561281c57600080fd5b505afa158015612830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128549190614cd7565b6040518363ffffffff1660e01b8152600401612871929190614f6c565b602060405180830381600087803b15801561288b57600080fd5b505af115801561289f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c39190614c48565b6128df5760405162461bcd60e51b81526004016105ad90615110565b896001600160a01b03167f3dad173153e728b4c08a837601fdd63f2cc18161a56b3d9e4cb56f624cf24c4a8584868560405161291e9493929190614f85565b60405180910390a25050505050505050505050565b6001600160a01b038516600090815260036020526040812081908190818686828161296e57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061298391906143a1565b6001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a90046001600160a01b031690506000816001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b1580156129f457600080fd5b505afa158015612a08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a2c9190614cd7565b9050670de0b6b3a764000081612a506a0c097ce7bc90715b34b9f160241b8b615477565b612a5a9190615457565b612a649190615457565b935060007f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae6001600160a01b031663d06ca61f8a89896040518463ffffffff1660e01b8152600401612ab8939291906152ea565b60006040518083038186803b158015612ad057600080fd5b505afa158015612ae4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b0c9190810190614b9a565b9050670de0b6b3a7640000612b218982615496565b8260018451612b309190615496565b81518110612b4e57634e487b7160e01b600052603260045260246000fd5b6020026020010151612b609190615477565b612b6a9190615457565b93505050509550959350505050565b33612b82611793565b6001600160a01b031614612ba85760405162461bcd60e51b81526004016105ad906151fb565b6001600160a01b038116612c0d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105ad565b612c168161386d565b50565b3360009081526001602052604090205460ff16612c485760405162461bcd60e51b81526004016105ad90615230565b60008060008060008086806020019051810190612c659190614475565b3360009081526003602090815260408083206001600160a01b0387811685529252808320548583168085529190932054989e50969c50949a5092985090965094508116928116917f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae239091161415612cee5760405162461bcd60e51b81526004016105ad90615177565b612cf6614261565b6001600160a01b03898116825260208201889052604082018990527f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae23811690871614612d595780516040820151612d59916001600160a01b0389169130906138bd565b8051602082015160405163654c3dcf60e01b81526001600160a01b0385169263654c3dcf92612d8d92309190600401614e79565b602060405180830381600087803b158015612da757600080fd5b505af1158015612dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddf9190614cd7565b15612dfc5760405162461bcd60e51b81526004016105ad906151cc565b6000807f000000000000000000000000db37a3132eb2df17fd17135ed780ed2d0385cdb66001600160a01b031686604051612e379190614e49565b6000604051808303816000865af19150503d8060008114612e74576040519150601f19603f3d011682016040523d82523d6000602084013e612e79565b606091505b509150915080518260008114612e8e57612e95565b8183602001fd5b50506000612ea289613568565b9050612eaf898783613915565b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190612ede903090600401614e65565b60206040518083038186803b158015612ef657600080fd5b505afa158015612f0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2e9190614cd7565b855160405163a9059cbb60e01b81529192506001600160a01b0389169163a9059cbb91612f5f918590600401614f6c565b602060405180830381600087803b158015612f7957600080fd5b505af1158015612f8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb19190614c48565b612fcd5760405162461bcd60e51b81526004016105ad90615145565b84600001516001600160a01b03166000805160206155298339815191528787602001518a896040015187604051613008959493929190614faf565b60405180910390a25050505050505050505050505050565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316856001600160a01b031614156130c457604051635572051560e11b81526001600160a01b038381166004830152848116602483015285169063aae40a2a9083906044016000604051808303818588803b1580156130a657600080fd5b505af11580156130ba573d6000803e3d6000fd5b505050505061178c565b604051637af1e23160e11b81526001600160a01b03838116600483015260248201839052848116604483015285169063f5e3c46290606401602060405180830381600087803b15801561311657600080fd5b505af115801561312a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061314e9190614cd7565b1561178c5760405162461bcd60e51b81526020600482015260166024820152751b1a5c5d5a59185d19509bdc9c9bddc819985a5b195960521b60448201526064016105ad565b805160005b818110156135625760008482815181106131c357634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b0381166000908152600290925260409091205490915060ff1661322d5760405162461bcd60e51b815260206004820152600f60248201526e0eadce6eae0e0dee4e8cac840c8caf608b1b60448201526064016105ad565b600084838151811061324f57634e487b7160e01b600052603260045260246000fd5b60200260200101519050600061328c8260008151811061327f57634e487b7160e01b600052603260045260246000fd5b6020026020010151613fc7565b90507f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae6001600160a01b0316836001600160a01b0316141561335457604051635c11d79560e01b81526001600160a01b037f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae1690635c11d7959061331d908490600090879030904290600401615342565b600060405180830381600087803b15801561333757600080fd5b505af115801561334b573d6000803e3d6000fd5b50505050613557565b60008390506000816001600160a01b03166366c0bd248560008151811061338b57634e487b7160e01b600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b81526004016133af9190614e65565b602060405180830381600087803b1580156133c957600080fd5b505af11580156133dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134019190614cef565b90506000826001600160a01b03166366c0bd2486600188516134239190615496565b8151811061344157634e487b7160e01b600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b81526004016134659190614e65565b602060405180830381600087803b15801561347f57600080fd5b505af1158015613493573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134b79190614cef565b6040516348b4aac360e11b815260ff80851660048301528216602482015260448101869052600060648201524260848201529091506001600160a01b0384169063916955869060a401602060405180830381600087803b15801561351a57600080fd5b505af115801561352e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135529190614cd7565b505050505b505050600101613199565b50505050565b60007f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316826001600160a01b031614156135ab57504761362a565b6040516370a0823160e01b81526001600160a01b038316906370a08231906135d7903090600401614e65565b60206040518083038186803b1580156135ef57600080fd5b505afa158015613603573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136279190614cd7565b90505b919050565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316836001600160a01b031614156136c257816001600160a01b0316634e4d9fea826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156136a457600080fd5b505af11580156136b8573d6000803e3d6000fd5b505050505061377e565b60405163073a938160e11b8152600481018290526001600160a01b03831690630e75270290602401602060405180830381600087803b15801561370457600080fd5b505af1158015613718573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373c9190614cd7565b1561377e5760405162461bcd60e51b81526020600482015260126024820152711c995c185e509bdc9c9bddc819985a5b195960721b60448201526064016105ad565b505050565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316836001600160a01b03161415613859576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461380a576040519150601f19603f3d011682016040523d82523d6000602084013e61380f565b606091505b50509050806138535760405162461bcd60e51b815260206004820152601060248201526f17dd1c985b9cd9995c8819985a5b195960821b60448201526064016105ad565b5061377e565b61377e6001600160a01b0384168383613ff6565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b613562846323b872dd60e01b8585856040516024016138de93929190614e79565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614015565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316836001600160a01b0316141561398a57816001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156136a457600080fd5b60405163140e25ad60e31b8152600481018290526001600160a01b0383169063a0712d6890602401602060405180830381600087803b1580156139cc57600080fd5b505af11580156139e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a049190614cd7565b1561377e5760405162461bcd60e51b81526020600482015260126024820152711b5a5b9d081d151bdad95b8819985a5b195960721b60448201526064016105ad565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b031681600081518110613a9157634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613b155760405163fb3bdb4160e01b81526001600160a01b037f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae169063fb3bdb41908590613afc90869086903090429060040161530d565b6000604051808303818588803b1580156136a457600080fd5b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b03168160018351613b4e9190615496565b81518110613b6c57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613c0e57604051632512eca560e11b81526001600160a01b037f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae1690634a25d94a90613bd79085908790869030904290600401615342565b600060405180830381600087803b158015613bf157600080fd5b505af1158015613c05573d6000803e3d6000fd5b5050505061377e565b604051634401edf760e11b81526001600160a01b037f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae1690638803dbee90613c629085908790869030904290600401615342565b600060405180830381600087803b158015613c7c57600080fd5b505af1158015613c90573d6000803e3d6000fd5b50505050505050565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b0316846001600160a01b03161415613d385760405163e597461960e01b81526001600160a01b0384169063e5974619908390613d01908690600401614e65565b6000604051808303818588803b158015613d1a57600080fd5b505af1158015613d2e573d6000803e3d6000fd5b5050505050613562565b6040516304c11f0360e31b81526001600160a01b03841690632608f81890613d669085908590600401614f6c565b602060405180830381600087803b158015613d8057600080fd5b505af1158015613d94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db89190614cd7565b156135625760405162461bcd60e51b81526020600482015260136024820152721c995c185e48189bdc9c9bddc819985a5b1959606a1b60448201526064016105ad565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b031681600081518110613e4657634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613eb15760405163b6f9de9560e01b81526001600160a01b037f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae169063b6f9de95908590613afc90869086903090429060040161530d565b7f0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae236001600160a01b03168160018351613eea9190615496565b81518110613f0857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415613f735760405163791ac94760e01b81526001600160a01b037f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae169063791ac94790613bd79086908690869030904290600401615342565b604051635c11d79560e01b81526001600160a01b037f000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae1690635c11d79590613c629086908690869030904290600401615342565b6040516370a0823160e01b81526000906001600160a01b038316906370a08231906135d7903090600401614e65565b61377e8363a9059cbb60e01b84846040516024016138de929190614f6c565b600061406a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166140e79092919063ffffffff16565b80519091501561377e57808060200190518101906140889190614c48565b61377e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105ad565b60606140f68484600085614100565b90505b9392505050565b6060824710156141615760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105ad565b843b6141af5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105ad565b600080866001600160a01b031685876040516141cb9190614e49565b60006040518083038185875af1925050503d8060008114614208576040519150601f19603f3d011682016040523d82523d6000602084013e61420d565b606091505b509150915061421d828286614228565b979650505050505050565b606083156142375750816140f9565b8251156142475782518084602001fd5b8160405162461bcd60e51b81526004016105ad91906150fd565b604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b60008083601f84011261429c578182fd5b5081356001600160401b038111156142b2578182fd5b6020830191508360208260051b85010111156142cd57600080fd5b9250929050565b600082601f8301126142e4578081fd5b815160206142f96142f4836153f5565b6153c5565b80838252828201915082860187848660051b8901011115614318578586fd5b855b8581101561433f57815161432d81615505565b8452928401929084019060010161431a565b5090979650505050505050565b600082601f83011261435c578081fd5b8151602061436c6142f4836153f5565b82815281810190858301855b8581101561433f5761438f898684518b01016142d4565b84529284019290840190600101614378565b6000602082840312156143b2578081fd5b81356140f981615505565b600080600080600080600060e0888a0312156143d7578283fd5b87516143e281615505565b60208901519097506143f381615505565b604089015190965061440481615505565b606089015190955061441581615505565b608089015160a08a015191955093506001600160401b0380821115614438578384fd5b6144448b838c016142d4565b935060c08a0151915080821115614459578283fd5b506144668a828b0161434c565b91505092959891949750929550565b60008060008060008060c0878903121561448d578384fd5b865161449881615505565b80965050602087015194506040870151935060608701516144b881615505565b60808801519093506144c981615505565b60a08801519092506001600160401b038111156144e4578182fd5b8701601f810189136144f4578182fd5b80516145026142f482615418565b8181528a6020838501011115614516578384fd5b6145278260208301602086016154ad565b8093505050509295509295509295565b6000806000806080858703121561454c578182fd5b845161455781615505565b60208601516040870151606088015192965090945092506001600160401b03811115614581578182fd5b61458d878288016142d4565b91505092959194509250565b600080600080600060a086880312156145b0578283fd5b85516145bb81615505565b60208701516040880151606089015160808a0151939850919650945092506001600160401b038111156145ec578182fd5b6145f8888289016142d4565b9150509295509295909350565b60008060008060008060c0878903121561461d578384fd5b865161462881615505565b6020880151604089015160608a015160808b0151939950919750955093506001600160401b038082111561465a578384fd5b6146668a838b016142d4565b935060a089015191508082111561467b578283fd5b5061468889828a0161434c565b9150509295509295509295565b600080604083850312156146a7578182fd5b82356146b281615505565b915060208301356146c281615505565b809150509250929050565b600080600080600080600080600060e08a8c0312156146ea578283fd5b89356146f581615505565b985060208a013561470581615505565b975060408a013561471581615505565b965060608a013561472581615505565b955060808a0135945060a08a01356001600160401b0380821115614747578485fd5b6147538d838e0161428b565b909650945060c08c013591508082111561476b578384fd5b506147788c828d0161428b565b915080935050809150509295985092959850929598565b60008060008060008060a087890312156147a7578384fd5b86356147b281615505565b955060208701356147c281615505565b9450604087013593506060870135925060808701356001600160401b038111156147ea578283fd5b6147f689828a0161428b565b979a9699509497509295939492505050565b600080600080600080600060c0888a031215614822578081fd5b873561482d81615505565b9650602088013561483d81615505565b955060408801359450606088013593506080880135925060a08801356001600160401b0381111561486c578182fd5b6148788a828b0161428b565b989b979a50959850939692959293505050565b60008060006040848603121561489f578081fd5b83356148aa81615505565b925060208401356001600160401b038111156148c4578182fd5b6148d08682870161428b565b9497909650939450505050565b6000806000806000606086880312156148f4578283fd5b85356148ff81615505565b945060208601356001600160401b038082111561491a578485fd5b61492689838a0161428b565b9096509450604088013591508082111561493e578283fd5b5061494b8882890161428b565b969995985093965092949392505050565b6000806040838503121561496e578182fd5b823561497981615505565b915060208301356146c28161551a565b600080600080600080600060c0888a0312156149a3578081fd5b87356149ae81615505565b9650602088013595506040880135945060608801356149cc81615505565b935060808801356149dc81615505565b925060a08801356001600160401b03808211156149f7578283fd5b818a0191508a601f830112614a0a578283fd5b813581811115614a18578384fd5b8b6020828501011115614a29578384fd5b60208301945080935050505092959891949750929550565b600080600080600060808688031215614a58578283fd5b8535614a6381615505565b9450602086013593506040860135925060608601356001600160401b03811115614a8b578182fd5b61494b8882890161428b565b60008060008060008060008060c0898b031215614ab2578182fd5b8835614abd81615505565b975060208901359650604089013595506060890135945060808901356001600160401b0380821115614aed578384fd5b614af98c838d0161428b565b909650945060a08b0135915080821115614b11578384fd5b50614b1e8b828c0161428b565b999c989b5096995094979396929594505050565b60008060008060408587031215614b47578182fd5b84356001600160401b0380821115614b5d578384fd5b614b698883890161428b565b90965094506020870135915080821115614b81578384fd5b50614b8e8782880161428b565b95989497509550505050565b60006020808385031215614bac578182fd5b82516001600160401b03811115614bc1578283fd5b8301601f81018513614bd1578283fd5b8051614bdf6142f4826153f5565b80828252848201915084840188868560051b8701011115614bfe578687fd5b8694505b83851015614c20578051835260019490940193918501918501614c02565b50979650505050505050565b600060208284031215614c3d578081fd5b81356140f98161551a565b600060208284031215614c59578081fd5b81516140f98161551a565b600060208284031215614c75578081fd5b81356001600160401b03811115614c8a578182fd5b8201601f81018413614c9a578182fd5b8035614ca86142f482615418565b818152856020838501011115614cbc578384fd5b81602084016020830137908101602001929092525092915050565b600060208284031215614ce8578081fd5b5051919050565b600060208284031215614d00578081fd5b815160ff811681146140f9578182fd5b60008284526020808501945082825b85811015614d4d578135614d3281615505565b6001600160a01b031687529582019590820190600101614d1f565b509495945050505050565b6000815180845260208085019450808401835b83811015614d4d5781516001600160a01b031687529582019590820190600101614d6b565b60008284526020808501945084600585811b870185855b88811015614e0f578483038a528135601e19893603018112614dc7578788fd5b880180356001600160401b03811115614dde578889fd5b80861b36038a1315614dee578889fd5b614dfb85828a8501614d10565b9b88019b9450505090850190600101614da7565b509098975050505050505050565b60008151808452614e358160208601602086016154ad565b601f01601f19169290920160200192915050565b60008251614e5b8184602087016154ad565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038a8116825289811660208301528881166040830152871660608201526080810186905260e060a08201819052600090614ee19083018688614d10565b82810360c0840152614ef4818587614d90565b9c9b505050505050505050505050565b6001600160a01b0386168152606060208201819052600090614f299083018688614d10565b8281036040840152614f3c818587614d10565b98975050505050505050565b6001600160a01b03831681526040602082018190526000906140f690830184614e1d565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b038881168252602082018890526040820187905285811660608301528416608082015260c060a0820181905281018290526000828460e084013781830160e090810191909152601f909201601f191601019695505050505050565b600060018060a01b03871682528560208301528460408301526080606083015261421d608083018486614d10565b600060018060a01b038816825286602083015285604083015284606083015260a06080830152614f3c60a083018486614d10565b600060018060a01b038a16825288602083015287604083015286606083015260c060808301526150db60c083018688614d10565b82810360a08401526150ee818587614d90565b9b9a5050505050505050505050565b6000602082526140f96020830184614e1d565b6020808252818101527f7472616e736665722072656d61696e696e672074546f6b656e206661696c6564604082015260600190565b6020808252601890820152771d1c985b9cd9995c881d151bdad95b88104819985a5b195960421b604082015260600190565b602080825260159082015274756e737570706f727465642073686f72742043524f60581b604082015260600190565b6020808252600c908201526b73616d65206d61726b65747360a01b604082015260600190565b602080825260159082015274189bdc9c9bddd3db90995a185b198819985a5b1959605a1b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602a908201527f6f6e6c7920746563746f6e6963436f72652063616e20616363657373207468696040820152693990333ab731ba34b7b760b11b606082015260800190565b60208082526022908201527f6d73672e76616c7565206d75737420626520657175616c206c6f6e67416d6f756040820152611b9d60f21b606082015260800190565b6020808252601490820152731c995919595b481d151bdad95b8819985a5b195960621b604082015260600190565b600084825260406020830152615304604083018486614d10565b95945050505050565b6000858252608060208301526153266080830186614d58565b6001600160a01b03949094166040830152506060015292915050565b600086825285602083015260a0604083015261536160a0830186614d58565b6001600160a01b0394909416606083015250608001529392505050565b6000808335601e19843603018112615394578283fd5b8301803591506001600160401b038211156153ad578283fd5b6020019150600581901b36038213156142cd57600080fd5b604051601f8201601f191681016001600160401b03811182821017156153ed576153ed6154ef565b604052919050565b60006001600160401b0382111561540e5761540e6154ef565b5060051b60200190565b60006001600160401b03821115615431576154316154ef565b50601f01601f191660200190565b60008219821115615452576154526154d9565b500190565b60008261547257634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615491576154916154d9565b500290565b6000828210156154a8576154a86154d9565b500390565b60005b838110156154c85781810151838201526020016154b0565b838111156135625750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114612c1657600080fd5b8015158114612c1657600080fdfe255bc41afe8d8409fb085d5e9c36bf9917671efdb2f3d452e9d65271da35480da2646970667358221220835c404ee10eb99e583b7af1a58bb3e4ab872098a0f31bdfa83f89715948b8ab64736f6c63430008030033

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

0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae23000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae000000000000000000000000db37a3132eb2df17fd17135ed780ed2d0385cdb6

-----Decoded View---------------
Arg [0] : _WETH (address): 0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23
Arg [1] : _vvs (address): 0x145863Eb42Cf62847A6Ca784e6416C1682b1b2Ae
Arg [2] : _wowmaxRouter (address): 0xDb37A3132eB2Df17Fd17135Ed780ED2d0385Cdb6

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000005c7f8a570d578ed84e63fdfa7b1ee72deae1ae23
Arg [1] : 000000000000000000000000145863eb42cf62847a6ca784e6416c1682b1b2ae
Arg [2] : 000000000000000000000000db37a3132eb2df17fd17135ed780ed2d0385cdb6


Block Transaction Gas Used Reward
view all blocks validated

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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