ETH Price: $3,191.89 (+1.45%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Remove Market Li...216976242025-01-24 23:23:355 days ago1737761015IN
Pendle: Router
0 ETH0.003540336.90424866
Remove Market Li...214656462024-12-23 14:01:2337 days ago1734962483IN
Pendle: Router
0 ETH0.0092735115.69642463
Remove Market Li...214656282024-12-23 13:57:4737 days ago1734962267IN
Pendle: Router
0 ETH0.002102078.84218166
Redeem After Exp...214607232024-12-22 21:28:4738 days ago1734902927IN
Pendle: Router
0 ETH0.000924026.53736637
Remove Market Li...214607002024-12-22 21:24:1138 days ago1734902651IN
Pendle: Router
0 ETH0.003881156.80047813
Redeem After Exp...205702302024-08-20 13:48:11162 days ago1724161691IN
Pendle: Router
0 ETH0.000704832.50481699
Swap Exact In202852272024-07-11 19:02:11202 days ago1720724531IN
Pendle: Router
0 ETH0.000308285.64781254
Redeem After Exp...202842152024-07-11 15:38:59202 days ago1720712339IN
Pendle: Router
0 ETH0.002233918.48833581
Remove Market Li...202513232024-07-07 1:21:59207 days ago1720315319IN
Pendle: Router
0 ETH0.0008751.35407781
Redeem After Exp...202513042024-07-07 1:18:11207 days ago1720315091IN
Pendle: Router
0 ETH0.000194561.1968263
Remove Market Li...202169082024-07-02 6:01:35212 days ago1719900095IN
Pendle: Router
0 ETH0.001310712.88533719
Remove Market Li...201338132024-06-20 15:23:59223 days ago1718897039IN
Pendle: Router
0 ETH0.0057901910.08058295
Redeem After Exp...201338012024-06-20 15:21:35223 days ago1718896895IN
Pendle: Router
0 ETH0.0016134711.09141254
Redeem After Exp...199278052024-05-22 20:28:23252 days ago1716409703IN
Pendle: Router
0 ETH0.0057182914.67014861
Remove Market Li...198010572024-05-05 2:56:59270 days ago1714877819IN
Pendle: Router
0 ETH0.0022484.14636635
Remove Market Li...197449082024-04-27 6:32:35278 days ago1714199555IN
Pendle: Router
0 ETH0.002650015.34323644
Redeem After Exp...196008352024-04-07 2:26:35298 days ago1712456795IN
Pendle: Router
0 ETH0.0038654210.29706149
Redeem After Exp...195560462024-03-31 19:49:35304 days ago1711914575IN
Pendle: Router
0 ETH0.0036577520.51071256
Redeem After Exp...194880552024-03-22 5:22:23314 days ago1711084943IN
Pendle: Router
0 ETH0.0038961821.84767876
Redeem After Exp...192861182024-02-22 22:26:47342 days ago1708640807IN
Pendle: Router
0 ETH0.0101197161.92460575
Remove Market Li...192821882024-02-22 9:12:23342 days ago1708593143IN
Pendle: Router
0 ETH0.0165868829.85014404
Remove Market Li...192625872024-02-19 15:11:47345 days ago1708355507IN
Pendle: Router
0 ETH0.0255404646.86315077
Redeem After Exp...192625542024-02-19 15:05:11345 days ago1708355111IN
Pendle: Router
0 ETH0.0161316949.89342899
Remove Market Li...192474202024-02-17 11:56:11347 days ago1708170971IN
Pendle: Router
0 ETH0.008918816.03498688
Remove Market Li...192105302024-02-12 7:42:59352 days ago1707723779IN
Pendle: Router
0 ETH0.0117688823.01427836
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PendleRouter

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 23 : PendleRouter.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../libraries/MathLib.sol";
import "../interfaces/IPendleRouter.sol";
import "../interfaces/IPendleData.sol";
import "../interfaces/IPendleForge.sol";
import "../interfaces/IPendleMarketFactory.sol";
import "../interfaces/IPendleMarket.sol";
import "../periphery/PermissionsV2.sol";
import "../periphery/WithdrawableV2.sol";
import "../periphery/PendleRouterNonReentrant.sol";

/**
@dev OVERALL NOTE:
* The router will not hold any funds, instead it will just help sending funds to other contracts & users
* addLiquidity/removeLiquidity/swap all supports auto wrap of ETH
    - There will be no markets of XYT-ETH, only markets of XYT-WETH
    - If users want to send in / receive ETH, just pass the ETH_ADDRESS to the corresponding field,
    the router will automatically wrap/unwrap WETH and interact with markets
    - principle of ETH wrap implementation: always use the token with the "original" prefix for transfer,
    and use the non-original token (_xyt, _token...) in all other cases
* Markets will not transfer any XYT/baseToken, but instead make requests to Router through the transfer array
    and the Router will transfer them
*/
contract PendleRouter is IPendleRouter, WithdrawableV2, PendleRouterNonReentrant {
    using SafeERC20 for IERC20;
    using SafeMath for uint256;
    using Math for uint256;

    IWETH public immutable override weth;
    IPendleData public immutable override data;
    address private constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
    // if someone's allowance for the router is below this amount,
    // we will approve the router again (to spend from their account)
    // if we already call .approveRouter for the a token, we shouldn't need to approve again
    uint256 private constant REASONABLE_ALLOWANCE_AMOUNT = type(uint256).max / 2;

    constructor(
        address _governanceManager,
        IWETH _weth,
        IPendleData _data
    ) PermissionsV2(_governanceManager) PendleRouterNonReentrant() {
        weth = _weth;
        data = _data;
    }

    /**
     * @dev Accepts ETH via fallback from the WETH contract.
     **/
    receive() external payable {
        require(msg.sender == address(weth), "ETH_NOT_FROM_WETH");
    }

    /**
     * @notice Create a new pair of OT + XYT tokens to represent the
     *   principal and interest for an underlying asset, until an expiry
     Conditions:
     * _expiry must be divisible for expiryDivisor() so that there are not too many yieldContracts
     * Any _underlyingAsset can be passed in, since there is no way to validate them
     * Have Reentrancy protection
     **/
    function newYieldContracts(
        bytes32 _forgeId,
        address _underlyingAsset,
        uint256 _expiry
    ) external override nonReentrant returns (address ot, address xyt) {
        require(_underlyingAsset != address(0), "ZERO_ADDRESS");
        require(_expiry > block.timestamp, "INVALID_EXPIRY");
        require(_expiry % data.expiryDivisor() == 0, "INVALID_EXPIRY");
        IPendleForge forge = IPendleForge(data.getForgeAddress(_forgeId));
        require(address(forge) != address(0), "FORGE_NOT_EXISTS");

        ot = address(data.otTokens(_forgeId, _underlyingAsset, _expiry));
        xyt = address(data.xytTokens(_forgeId, _underlyingAsset, _expiry));
        require(ot == address(0) && xyt == address(0), "DUPLICATE_YIELD_CONTRACT");

        (ot, xyt) = forge.newYieldContracts(_underlyingAsset, _expiry);
    }

    /**
     * @notice After an expiry, redeem OT tokens to get back the underlyingYieldToken
     *         and also any interests
     * @notice This function acts as a proxy to the actual function
     * @dev The interest from "the last global action before expiry" until the expiry
     *      is given to the OT holders. This is to simplify accounting. An assumption
     *      is that the last global action before expiry will be close to the expiry
     * @dev all validity checks are in the internal function
    Conditions:
     * Have Reentrancy protection
     **/
    function redeemAfterExpiry(
        bytes32 _forgeId,
        address _underlyingAsset,
        uint256 _expiry
    ) public override nonReentrant returns (uint256 redeemedAmount) {
        require(data.isValidXYT(_forgeId, _underlyingAsset, _expiry), "INVALID_YT");
        require(_expiry < block.timestamp, "MUST_BE_AFTER_EXPIRY");

        // guaranteed to be a valid forge by the isValidXYT check
        IPendleForge forge = IPendleForge(data.getForgeAddress(_forgeId));

        redeemedAmount = forge.redeemAfterExpiry(msg.sender, _underlyingAsset, _expiry);
    }

    /**
     * @notice redeem the dueInterests from XYTs
     * @dev all validity checks are in the internal function
     Conditions:
     * Have Reentrancy protection
     **/
    function redeemDueInterests(
        bytes32 _forgeId,
        address _underlyingAsset,
        uint256 _expiry,
        address _user
    ) external override nonReentrant returns (uint256 interests) {
        require(data.isValidXYT(_forgeId, _underlyingAsset, _expiry), "INVALID_YT");
        require(_user != address(0), "ZERO_ADDRESS");
        IPendleForge forge = IPendleForge(data.getForgeAddress(_forgeId));
        interests = forge.redeemDueInterests(_user, _underlyingAsset, _expiry);
    }

    /**
     * @notice Before the expiry, a user can redeem the same amount of OT+XYT to get back
     *       the underlying yield token
     Conditions:
     * Have Reentrancy protection
     **/
    function redeemUnderlying(
        bytes32 _forgeId,
        address _underlyingAsset,
        uint256 _expiry,
        uint256 _amountToRedeem
    ) external override nonReentrant returns (uint256 redeemedAmount) {
        require(data.isValidXYT(_forgeId, _underlyingAsset, _expiry), "INVALID_YT");
        require(block.timestamp < _expiry, "YIELD_CONTRACT_EXPIRED");
        require(_amountToRedeem != 0, "ZERO_AMOUNT");

        // guaranteed to be a valid forge by the isValidXYT check
        IPendleForge forge = IPendleForge(data.getForgeAddress(_forgeId));

        redeemedAmount = forge.redeemUnderlying(
            msg.sender,
            _underlyingAsset,
            _expiry,
            _amountToRedeem
        );
    }

    /**
     * @notice Use to renewYield. Basically a proxy to call redeemAfterExpiry & tokenizeYield
     * @param _renewalRate a Fixed Point number, shows how much of the total redeemedAmount is renewed.
        We allowed _renewalRate > RONE in case the user wants to increase his position
     Conditions:
     * No Reentrancy protection because it will just act as a proxy for 2 calls
     **/
    function renewYield(
        bytes32 _forgeId,
        uint256 _oldExpiry,
        address _underlyingAsset,
        uint256 _newExpiry,
        uint256 _renewalRate
    )
        external
        override
        returns (
            uint256 redeemedAmount,
            uint256 amountRenewed,
            address ot,
            address xyt,
            uint256 amountTokenMinted
        )
    {
        require(0 < _renewalRate, "INVALID_RENEWAL_RATE");
        redeemedAmount = redeemAfterExpiry(_forgeId, _underlyingAsset, _oldExpiry);
        amountRenewed = redeemedAmount.rmul(_renewalRate);
        (ot, xyt, amountTokenMinted) = tokenizeYield(
            _forgeId,
            _underlyingAsset,
            _newExpiry,
            amountRenewed,
            msg.sender
        );
    }

    /**
     * @notice tokenize yield tokens to get OT+XYT. We allows tokenizing for others too
     * @dev each forge is for a yield protocol (for example: Aave, Compound)
    Conditions:
     * Have Reentrancy protection
     * Can only tokenize to a not-yet-expired XYT
     **/
    function tokenizeYield(
        bytes32 _forgeId,
        address _underlyingAsset,
        uint256 _expiry,
        uint256 _amountToTokenize,
        address _to
    )
        public
        override
        nonReentrant
        returns (
            address ot,
            address xyt,
            uint256 amountTokenMinted
        )
    {
        require(data.isValidXYT(_forgeId, _underlyingAsset, _expiry), "INVALID_YT");
        require(block.timestamp < _expiry, "YIELD_CONTRACT_EXPIRED");
        require(_to != address(0), "ZERO_ADDRESS");
        require(_amountToTokenize != 0, "ZERO_AMOUNT");

        // guaranteed to be a valid forge by the isValidXYT check
        IPendleForge forge = IPendleForge(data.getForgeAddress(_forgeId));

        // In this getYieldBearingToken call, the forge will check if there is
        // any yieldToken that matches the underlyingAsset. For more details please
        // check the getYieldBearingToken in forge
        IERC20 yieldToken = IERC20(forge.getYieldBearingToken(_underlyingAsset));

        // pull tokens in
        yieldToken.safeTransferFrom(
            msg.sender,
            forge.yieldTokenHolders(_underlyingAsset, _expiry),
            _amountToTokenize
        );

        // mint OT&XYT for users
        (ot, xyt, amountTokenMinted) = forge.mintOtAndXyt(
            _underlyingAsset,
            _expiry,
            _amountToTokenize,
            _to
        );
    }

    /**
     * @notice add market liquidity by both xyt and baseToken
     Conditions:
     * Have Reentrancy protection
     */
    function addMarketLiquidityDual(
        bytes32 _marketFactoryId,
        address _xyt,
        address _token,
        uint256 _desiredXytAmount,
        uint256 _desiredTokenAmount,
        uint256 _xytMinAmount,
        uint256 _tokenMinAmount
    )
        public
        payable
        override
        nonReentrant
        returns (
            uint256 amountXytUsed,
            uint256 amountTokenUsed,
            uint256 lpOut
        )
    {
        require(
            _desiredXytAmount != 0 && _desiredXytAmount >= _xytMinAmount,
            "INVALID_YT_AMOUNTS"
        );
        require(
            _desiredTokenAmount != 0 && _desiredTokenAmount >= _tokenMinAmount,
            "INVALID_TOKEN_AMOUNTS"
        );

        address originalToken = _token;
        _token = _isETH(_token) ? address(weth) : _token;

        IPendleMarket market = IPendleMarket(data.getMarket(_marketFactoryId, _xyt, _token));
        require(address(market) != address(0), "MARKET_NOT_FOUND");

        // note that LP minting will be done in the market
        PendingTransfer[2] memory transfers;
        (transfers, lpOut) = market.addMarketLiquidityDual(
            msg.sender,
            _desiredXytAmount,
            _desiredTokenAmount,
            _xytMinAmount,
            _tokenMinAmount
        );
        _settlePendingTransfers(transfers, _xyt, originalToken, address(market));

        amountXytUsed = transfers[0].amount;
        amountTokenUsed = transfers[1].amount;
        emit Join(msg.sender, amountXytUsed, amountTokenUsed, address(market), lpOut);
    }

    /**
     * @notice add market liquidity by xyt or base token
     * @dev no checks on _minOutLp
     * @param _forXyt whether the user wants to addLiquidity by _xyt or _token
     Conditions:
     * Have Reentrancy protection
     */
    function addMarketLiquiditySingle(
        bytes32 _marketFactoryId,
        address _xyt,
        address _token,
        bool _forXyt,
        uint256 _exactIn,
        uint256 _minOutLp
    ) external payable override nonReentrant returns (uint256 exactOutLp) {
        require(_exactIn != 0, "ZERO_AMOUNTS");

        address originalToken = _token;
        _token = _isETH(_token) ? address(weth) : _token;

        IPendleMarket market = IPendleMarket(data.getMarket(_marketFactoryId, _xyt, _token));
        require(address(market) != address(0), "MARKET_NOT_FOUND");

        address assetToTransferIn = _forXyt ? _xyt : originalToken;
        address assetForMarket = _forXyt ? _xyt : _token;

        // note that LP minting will be done in the market
        PendingTransfer[2] memory transfers;
        (transfers, exactOutLp) = market.addMarketLiquiditySingle(
            msg.sender,
            assetForMarket,
            _exactIn,
            _minOutLp
        );

        if (_forXyt) {
            emit Join(msg.sender, _exactIn, 0, address(market), exactOutLp);
        } else {
            emit Join(msg.sender, 0, _exactIn, address(market), exactOutLp);
        }
        // We only need settle the transfering in of the assetToTransferIn
        _settleTokenTransfer(assetToTransferIn, transfers[0], address(market));
    }

    /**
     * @notice remove market liquidity by xyt and base tokens
     * @dev no checks on _minOutXyt, _minOutToken
     Conditions:
     * Have Reentrancy protection
     */
    function removeMarketLiquidityDual(
        bytes32 _marketFactoryId,
        address _xyt,
        address _token,
        uint256 _exactInLp,
        uint256 _minOutXyt,
        uint256 _minOutToken
    ) external override nonReentrant returns (uint256 exactOutXyt, uint256 exactOutToken) {
        require(_exactInLp != 0, "ZERO_LP_IN");

        address originalToken = _token;
        _token = _isETH(_token) ? address(weth) : _token;

        IPendleMarket market = IPendleMarket(data.getMarket(_marketFactoryId, _xyt, _token));
        require(address(market) != address(0), "MARKET_NOT_FOUND");

        // note that LP burning will be done in the market
        PendingTransfer[2] memory transfers =
            market.removeMarketLiquidityDual(msg.sender, _exactInLp, _minOutXyt, _minOutToken);

        _settlePendingTransfers(transfers, _xyt, originalToken, address(market));
        exactOutXyt = transfers[0].amount;
        exactOutToken = transfers[1].amount;
        emit Exit(msg.sender, exactOutXyt, exactOutToken, address(market), _exactInLp);
    }

    /**
     * @notice remove market liquidity by xyt or base tokens
     * @dev no checks on  _minOutAsset
     * @param _forXyt whether the user wants to addLiquidity by _xyt or _token
     Conditions:
     * Have Reentrancy protection
     */
    function removeMarketLiquiditySingle(
        bytes32 _marketFactoryId,
        address _xyt,
        address _token,
        bool _forXyt,
        uint256 _exactInLp,
        uint256 _minOutAsset
    ) external override nonReentrant returns (uint256 exactOutXyt, uint256 exactOutToken) {
        require(_exactInLp != 0, "ZERO_LP_IN");

        address originalToken = _token;
        _token = _isETH(_token) ? address(weth) : _token;

        IPendleMarket market = IPendleMarket(data.getMarket(_marketFactoryId, _xyt, _token));
        require(address(market) != address(0), "MARKET_NOT_FOUND");

        address assetForMarket = _forXyt ? _xyt : _token;

        // note that LP burning will be done in the market
        PendingTransfer[2] memory transfers =
            market.removeMarketLiquiditySingle(
                msg.sender,
                assetForMarket,
                _exactInLp,
                _minOutAsset
            );

        address assetToTransferOut = _forXyt ? _xyt : originalToken;
        _settleTokenTransfer(assetToTransferOut, transfers[0], address(market));

        if (_forXyt) {
            emit Exit(msg.sender, transfers[0].amount, 0, address(market), _exactInLp);
            return (transfers[0].amount, 0);
        } else {
            emit Exit(msg.sender, 0, transfers[0].amount, address(market), _exactInLp);
            return (0, transfers[0].amount);
        }
    }

    /**
     * @notice create a new market for a pair of xyt & token
     * @dev A market can be uniquely identified by the triplet(_marketFactoryId,_xyt,_token)
     Conditions:
     * Have Reentrancy protection
     */
    function createMarket(
        bytes32 _marketFactoryId,
        address _xyt,
        address _token
    ) external override nonReentrant returns (address market) {
        require(_xyt != address(0), "ZERO_ADDRESS");
        require(_token != address(0), "ZERO_ADDRESS");
        require(data.isXyt(_xyt), "INVALID_YT");
        require(!data.isXyt(_token), "YT_QUOTE_PAIR_FORBIDDEN");
        require(data.getMarket(_marketFactoryId, _xyt, _token) == address(0), "EXISTED_MARKET");

        IPendleMarketFactory factory =
            IPendleMarketFactory(data.getMarketFactoryAddress(_marketFactoryId));
        require(address(factory) != address(0), "ZERO_ADDRESS");

        bytes32 forgeId = IPendleForge(IPendleYieldToken(_xyt).forge()).forgeId();
        require(data.validForgeFactoryPair(forgeId, _marketFactoryId), "INVALID_FORGE_FACTORY");

        market = factory.createMarket(_xyt, _token);

        emit MarketCreated(_marketFactoryId, _xyt, _token, market);
    }

    /**
     * @notice bootstrap a market (aka the first one to add liquidity)
     Conditions:
     * Have Reentrancy protection
     */
    function bootstrapMarket(
        bytes32 _marketFactoryId,
        address _xyt,
        address _token,
        uint256 _initialXytLiquidity,
        uint256 _initialTokenLiquidity
    ) external payable override nonReentrant {
        require(_initialXytLiquidity > 0, "INVALID_YT_AMOUNT");
        require(_initialTokenLiquidity > 0, "INVALID_TOKEN_AMOUNT");

        address originalToken = _token;
        _token = _isETH(_token) ? address(weth) : _token;

        IPendleMarket market = IPendleMarket(data.getMarket(_marketFactoryId, _xyt, _token));
        require(address(market) != address(0), "MARKET_NOT_FOUND");

        PendingTransfer[2] memory transfers;
        uint256 exactOutLp;
        (transfers, exactOutLp) = market.bootstrap(
            msg.sender,
            _initialXytLiquidity,
            _initialTokenLiquidity
        );

        _settlePendingTransfers(transfers, _xyt, originalToken, address(market));
        emit Join(
            msg.sender,
            _initialXytLiquidity,
            _initialTokenLiquidity,
            address(market),
            exactOutLp
        );
    }

    /**
     * @notice trade by swap exact amount of token into market
     * @dev no checks on _minOutAmount
     Conditions:
     * Have Reentrancy protection
     */
    function swapExactIn(
        address _tokenIn,
        address _tokenOut,
        uint256 _inAmount,
        uint256 _minOutAmount,
        bytes32 _marketFactoryId
    ) external payable override nonReentrant returns (uint256 outSwapAmount) {
        require(_inAmount != 0, "ZERO_IN_AMOUNT");

        address originalTokenIn = _tokenIn;
        address originalTokenOut = _tokenOut;
        _tokenIn = _isETH(_tokenIn) ? address(weth) : _tokenIn;
        _tokenOut = _isETH(_tokenOut) ? address(weth) : _tokenOut;

        IPendleMarket market =
            IPendleMarket(data.getMarketFromKey(_tokenIn, _tokenOut, _marketFactoryId));
        require(address(market) != address(0), "MARKET_NOT_FOUND");

        PendingTransfer[2] memory transfers;
        (outSwapAmount, transfers) = market.swapExactIn(
            _tokenIn,
            _inAmount,
            _tokenOut,
            _minOutAmount
        );

        _settlePendingTransfers(transfers, originalTokenIn, originalTokenOut, address(market));

        emit SwapEvent(msg.sender, _tokenIn, _tokenOut, _inAmount, outSwapAmount, address(market));
    }

    /**
     * @notice trade by swap exact amount of token out of market
     * @dev no checks on _maxInAmount
     Conditions:
     * Have Reentrancy protection
     */
    function swapExactOut(
        address _tokenIn,
        address _tokenOut,
        uint256 _outAmount,
        uint256 _maxInAmount,
        bytes32 _marketFactoryId
    ) external payable override nonReentrant returns (uint256 inSwapAmount) {
        require(_outAmount != 0, "ZERO_OUT_AMOUNT");

        address originalTokenIn = _tokenIn;
        address originalTokenOut = _tokenOut;
        _tokenIn = _isETH(_tokenIn) ? address(weth) : _tokenIn;
        _tokenOut = _isETH(_tokenOut) ? address(weth) : _tokenOut;

        IPendleMarket market =
            IPendleMarket(data.getMarketFromKey(_tokenIn, _tokenOut, _marketFactoryId));
        require(address(market) != address(0), "MARKET_NOT_FOUND");

        PendingTransfer[2] memory transfers;
        (inSwapAmount, transfers) = market.swapExactOut(
            _tokenIn,
            _maxInAmount,
            _tokenOut,
            _outAmount
        );

        _settlePendingTransfers(transfers, originalTokenIn, originalTokenOut, address(market));

        emit SwapEvent(msg.sender, _tokenIn, _tokenOut, inSwapAmount, _outAmount, address(market));
    }

    /**
     * @notice For Lp holders to claim Lp interests
    Conditions:
     * Have Reentrancy protection
     */
    function redeemLpInterests(address market, address user)
        external
        override
        nonReentrant
        returns (uint256 interests)
    {
        require(data.isMarket(market), "INVALID_MARKET");
        require(user != address(0), "ZERO_ADDRESS");
        interests = IPendleMarket(market).redeemLpInterests(user);
    }

    function _getData() internal view override returns (IPendleData) {
        return data;
    }

    function _isETH(address token) internal pure returns (bool) {
        return (token == ETH_ADDRESS);
    }

    /**
     * @notice This function takes in the standard array PendingTransfer[2] that represents
     *        any pending transfers of tokens to be done between a market and msg.sender
     * @dev transfers[0] and transfers[1] always represent the tokens that are traded
     *    The convention is that:
     *      - if its a function with xyt and baseToken, transfers[0] is always xyt
     *      - if its a function with tokenIn and tokenOut, transfers[0] is always tokenOut
     */
    function _settlePendingTransfers(
        PendingTransfer[2] memory transfers,
        address firstToken,
        address secondToken,
        address market
    ) internal {
        _settleTokenTransfer(firstToken, transfers[0], market);
        _settleTokenTransfer(secondToken, transfers[1], market);
    }

    /**
     * @notice This function settles a PendingTransfer, where the token could be ETH_ADDRESS
     *        a PendingTransfer is always between a market and msg.sender
     */
    function _settleTokenTransfer(
        address token,
        PendingTransfer memory transfer,
        address market
    ) internal {
        if (transfer.amount == 0) {
            return;
        }
        if (transfer.isOut) {
            if (_isETH(token)) {
                weth.transferFrom(market, address(this), transfer.amount);
                weth.withdraw(transfer.amount);
                (bool success, ) = msg.sender.call{value: transfer.amount}("");
                require(success, "TRANSFER_FAILED");
            } else {
                IERC20(token).safeTransferFrom(market, msg.sender, transfer.amount);
            }
        } else {
            if (_isETH(token)) {
                require(msg.value >= transfer.amount, "INSUFFICENT_ETH_AMOUNT");
                // we only need transfer.amount, so we return the excess
                uint256 excess = msg.value.sub(transfer.amount);
                if (excess != 0) {
                    (bool success, ) = msg.sender.call{value: excess}("");
                    require(success, "TRANSFER_FAILED");
                }

                weth.deposit{value: transfer.amount}();
                weth.transfer(market, transfer.amount);
            } else {
                // its a transfer in of token. If its an XYT
                // we will auto approve the router to spend from the user account;
                if (data.isXyt(token)) {
                    _checkApproveRouter(token);
                }
                IERC20(token).safeTransferFrom(msg.sender, market, transfer.amount);
            }
        }
    }

    // Check if an user has approved the router to spend the amount
    // if not, approve the router to spend the token from the user account
    function _checkApproveRouter(address token) internal {
        uint256 allowance = IPendleBaseToken(token).allowance(msg.sender, address(this));
        if (allowance >= REASONABLE_ALLOWANCE_AMOUNT) return;
        IPendleYieldToken(token).approveRouter(msg.sender);
    }

    // There shouldn't be any fund in here
    // hence governance is allowed to withdraw anything from here.
    function _allowedToWithdraw(address) internal pure override returns (bool allowed) {
        allowed = true;
    }
}

File 2 of 23 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "../../math/SafeMath.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 SafeMath for uint256;
    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'
        // solhint-disable-next-line max-line-length
        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).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _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
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 3 of 23 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

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

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

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

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

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

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

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

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

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

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

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

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

File 4 of 23 : MathLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.0;
pragma abicoder v2;

import "@openzeppelin/contracts/math/SafeMath.sol";

library Math {
    using SafeMath for uint256;

    uint256 internal constant BIG_NUMBER = (uint256(1) << uint256(200));
    uint256 internal constant PRECISION_BITS = 40;
    uint256 internal constant RONE = uint256(1) << PRECISION_BITS;
    uint256 internal constant PI = (314 * RONE) / 10**2;
    uint256 internal constant PI_PLUSONE = (414 * RONE) / 10**2;
    uint256 internal constant PRECISION_POW = 1e2;

    function checkMultOverflow(uint256 _x, uint256 _y) internal pure returns (bool) {
        if (_y == 0) return false;
        return (((_x * _y) / _y) != _x);
    }

    /**
    @notice find the integer part of log2(p/q)
        => find largest x s.t p >= q * 2^x
        => find largest x s.t 2^x <= p / q
     */
    function log2Int(uint256 _p, uint256 _q) internal pure returns (uint256) {
        uint256 res = 0;
        uint256 remain = _p / _q;
        while (remain > 0) {
            res++;
            remain /= 2;
        }
        return res - 1;
    }

    /**
    @notice log2 for a number that it in [1,2)
    @dev _x is FP, return a FP
    @dev function is from Kyber. Long modified the condition to be (_x >= one) && (_x < two)
    to avoid the case where x = 2 may lead to incorrect result
     */
    function log2ForSmallNumber(uint256 _x) internal pure returns (uint256) {
        uint256 res = 0;
        uint256 one = (uint256(1) << PRECISION_BITS);
        uint256 two = 2 * one;
        uint256 addition = one;

        require((_x >= one) && (_x < two), "MATH_ERROR");
        require(PRECISION_BITS < 125, "MATH_ERROR");

        for (uint256 i = PRECISION_BITS; i > 0; i--) {
            _x = (_x * _x) / one;
            addition = addition / 2;
            if (_x >= two) {
                _x = _x / 2;
                res += addition;
            }
        }

        return res;
    }

    /**
    @notice log2 of (p/q). returns result in FP form
    @dev function is from Kyber.
    @dev _p & _q is FP, return a FP
     */
    function logBase2(uint256 _p, uint256 _q) internal pure returns (uint256) {
        uint256 n = 0;

        if (_p > _q) {
            n = log2Int(_p, _q);
        }

        require(n * RONE <= BIG_NUMBER, "MATH_ERROR");
        require(!checkMultOverflow(_p, RONE), "MATH_ERROR");
        require(!checkMultOverflow(n, RONE), "MATH_ERROR");
        require(!checkMultOverflow(uint256(1) << n, _q), "MATH_ERROR");

        uint256 y = (_p * RONE) / (_q * (uint256(1) << n));
        uint256 log2Small = log2ForSmallNumber(y);

        assert(log2Small <= BIG_NUMBER);

        return n * RONE + log2Small;
    }

    /**
    @notice calculate ln(p/q). returned result >= 0
    @dev function is from Kyber.
    @dev _p & _q is FP, return a FP
    */
    function ln(uint256 p, uint256 q) internal pure returns (uint256) {
        uint256 ln2Numerator = 6931471805599453094172;
        uint256 ln2Denomerator = 10000000000000000000000;

        uint256 log2x = logBase2(p, q);

        require(!checkMultOverflow(ln2Numerator, log2x), "MATH_ERROR");

        return (ln2Numerator * log2x) / ln2Denomerator;
    }

    /**
    @notice extract the fractional part of a FP
    @dev value is a FP, return a FP
     */
    function fpart(uint256 value) internal pure returns (uint256) {
        return value % RONE;
    }

    /**
    @notice convert a FP to an Int
    @dev value is a FP, return an Int
     */
    function toInt(uint256 value) internal pure returns (uint256) {
        return value / RONE;
    }

    /**
    @notice convert an Int to a FP
    @dev value is an Int, return a FP
     */
    function toFP(uint256 value) internal pure returns (uint256) {
        return value * RONE;
    }

    /**
    @notice return e^exp in FP form
    @dev estimation by formula at http://pages.mtu.edu/~shene/COURSES/cs201/NOTES/chap04/exp.html
        the function is based on exp function of:
        https://github.com/NovakDistributed/macroverse/blob/master/contracts/RealMath.sol
    @dev the function is expected to converge quite fast, after about 20 iteration
    @dev exp is a FP, return a FP
     */
    function rpowe(uint256 exp) internal pure returns (uint256) {
        uint256 res = 0;

        uint256 curTerm = RONE;

        for (uint256 n = 0; ; n++) {
            res += curTerm;
            curTerm = rmul(curTerm, rdiv(exp, toFP(n + 1)));
            if (curTerm == 0) {
                break;
            }
            if (n == 500) {
                /*
                testing shows that in the most extreme case, it will take 430 turns to converge.
                however, it's expected that the numbers will not exceed 2^120 in normal situation
                the most extreme case is rpow((1<<256)-1,(1<<40)-1) (equal to rpow((2^256-1)/2^40,0.99..9))
                */
                revert("RPOWE_SLOW_CONVERGE");
            }
        }

        return res;
    }

    /**
    @notice calculate base^exp with base and exp being FP int
    @dev to improve accuracy, base^exp = base^(int(exp)+frac(exp))
                                       = base^int(exp) * base^frac
    @dev base & exp are FP, return a FP
     */
    function rpow(uint256 base, uint256 exp) internal pure returns (uint256) {
        if (exp == 0) {
            // Anything to the 0 is 1
            return RONE;
        }
        if (base == 0) {
            // 0 to anything except 0 is 0
            return 0;
        }

        uint256 frac = fpart(exp); // get the fractional part
        uint256 whole = exp - frac;

        uint256 wholePow = rpowi(base, toInt(whole)); // whole is a FP, convert to Int
        uint256 fracPow;

        // instead of calculating base ^ frac, we will calculate e ^ (frac*ln(base))
        if (base < RONE) {
            /* since the base is smaller than 1.0, ln(base) < 0.
            Since 1 / (e^(frac*ln(1/base))) = e ^ (frac*ln(base)),
            we will calculate 1 / (e^(frac*ln(1/base))) instead.
            */
            uint256 newExp = rmul(frac, ln(rdiv(RONE, base), RONE));
            fracPow = rdiv(RONE, rpowe(newExp));
        } else {
            /* base is greater than 1, calculate normally */
            uint256 newExp = rmul(frac, ln(base, RONE));
            fracPow = rpowe(newExp);
        }
        return rmul(wholePow, fracPow);
    }

    /**
    @notice return base^exp with base in FP form and exp in Int
    @dev this function use a technique called: exponentiating by squaring
        complexity O(log(q))
    @dev function is from Kyber.
    @dev base is a FP, exp is an Int, return a FP
     */
    function rpowi(uint256 base, uint256 exp) internal pure returns (uint256) {
        uint256 res = exp % 2 != 0 ? base : RONE;

        for (exp /= 2; exp != 0; exp /= 2) {
            base = rmul(base, base);

            if (exp % 2 != 0) {
                res = rmul(res, base);
            }
        }
        return res;
    }

    /**
    @dev y is an Int, returns an Int
    @dev babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    @dev from Uniswap
     */
    function sqrt(uint256 y) internal pure returns (uint256 z) {
        if (y > 3) {
            z = y;
            uint256 x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }

    /**
    @notice divide 2 FP, return a FP
    @dev function is from Balancer.
    @dev x & y are FP, return a FP
     */
    function rdiv(uint256 x, uint256 y) internal pure returns (uint256) {
        return (y / 2).add(x.mul(RONE)).div(y);
    }

    /**
    @notice multiply 2 FP, return a FP
    @dev function is from Balancer.
    @dev x & y are FP, return a FP
     */
    function rmul(uint256 x, uint256 y) internal pure returns (uint256) {
        return (RONE / 2).add(x.mul(y)).div(RONE);
    }

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    function subMax0(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a - b : 0;
    }
}

File 5 of 23 : IPendleRouter.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;
pragma abicoder v2;

import "../interfaces/IWETH.sol";
import "./IPendleData.sol";
import "../libraries/PendleStructs.sol";
import "./IPendleMarketFactory.sol";

interface IPendleRouter {
    /**
     * @notice Emitted when a market for a future yield token and an ERC20 token is created.
     * @param marketFactoryId Forge identifier.
     * @param xyt The address of the tokenized future yield token as the base asset.
     * @param token The address of an ERC20 token as the quote asset.
     * @param market The address of the newly created market.
     **/
    event MarketCreated(
        bytes32 marketFactoryId,
        address indexed xyt,
        address indexed token,
        address indexed market
    );

    /**
     * @notice Emitted when a swap happens on the market.
     * @param trader The address of msg.sender.
     * @param inToken The input token.
     * @param outToken The output token.
     * @param exactIn The exact amount being traded.
     * @param exactOut The exact amount received.
     * @param market The market address.
     **/
    event SwapEvent(
        address indexed trader,
        address inToken,
        address outToken,
        uint256 exactIn,
        uint256 exactOut,
        address market
    );

    /**
     * @dev Emitted when user adds liquidity
     * @param sender The user who added liquidity.
     * @param token0Amount the amount of token0 (xyt) provided by user
     * @param token1Amount the amount of token1 provided by user
     * @param market The market address.
     * @param exactOutLp The exact LP minted
     */
    event Join(
        address indexed sender,
        uint256 token0Amount,
        uint256 token1Amount,
        address market,
        uint256 exactOutLp
    );

    /**
     * @dev Emitted when user removes liquidity
     * @param sender The user who removed liquidity.
     * @param token0Amount the amount of token0 (xyt) given to user
     * @param token1Amount the amount of token1 given to user
     * @param market The market address.
     * @param exactInLp The exact Lp to remove
     */
    event Exit(
        address indexed sender,
        uint256 token0Amount,
        uint256 token1Amount,
        address market,
        uint256 exactInLp
    );

    /**
     * @notice Gets a reference to the PendleData contract.
     * @return Returns the data contract reference.
     **/
    function data() external view returns (IPendleData);

    /**
     * @notice Gets a reference of the WETH9 token contract address.
     * @return WETH token reference.
     **/
    function weth() external view returns (IWETH);

    /***********
     *  FORGE  *
     ***********/

    function newYieldContracts(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry
    ) external returns (address ot, address xyt);

    function redeemAfterExpiry(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry
    ) external returns (uint256 redeemedAmount);

    function redeemDueInterests(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry,
        address user
    ) external returns (uint256 interests);

    function redeemUnderlying(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry,
        uint256 amountToRedeem
    ) external returns (uint256 redeemedAmount);

    function renewYield(
        bytes32 forgeId,
        uint256 oldExpiry,
        address underlyingAsset,
        uint256 newExpiry,
        uint256 renewalRate
    )
        external
        returns (
            uint256 redeemedAmount,
            uint256 amountRenewed,
            address ot,
            address xyt,
            uint256 amountTokenMinted
        );

    function tokenizeYield(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry,
        uint256 amountToTokenize,
        address to
    )
        external
        returns (
            address ot,
            address xyt,
            uint256 amountTokenMinted
        );

    /***********
     *  MARKET *
     ***********/

    function addMarketLiquidityDual(
        bytes32 _marketFactoryId,
        address _xyt,
        address _token,
        uint256 _desiredXytAmount,
        uint256 _desiredTokenAmount,
        uint256 _xytMinAmount,
        uint256 _tokenMinAmount
    )
        external
        payable
        returns (
            uint256 amountXytUsed,
            uint256 amountTokenUsed,
            uint256 lpOut
        );

    function addMarketLiquiditySingle(
        bytes32 marketFactoryId,
        address xyt,
        address token,
        bool forXyt,
        uint256 exactInAsset,
        uint256 minOutLp
    ) external payable returns (uint256 exactOutLp);

    function removeMarketLiquidityDual(
        bytes32 marketFactoryId,
        address xyt,
        address token,
        uint256 exactInLp,
        uint256 minOutXyt,
        uint256 minOutToken
    ) external returns (uint256 exactOutXyt, uint256 exactOutToken);

    function removeMarketLiquiditySingle(
        bytes32 marketFactoryId,
        address xyt,
        address token,
        bool forXyt,
        uint256 exactInLp,
        uint256 minOutAsset
    ) external returns (uint256 exactOutXyt, uint256 exactOutToken);

    /**
     * @notice Creates a market given a protocol ID, future yield token, and an ERC20 token.
     * @param marketFactoryId Market Factory identifier.
     * @param xyt Token address of the future yield token as base asset.
     * @param token Token address of an ERC20 token as quote asset.
     * @return market Returns the address of the newly created market.
     **/
    function createMarket(
        bytes32 marketFactoryId,
        address xyt,
        address token
    ) external returns (address market);

    function bootstrapMarket(
        bytes32 marketFactoryId,
        address xyt,
        address token,
        uint256 initialXytLiquidity,
        uint256 initialTokenLiquidity
    ) external payable;

    function swapExactIn(
        address tokenIn,
        address tokenOut,
        uint256 inTotalAmount,
        uint256 minOutTotalAmount,
        bytes32 marketFactoryId
    ) external payable returns (uint256 outTotalAmount);

    function swapExactOut(
        address tokenIn,
        address tokenOut,
        uint256 outTotalAmount,
        uint256 maxInTotalAmount,
        bytes32 marketFactoryId
    ) external payable returns (uint256 inTotalAmount);

    function redeemLpInterests(address market, address user) external returns (uint256 interests);
}

File 6 of 23 : IPendleData.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;

import "./IPendleRouter.sol";
import "./IPendleYieldToken.sol";
import "./IPendlePausingManager.sol";
import "./IPendleMarket.sol";

interface IPendleData {
    /**
     * @notice Emitted when validity of a forge-factory pair is updated
     * @param _forgeId the forge id
     * @param _marketFactoryId the market factory id
     * @param _valid valid or not
     **/
    event ForgeFactoryValiditySet(bytes32 _forgeId, bytes32 _marketFactoryId, bool _valid);

    /**
     * @notice Emitted when Pendle and PendleFactory addresses have been updated.
     * @param treasury The address of the new treasury contract.
     **/
    event TreasurySet(address treasury);

    /**
     * @notice Emitted when LockParams is changed
     **/
    event LockParamsSet(uint256 lockNumerator, uint256 lockDenominator);

    /**
     * @notice Emitted when ExpiryDivisor is changed
     **/
    event ExpiryDivisorSet(uint256 expiryDivisor);

    /**
     * @notice Emitted when forge fee is changed
     **/
    event ForgeFeeSet(uint256 forgeFee);

    /**
     * @notice Emitted when interestUpdateRateDeltaForMarket is changed
     * @param interestUpdateRateDeltaForMarket new interestUpdateRateDeltaForMarket setting
     **/
    event InterestUpdateRateDeltaForMarketSet(uint256 interestUpdateRateDeltaForMarket);

    /**
     * @notice Emitted when market fees are changed
     * @param _swapFee new swapFee setting
     * @param _protocolSwapFee new protocolSwapFee setting
     **/
    event MarketFeesSet(uint256 _swapFee, uint256 _protocolSwapFee);

    /**
     * @notice Emitted when the curve shift block delta is changed
     * @param _blockDelta new block delta setting
     **/
    event CurveShiftBlockDeltaSet(uint256 _blockDelta);

    /**
     * @dev Emitted when new forge is added
     * @param marketFactoryId Human Readable Market Factory ID in Bytes
     * @param marketFactoryAddress The Market Factory Address
     */
    event NewMarketFactory(bytes32 indexed marketFactoryId, address indexed marketFactoryAddress);

    /**
     * @notice Set/update validity of a forge-factory pair
     * @param _forgeId the forge id
     * @param _marketFactoryId the market factory id
     * @param _valid valid or not
     **/
    function setForgeFactoryValidity(
        bytes32 _forgeId,
        bytes32 _marketFactoryId,
        bool _valid
    ) external;

    /**
     * @notice Sets the PendleTreasury contract addresses.
     * @param newTreasury Address of new treasury contract.
     **/
    function setTreasury(address newTreasury) external;

    /**
     * @notice Gets a reference to the PendleRouter contract.
     * @return Returns the router contract reference.
     **/
    function router() external view returns (IPendleRouter);

    /**
     * @notice Gets a reference to the PendleRouter contract.
     * @return Returns the router contract reference.
     **/
    function pausingManager() external view returns (IPendlePausingManager);

    /**
     * @notice Gets the treasury contract address where fees are being sent to.
     * @return Address of the treasury contract.
     **/
    function treasury() external view returns (address);

    /***********
     *  FORGE  *
     ***********/

    /**
     * @notice Emitted when a forge for a protocol is added.
     * @param forgeId Forge and protocol identifier.
     * @param forgeAddress The address of the added forge.
     **/
    event ForgeAdded(bytes32 indexed forgeId, address indexed forgeAddress);

    /**
     * @notice Adds a new forge for a protocol.
     * @param forgeId Forge and protocol identifier.
     * @param forgeAddress The address of the added forge.
     **/
    function addForge(bytes32 forgeId, address forgeAddress) external;

    /**
     * @notice Store new OT and XYT details.
     * @param forgeId Forge and protocol identifier.
     * @param ot The address of the new XYT.
     * @param xyt The address of the new XYT.
     * @param underlyingAsset Token address of the underlying asset.
     * @param expiry Yield contract expiry in epoch time.
     **/
    function storeTokens(
        bytes32 forgeId,
        address ot,
        address xyt,
        address underlyingAsset,
        uint256 expiry
    ) external;

    /**
     * @notice Set a new forge fee
     * @param _forgeFee new forge fee
     **/
    function setForgeFee(uint256 _forgeFee) external;

    /**
     * @notice Gets the OT and XYT tokens.
     * @param forgeId Forge and protocol identifier.
     * @param underlyingYieldToken Token address of the underlying yield token.
     * @param expiry Yield contract expiry in epoch time.
     * @return ot The OT token references.
     * @return xyt The XYT token references.
     **/
    function getPendleYieldTokens(
        bytes32 forgeId,
        address underlyingYieldToken,
        uint256 expiry
    ) external view returns (IPendleYieldToken ot, IPendleYieldToken xyt);

    /**
     * @notice Gets a forge given the identifier.
     * @param forgeId Forge and protocol identifier.
     * @return forgeAddress Returns the forge address.
     **/
    function getForgeAddress(bytes32 forgeId) external view returns (address forgeAddress);

    /**
     * @notice Checks if an XYT token is valid.
     * @param forgeId The forgeId of the forge.
     * @param underlyingAsset Token address of the underlying asset.
     * @param expiry Yield contract expiry in epoch time.
     * @return True if valid, false otherwise.
     **/
    function isValidXYT(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry
    ) external view returns (bool);

    /**
     * @notice Checks if an OT token is valid.
     * @param forgeId The forgeId of the forge.
     * @param underlyingAsset Token address of the underlying asset.
     * @param expiry Yield contract expiry in epoch time.
     * @return True if valid, false otherwise.
     **/
    function isValidOT(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry
    ) external view returns (bool);

    function validForgeFactoryPair(bytes32 _forgeId, bytes32 _marketFactoryId)
        external
        view
        returns (bool);

    /**
     * @notice Gets a reference to a specific OT.
     * @param forgeId Forge and protocol identifier.
     * @param underlyingYieldToken Token address of the underlying yield token.
     * @param expiry Yield contract expiry in epoch time.
     * @return ot Returns the reference to an OT.
     **/
    function otTokens(
        bytes32 forgeId,
        address underlyingYieldToken,
        uint256 expiry
    ) external view returns (IPendleYieldToken ot);

    /**
     * @notice Gets a reference to a specific XYT.
     * @param forgeId Forge and protocol identifier.
     * @param underlyingAsset Token address of the underlying asset
     * @param expiry Yield contract expiry in epoch time.
     * @return xyt Returns the reference to an XYT.
     **/
    function xytTokens(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry
    ) external view returns (IPendleYieldToken xyt);

    /***********
     *  MARKET *
     ***********/

    event MarketPairAdded(address indexed market, address indexed xyt, address indexed token);

    function addMarketFactory(bytes32 marketFactoryId, address marketFactoryAddress) external;

    function isMarket(address _addr) external view returns (bool result);

    function isXyt(address _addr) external view returns (bool result);

    function addMarket(
        bytes32 marketFactoryId,
        address xyt,
        address token,
        address market
    ) external;

    function setMarketFees(uint256 _swapFee, uint256 _protocolSwapFee) external;

    function setInterestUpdateRateDeltaForMarket(uint256 _interestUpdateRateDeltaForMarket)
        external;

    function setLockParams(uint256 _lockNumerator, uint256 _lockDenominator) external;

    function setExpiryDivisor(uint256 _expiryDivisor) external;

    function setCurveShiftBlockDelta(uint256 _blockDelta) external;

    /**
     * @notice Displays the number of markets currently existing.
     * @return Returns markets length,
     **/
    function allMarketsLength() external view returns (uint256);

    function forgeFee() external view returns (uint256);

    function interestUpdateRateDeltaForMarket() external view returns (uint256);

    function expiryDivisor() external view returns (uint256);

    function lockNumerator() external view returns (uint256);

    function lockDenominator() external view returns (uint256);

    function swapFee() external view returns (uint256);

    function protocolSwapFee() external view returns (uint256);

    function curveShiftBlockDelta() external view returns (uint256);

    function getMarketByIndex(uint256 index) external view returns (address market);

    /**
     * @notice Gets a market given a future yield token and an ERC20 token.
     * @param xyt Token address of the future yield token as base asset.
     * @param token Token address of an ERC20 token as quote asset.
     * @return market Returns the market address.
     **/
    function getMarket(
        bytes32 marketFactoryId,
        address xyt,
        address token
    ) external view returns (address market);

    /**
     * @notice Gets a market factory given the identifier.
     * @param marketFactoryId MarketFactory identifier.
     * @return marketFactoryAddress Returns the factory address.
     **/
    function getMarketFactoryAddress(bytes32 marketFactoryId)
        external
        view
        returns (address marketFactoryAddress);

    function getMarketFromKey(
        address xyt,
        address token,
        bytes32 marketFactoryId
    ) external view returns (address market);
}

File 7 of 23 : IPendleForge.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IPendleRouter.sol";
import "./IPendleData.sol";
import "./IPendleRewardManager.sol";
import "./IPendleYieldContractDeployer.sol";

interface IPendleForge {
    /**
     * @dev Emitted when the Forge has minted the OT and XYT tokens.
     * @param forgeId The forgeId
     * @param underlyingAsset The address of the underlying yield token.
     * @param expiry The expiry of the XYT token
     * @param amountToTokenize The amount of yield bearing assets to tokenize
     * @param amountTokenMinted The amount of OT/XYT minted
     **/
    event MintYieldTokens(
        bytes32 forgeId,
        address indexed underlyingAsset,
        uint256 indexed expiry,
        uint256 amountToTokenize,
        uint256 amountTokenMinted,
        address indexed user
    );

    /**
     * @dev Emitted when the Forge has created new yield token contracts.
     * @param forgeId The forgeId
     * @param underlyingAsset The address of the underlying asset.
     * @param expiry The date in epoch time when the contract will expire.
     * @param ot The address of the ownership token.
     * @param xyt The address of the new future yield token.
     **/
    event NewYieldContracts(
        bytes32 forgeId,
        address indexed underlyingAsset,
        uint256 indexed expiry,
        address ot,
        address xyt,
        address yieldBearingAsset
    );

    /**
     * @dev Emitted when the Forge has redeemed the OT and XYT tokens.
     * @param forgeId The forgeId
     * @param underlyingAsset the address of the underlying asset
     * @param expiry The expiry of the XYT token
     * @param amountToRedeem The amount of OT to be redeemed.
     * @param redeemedAmount The amount of yield token received
     **/
    event RedeemYieldToken(
        bytes32 forgeId,
        address indexed underlyingAsset,
        uint256 indexed expiry,
        uint256 amountToRedeem,
        uint256 redeemedAmount,
        address indexed user
    );

    /**
     * @dev Emitted when interest claim is settled
     * @param forgeId The forgeId
     * @param underlyingAsset the address of the underlying asset
     * @param expiry The expiry of the XYT token
     * @param user Interest receiver Address
     * @param amount The amount of interest claimed
     **/
    event DueInterestsSettled(
        bytes32 forgeId,
        address indexed underlyingAsset,
        uint256 indexed expiry,
        uint256 amount,
        uint256 forgeFeeAmount,
        address indexed user
    );

    /**
     * @dev Emitted when forge fee is withdrawn
     * @param forgeId The forgeId
     * @param underlyingAsset the address of the underlying asset
     * @param expiry The expiry of the XYT token
     * @param amount The amount of interest claimed
     **/
    event ForgeFeeWithdrawn(
        bytes32 forgeId,
        address indexed underlyingAsset,
        uint256 indexed expiry,
        uint256 amount
    );

    function setUpEmergencyMode(
        address _underlyingAsset,
        uint256 _expiry,
        address spender
    ) external;

    function newYieldContracts(address underlyingAsset, uint256 expiry)
        external
        returns (address ot, address xyt);

    function redeemAfterExpiry(
        address user,
        address underlyingAsset,
        uint256 expiry
    ) external returns (uint256 redeemedAmount);

    function redeemDueInterests(
        address user,
        address underlyingAsset,
        uint256 expiry
    ) external returns (uint256 interests);

    function updateDueInterests(
        address underlyingAsset,
        uint256 expiry,
        address user
    ) external;

    function updatePendingRewards(
        address _underlyingAsset,
        uint256 _expiry,
        address _user
    ) external;

    function redeemUnderlying(
        address user,
        address underlyingAsset,
        uint256 expiry,
        uint256 amountToRedeem
    ) external returns (uint256 redeemedAmount);

    function mintOtAndXyt(
        address underlyingAsset,
        uint256 expiry,
        uint256 amountToTokenize,
        address to
    )
        external
        returns (
            address ot,
            address xyt,
            uint256 amountTokenMinted
        );

    function withdrawForgeFee(address underlyingAsset, uint256 expiry) external;

    function getYieldBearingToken(address underlyingAsset) external returns (address);

    /**
     * @notice Gets a reference to the PendleRouter contract.
     * @return Returns the router contract reference.
     **/
    function router() external view returns (IPendleRouter);

    function data() external view returns (IPendleData);

    function rewardManager() external view returns (IPendleRewardManager);

    function yieldContractDeployer() external view returns (IPendleYieldContractDeployer);

    function rewardToken() external view returns (IERC20);

    /**
     * @notice Gets the bytes32 ID of the forge.
     * @return Returns the forge and protocol identifier.
     **/
    function forgeId() external view returns (bytes32);

    function dueInterests(
        address _underlyingAsset,
        uint256 expiry,
        address _user
    ) external view returns (uint256);

    function yieldTokenHolders(address _underlyingAsset, uint256 _expiry)
        external
        view
        returns (address yieldTokenHolder);
}

File 8 of 23 : IPendleMarketFactory.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;

import "./IPendleRouter.sol";

interface IPendleMarketFactory {
    /**
     * @notice Creates a market given a protocol ID, future yield token, and an ERC20 token.
     * @param xyt Token address of the futuonlyCorere yield token as base asset.
     * @param token Token address of an ERC20 token as quote asset.
     * @return market Returns the address of the newly created market.
     **/
    function createMarket(address xyt, address token) external returns (address market);

    /**
     * @notice Gets a reference to the PendleRouter contract.
     * @return Returns the router contract reference.
     **/
    function router() external view returns (IPendleRouter);

    function marketFactoryId() external view returns (bytes32);
}

File 9 of 23 : IPendleMarket.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;
pragma abicoder v2;

import "./IPendleRouter.sol";
import "./IPendleBaseToken.sol";
import "../libraries/PendleStructs.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IPendleMarket is IERC20 {
    /**
     * @notice Emitted when reserves pool has been updated
     * @param reserve0 The XYT reserves.
     * @param weight0  The XYT weight
     * @param reserve1 The generic token reserves.
     * For the generic Token weight it can be inferred by (2^40) - weight0
     **/
    event Sync(uint256 reserve0, uint256 weight0, uint256 reserve1);

    function setUpEmergencyMode(address spender) external;

    function bootstrap(
        address user,
        uint256 initialXytLiquidity,
        uint256 initialTokenLiquidity
    ) external returns (PendingTransfer[2] memory transfers, uint256 exactOutLp);

    function addMarketLiquiditySingle(
        address user,
        address inToken,
        uint256 inAmount,
        uint256 minOutLp
    ) external returns (PendingTransfer[2] memory transfers, uint256 exactOutLp);

    function addMarketLiquidityDual(
        address user,
        uint256 _desiredXytAmount,
        uint256 _desiredTokenAmount,
        uint256 _xytMinAmount,
        uint256 _tokenMinAmount
    ) external returns (PendingTransfer[2] memory transfers, uint256 lpOut);

    function removeMarketLiquidityDual(
        address user,
        uint256 inLp,
        uint256 minOutXyt,
        uint256 minOutToken
    ) external returns (PendingTransfer[2] memory transfers);

    function removeMarketLiquiditySingle(
        address user,
        address outToken,
        uint256 exactInLp,
        uint256 minOutToken
    ) external returns (PendingTransfer[2] memory transfers);

    function swapExactIn(
        address inToken,
        uint256 inAmount,
        address outToken,
        uint256 minOutAmount
    ) external returns (uint256 outAmount, PendingTransfer[2] memory transfers);

    function swapExactOut(
        address inToken,
        uint256 maxInAmount,
        address outToken,
        uint256 outAmount
    ) external returns (uint256 inAmount, PendingTransfer[2] memory transfers);

    function redeemLpInterests(address user) external returns (uint256 interests);

    function getReserves()
        external
        view
        returns (
            uint256 xytBalance,
            uint256 xytWeight,
            uint256 tokenBalance,
            uint256 tokenWeight,
            uint256 currentBlock
        );

    function factoryId() external view returns (bytes32);

    function token() external view returns (address);

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

File 10 of 23 : PermissionsV2.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../core/PendleGovernanceManager.sol";
import "../interfaces/IPermissionsV2.sol";

abstract contract PermissionsV2 is IPermissionsV2 {
    PendleGovernanceManager public immutable override governanceManager;
    address internal initializer;

    constructor(address _governanceManager) {
        require(_governanceManager != address(0), "ZERO_ADDRESS");
        initializer = msg.sender;
        governanceManager = PendleGovernanceManager(_governanceManager);
    }

    modifier initialized() {
        require(initializer == address(0), "NOT_INITIALIZED");
        _;
    }

    modifier onlyGovernance() {
        require(msg.sender == _governance(), "ONLY_GOVERNANCE");
        _;
    }

    function _governance() internal view returns (address) {
        return governanceManager.governance();
    }
}

File 11 of 23 : WithdrawableV2.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "./PermissionsV2.sol";

abstract contract WithdrawableV2 is PermissionsV2 {
    using SafeERC20 for IERC20;

    event EtherWithdraw(uint256 amount, address sendTo);
    event TokenWithdraw(IERC20 token, uint256 amount, address sendTo);

    /**
     * @dev Allows governance to withdraw Ether in a Pendle contract
     *      in case of accidental ETH transfer into the contract.
     * @param amount The amount of Ether to withdraw.
     * @param sendTo The recipient address.
     */
    function withdrawEther(uint256 amount, address payable sendTo) external onlyGovernance {
        (bool success, ) = sendTo.call{value: amount}("");
        require(success, "WITHDRAW_FAILED");
        emit EtherWithdraw(amount, sendTo);
    }

    /**
     * @dev Allows governance to withdraw all IERC20 compatible tokens in a Pendle
     *      contract in case of accidental token transfer into the contract.
     * @param token IERC20 The address of the token contract.
     * @param amount The amount of IERC20 tokens to withdraw.
     * @param sendTo The recipient address.
     */
    function withdrawToken(
        IERC20 token,
        uint256 amount,
        address sendTo
    ) external onlyGovernance {
        require(_allowedToWithdraw(address(token)), "TOKEN_NOT_ALLOWED");
        token.safeTransfer(sendTo, amount);
        emit TokenWithdraw(token, amount, sendTo);
    }

    // must be overridden by the sub contracts, so we must consider explicitly
    // in each and every contract which tokens are allowed to be withdrawn
    function _allowedToWithdraw(address) internal view virtual returns (bool allowed);
}

File 12 of 23 : PendleRouterNonReentrant.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
import "../interfaces/IPendleData.sol";

abstract contract PendleRouterNonReentrant {
    uint8 internal _guardCounter;

    modifier nonReentrant() {
        _checkNonReentrancy(); // use functions to reduce bytecode size
        _;
        _guardCounter--;
    }

    constructor() {
        _guardCounter = 1;
    }

    /**
    * We allow markets to make at most ONE Reentrant call
    in the case of redeemLpInterests
    * The flow of redeemLpInterests will be: Router.redeemLpInterests -> market.redeemLpInterests
    -> Router.redeemDueInterests (so there is at most ONE Reentrant call)
    */
    function _checkNonReentrancy() internal {
        if (_getData().isMarket(msg.sender)) {
            require(_guardCounter <= 2, "REENTRANT_CALL");
        } else {
            require(_guardCounter == 1, "REENTRANT_CALL");
        }
        _guardCounter++;
    }

    function _getData() internal view virtual returns (IPendleData);
}

File 13 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 14 of 23 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <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;
        // solhint-disable-next-line no-inline-assembly
        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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 15 of 23 : IWETH.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */
pragma solidity 0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IWETH is IERC20 {
    function deposit() external payable;

    function withdraw(uint256 wad) external;
}

File 16 of 23 : PendleStructs.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.7.6;

struct TokenReserve {
    uint256 weight;
    uint256 balance;
}

struct PendingTransfer {
    uint256 amount;
    bool isOut;
}

File 17 of 23 : IPendleYieldToken.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IPendleBaseToken.sol";
import "./IPendleForge.sol";

interface IPendleYieldToken is IERC20, IPendleBaseToken {
    /**
     * @notice Emitted when burning OT or XYT tokens.
     * @param user The address performing the burn.
     * @param amount The amount to be burned.
     **/
    event Burn(address indexed user, uint256 amount);

    /**
     * @notice Emitted when minting OT or XYT tokens.
     * @param user The address performing the mint.
     * @param amount The amount to be minted.
     **/
    event Mint(address indexed user, uint256 amount);

    /**
     * @notice Burns OT or XYT tokens from user, reducing the total supply.
     * @param user The address performing the burn.
     * @param amount The amount to be burned.
     **/
    function burn(address user, uint256 amount) external;

    /**
     * @notice Mints new OT or XYT tokens for user, increasing the total supply.
     * @param user The address to send the minted tokens.
     * @param amount The amount to be minted.
     **/
    function mint(address user, uint256 amount) external;

    /**
     * @notice Gets the forge address of the PendleForge contract for this yield token.
     * @return Retuns the forge address.
     **/
    function forge() external view returns (IPendleForge);

    /**
     * @notice Returns the address of the underlying asset.
     * @return Returns the underlying asset address.
     **/
    function underlyingAsset() external view returns (address);

    /**
     * @notice Returns the address of the underlying yield token.
     * @return Returns the underlying yield token address.
     **/
    function underlyingYieldToken() external view returns (address);

    /**
     * @notice let the router approve itself to spend OT/XYT/LP from any wallet
     * @param user user to approve
     **/
    function approveRouter(address user) external;
}

File 18 of 23 : IPendlePausingManager.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */
pragma solidity 0.7.6;

interface IPendlePausingManager {
    event AddPausingAdmin(address admin);
    event RemovePausingAdmin(address admin);
    event PendingForgeEmergencyHandler(address _pendingForgeHandler);
    event PendingMarketEmergencyHandler(address _pendingMarketHandler);
    event PendingLiqMiningEmergencyHandler(address _pendingLiqMiningHandler);
    event ForgeEmergencyHandlerSet(address forgeEmergencyHandler);
    event MarketEmergencyHandlerSet(address marketEmergencyHandler);
    event LiqMiningEmergencyHandlerSet(address liqMiningEmergencyHandler);

    event PausingManagerLocked();
    event ForgeHandlerLocked();
    event MarketHandlerLocked();
    event LiqMiningHandlerLocked();

    event SetForgePaused(bytes32 forgeId, bool settingToPaused);
    event SetForgeAssetPaused(bytes32 forgeId, address underlyingAsset, bool settingToPaused);
    event SetForgeAssetExpiryPaused(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry,
        bool settingToPaused
    );

    event SetForgeLocked(bytes32 forgeId);
    event SetForgeAssetLocked(bytes32 forgeId, address underlyingAsset);
    event SetForgeAssetExpiryLocked(bytes32 forgeId, address underlyingAsset, uint256 expiry);

    event SetMarketFactoryPaused(bytes32 marketFactoryId, bool settingToPaused);
    event SetMarketPaused(bytes32 marketFactoryId, address market, bool settingToPaused);

    event SetMarketFactoryLocked(bytes32 marketFactoryId);
    event SetMarketLocked(bytes32 marketFactoryId, address market);

    event SetLiqMiningPaused(address liqMiningContract, bool settingToPaused);
    event SetLiqMiningLocked(address liqMiningContract);

    function forgeEmergencyHandler()
        external
        view
        returns (
            address handler,
            address pendingHandler,
            uint256 timelockDeadline
        );

    function marketEmergencyHandler()
        external
        view
        returns (
            address handler,
            address pendingHandler,
            uint256 timelockDeadline
        );

    function liqMiningEmergencyHandler()
        external
        view
        returns (
            address handler,
            address pendingHandler,
            uint256 timelockDeadline
        );

    function permLocked() external view returns (bool);

    function permForgeHandlerLocked() external view returns (bool);

    function permMarketHandlerLocked() external view returns (bool);

    function permLiqMiningHandlerLocked() external view returns (bool);

    function isPausingAdmin(address) external view returns (bool);

    function setPausingAdmin(address admin, bool isAdmin) external;

    function requestForgeHandlerChange(address _pendingForgeHandler) external;

    function requestMarketHandlerChange(address _pendingMarketHandler) external;

    function requestLiqMiningHandlerChange(address _pendingLiqMiningHandler) external;

    function applyForgeHandlerChange() external;

    function applyMarketHandlerChange() external;

    function applyLiqMiningHandlerChange() external;

    function lockPausingManagerPermanently() external;

    function lockForgeHandlerPermanently() external;

    function lockMarketHandlerPermanently() external;

    function lockLiqMiningHandlerPermanently() external;

    function setForgePaused(bytes32 forgeId, bool paused) external;

    function setForgeAssetPaused(
        bytes32 forgeId,
        address underlyingAsset,
        bool paused
    ) external;

    function setForgeAssetExpiryPaused(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry,
        bool paused
    ) external;

    function setForgeLocked(bytes32 forgeId) external;

    function setForgeAssetLocked(bytes32 forgeId, address underlyingAsset) external;

    function setForgeAssetExpiryLocked(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry
    ) external;

    function checkYieldContractStatus(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry
    ) external returns (bool _paused, bool _locked);

    function setMarketFactoryPaused(bytes32 marketFactoryId, bool paused) external;

    function setMarketPaused(
        bytes32 marketFactoryId,
        address market,
        bool paused
    ) external;

    function setMarketFactoryLocked(bytes32 marketFactoryId) external;

    function setMarketLocked(bytes32 marketFactoryId, address market) external;

    function checkMarketStatus(bytes32 marketFactoryId, address market)
        external
        returns (bool _paused, bool _locked);

    function setLiqMiningPaused(address liqMiningContract, bool settingToPaused) external;

    function setLiqMiningLocked(address liqMiningContract) external;

    function checkLiqMiningStatus(address liqMiningContract)
        external
        returns (bool _paused, bool _locked);
}

File 19 of 23 : IPendleBaseToken.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IPendleBaseToken is IERC20 {
    /**
     * @notice Decreases the allowance granted to spender by the caller.
     * @param spender The address to reduce the allowance from.
     * @param subtractedValue The amount allowance to subtract.
     * @return Returns true if allowance has decreased, otherwise false.
     **/
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /**
     * @notice The yield contract start in epoch time.
     * @return Returns the yield start date.
     **/
    function start() external view returns (uint256);

    /**
     * @notice The yield contract expiry in epoch time.
     * @return Returns the yield expiry date.
     **/
    function expiry() external view returns (uint256);

    /**
     * @notice Increases the allowance granted to spender by the caller.
     * @param spender The address to increase the allowance from.
     * @param addedValue The amount allowance to add.
     * @return Returns true if allowance has increased, otherwise false
     **/
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);

    /**
     * @notice Returns the number of decimals the token uses.
     * @return Returns the token's decimals.
     **/
    function decimals() external view returns (uint8);

    /**
     * @notice Returns the name of the token.
     * @return Returns the token's name.
     **/
    function name() external view returns (string memory);

    /**
     * @notice Returns the symbol of the token.
     * @return Returns the token's symbol.
     **/
    function symbol() external view returns (string memory);

    /**
     * @notice approve using the owner's signature
     **/
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

File 20 of 23 : IPendleRewardManager.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */
pragma solidity 0.7.6;

interface IPendleRewardManager {
    event UpdateFrequencySet(address[], uint256[]);
    event SkippingRewardsSet(bool);

    event DueRewardsSettled(
        bytes32 forgeId,
        address underlyingAsset,
        uint256 expiry,
        uint256 amountOut,
        address user
    );

    function redeemRewards(
        address _underlyingAsset,
        uint256 _expiry,
        address _user
    ) external returns (uint256 dueRewards);

    function updatePendingRewards(
        address _underlyingAsset,
        uint256 _expiry,
        address _user
    ) external;

    function updateParamLManual(address _underlyingAsset, uint256 _expiry) external;

    function setUpdateFrequency(
        address[] calldata underlyingAssets,
        uint256[] calldata frequencies
    ) external;

    function setSkippingRewards(bool skippingRewards) external;

    function forgeId() external returns (bytes32);
}

File 21 of 23 : IPendleYieldContractDeployer.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */
pragma solidity 0.7.6;

interface IPendleYieldContractDeployer {
    function forgeId() external returns (bytes32);

    function forgeOwnershipToken(
        address _underlyingAsset,
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        uint256 _expiry
    ) external returns (address ot);

    function forgeFutureYieldToken(
        address _underlyingAsset,
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        uint256 _expiry
    ) external returns (address xyt);

    function deployYieldTokenHolder(address yieldToken, uint256 expiry)
        external
        returns (address yieldTokenHolder);
}

File 22 of 23 : PendleGovernanceManager.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;

contract PendleGovernanceManager {
    address public governance;
    address public pendingGovernance;

    event GovernanceClaimed(address newGovernance, address previousGovernance);

    event TransferGovernancePending(address pendingGovernance);

    constructor(address _governance) {
        require(_governance != address(0), "ZERO_ADDRESS");
        governance = _governance;
    }

    modifier onlyGovernance() {
        require(msg.sender == governance, "ONLY_GOVERNANCE");
        _;
    }

    /**
     * @dev Allows the pendingGovernance address to finalize the change governance process.
     */
    function claimGovernance() external {
        require(pendingGovernance == msg.sender, "WRONG_GOVERNANCE");
        emit GovernanceClaimed(pendingGovernance, governance);
        governance = pendingGovernance;
        pendingGovernance = address(0);
    }

    /**
     * @dev Allows the current governance to set the pendingGovernance address.
     * @param _governance The address to transfer ownership to.
     */
    function transferGovernance(address _governance) external onlyGovernance {
        require(_governance != address(0), "ZERO_ADDRESS");
        pendingGovernance = _governance;

        emit TransferGovernancePending(pendingGovernance);
    }
}

File 23 of 23 : IPermissionsV2.sol
// SPDX-License-Identifier: MIT
/*
 * MIT License
 * ===========
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */

pragma solidity 0.7.6;
pragma abicoder v2;

import "../core/PendleGovernanceManager.sol";

interface IPermissionsV2 {
    function governanceManager() external returns (PendleGovernanceManager);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_governanceManager","type":"address"},{"internalType":"contract IWETH","name":"_weth","type":"address"},{"internalType":"contract IPendleData","name":"_data","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"sendTo","type":"address"}],"name":"EtherWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"token0Amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"token1Amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint256","name":"exactInLp","type":"uint256"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"token0Amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"token1Amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint256","name":"exactOutLp","type":"uint256"}],"name":"Join","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"marketFactoryId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"xyt","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"market","type":"address"}],"name":"MarketCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"address","name":"inToken","type":"address"},{"indexed":false,"internalType":"address","name":"outToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"exactIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exactOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"market","type":"address"}],"name":"SwapEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"sendTo","type":"address"}],"name":"TokenWithdraw","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"},{"internalType":"address","name":"_xyt","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_desiredXytAmount","type":"uint256"},{"internalType":"uint256","name":"_desiredTokenAmount","type":"uint256"},{"internalType":"uint256","name":"_xytMinAmount","type":"uint256"},{"internalType":"uint256","name":"_tokenMinAmount","type":"uint256"}],"name":"addMarketLiquidityDual","outputs":[{"internalType":"uint256","name":"amountXytUsed","type":"uint256"},{"internalType":"uint256","name":"amountTokenUsed","type":"uint256"},{"internalType":"uint256","name":"lpOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"},{"internalType":"address","name":"_xyt","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_forXyt","type":"bool"},{"internalType":"uint256","name":"_exactIn","type":"uint256"},{"internalType":"uint256","name":"_minOutLp","type":"uint256"}],"name":"addMarketLiquiditySingle","outputs":[{"internalType":"uint256","name":"exactOutLp","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"},{"internalType":"address","name":"_xyt","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_initialXytLiquidity","type":"uint256"},{"internalType":"uint256","name":"_initialTokenLiquidity","type":"uint256"}],"name":"bootstrapMarket","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"},{"internalType":"address","name":"_xyt","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"createMarket","outputs":[{"internalType":"address","name":"market","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"data","outputs":[{"internalType":"contract IPendleData","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governanceManager","outputs":[{"internalType":"contract PendleGovernanceManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_forgeId","type":"bytes32"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"}],"name":"newYieldContracts","outputs":[{"internalType":"address","name":"ot","type":"address"},{"internalType":"address","name":"xyt","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_forgeId","type":"bytes32"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"}],"name":"redeemAfterExpiry","outputs":[{"internalType":"uint256","name":"redeemedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_forgeId","type":"bytes32"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"redeemDueInterests","outputs":[{"internalType":"uint256","name":"interests","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"redeemLpInterests","outputs":[{"internalType":"uint256","name":"interests","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_forgeId","type":"bytes32"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"uint256","name":"_amountToRedeem","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"redeemedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"},{"internalType":"address","name":"_xyt","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_exactInLp","type":"uint256"},{"internalType":"uint256","name":"_minOutXyt","type":"uint256"},{"internalType":"uint256","name":"_minOutToken","type":"uint256"}],"name":"removeMarketLiquidityDual","outputs":[{"internalType":"uint256","name":"exactOutXyt","type":"uint256"},{"internalType":"uint256","name":"exactOutToken","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"},{"internalType":"address","name":"_xyt","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_forXyt","type":"bool"},{"internalType":"uint256","name":"_exactInLp","type":"uint256"},{"internalType":"uint256","name":"_minOutAsset","type":"uint256"}],"name":"removeMarketLiquiditySingle","outputs":[{"internalType":"uint256","name":"exactOutXyt","type":"uint256"},{"internalType":"uint256","name":"exactOutToken","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_forgeId","type":"bytes32"},{"internalType":"uint256","name":"_oldExpiry","type":"uint256"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_newExpiry","type":"uint256"},{"internalType":"uint256","name":"_renewalRate","type":"uint256"}],"name":"renewYield","outputs":[{"internalType":"uint256","name":"redeemedAmount","type":"uint256"},{"internalType":"uint256","name":"amountRenewed","type":"uint256"},{"internalType":"address","name":"ot","type":"address"},{"internalType":"address","name":"xyt","type":"address"},{"internalType":"uint256","name":"amountTokenMinted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_inAmount","type":"uint256"},{"internalType":"uint256","name":"_minOutAmount","type":"uint256"},{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"}],"name":"swapExactIn","outputs":[{"internalType":"uint256","name":"outSwapAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_outAmount","type":"uint256"},{"internalType":"uint256","name":"_maxInAmount","type":"uint256"},{"internalType":"bytes32","name":"_marketFactoryId","type":"bytes32"}],"name":"swapExactOut","outputs":[{"internalType":"uint256","name":"inSwapAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_forgeId","type":"bytes32"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"uint256","name":"_amountToTokenize","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"tokenizeYield","outputs":[{"internalType":"address","name":"ot","type":"address"},{"internalType":"address","name":"xyt","type":"address"},{"internalType":"uint256","name":"amountTokenMinted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"sendTo","type":"address"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"sendTo","type":"address"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b5060405162004a4938038062004a498339810160408190526200003491620000cc565b826001600160a01b03811662000080576040805162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b604482015290519081900360640190fd5b600080546001600160601b0319606093841b811660805260ff60a01b196001600160a01b0319909216331791909116600160a01b1790915592811b831660a0521b1660c0525062000138565b600080600060608486031215620000e1578283fd5b8351620000ee816200011f565b602085015190935062000101816200011f565b604085015190925062000114816200011f565b809150509250925092565b6001600160a01b03811681146200013557600080fd5b50565b60805160601c60a05160601c60c05160601c61480962000240600039806104a752806106a7528061078c52806109495280610b765280610da65280610e755280610f395280610fdc528061130a528061151652806116bc528061177d52806119765280611a715280611b8f5280611e555280611f0d5280611fc15280612092528061223c5280612408528061252952806128e252806129c05280612b7f52806134015280613506525080610133528061044a528061048152806109235280610b50528061126452806114b952806114f052806117575280611b695280612b595280613060528061310452806132cc5280613358525080612afa5280612f0b52506148096000f3fe6080604052600436106101235760003560e01c806373d4a13a116100a0578063bd73897011610064578063bd73897014610375578063ce56c454146103a4578063d230566c146103c4578063d2e6d1c3146103e4578063e612b996146103f95761017b565b806373d4a13a146102de57806374f62c0d146102f35780637e6dbccf14610315578063825fedd214610335578063b7edadef146103555761017b565b80633ccdbb28116100e75780633ccdbb28146102385780633fc8cef3146102585780635697fae91461027a57806356c132cf146102ab578063640a06a8146102cb5761017b565b806309077c1f146101805780631251ae7c146101a9578063205b5fb7146101c957806339f46c31146101dc5780633a884f901461020a5761017b565b3661017b57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101795760405162461bcd60e51b8152600401610170906145f0565b60405180910390fd5b005b600080fd5b61019361018e366004613c09565b61040c565b6040516101a091906141e1565b60405180910390f35b3480156101b557600080fd5b506101936101c4366004613ec0565b610686565b6101796101d7366004613d79565b6108c5565b3480156101e857600080fd5b506101fc6101f7366004613dca565b610b12565b6040516101a0929190614228565b34801561021657600080fd5b5061022a610225366004613e89565b610d54565b6040516101a0929190614067565b34801561024457600080fd5b50610179610253366004613fca565b611152565b34801561026457600080fd5b5061026d611262565b6040516101a09190614053565b34801561028657600080fd5b5061029a610295366004613f9a565b611286565b6040516101a09594939291906146b9565b3480156102b757600080fd5b506101936102c6366004613b61565b6112e9565b6101936102d9366004613c09565b61147b565b3480156102ea57600080fd5b5061026d6116ba565b610306610301366004613e25565b6116de565b6040516101a0939291906146e5565b34801561032157600080fd5b50610193610330366004613f09565b611955565b34801561034157600080fd5b506101fc610350366004613d15565b611b2b565b34801561036157600080fd5b5061026d610370366004613cd4565b611de8565b34801561038157600080fd5b50610395610390366004613f45565b6123e4565b6040516101a093929190614081565b3480156103b057600080fd5b506101796103bf366004614000565b612782565b3480156103d057600080fd5b506101936103df366004613e89565b6128c1565b3480156103f057600080fd5b5061026d612af8565b610193610407366004613d15565b612b1c565b6000610416612db0565b836104335760405162461bcd60e51b81526004016101709061425a565b858561043e82612ebd565b610448578761046a565b7f00000000000000000000000000000000000000000000000000000000000000005b975061047587612ebd565b61047f57866104a1565b7f00000000000000000000000000000000000000000000000000000000000000005b965060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b4238f498a8a886040518463ffffffff1660e01b81526004016104f593929190614081565b60206040518083038186803b15801561050d57600080fd5b505afa158015610521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105459190613b45565b90506001600160a01b03811661056d5760405162461bcd60e51b815260040161017090614667565b610575613a68565b60405163055a7da960e21b81526001600160a01b03831690631569f6a4906105a7908d908b908e908e9060040161418c565b60a060405180830381600087803b1580156105c157600080fd5b505af11580156105d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f99190614024565b909550905061060a81858585612ee2565b336001600160a01b03167ff5fd10e802251a919c2bfd2cfc15e2526d3864c819e2b4dc346ca1ade0f516588b8b888c8760405161064b959493929190614143565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b1990911617905550909695505050505050565b6000610690612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906394c0c1e0906106e090889088908890600401614209565b60206040518083038186803b1580156106f857600080fd5b505afa15801561070c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107309190613ca0565b61074c5760405162461bcd60e51b8152600401610170906143df565b6001600160a01b0382166107725760405162461bcd60e51b815260040161017090614493565b60405163288b600960e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a22d8024906107c19089906004016141e1565b60206040518083038186803b1580156107d957600080fd5b505afa1580156107ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108119190613b45565b60405163097660b960e01b81529091506001600160a01b0382169063097660b99061084490869089908990600401614081565b602060405180830381600087803b15801561085e57600080fd5b505af1158015610872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108969190613cbc565b6000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559695505050505050565b6108cd612db0565b600082116108ed5760405162461bcd60e51b815260040161017090614468565b6000811161090d5760405162461bcd60e51b815260040161017090614403565b8261091781612ebd565b6109215783610943565b7f00000000000000000000000000000000000000000000000000000000000000005b935060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638e7cf7668888886040518463ffffffff1660e01b8152600401610997939291906141ea565b60206040518083038186803b1580156109af57600080fd5b505afa1580156109c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e79190613b45565b90506001600160a01b038116610a0f5760405162461bcd60e51b815260040161017090614667565b610a17613a68565b60405163a6f319bb60e01b81526000906001600160a01b0384169063a6f319bb90610a4a9033908a908a906004016140ce565b60a060405180830381600087803b158015610a6457600080fd5b505af1158015610a78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9c9190613c74565b9092509050610aad82898686612ee2565b336001600160a01b031660008051602061478a83398151915287878685604051610ada9493929190614236565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b1990911617905550505050505050565b600080610b1d612db0565b84610b3a5760405162461bcd60e51b81526004016101709061461b565b85610b4481612ebd565b610b4e5786610b70565b7f00000000000000000000000000000000000000000000000000000000000000005b965060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638e7cf7668b8b8b6040518463ffffffff1660e01b8152600401610bc4939291906141ea565b60206040518083038186803b158015610bdc57600080fd5b505afa158015610bf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c149190613b45565b90506001600160a01b038116610c3c5760405162461bcd60e51b815260040161017090614667565b60405163834c295560e01b81526000906001600160a01b0383169063834c295590610c719033908c908c908c906004016140ef565b608060405180830381600087803b158015610c8b57600080fd5b505af1158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc39190613c59565b9050610cd1818b8585612ee2565b805151602082015151604051919650945033907f3af46289ed754c6821a8849534b8412a33bcd8387cb986f39e7e9937fb251cde90610d17908890889087908e90614236565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055509097909650945050505050565b600080610d5f612db0565b6001600160a01b038416610d855760405162461bcd60e51b815260040161017090614493565b428311610da45760405162461bcd60e51b81526004016101709061463f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e9e5f3cf6040518163ffffffff1660e01b815260040160206040518083038186803b158015610dfd57600080fd5b505afa158015610e11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e359190613cbc565b8381610e3d57fe5b0615610e5b5760405162461bcd60e51b81526004016101709061463f565b60405163288b600960e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a22d802490610eaa9089906004016141e1565b60206040518083038186803b158015610ec257600080fd5b505afa158015610ed6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610efa9190613b45565b90506001600160a01b038116610f225760405162461bcd60e51b8152600401610170906142b3565b604051631f019ead60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631f019ead90610f7290899089908990600401614209565b60206040518083038186803b158015610f8a57600080fd5b505afa158015610f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc29190613b45565b604051631771964d60e21b81529093506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dc659349061101590899089908990600401614209565b60206040518083038186803b15801561102d57600080fd5b505afa158015611041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110659190613b45565b91506001600160a01b03831615801561108557506001600160a01b038216155b6110a15760405162461bcd60e51b815260040161017090614431565b6040516304c2fceb60e51b81526001600160a01b0382169063985f9d60906110cf9088908890600401614173565b6040805180830381600087803b1580156110e857600080fd5b505af11580156110fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111209190613b99565b6000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559097909650945050505050565b61115a612f07565b6001600160a01b0316336001600160a01b0316146111b1576040805162461bcd60e51b815260206004820152600f60248201526e4f4e4c595f474f5645524e414e434560881b604482015290519081900360640190fd5b6111ba83612f93565b6111ff576040805162461bcd60e51b81526020600482015260116024820152701513d2d15397d393d517d0531313d5d151607a1b604482015290519081900360640190fd5b6112136001600160a01b0384168284612f99565b604080516001600160a01b0380861682526020820185905283168183015290517f72cb8a894ddb372ceec3d2a7648d86f17d5a15caae0e986c53109b8a9a9385e69181900360600190a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806000806000856000106112ae5760405162461bcd60e51b8152600401610170906144b9565b6112b98a898b6128c1565b94506112c58587612ff0565b93506112d48a898987336123e4565b969c959b509099509750939550919350505050565b60006112f3612db0565b6040516337649a6d60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636ec934da9061133f908690600401614053565b60206040518083038186803b15801561135757600080fd5b505afa15801561136b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138f9190613ca0565b6113ab5760405162461bcd60e51b815260040161017090614305565b6001600160a01b0382166113d15760405162461bcd60e51b815260040161017090614493565b604051633c12f35f60e21b81526001600160a01b0384169063f04bcd7c906113fd908590600401614053565b602060405180830381600087803b15801561141757600080fd5b505af115801561142b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144f9190613cbc565b6000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559392505050565b6000611485612db0565b836114a25760405162461bcd60e51b815260040161017090614691565b85856114ad82612ebd565b6114b757876114d9565b7f00000000000000000000000000000000000000000000000000000000000000005b97506114e487612ebd565b6114ee5786611510565b7f00000000000000000000000000000000000000000000000000000000000000005b965060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b4238f498a8a886040518463ffffffff1660e01b815260040161156493929190614081565b60206040518083038186803b15801561157c57600080fd5b505afa158015611590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b49190613b45565b90506001600160a01b0381166115dc5760405162461bcd60e51b815260040161017090614667565b6115e4613a68565b604051637c2e4e7160e11b81526001600160a01b0383169063f85c9ce290611616908d908c908e908d9060040161418c565b60a060405180830381600087803b15801561163057600080fd5b505af1158015611644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116689190614024565b909550905061167981858585612ee2565b336001600160a01b03167ff5fd10e802251a919c2bfd2cfc15e2526d3864c819e2b4dc346ca1ade0f516588b8b8b898760405161064b959493929190614143565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008060006116eb612db0565b86158015906116fa5750848710155b6117165760405162461bcd60e51b815260040161017090614568565b85158015906117255750838610155b6117415760405162461bcd60e51b81526004016101709061432d565b8761174b81612ebd565b6117555788611777565b7f00000000000000000000000000000000000000000000000000000000000000005b985060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638e7cf7668d8d8d6040518463ffffffff1660e01b81526004016117cb939291906141ea565b60206040518083038186803b1580156117e357600080fd5b505afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b9190613b45565b90506001600160a01b0381166118435760405162461bcd60e51b815260040161017090614667565b61184b613a68565b60405163055392f960e11b81526001600160a01b03831690630aa725f29061187f9033908e908e908e908e90600401614115565b60a060405180830381600087803b15801561189957600080fd5b505af11580156118ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d19190613c74565b945090506118e1818d8585612ee2565b8051516020820151516040519197509550339060008051602061478a83398151915290611915908990899087908a90614236565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055509199909850909650945050505050565b600061195f612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906394c0c1e0906119af90889088908890600401614209565b60206040518083038186803b1580156119c757600080fd5b505afa1580156119db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ff9190613ca0565b611a1b5760405162461bcd60e51b8152600401610170906143df565b824210611a3a5760405162461bcd60e51b815260040161017090614283565b81611a575760405162461bcd60e51b815260040161017090614594565b60405163288b600960e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a22d802490611aa69089906004016141e1565b60206040518083038186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af69190613b45565b604051631312bc7b60e31b81529091506001600160a01b03821690639895e3d8906108449033908990899089906004016140a5565b600080611b36612db0565b83611b535760405162461bcd60e51b81526004016101709061461b565b85611b5d81612ebd565b611b675786611b89565b7f00000000000000000000000000000000000000000000000000000000000000005b965060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638e7cf7668b8b8b6040518463ffffffff1660e01b8152600401611bdd939291906141ea565b60206040518083038186803b158015611bf557600080fd5b505afa158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d9190613b45565b90506001600160a01b038116611c555760405162461bcd60e51b815260040161017090614667565b600087611c625788611c64565b895b90506000826001600160a01b0316630dd2cbb933848b8b6040518563ffffffff1660e01b8152600401611c9a94939291906140a5565b608060405180830381600087803b158015611cb457600080fd5b505af1158015611cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cec9190613c59565b9050600089611cfb5784611cfd565b8b5b9050611d12818360005b602002015186613024565b8915611d6d5781515160405133917f3af46289ed754c6821a8849534b8412a33bcd8387cb986f39e7e9937fb251cde91611d53919060009089908f90614236565b60405180910390a250515194506000935061112092505050565b81515160405133917f3af46289ed754c6821a8849534b8412a33bcd8387cb986f39e7e9937fb251cde91611da79160009189908f90614236565b60405180910390a25051516000805460ff60a01b198116600160a01b9182900460ff90811660001901169091021781559c909b509950505050505050505050565b6000611df2612db0565b6001600160a01b038316611e185760405162461bcd60e51b815260040161017090614493565b6001600160a01b038216611e3e5760405162461bcd60e51b815260040161017090614493565b604051631a209e5560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631a209e5590611e8a908690600401614053565b60206040518083038186803b158015611ea257600080fd5b505afa158015611eb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eda9190613ca0565b611ef65760405162461bcd60e51b8152600401610170906143df565b604051631a209e5560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631a209e5590611f42908590600401614053565b60206040518083038186803b158015611f5a57600080fd5b505afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f929190613ca0565b15611faf5760405162461bcd60e51b8152600401610170906145b9565b60405163473e7bb360e11b81526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638e7cf76690612002908890889088906004016141ea565b60206040518083038186803b15801561201a57600080fd5b505afa15801561202e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120529190613b45565b6001600160a01b0316146120785760405162461bcd60e51b8152600401610170906144e7565b60405163c6069e4560e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c6069e45906120c79088906004016141e1565b60206040518083038186803b1580156120df57600080fd5b505afa1580156120f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121179190613b45565b90506001600160a01b03811661213f5760405162461bcd60e51b815260040161017090614493565b6000846001600160a01b0316636c6f42396040518163ffffffff1660e01b815260040160206040518083038186803b15801561217a57600080fd5b505afa15801561218e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b29190613b45565b6001600160a01b031663beb9a9736040518163ffffffff1660e01b815260040160206040518083038186803b1580156121ea57600080fd5b505afa1580156121fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122229190613cbc565b604051631ad19d3160e01b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631ad19d31906122739084908a90600401614228565b60206040518083038186803b15801561228b57600080fd5b505afa15801561229f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c39190613ca0565b6122df5760405162461bcd60e51b8152600401610170906143b0565b60405163103fe89360e11b81526001600160a01b0383169063207fd1269061230d9088908890600401614067565b602060405180830381600087803b15801561232757600080fd5b505af115801561233b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235f9190613b45565b9250826001600160a01b0316846001600160a01b0316866001600160a01b03167fb18af3690cc6a832c9b2e802aab7a21111f4cfca5c2e4fcf614f6ea55b405f4a896040516123ae91906141e1565b60405180910390a450506000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559392505050565b60008060006123f1612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906394c0c1e090612441908b908b908b90600401614209565b60206040518083038186803b15801561245957600080fd5b505afa15801561246d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124919190613ca0565b6124ad5760405162461bcd60e51b8152600401610170906143df565b8542106124cc5760405162461bcd60e51b815260040161017090614283565b6001600160a01b0384166124f25760405162461bcd60e51b815260040161017090614493565b8461250f5760405162461bcd60e51b815260040161017090614594565b60405163288b600960e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a22d80249061255e908c906004016141e1565b60206040518083038186803b15801561257657600080fd5b505afa15801561258a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ae9190613b45565b90506000816001600160a01b03166319d515ec8a6040518263ffffffff1660e01b81526004016125de9190614053565b602060405180830381600087803b1580156125f857600080fd5b505af115801561260c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126309190613b45565b90506126c633836001600160a01b03166339f4e3368c8c6040518363ffffffff1660e01b8152600401612664929190614173565b60206040518083038186803b15801561267c57600080fd5b505afa158015612690573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b49190613b45565b6001600160a01b03841691908a6134aa565b6040516311e1c13360e31b81526001600160a01b03831690638f0e0998906126f8908c908c908c908c906004016141b6565b606060405180830381600087803b15801561271257600080fd5b505af1158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190613bc7565b6000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055919c909b50909950975050505050505050565b61278a612f07565b6001600160a01b0316336001600160a01b0316146127e1576040805162461bcd60e51b815260206004820152600f60248201526e4f4e4c595f474f5645524e414e434560881b604482015290519081900360640190fd5b6040516000906001600160a01b0383169084908381818185875af1925050503d806000811461282c576040519150601f19603f3d011682016040523d82523d6000602084013e612831565b606091505b5050905080612879576040805162461bcd60e51b815260206004820152600f60248201526e15d2551211149055d7d19052531151608a1b604482015290519081900360640190fd5b604080518481526001600160a01b038416602082015281517fec47e7ed86c86774d1a72c19f35c639911393fe7c1a34031fdbd260890da90de929181900390910190a1505050565b60006128cb612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906394c0c1e09061291b90879087908790600401614209565b60206040518083038186803b15801561293357600080fd5b505afa158015612947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296b9190613ca0565b6129875760405162461bcd60e51b8152600401610170906143df565b4282106129a65760405162461bcd60e51b815260040161017090614382565b60405163288b600960e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a22d8024906129f59088906004016141e1565b60206040518083038186803b158015612a0d57600080fd5b505afa158015612a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a459190613b45565b60405163bdc6c01560e01b81529091506001600160a01b0382169063bdc6c01590612a7890339088908890600401614081565b602060405180830381600087803b158015612a9257600080fd5b505af1158015612aa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aca9190613cbc565b6000805460001960ff600160a01b808404821692909201160260ff60a01b1990911617905595945050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000612b26612db0565b82612b435760405162461bcd60e51b81526004016101709061435c565b84612b4d81612ebd565b612b575785612b79565b7f00000000000000000000000000000000000000000000000000000000000000005b955060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638e7cf7668a8a8a6040518463ffffffff1660e01b8152600401612bcd939291906141ea565b60206040518083038186803b158015612be557600080fd5b505afa158015612bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1d9190613b45565b90506001600160a01b038116612c455760405162461bcd60e51b815260040161017090614667565b600086612c525782612c54565b885b9050600087612c635788612c65565b895b9050612c6f613a68565b60405163247d376f60e11b81526001600160a01b038516906348fa6ede90612ca190339086908d908d906004016140a5565b60a060405180830381600087803b158015612cbb57600080fd5b505af1158015612ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf39190613c74565b965090508815612d3857336001600160a01b031660008051602061478a833981519152896000878a604051612d2b9493929190614236565b60405180910390a2612d6f565b336001600160a01b031660008051602061478a83398151915260008a878a604051612d669493929190614236565b60405180910390a25b612d7b83826000611d07565b50506000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055509198975050505050505050565b612db8613504565b6001600160a01b0316636ec934da336040518263ffffffff1660e01b8152600401612de39190614053565b60206040518083038186803b158015612dfb57600080fd5b505afa158015612e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e339190613ca0565b15612e6b576000546002600160a01b90910460ff161115612e665760405162461bcd60e51b8152600401610170906142dd565b612e97565b600054600160a01b900460ff16600114612e975760405162461bcd60e51b8152600401610170906142dd565b60008054600160ff600160a01b808404821692909201160260ff60a01b19909116179055565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14919050565b612ef5838560005b602002015183613024565b612f0182856001612eea565b50505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b158015612f6257600080fd5b505afa158015612f76573d6000803e3d6000fd5b505050506040513d6020811015612f8c57600080fd5b5051905090565b50600190565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612feb908490613528565b505050565b600061301b6501000000000061301561300986866135d9565b64800000000090613632565b9061368c565b90505b92915050565b815161302f57612feb565b8160200151156132055761304283612ebd565b156131e65781516040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916323b872dd91613098918591309190600401614081565b602060405180830381600087803b1580156130b257600080fd5b505af11580156130c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ea9190613ca0565b508151604051632e1a7d4d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691632e1a7d4d9161313891906004016141e1565b600060405180830381600087803b15801561315257600080fd5b505af1158015613166573d6000803e3d6000fd5b505083516040516000935033925061317d90614050565b60006040518083038185875af1925050503d80600081146131ba576040519150601f19603f3d011682016040523d82523d6000602084013e6131bf565b606091505b50509050806131e05760405162461bcd60e51b81526004016101709061453f565b50613200565b8151613200906001600160a01b03851690839033906134aa565b612feb565b61320e83612ebd565b156133ea5781513410156132345760405162461bcd60e51b81526004016101709061450f565b81516000906132449034906136f3565b905080156132ca576000336001600160a01b03168260405161326590614050565b60006040518083038185875af1925050503d80600081146132a2576040519150601f19603f3d011682016040523d82523d6000602084013e6132a7565b606091505b50509050806132c85760405162461bcd60e51b81526004016101709061453f565b505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db084600001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561332957600080fd5b505af115801561333d573d6000803e3d6000fd5b5050855160405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016945063a9059cbb93506133919250869190600401614173565b602060405180830381600087803b1580156133ab57600080fd5b505af11580156133bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e39190613ca0565b5050612feb565b604051631a209e5560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631a209e5590613436908690600401614053565b60206040518083038186803b15801561344e57600080fd5b505afa158015613462573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134869190613ca0565b156134945761349483613750565b8151612feb906001600160a01b03851690339084905b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612f01908590613528565b7f000000000000000000000000000000000000000000000000000000000000000090565b600061357d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661384a9092919063ffffffff16565b805190915015612feb5780806020019051602081101561359c57600080fd5b5051612feb5760405162461bcd60e51b815260040180806020018281038252602a8152602001806147aa602a913960400191505060405180910390fd5b6000826135e85750600061301e565b828202828482816135f557fe5b041461301b5760405162461bcd60e51b81526004018080602001828103825260218152602001806147696021913960400191505060405180910390fd5b60008282018381101561301b576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008082116136e2576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816136eb57fe5b049392505050565b60008282111561374a576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b604051636eb1769f60e11b81526000906001600160a01b0383169063dd62ed3e906137819033903090600401614067565b60206040518083038186803b15801561379957600080fd5b505afa1580156137ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d19190613cbc565b90506001600160ff1b0381106137e75750613847565b60405163f259cd2760e01b81526001600160a01b0383169063f259cd2790613813903390600401614053565b600060405180830381600087803b15801561382d57600080fd5b505af1158015613841573d6000803e3d6000fd5b50505050505b50565b60606138598484600085613863565b90505b9392505050565b6060824710156138a45760405162461bcd60e51b81526004018080602001828103825260268152602001806147436026913960400191505060405180910390fd5b6138ad856139be565b6138fe576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b6020831061393c5780518252601f19909201916020918201910161391d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461399e576040519150601f19603f3d011682016040523d82523d6000602084013e6139a3565b606091505b50915091506139b38282866139c4565b979650505050505050565b3b151590565b606083156139d357508161385c565b8251156139e35782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613a2d578181015183820152602001613a15565b50505050905090810190601f168015613a5a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60405180604001604052806002905b613a7f613a95565b815260200190600190039081613a775790505090565b604080518082019091526000808252602082015290565b600082601f830112613abc578081fd5b6040613ac7816146fb565b808486608087011115613ad8578485fd5b845b6002811015613b3957848289031215613af1578586fd5b845185810181811067ffffffffffffffff82111715613b0c57fe5b865282518152602080840151613b2181614734565b82820152908552939093019290840190600101613ada565b50909695505050505050565b600060208284031215613b56578081fd5b815161301b8161471f565b60008060408385031215613b73578081fd5b8235613b7e8161471f565b91506020830135613b8e8161471f565b809150509250929050565b60008060408385031215613bab578182fd5b8251613bb68161471f565b6020840151909250613b8e8161471f565b600080600060608486031215613bdb578081fd5b8351613be68161471f565b6020850151909350613bf78161471f565b80925050604084015190509250925092565b600080600080600060a08688031215613c20578081fd5b8535613c2b8161471f565b94506020860135613c3b8161471f565b94979496505050506040830135926060810135926080909101359150565b600060808284031215613c6a578081fd5b61301b8383613aac565b60008060a08385031215613c86578182fd5b613c908484613aac565b9150608083015190509250929050565b600060208284031215613cb1578081fd5b815161301b81614734565b600060208284031215613ccd578081fd5b5051919050565b600080600060608486031215613ce8578283fd5b833592506020840135613cfa8161471f565b91506040840135613d0a8161471f565b809150509250925092565b60008060008060008060c08789031215613d2d578384fd5b863595506020870135613d3f8161471f565b94506040870135613d4f8161471f565b93506060870135613d5f81614734565b9598949750929560808101359460a0909101359350915050565b600080600080600060a08688031215613d90578283fd5b853594506020860135613da28161471f565b93506040860135613db28161471f565b94979396509394606081013594506080013592915050565b60008060008060008060c08789031215613de2578384fd5b863595506020870135613df48161471f565b94506040870135613e048161471f565b959894975094956060810135955060808101359460a0909101359350915050565b600080600080600080600060e0888a031215613e3f578485fd5b873596506020880135613e518161471f565b95506040880135613e618161471f565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080600060608486031215613e9d578081fd5b833592506020840135613eaf8161471f565b929592945050506040919091013590565b60008060008060808587031215613ed5578182fd5b843593506020850135613ee78161471f565b9250604085013591506060850135613efe8161471f565b939692955090935050565b60008060008060808587031215613f1e578182fd5b843593506020850135613f308161471f565b93969395505050506040820135916060013590565b600080600080600060a08688031215613f5c578283fd5b853594506020860135613f6e8161471f565b935060408601359250606086013591506080860135613f8c8161471f565b809150509295509295909350565b600080600080600060a08688031215613fb1578283fd5b85359450602086013593506040860135613db28161471f565b600080600060608486031215613fde578081fd5b8335613fe98161471f565b9250602084013591506040840135613d0a8161471f565b60008060408385031215614012578182fd5b823591506020830135613b8e8161471f565b60008060a08385031215614036578182fd5b825191506140478460208501613aac565b90509250929050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b6001600160a01b039586168152938516602085015260408401929092526060830152909116608082015260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9283526001600160a01b03919091166020830152604082015260600190565b918252602082015260400190565b93845260208401929092526001600160a01b03166040830152606082015260800190565b6020808252600f908201526e16915493d7d3d55517d05353d55395608a1b604082015260600190565b602080825260169082015275165251531117d0d3d395149050d517d156141254915160521b604082015260600190565b60208082526010908201526f464f5247455f4e4f545f45584953545360801b604082015260600190565b6020808252600e908201526d14915153951490539517d0d0531360921b604082015260600190565b6020808252600e908201526d1253959053125117d3505492d15560921b604082015260600190565b602080825260159082015274494e56414c49445f544f4b454e5f414d4f554e545360581b604082015260600190565b6020808252600c908201526b5a45524f5f414d4f554e545360a01b604082015260600190565b6020808252601490820152734d5553545f42455f41465445525f45585049525960601b604082015260600190565b602080825260159082015274494e56414c49445f464f5247455f464143544f525960581b604082015260600190565b6020808252600a90820152691253959053125117d65560b21b604082015260600190565b6020808252601490820152731253959053125117d513d2d15397d05353d5539560621b604082015260600190565b60208082526018908201527f4455504c49434154455f5949454c445f434f4e54524143540000000000000000604082015260600190565b6020808252601190820152701253959053125117d65517d05353d55395607a1b604082015260600190565b6020808252600c908201526b5a45524f5f4144445245535360a01b604082015260600190565b602080825260149082015273494e56414c49445f52454e4557414c5f5241544560601b604082015260600190565b6020808252600e908201526d11561254d5115117d3505492d15560921b604082015260600190565b602080825260169082015275125394d551919250d1539517d1551217d05353d5539560521b604082015260600190565b6020808252600f908201526e1514905394d1915497d19052531151608a1b604082015260600190565b602080825260129082015271494e56414c49445f59545f414d4f554e545360701b604082015260600190565b6020808252600b908201526a16915493d7d05353d5539560aa1b604082015260600190565b60208082526017908201527f59545f51554f54455f504149525f464f5242494444454e000000000000000000604082015260600190565b60208082526011908201527008aa890be9c9ea8be8ca49e9abeae8aa89607b1b604082015260600190565b6020808252600a90820152692d22a927afa6282fa4a760b11b604082015260600190565b6020808252600e908201526d494e56414c49445f45585049525960901b604082015260600190565b60208082526010908201526f13505492d15517d393d517d193d5539160821b604082015260600190565b6020808252600e908201526d16915493d7d25397d05353d5539560921b604082015260600190565b94855260208501939093526001600160a01b039182166040850152166060830152608082015260a00190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff8111828210171561471757fe5b604052919050565b6001600160a01b038116811461384757600080fd5b801515811461384757600080fdfe416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77e37fea01e65dea7d589abafc4bd0d5282a09ddce3e9ea971ed3399d776a1a2965361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212209626ffd93186e1b8f8d1dca57ff67323512eb5b53bb896d8c2322bc538e936f664736f6c634300070600330000000000000000000000009b528bf0639fc31ae6d698c48d830873227741f1000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6

Deployed Bytecode

0x6080604052600436106101235760003560e01c806373d4a13a116100a0578063bd73897011610064578063bd73897014610375578063ce56c454146103a4578063d230566c146103c4578063d2e6d1c3146103e4578063e612b996146103f95761017b565b806373d4a13a146102de57806374f62c0d146102f35780637e6dbccf14610315578063825fedd214610335578063b7edadef146103555761017b565b80633ccdbb28116100e75780633ccdbb28146102385780633fc8cef3146102585780635697fae91461027a57806356c132cf146102ab578063640a06a8146102cb5761017b565b806309077c1f146101805780631251ae7c146101a9578063205b5fb7146101c957806339f46c31146101dc5780633a884f901461020a5761017b565b3661017b57336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101795760405162461bcd60e51b8152600401610170906145f0565b60405180910390fd5b005b600080fd5b61019361018e366004613c09565b61040c565b6040516101a091906141e1565b60405180910390f35b3480156101b557600080fd5b506101936101c4366004613ec0565b610686565b6101796101d7366004613d79565b6108c5565b3480156101e857600080fd5b506101fc6101f7366004613dca565b610b12565b6040516101a0929190614228565b34801561021657600080fd5b5061022a610225366004613e89565b610d54565b6040516101a0929190614067565b34801561024457600080fd5b50610179610253366004613fca565b611152565b34801561026457600080fd5b5061026d611262565b6040516101a09190614053565b34801561028657600080fd5b5061029a610295366004613f9a565b611286565b6040516101a09594939291906146b9565b3480156102b757600080fd5b506101936102c6366004613b61565b6112e9565b6101936102d9366004613c09565b61147b565b3480156102ea57600080fd5b5061026d6116ba565b610306610301366004613e25565b6116de565b6040516101a0939291906146e5565b34801561032157600080fd5b50610193610330366004613f09565b611955565b34801561034157600080fd5b506101fc610350366004613d15565b611b2b565b34801561036157600080fd5b5061026d610370366004613cd4565b611de8565b34801561038157600080fd5b50610395610390366004613f45565b6123e4565b6040516101a093929190614081565b3480156103b057600080fd5b506101796103bf366004614000565b612782565b3480156103d057600080fd5b506101936103df366004613e89565b6128c1565b3480156103f057600080fd5b5061026d612af8565b610193610407366004613d15565b612b1c565b6000610416612db0565b836104335760405162461bcd60e51b81526004016101709061425a565b858561043e82612ebd565b610448578761046a565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b975061047587612ebd565b61047f57866104a1565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b965060007f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b031663b4238f498a8a886040518463ffffffff1660e01b81526004016104f593929190614081565b60206040518083038186803b15801561050d57600080fd5b505afa158015610521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105459190613b45565b90506001600160a01b03811661056d5760405162461bcd60e51b815260040161017090614667565b610575613a68565b60405163055a7da960e21b81526001600160a01b03831690631569f6a4906105a7908d908b908e908e9060040161418c565b60a060405180830381600087803b1580156105c157600080fd5b505af11580156105d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f99190614024565b909550905061060a81858585612ee2565b336001600160a01b03167ff5fd10e802251a919c2bfd2cfc15e2526d3864c819e2b4dc346ca1ade0f516588b8b888c8760405161064b959493929190614143565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b1990911617905550909695505050505050565b6000610690612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d616906394c0c1e0906106e090889088908890600401614209565b60206040518083038186803b1580156106f857600080fd5b505afa15801561070c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107309190613ca0565b61074c5760405162461bcd60e51b8152600401610170906143df565b6001600160a01b0382166107725760405162461bcd60e51b815260040161017090614493565b60405163288b600960e21b81526000906001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6169063a22d8024906107c19089906004016141e1565b60206040518083038186803b1580156107d957600080fd5b505afa1580156107ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108119190613b45565b60405163097660b960e01b81529091506001600160a01b0382169063097660b99061084490869089908990600401614081565b602060405180830381600087803b15801561085e57600080fd5b505af1158015610872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108969190613cbc565b6000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559695505050505050565b6108cd612db0565b600082116108ed5760405162461bcd60e51b815260040161017090614468565b6000811161090d5760405162461bcd60e51b815260040161017090614403565b8261091781612ebd565b6109215783610943565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b935060007f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b0316638e7cf7668888886040518463ffffffff1660e01b8152600401610997939291906141ea565b60206040518083038186803b1580156109af57600080fd5b505afa1580156109c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e79190613b45565b90506001600160a01b038116610a0f5760405162461bcd60e51b815260040161017090614667565b610a17613a68565b60405163a6f319bb60e01b81526000906001600160a01b0384169063a6f319bb90610a4a9033908a908a906004016140ce565b60a060405180830381600087803b158015610a6457600080fd5b505af1158015610a78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9c9190613c74565b9092509050610aad82898686612ee2565b336001600160a01b031660008051602061478a83398151915287878685604051610ada9493929190614236565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b1990911617905550505050505050565b600080610b1d612db0565b84610b3a5760405162461bcd60e51b81526004016101709061461b565b85610b4481612ebd565b610b4e5786610b70565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b965060007f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b0316638e7cf7668b8b8b6040518463ffffffff1660e01b8152600401610bc4939291906141ea565b60206040518083038186803b158015610bdc57600080fd5b505afa158015610bf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c149190613b45565b90506001600160a01b038116610c3c5760405162461bcd60e51b815260040161017090614667565b60405163834c295560e01b81526000906001600160a01b0383169063834c295590610c719033908c908c908c906004016140ef565b608060405180830381600087803b158015610c8b57600080fd5b505af1158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc39190613c59565b9050610cd1818b8585612ee2565b805151602082015151604051919650945033907f3af46289ed754c6821a8849534b8412a33bcd8387cb986f39e7e9937fb251cde90610d17908890889087908e90614236565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055509097909650945050505050565b600080610d5f612db0565b6001600160a01b038416610d855760405162461bcd60e51b815260040161017090614493565b428311610da45760405162461bcd60e51b81526004016101709061463f565b7f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b031663e9e5f3cf6040518163ffffffff1660e01b815260040160206040518083038186803b158015610dfd57600080fd5b505afa158015610e11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e359190613cbc565b8381610e3d57fe5b0615610e5b5760405162461bcd60e51b81526004016101709061463f565b60405163288b600960e21b81526000906001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6169063a22d802490610eaa9089906004016141e1565b60206040518083038186803b158015610ec257600080fd5b505afa158015610ed6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610efa9190613b45565b90506001600160a01b038116610f225760405162461bcd60e51b8152600401610170906142b3565b604051631f019ead60e01b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d61690631f019ead90610f7290899089908990600401614209565b60206040518083038186803b158015610f8a57600080fd5b505afa158015610f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc29190613b45565b604051631771964d60e21b81529093506001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d61690635dc659349061101590899089908990600401614209565b60206040518083038186803b15801561102d57600080fd5b505afa158015611041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110659190613b45565b91506001600160a01b03831615801561108557506001600160a01b038216155b6110a15760405162461bcd60e51b815260040161017090614431565b6040516304c2fceb60e51b81526001600160a01b0382169063985f9d60906110cf9088908890600401614173565b6040805180830381600087803b1580156110e857600080fd5b505af11580156110fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111209190613b99565b6000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559097909650945050505050565b61115a612f07565b6001600160a01b0316336001600160a01b0316146111b1576040805162461bcd60e51b815260206004820152600f60248201526e4f4e4c595f474f5645524e414e434560881b604482015290519081900360640190fd5b6111ba83612f93565b6111ff576040805162461bcd60e51b81526020600482015260116024820152701513d2d15397d393d517d0531313d5d151607a1b604482015290519081900360640190fd5b6112136001600160a01b0384168284612f99565b604080516001600160a01b0380861682526020820185905283168183015290517f72cb8a894ddb372ceec3d2a7648d86f17d5a15caae0e986c53109b8a9a9385e69181900360600190a1505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000806000806000856000106112ae5760405162461bcd60e51b8152600401610170906144b9565b6112b98a898b6128c1565b94506112c58587612ff0565b93506112d48a898987336123e4565b969c959b509099509750939550919350505050565b60006112f3612db0565b6040516337649a6d60e11b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d61690636ec934da9061133f908690600401614053565b60206040518083038186803b15801561135757600080fd5b505afa15801561136b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138f9190613ca0565b6113ab5760405162461bcd60e51b815260040161017090614305565b6001600160a01b0382166113d15760405162461bcd60e51b815260040161017090614493565b604051633c12f35f60e21b81526001600160a01b0384169063f04bcd7c906113fd908590600401614053565b602060405180830381600087803b15801561141757600080fd5b505af115801561142b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144f9190613cbc565b6000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559392505050565b6000611485612db0565b836114a25760405162461bcd60e51b815260040161017090614691565b85856114ad82612ebd565b6114b757876114d9565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b97506114e487612ebd565b6114ee5786611510565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b965060007f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b031663b4238f498a8a886040518463ffffffff1660e01b815260040161156493929190614081565b60206040518083038186803b15801561157c57600080fd5b505afa158015611590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b49190613b45565b90506001600160a01b0381166115dc5760405162461bcd60e51b815260040161017090614667565b6115e4613a68565b604051637c2e4e7160e11b81526001600160a01b0383169063f85c9ce290611616908d908c908e908d9060040161418c565b60a060405180830381600087803b15801561163057600080fd5b505af1158015611644573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116689190614024565b909550905061167981858585612ee2565b336001600160a01b03167ff5fd10e802251a919c2bfd2cfc15e2526d3864c819e2b4dc346ca1ade0f516588b8b8b898760405161064b959493929190614143565b7f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d681565b60008060006116eb612db0565b86158015906116fa5750848710155b6117165760405162461bcd60e51b815260040161017090614568565b85158015906117255750838610155b6117415760405162461bcd60e51b81526004016101709061432d565b8761174b81612ebd565b6117555788611777565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b985060007f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b0316638e7cf7668d8d8d6040518463ffffffff1660e01b81526004016117cb939291906141ea565b60206040518083038186803b1580156117e357600080fd5b505afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b9190613b45565b90506001600160a01b0381166118435760405162461bcd60e51b815260040161017090614667565b61184b613a68565b60405163055392f960e11b81526001600160a01b03831690630aa725f29061187f9033908e908e908e908e90600401614115565b60a060405180830381600087803b15801561189957600080fd5b505af11580156118ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d19190613c74565b945090506118e1818d8585612ee2565b8051516020820151516040519197509550339060008051602061478a83398151915290611915908990899087908a90614236565b60405180910390a250506000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055509199909850909650945050505050565b600061195f612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d616906394c0c1e0906119af90889088908890600401614209565b60206040518083038186803b1580156119c757600080fd5b505afa1580156119db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ff9190613ca0565b611a1b5760405162461bcd60e51b8152600401610170906143df565b824210611a3a5760405162461bcd60e51b815260040161017090614283565b81611a575760405162461bcd60e51b815260040161017090614594565b60405163288b600960e21b81526000906001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6169063a22d802490611aa69089906004016141e1565b60206040518083038186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af69190613b45565b604051631312bc7b60e31b81529091506001600160a01b03821690639895e3d8906108449033908990899089906004016140a5565b600080611b36612db0565b83611b535760405162461bcd60e51b81526004016101709061461b565b85611b5d81612ebd565b611b675786611b89565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b965060007f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b0316638e7cf7668b8b8b6040518463ffffffff1660e01b8152600401611bdd939291906141ea565b60206040518083038186803b158015611bf557600080fd5b505afa158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d9190613b45565b90506001600160a01b038116611c555760405162461bcd60e51b815260040161017090614667565b600087611c625788611c64565b895b90506000826001600160a01b0316630dd2cbb933848b8b6040518563ffffffff1660e01b8152600401611c9a94939291906140a5565b608060405180830381600087803b158015611cb457600080fd5b505af1158015611cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cec9190613c59565b9050600089611cfb5784611cfd565b8b5b9050611d12818360005b602002015186613024565b8915611d6d5781515160405133917f3af46289ed754c6821a8849534b8412a33bcd8387cb986f39e7e9937fb251cde91611d53919060009089908f90614236565b60405180910390a250515194506000935061112092505050565b81515160405133917f3af46289ed754c6821a8849534b8412a33bcd8387cb986f39e7e9937fb251cde91611da79160009189908f90614236565b60405180910390a25051516000805460ff60a01b198116600160a01b9182900460ff90811660001901169091021781559c909b509950505050505050505050565b6000611df2612db0565b6001600160a01b038316611e185760405162461bcd60e51b815260040161017090614493565b6001600160a01b038216611e3e5760405162461bcd60e51b815260040161017090614493565b604051631a209e5560e01b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d61690631a209e5590611e8a908690600401614053565b60206040518083038186803b158015611ea257600080fd5b505afa158015611eb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eda9190613ca0565b611ef65760405162461bcd60e51b8152600401610170906143df565b604051631a209e5560e01b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d61690631a209e5590611f42908590600401614053565b60206040518083038186803b158015611f5a57600080fd5b505afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f929190613ca0565b15611faf5760405162461bcd60e51b8152600401610170906145b9565b60405163473e7bb360e11b81526000907f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b031690638e7cf76690612002908890889088906004016141ea565b60206040518083038186803b15801561201a57600080fd5b505afa15801561202e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120529190613b45565b6001600160a01b0316146120785760405162461bcd60e51b8152600401610170906144e7565b60405163c6069e4560e01b81526000906001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6169063c6069e45906120c79088906004016141e1565b60206040518083038186803b1580156120df57600080fd5b505afa1580156120f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121179190613b45565b90506001600160a01b03811661213f5760405162461bcd60e51b815260040161017090614493565b6000846001600160a01b0316636c6f42396040518163ffffffff1660e01b815260040160206040518083038186803b15801561217a57600080fd5b505afa15801561218e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b29190613b45565b6001600160a01b031663beb9a9736040518163ffffffff1660e01b815260040160206040518083038186803b1580156121ea57600080fd5b505afa1580156121fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122229190613cbc565b604051631ad19d3160e01b81529091506001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d61690631ad19d31906122739084908a90600401614228565b60206040518083038186803b15801561228b57600080fd5b505afa15801561229f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c39190613ca0565b6122df5760405162461bcd60e51b8152600401610170906143b0565b60405163103fe89360e11b81526001600160a01b0383169063207fd1269061230d9088908890600401614067565b602060405180830381600087803b15801561232757600080fd5b505af115801561233b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235f9190613b45565b9250826001600160a01b0316846001600160a01b0316866001600160a01b03167fb18af3690cc6a832c9b2e802aab7a21111f4cfca5c2e4fcf614f6ea55b405f4a896040516123ae91906141e1565b60405180910390a450506000805460001960ff600160a01b808404821692909201160260ff60a01b199091161790559392505050565b60008060006123f1612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d616906394c0c1e090612441908b908b908b90600401614209565b60206040518083038186803b15801561245957600080fd5b505afa15801561246d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124919190613ca0565b6124ad5760405162461bcd60e51b8152600401610170906143df565b8542106124cc5760405162461bcd60e51b815260040161017090614283565b6001600160a01b0384166124f25760405162461bcd60e51b815260040161017090614493565b8461250f5760405162461bcd60e51b815260040161017090614594565b60405163288b600960e21b81526000906001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6169063a22d80249061255e908c906004016141e1565b60206040518083038186803b15801561257657600080fd5b505afa15801561258a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ae9190613b45565b90506000816001600160a01b03166319d515ec8a6040518263ffffffff1660e01b81526004016125de9190614053565b602060405180830381600087803b1580156125f857600080fd5b505af115801561260c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126309190613b45565b90506126c633836001600160a01b03166339f4e3368c8c6040518363ffffffff1660e01b8152600401612664929190614173565b60206040518083038186803b15801561267c57600080fd5b505afa158015612690573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b49190613b45565b6001600160a01b03841691908a6134aa565b6040516311e1c13360e31b81526001600160a01b03831690638f0e0998906126f8908c908c908c908c906004016141b6565b606060405180830381600087803b15801561271257600080fd5b505af1158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190613bc7565b6000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055919c909b50909950975050505050505050565b61278a612f07565b6001600160a01b0316336001600160a01b0316146127e1576040805162461bcd60e51b815260206004820152600f60248201526e4f4e4c595f474f5645524e414e434560881b604482015290519081900360640190fd5b6040516000906001600160a01b0383169084908381818185875af1925050503d806000811461282c576040519150601f19603f3d011682016040523d82523d6000602084013e612831565b606091505b5050905080612879576040805162461bcd60e51b815260206004820152600f60248201526e15d2551211149055d7d19052531151608a1b604482015290519081900360640190fd5b604080518481526001600160a01b038416602082015281517fec47e7ed86c86774d1a72c19f35c639911393fe7c1a34031fdbd260890da90de929181900390910190a1505050565b60006128cb612db0565b6040516304a6060f60e51b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d616906394c0c1e09061291b90879087908790600401614209565b60206040518083038186803b15801561293357600080fd5b505afa158015612947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296b9190613ca0565b6129875760405162461bcd60e51b8152600401610170906143df565b4282106129a65760405162461bcd60e51b815260040161017090614382565b60405163288b600960e21b81526000906001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6169063a22d8024906129f59088906004016141e1565b60206040518083038186803b158015612a0d57600080fd5b505afa158015612a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a459190613b45565b60405163bdc6c01560e01b81529091506001600160a01b0382169063bdc6c01590612a7890339088908890600401614081565b602060405180830381600087803b158015612a9257600080fd5b505af1158015612aa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aca9190613cbc565b6000805460001960ff600160a01b808404821692909201160260ff60a01b1990911617905595945050505050565b7f0000000000000000000000009b528bf0639fc31ae6d698c48d830873227741f181565b6000612b26612db0565b82612b435760405162461bcd60e51b81526004016101709061435c565b84612b4d81612ebd565b612b575785612b79565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b955060007f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d66001600160a01b0316638e7cf7668a8a8a6040518463ffffffff1660e01b8152600401612bcd939291906141ea565b60206040518083038186803b158015612be557600080fd5b505afa158015612bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1d9190613b45565b90506001600160a01b038116612c455760405162461bcd60e51b815260040161017090614667565b600086612c525782612c54565b885b9050600087612c635788612c65565b895b9050612c6f613a68565b60405163247d376f60e11b81526001600160a01b038516906348fa6ede90612ca190339086908d908d906004016140a5565b60a060405180830381600087803b158015612cbb57600080fd5b505af1158015612ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf39190613c74565b965090508815612d3857336001600160a01b031660008051602061478a833981519152896000878a604051612d2b9493929190614236565b60405180910390a2612d6f565b336001600160a01b031660008051602061478a83398151915260008a878a604051612d669493929190614236565b60405180910390a25b612d7b83826000611d07565b50506000805460001960ff600160a01b808404821692909201160260ff60a01b19909116179055509198975050505050505050565b612db8613504565b6001600160a01b0316636ec934da336040518263ffffffff1660e01b8152600401612de39190614053565b60206040518083038186803b158015612dfb57600080fd5b505afa158015612e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e339190613ca0565b15612e6b576000546002600160a01b90910460ff161115612e665760405162461bcd60e51b8152600401610170906142dd565b612e97565b600054600160a01b900460ff16600114612e975760405162461bcd60e51b8152600401610170906142dd565b60008054600160ff600160a01b808404821692909201160260ff60a01b19909116179055565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14919050565b612ef5838560005b602002015183613024565b612f0182856001612eea565b50505050565b60007f0000000000000000000000009b528bf0639fc31ae6d698c48d830873227741f16001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b158015612f6257600080fd5b505afa158015612f76573d6000803e3d6000fd5b505050506040513d6020811015612f8c57600080fd5b5051905090565b50600190565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612feb908490613528565b505050565b600061301b6501000000000061301561300986866135d9565b64800000000090613632565b9061368c565b90505b92915050565b815161302f57612feb565b8160200151156132055761304283612ebd565b156131e65781516040516323b872dd60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216916323b872dd91613098918591309190600401614081565b602060405180830381600087803b1580156130b257600080fd5b505af11580156130c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ea9190613ca0565b508151604051632e1a7d4d60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21691632e1a7d4d9161313891906004016141e1565b600060405180830381600087803b15801561315257600080fd5b505af1158015613166573d6000803e3d6000fd5b505083516040516000935033925061317d90614050565b60006040518083038185875af1925050503d80600081146131ba576040519150601f19603f3d011682016040523d82523d6000602084013e6131bf565b606091505b50509050806131e05760405162461bcd60e51b81526004016101709061453f565b50613200565b8151613200906001600160a01b03851690839033906134aa565b612feb565b61320e83612ebd565b156133ea5781513410156132345760405162461bcd60e51b81526004016101709061450f565b81516000906132449034906136f3565b905080156132ca576000336001600160a01b03168260405161326590614050565b60006040518083038185875af1925050503d80600081146132a2576040519150601f19603f3d011682016040523d82523d6000602084013e6132a7565b606091505b50509050806132c85760405162461bcd60e51b81526004016101709061453f565b505b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db084600001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561332957600080fd5b505af115801561333d573d6000803e3d6000fd5b5050855160405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216945063a9059cbb93506133919250869190600401614173565b602060405180830381600087803b1580156133ab57600080fd5b505af11580156133bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e39190613ca0565b5050612feb565b604051631a209e5560e01b81526001600160a01b037f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d61690631a209e5590613436908690600401614053565b60206040518083038186803b15801561344e57600080fd5b505afa158015613462573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134869190613ca0565b156134945761349483613750565b8151612feb906001600160a01b03851690339084905b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612f01908590613528565b7f000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d690565b600061357d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661384a9092919063ffffffff16565b805190915015612feb5780806020019051602081101561359c57600080fd5b5051612feb5760405162461bcd60e51b815260040180806020018281038252602a8152602001806147aa602a913960400191505060405180910390fd5b6000826135e85750600061301e565b828202828482816135f557fe5b041461301b5760405162461bcd60e51b81526004018080602001828103825260218152602001806147696021913960400191505060405180910390fd5b60008282018381101561301b576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008082116136e2576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816136eb57fe5b049392505050565b60008282111561374a576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b604051636eb1769f60e11b81526000906001600160a01b0383169063dd62ed3e906137819033903090600401614067565b60206040518083038186803b15801561379957600080fd5b505afa1580156137ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d19190613cbc565b90506001600160ff1b0381106137e75750613847565b60405163f259cd2760e01b81526001600160a01b0383169063f259cd2790613813903390600401614053565b600060405180830381600087803b15801561382d57600080fd5b505af1158015613841573d6000803e3d6000fd5b50505050505b50565b60606138598484600085613863565b90505b9392505050565b6060824710156138a45760405162461bcd60e51b81526004018080602001828103825260268152602001806147436026913960400191505060405180910390fd5b6138ad856139be565b6138fe576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b6020831061393c5780518252601f19909201916020918201910161391d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461399e576040519150601f19603f3d011682016040523d82523d6000602084013e6139a3565b606091505b50915091506139b38282866139c4565b979650505050505050565b3b151590565b606083156139d357508161385c565b8251156139e35782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613a2d578181015183820152602001613a15565b50505050905090810190601f168015613a5a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60405180604001604052806002905b613a7f613a95565b815260200190600190039081613a775790505090565b604080518082019091526000808252602082015290565b600082601f830112613abc578081fd5b6040613ac7816146fb565b808486608087011115613ad8578485fd5b845b6002811015613b3957848289031215613af1578586fd5b845185810181811067ffffffffffffffff82111715613b0c57fe5b865282518152602080840151613b2181614734565b82820152908552939093019290840190600101613ada565b50909695505050505050565b600060208284031215613b56578081fd5b815161301b8161471f565b60008060408385031215613b73578081fd5b8235613b7e8161471f565b91506020830135613b8e8161471f565b809150509250929050565b60008060408385031215613bab578182fd5b8251613bb68161471f565b6020840151909250613b8e8161471f565b600080600060608486031215613bdb578081fd5b8351613be68161471f565b6020850151909350613bf78161471f565b80925050604084015190509250925092565b600080600080600060a08688031215613c20578081fd5b8535613c2b8161471f565b94506020860135613c3b8161471f565b94979496505050506040830135926060810135926080909101359150565b600060808284031215613c6a578081fd5b61301b8383613aac565b60008060a08385031215613c86578182fd5b613c908484613aac565b9150608083015190509250929050565b600060208284031215613cb1578081fd5b815161301b81614734565b600060208284031215613ccd578081fd5b5051919050565b600080600060608486031215613ce8578283fd5b833592506020840135613cfa8161471f565b91506040840135613d0a8161471f565b809150509250925092565b60008060008060008060c08789031215613d2d578384fd5b863595506020870135613d3f8161471f565b94506040870135613d4f8161471f565b93506060870135613d5f81614734565b9598949750929560808101359460a0909101359350915050565b600080600080600060a08688031215613d90578283fd5b853594506020860135613da28161471f565b93506040860135613db28161471f565b94979396509394606081013594506080013592915050565b60008060008060008060c08789031215613de2578384fd5b863595506020870135613df48161471f565b94506040870135613e048161471f565b959894975094956060810135955060808101359460a0909101359350915050565b600080600080600080600060e0888a031215613e3f578485fd5b873596506020880135613e518161471f565b95506040880135613e618161471f565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080600060608486031215613e9d578081fd5b833592506020840135613eaf8161471f565b929592945050506040919091013590565b60008060008060808587031215613ed5578182fd5b843593506020850135613ee78161471f565b9250604085013591506060850135613efe8161471f565b939692955090935050565b60008060008060808587031215613f1e578182fd5b843593506020850135613f308161471f565b93969395505050506040820135916060013590565b600080600080600060a08688031215613f5c578283fd5b853594506020860135613f6e8161471f565b935060408601359250606086013591506080860135613f8c8161471f565b809150509295509295909350565b600080600080600060a08688031215613fb1578283fd5b85359450602086013593506040860135613db28161471f565b600080600060608486031215613fde578081fd5b8335613fe98161471f565b9250602084013591506040840135613d0a8161471f565b60008060408385031215614012578182fd5b823591506020830135613b8e8161471f565b60008060a08385031215614036578182fd5b825191506140478460208501613aac565b90509250929050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b6001600160a01b039586168152938516602085015260408401929092526060830152909116608082015260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9283526001600160a01b03919091166020830152604082015260600190565b918252602082015260400190565b93845260208401929092526001600160a01b03166040830152606082015260800190565b6020808252600f908201526e16915493d7d3d55517d05353d55395608a1b604082015260600190565b602080825260169082015275165251531117d0d3d395149050d517d156141254915160521b604082015260600190565b60208082526010908201526f464f5247455f4e4f545f45584953545360801b604082015260600190565b6020808252600e908201526d14915153951490539517d0d0531360921b604082015260600190565b6020808252600e908201526d1253959053125117d3505492d15560921b604082015260600190565b602080825260159082015274494e56414c49445f544f4b454e5f414d4f554e545360581b604082015260600190565b6020808252600c908201526b5a45524f5f414d4f554e545360a01b604082015260600190565b6020808252601490820152734d5553545f42455f41465445525f45585049525960601b604082015260600190565b602080825260159082015274494e56414c49445f464f5247455f464143544f525960581b604082015260600190565b6020808252600a90820152691253959053125117d65560b21b604082015260600190565b6020808252601490820152731253959053125117d513d2d15397d05353d5539560621b604082015260600190565b60208082526018908201527f4455504c49434154455f5949454c445f434f4e54524143540000000000000000604082015260600190565b6020808252601190820152701253959053125117d65517d05353d55395607a1b604082015260600190565b6020808252600c908201526b5a45524f5f4144445245535360a01b604082015260600190565b602080825260149082015273494e56414c49445f52454e4557414c5f5241544560601b604082015260600190565b6020808252600e908201526d11561254d5115117d3505492d15560921b604082015260600190565b602080825260169082015275125394d551919250d1539517d1551217d05353d5539560521b604082015260600190565b6020808252600f908201526e1514905394d1915497d19052531151608a1b604082015260600190565b602080825260129082015271494e56414c49445f59545f414d4f554e545360701b604082015260600190565b6020808252600b908201526a16915493d7d05353d5539560aa1b604082015260600190565b60208082526017908201527f59545f51554f54455f504149525f464f5242494444454e000000000000000000604082015260600190565b60208082526011908201527008aa890be9c9ea8be8ca49e9abeae8aa89607b1b604082015260600190565b6020808252600a90820152692d22a927afa6282fa4a760b11b604082015260600190565b6020808252600e908201526d494e56414c49445f45585049525960901b604082015260600190565b60208082526010908201526f13505492d15517d393d517d193d5539160821b604082015260600190565b6020808252600e908201526d16915493d7d25397d05353d5539560921b604082015260600190565b94855260208501939093526001600160a01b039182166040850152166060830152608082015260a00190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff8111828210171561471757fe5b604052919050565b6001600160a01b038116811461384757600080fd5b801515811461384757600080fdfe416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77e37fea01e65dea7d589abafc4bd0d5282a09ddce3e9ea971ed3399d776a1a2965361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212209626ffd93186e1b8f8d1dca57ff67323512eb5b53bb896d8c2322bc538e936f664736f6c63430007060033

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

0000000000000000000000009b528bf0639fc31ae6d698c48d830873227741f1000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6

-----Decoded View---------------
Arg [0] : _governanceManager (address): 0x9b528BF0639fC31Ae6D698c48D830873227741F1
Arg [1] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _data (address): 0xE8A6916576832AA5504092C1cCCC46E3bB9491d6

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000009b528bf0639fc31ae6d698c48d830873227741f1
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 000000000000000000000000e8a6916576832aa5504092c1cccc46e3bb9491d6


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.