ETH Price: $3,347.83 (-1.21%)

Token

ERC20 ***
 

Overview

Max Total Supply

80.30669239080257458 ERC20 ***

Holders

59

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
0.004603293857733576 ERC20 ***

Value
$0.00
0xddC60D163015CF5Ca1369D557A2ca1cC2de1F1e3
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Pool

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 17 : Pool.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.7.6;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "./libs/complifi/tokens/IERC20Metadata.sol";
import "./libs/complifi/tokens/EIP20NonStandardInterface.sol";
import "./libs/complifi/tokens/TokenMetadataGenerator.sol";

import "./Token.sol";
import "./Math.sol";
import "./repricers/IRepricer.sol";
import "./IDynamicFee.sol";
import "./IVault.sol";

contract Pool is Ownable, Pausable, Bronze, Token, Math, TokenMetadataGenerator {

    struct Record {
        uint leverage;
        uint balance;
    }

    event LOG_SWAP(
        address indexed caller,
        address indexed tokenIn,
        address indexed tokenOut,
        uint256         tokenAmountIn,
        uint256         tokenAmountOut,
        uint256         fee,
        uint256         tokenBalanceIn,
        uint256         tokenBalanceOut,
        uint256         tokenLeverageIn,
        uint256         tokenLeverageOut
    );

    event LOG_JOIN(
        address indexed caller,
        address indexed tokenIn,
        uint256         tokenAmountIn
    );

    event LOG_EXIT(
        address indexed caller,
        address indexed tokenOut,
        uint256         tokenAmountOut
    );

    event LOG_REPRICE(
        uint256         repricingBlock,
        uint256         balancePrimary,
        uint256         balanceComplement,
        uint256         leveragePrimary,
        uint256         leverageComplement,
        uint256         newLeveragePrimary,
        uint256         newLeverageComplement,
        int256          estPricePrimary,
        int256          estPriceComplement,
        int256          liveUnderlingValue
    );

    event LOG_CALL(
        bytes4  indexed sig,
        address indexed caller,
        bytes           data
    ) anonymous;

    modifier _logs_() {
        emit LOG_CALL(msg.sig, msg.sender, msg.data);
        _;
    }

    modifier _lock_() {
        requireLock();
        _mutex = true;
        _;
        _mutex = false;
    }

    modifier _viewlock_() {
        requireLock();
        _;
    }

    modifier onlyFinalized() {
        require(_finalized, "NOT_FINALIZED");
        _;
    }

    modifier onlyLiveDerivative() {
        require(
            block.timestamp < derivativeVault.settleTime(),
            "SETTLED"
        );
        _;
    }

    function requireLock() internal view
    {
        require(!_mutex, "REENTRY");
    }

    bool private _mutex;

    address private controller; // has CONTROL role

    // `finalize` sets `PUBLIC can SWAP`, `PUBLIC can JOIN`
    bool private _finalized;

    uint public constant BOUND_TOKENS  = 2;
    address[BOUND_TOKENS] private _tokens;
    mapping(address => Record) internal _records;

    uint public repricingBlock;

    uint public baseFee;
    uint public feeAmp;
    uint public maxFee;

    uint public pMin;
    uint public qMin;
    uint public exposureLimit;
    uint public volatility;

    IVault public derivativeVault;
    IDynamicFee public dynamicFee;
    IRepricer public repricer;

    constructor(
        address _derivativeVault,
        address _dynamicFee,
        address _repricer,
        uint _baseFee,
        uint _maxFee,
        uint _feeAmp,
        address _controller
    )
        public
    {
        require(_derivativeVault != address(0), "NOT_D_VAULT");
        derivativeVault = IVault(_derivativeVault);

        require(_dynamicFee != address(0), "NOT_FEE");
        dynamicFee = IDynamicFee(_dynamicFee);

        require(_repricer != address(0), "NOT_REPRICER");
        repricer = IRepricer(_repricer);

        baseFee = _baseFee;
        feeAmp = _feeAmp;
        maxFee = _maxFee;

        require(_controller != address(0), "NOT_CONTROLLER");
        controller = _controller;

        string memory settlementDate = formatDate(derivativeVault.settleTime());

        setName(makeTokenName(derivativeVault.derivativeSpecification().name(), settlementDate, " LP"));
        setSymbol(makeTokenSymbol(derivativeVault.derivativeSpecification().symbol(), settlementDate, "-LP"));
    }

    function pause() external onlyOwner
    {
        _pause();
    }
    function unpause() external onlyOwner
    {
        _unpause();
    }

    function isFinalized()
        external view
        returns (bool)
    {
        return _finalized;
    }

    function getTokens()
        external view _viewlock_
        returns (address[BOUND_TOKENS] memory tokens)
    {
        return _tokens;
    }

    function getLeverage(address token)
        external view
        _viewlock_
        returns (uint)
    {

        return _records[token].leverage;
    }

    function getBalance(address token)
        external view
        _viewlock_
        returns (uint)
    {

        return _records[token].balance;
    }

    function finalize(
        uint _primaryBalance,
        uint _primaryLeverage,
        uint _complementBalance,
        uint _complementLeverage,
        uint _exposureLimit,
        uint _volatility,
        uint _pMin,
        uint _qMin
    )
        external
        _logs_
        _lock_
        onlyLiveDerivative
    {
        require(!_finalized, "IS_FINALIZED");
        require(msg.sender == controller, "NOT_CONTROLLER");

        require(_primaryBalance == _complementBalance, "NOT_SYMMETRIC");

        pMin = _pMin;
        qMin = _qMin;
        exposureLimit = _exposureLimit;
        volatility = _volatility;

        _finalized = true;

        bind(0, address(derivativeVault.primaryToken()), _primaryBalance, _primaryLeverage);
        bind(1, address(derivativeVault.complementToken()), _complementBalance, _complementLeverage);

        uint initPoolSupply = getDerivativeDenomination() * _primaryBalance;

        uint collateralDecimals = uint(IERC20Metadata(address(derivativeVault.collateralToken())).decimals());
        if(collateralDecimals >= 0 && collateralDecimals < 18) {
            initPoolSupply = initPoolSupply * (10 ** (18 - collateralDecimals));
        }

        _mintPoolShare(initPoolSupply);
        _pushPoolShare(msg.sender, initPoolSupply);
    }

    function bind(uint index, address token, uint balance, uint leverage)
    internal
    {
        require(balance >= qMin, "MIN_BALANCE");
        require(leverage > 0, "ZERO_LEVERAGE");

        _records[token] = Record({
            leverage: leverage,
            balance: balance
        });

        _tokens[index] = token;

        _pullUnderlying(token, msg.sender, balance);
    }

    function joinPool(uint poolAmountOut, uint[2] calldata maxAmountsIn)
        external
        _logs_
        _lock_
        onlyFinalized
    {

        uint poolTotal = totalSupply();
        uint ratio = div(poolAmountOut, poolTotal);
        require(ratio != 0, "MATH_APPROX");

        for (uint i = 0; i < BOUND_TOKENS; i++) {
            address token = _tokens[i];
            uint bal = _records[token].balance;
            require(bal > 0, "NO_BALANCE");
            uint tokenAmountIn = mul(ratio, bal);
            require(tokenAmountIn <= maxAmountsIn[i], "LIMIT_IN");
            _records[token].balance = add(_records[token].balance, tokenAmountIn);
            emit LOG_JOIN(msg.sender, token, tokenAmountIn);
            _pullUnderlying(token, msg.sender, tokenAmountIn);
        }

        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOut);
    }

    function exitPool(uint poolAmountIn, uint[2] calldata minAmountsOut)
        external
        _logs_
        _lock_
        onlyFinalized
    {

        uint poolTotal = totalSupply();
        uint ratio = div(poolAmountIn, poolTotal);
        require(ratio != 0, "MATH_APPROX");

        _pullPoolShare(msg.sender, poolAmountIn);
        _burnPoolShare(poolAmountIn);

        for (uint i = 0; i < BOUND_TOKENS; i++) {
            address token = _tokens[i];
            uint bal = _records[token].balance;
            require(bal > 0, "NO_BALANCE");
            uint tokenAmountOut = mul(ratio, bal);
            require(tokenAmountOut >= minAmountsOut[i], "LIMIT_OUT");
            _records[token].balance = sub(_records[token].balance, tokenAmountOut);
            emit LOG_EXIT(msg.sender, token, tokenAmountOut);
            _pushUnderlying(token, msg.sender, tokenAmountOut);
        }
    }

    function reprice()
        internal virtual
    {
        if(repricingBlock == block.number) return;
        repricingBlock = block.number;

        Record storage primaryRecord = _records[_getPrimaryDerivativeAddress()];
        Record storage complementRecord = _records[_getComplementDerivativeAddress()];

        uint256[2] memory primaryParams = [primaryRecord.balance, primaryRecord.leverage];
        uint256[2] memory complementParams = [complementRecord.balance, complementRecord.leverage];

        (
            uint newPrimaryLeverage,
            uint newComplementLeverage,
            int estPricePrimary,
            int estPriceComplement
        ) = repricer.reprice(
            pMin,
            int(volatility),
            derivativeVault,
            primaryParams,
            complementParams,
            derivativeVault.underlyingStarts(0)
        );

        emit LOG_REPRICE(
            repricingBlock,
            primaryParams[0],
            complementParams[0],
            primaryParams[1],
            complementParams[1],
            newPrimaryLeverage,
            newComplementLeverage,
            estPricePrimary,
            estPriceComplement,
            derivativeVault.underlyingStarts(0)
        );

        primaryRecord.leverage = newPrimaryLeverage;
        complementRecord.leverage = newComplementLeverage;
    }

    function calcFee(
        Record memory inRecord,
        uint tokenAmountIn,
        Record memory outRecord,
        uint tokenAmountOut
    )
    internal
    returns (uint fee, int expStart)
    {
        int ifee;
        (ifee, expStart) = dynamicFee.calc(
            [int(inRecord.balance), int(inRecord.leverage), int(tokenAmountIn)],
            [int(outRecord.balance), int(outRecord.leverage), int(tokenAmountOut)],
            int(baseFee),
            int(feeAmp),
            int(maxFee)
        );
        require(ifee > 0, "BAD_FEE");
        fee = uint(ifee);
    }

    function calcExpStart(
        int _inBalance,
        int _outBalance
    )
    internal pure
    returns(int) {
        return (_inBalance - _outBalance) * iBONE / (_inBalance + _outBalance);
    }

    function performSwap(
        address tokenIn,
        uint tokenAmountIn,
        address tokenOut,
        uint tokenAmountOut,
        uint spotPriceBefore,
        uint fee
    )
    internal returns(uint spotPriceAfter)
    {
        Record storage inRecord = _records[tokenIn];
        Record storage outRecord = _records[tokenOut];

        requireBoundaryConditions(inRecord, tokenAmountIn, outRecord, tokenAmountOut);

        updateLeverages(inRecord, tokenAmountIn, outRecord, tokenAmountOut);

        inRecord.balance = add(inRecord.balance, tokenAmountIn);
        outRecord.balance = sub(outRecord.balance, tokenAmountOut);

        spotPriceAfter = calcSpotPrice(
            getLeveragedBalance(inRecord),
            getLeveragedBalance(outRecord),
            dynamicFee.calcSpotFee(
                calcExpStart(
                    int(inRecord.balance),
                    int(outRecord.balance)
                ),
                baseFee,
                feeAmp,
                maxFee
            )
        );

        require(spotPriceAfter >= spotPriceBefore, "MATH_APPROX");
        require(spotPriceBefore <= div(tokenAmountIn, tokenAmountOut), "MATH_APPROX_OTHER");

        emit LOG_SWAP(
            msg.sender,
            tokenIn,
            tokenOut,
            tokenAmountIn,
            tokenAmountOut,
            fee,
            inRecord.balance,
            outRecord.balance,
            inRecord.leverage,
            outRecord.leverage
        );

        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);
    }

    function swapExactAmountIn(
        address tokenIn,
        uint tokenAmountIn,
        address tokenOut,
        uint minAmountOut
    )
        external
        _logs_
        _lock_
        whenNotPaused
        onlyFinalized
        onlyLiveDerivative
        returns (uint tokenAmountOut, uint spotPriceAfter)
    {

        require(tokenIn != tokenOut, "SAME_TOKEN");
        require(tokenAmountIn >= qMin, "MIN_TOKEN_IN");

        reprice();

        Record memory inRecord = _records[tokenIn];
        Record memory outRecord = _records[tokenOut];

        require(tokenAmountIn <= mul(min(getLeveragedBalance(inRecord), inRecord.balance), MAX_IN_RATIO), "MAX_IN_RATIO");

        tokenAmountOut = calcOutGivenIn(
            getLeveragedBalance(inRecord),
            getLeveragedBalance(outRecord),
            tokenAmountIn,
            0
        );

        uint fee;
        int expStart;
        (fee, expStart) = calcFee(
            inRecord,
            tokenAmountIn,
            outRecord,
            tokenAmountOut
        );

        uint spotPriceBefore = calcSpotPrice(
                                    getLeveragedBalance(inRecord),
                                    getLeveragedBalance(outRecord),
                                    dynamicFee.calcSpotFee(expStart, baseFee, feeAmp, maxFee)
                                );

        tokenAmountOut = calcOutGivenIn(
                            getLeveragedBalance(inRecord),
                            getLeveragedBalance(outRecord),
                            tokenAmountIn,
                            fee
                        );
        require(tokenAmountOut >= minAmountOut, "LIMIT_OUT");

        spotPriceAfter = performSwap(
            tokenIn,
            tokenAmountIn,
            tokenOut,
            tokenAmountOut,
            spotPriceBefore,
            fee
        );
    }

    // Method temporary is not available for external usage.
    function swapExactAmountOut(
        address tokenIn,
        uint maxAmountIn,
        address tokenOut,
        uint tokenAmountOut
    )
        private
        _logs_
        _lock_
        whenNotPaused
        onlyFinalized
        onlyLiveDerivative
        returns (uint tokenAmountIn, uint spotPriceAfter)
    {
        require(tokenIn != tokenOut, "SAME_TOKEN");
        require(tokenAmountOut >= qMin, "MIN_TOKEN_OUT");

        reprice();

        Record memory inRecord = _records[tokenIn];
        Record memory outRecord = _records[tokenOut];

        require(tokenAmountOut <= mul(min(getLeveragedBalance(outRecord), outRecord.balance), MAX_OUT_RATIO), "MAX_OUT_RATIO");

        tokenAmountIn = calcInGivenOut(
            getLeveragedBalance(inRecord),
            getLeveragedBalance(outRecord),
            tokenAmountOut,
            0
        );

        uint fee;
        int expStart;
        (fee, expStart) = calcFee(
            inRecord,
            tokenAmountIn,
            outRecord,
            tokenAmountOut
        );

        uint spotPriceBefore = calcSpotPrice(
                                    getLeveragedBalance(inRecord),
                                    getLeveragedBalance(outRecord),
                                    dynamicFee.calcSpotFee(expStart, baseFee, feeAmp, maxFee)
                                );

        tokenAmountIn = calcInGivenOut(
                            getLeveragedBalance(inRecord),
                            getLeveragedBalance(outRecord),
                            tokenAmountOut,
                            fee
                        );

        require(tokenAmountIn <= maxAmountIn, "LIMIT_IN");

        spotPriceAfter = performSwap(
            tokenIn,
            tokenAmountIn,
            tokenOut,
            tokenAmountOut,
            spotPriceBefore,
            fee
        );
    }

    function getLeveragedBalance(
        Record memory r
    )
    internal pure
    returns(uint)
    {
        return mul(r.balance, r.leverage);
    }

    function requireBoundaryConditions(
        Record storage inToken,
        uint tokenAmountIn,
        Record storage outToken,
        uint tokenAmountOut
    )
    internal view
    {

        require( sub(getLeveragedBalance(outToken), tokenAmountOut) > qMin, "BOUNDARY_LEVERAGED");
        require( sub(outToken.balance, tokenAmountOut) > qMin, "BOUNDARY_NON_LEVERAGED");

        uint denomination = getDerivativeDenomination() * BONE;
        uint lowerBound = div(pMin, sub(denomination, pMin));
        uint upperBound = div(sub(denomination, pMin), pMin);
        uint value = div(add(getLeveragedBalance(inToken), tokenAmountIn), sub(getLeveragedBalance(outToken), tokenAmountOut));

        require(lowerBound < value, "BOUNDARY_LOWER");
        require(value < upperBound, "BOUNDARY_UPPER");

        uint numerator;
        (numerator,) = subSign(add(add(inToken.balance, tokenAmountIn), tokenAmountOut), outToken.balance);

        uint denominator = sub(add(add(inToken.balance, tokenAmountIn), outToken.balance), tokenAmountOut);
        require(div(numerator, denominator) < exposureLimit, "BOUNDARY_EXPOSURE");
    }

    function updateLeverages(
        Record storage inToken,
        uint tokenAmountIn,
        Record storage outToken,
        uint tokenAmountOut
    )
    internal
    {
        outToken.leverage = div(
            sub(getLeveragedBalance(outToken), tokenAmountOut),
            sub(outToken.balance, tokenAmountOut)
        );
        require(outToken.leverage > 0, "ZERO_OUT_LEVERAGE");

        inToken.leverage = div(
            add(getLeveragedBalance(inToken), tokenAmountIn),
            add(inToken.balance, tokenAmountIn)
        );
        require(inToken.leverage > 0, "ZERO_IN_LEVERAGE");
    }

    function getDerivativeDenomination()
    internal view
    returns(uint denomination)
    {
        denomination =
            derivativeVault.derivativeSpecification().primaryNominalValue() +
            derivativeVault.derivativeSpecification().complementNominalValue();
    }

    function _getPrimaryDerivativeAddress()
    internal view
    returns(address)
    {
        return _tokens[0];
    }

    function _getComplementDerivativeAddress()
    internal view
    returns(address)
    {
        return _tokens[1];
    }

    // ==
    // 'Underlying' token-manipulation functions make external calls but are NOT locked
    // You must `_lock_` or otherwise ensure reentry-safety

    function _pullPoolShare(address from, uint amount)
        internal
    {
        _pull(from, amount);
    }

    function _pushPoolShare(address to, uint amount)
        internal
    {
        _push(to, amount);
    }

    function _mintPoolShare(uint amount)
        internal
    {
        _mint(amount);
    }

    function _burnPoolShare(uint amount)
        internal
    {
        _burn(amount);
    }

    /// @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.
    /// This will revert due to insufficient balance or insufficient allowance.
    /// This function returns the actual amount received,
    /// which may be less than `amount` if there is a fee attached to the transfer.
    /// @notice This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
    /// See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
    function _pullUnderlying(address erc20, address from, uint256 amount)
    internal
    returns (uint256)
    {
        uint256 balanceBefore = IERC20(erc20).balanceOf(address(this));
        EIP20NonStandardInterface(erc20).transferFrom(
            from,
            address(this),
            amount
        );

        bool success;
        assembly {
            switch returndatasize()
            case 0 {
            // This is a non-standard ERC-20
                success := not(0) // set success to true
            }
            case 32 {
            // This is a compliant ERC-20
                returndatacopy(0, 0, 32)
                success := mload(0) // Set `success = returndata` of external call
            }
            default {
            // This is an excessively non-compliant ERC-20, revert.
                revert(0, 0)
            }
        }
        require(success, "TOKEN_TRANSFER_IN_FAILED");

        // Calculate the amount that was *actually* transferred
        uint256 balanceAfter = IERC20(erc20).balanceOf(address(this));
        require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW");
        return balanceAfter - balanceBefore; // underflow already checked above, just subtract
    }

    /// @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory
    /// error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to
    /// insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified
    /// it is >= amount, this should not revert in normal conditions.
    /// @notice This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
    /// See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
    function _pushUnderlying(address erc20, address to, uint256 amount) internal {
        EIP20NonStandardInterface(erc20).transfer(
            to,
            amount
        );

        bool success;
        assembly {
            switch returndatasize()
            case 0 {
            // This is a non-standard ERC-20
                success := not(0) // set success to true
            }
            case 32 {
            // This is a complaint ERC-20
                returndatacopy(0, 0, 32)
                success := mload(0) // Set `success = returndata` of external call
            }
            default {
            // This is an excessively non-compliant ERC-20, revert.
                revert(0, 0)
            }
        }
        require(success, "TOKEN_TRANSFER_OUT_FAILED");
    }
}

File 2 of 17 : Color.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.7.6;

abstract contract Color {
    function getColor()
        external view virtual
        returns (bytes32);
}

contract Bronze is Color {
    function getColor()
        external view override
        returns (bytes32) {
            return bytes32("BRONZE");
        }
}

File 3 of 17 : Const.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.7.6;

import "./Color.sol";

contract Const is Bronze {
    uint public constant BONE              = 10**18;
    int public constant  iBONE             = int(BONE);

    uint public constant MIN_POW_BASE      = 1 wei;
    uint public constant MAX_POW_BASE      = (2 * BONE) - 1 wei;
    uint public constant POW_PRECISION     = BONE / 10**10;

    uint public constant MAX_IN_RATIO      = BONE / 2;
    uint public constant MAX_OUT_RATIO     = (BONE / 3) + 1 wei;
}

File 4 of 17 : IDynamicFee.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

interface IDynamicFee {

    function calc(
        int[3] calldata _inRecord,
        int[3] calldata _outRecord,
        int _baseFee,
        int _feeAmp,
        int _maxFee
    )
    external
    returns(int fee, int expStart);

    function calcSpotFee(
        int _expStart,
        uint _baseFee,
        uint _feeAmp,
        uint _maxFee
    )
    external
    returns(uint);
}

File 5 of 17 : IVault.sol
// "SPDX-License-Identifier: GPL-3.0-or-later"

pragma solidity 0.7.6;

import "./libs/complifi/IDerivativeSpecification.sol";

/// @title Derivative implementation Vault
/// @notice A smart contract that references derivative specification and enables users to mint and redeem the derivative
interface IVault {
    enum State { Created, Live, Settled }

    /// @notice start of live period
    function liveTime() external view returns (uint256);

    /// @notice end of live period
    function settleTime() external view returns (uint256);

    /// @notice redeem function can only be called after the end of the Live period + delay
    function settlementDelay() external view returns (uint256);

    /// @notice underlying value at the start of live period
    function underlyingStarts(uint256 index) external view returns (int256);

    /// @notice underlying value at the end of live period
    function underlyingEnds(uint256 index) external view returns (int256);

    /// @notice primary token conversion rate multiplied by 10 ^ 12
    function primaryConversion() external view returns (uint256);

    /// @notice complement token conversion rate multiplied by 10 ^ 12
    function complementConversion() external view returns (uint256);

    /// @notice protocol fee multiplied by 10 ^ 12
    function protocolFee() external view returns (uint256);

    /// @notice limit on author fee multiplied by 10 ^ 12
    function authorFeeLimit() external view returns (uint256);

    // @notice protocol's fee receiving wallet
    function feeWallet() external view returns (address);

    // @notice current state of the vault
    function state() external view returns (State);

    // @notice derivative specification address
    function derivativeSpecification()
        external
        view
        returns (IDerivativeSpecification);

    // @notice collateral token address
    function collateralToken() external view returns (address);

    // @notice oracle address
    function oracles(uint256 index) external view returns (address);

    function oracleIterators(uint256 index) external view returns (address);

    // @notice collateral split address
    function collateralSplit() external view returns (address);

    // @notice derivative's token builder strategy address
    function tokenBuilder() external view returns (address);

    function feeLogger() external view returns (address);

    // @notice primary token address
    function primaryToken() external view returns (address);

    // @notice complement token address
    function complementToken() external view returns (address);

    /// @notice Switch to Settled state if appropriate time threshold is passed and
    /// set underlyingStarts value and set underlyingEnds value,
    /// calculate primaryConversion and complementConversion params
    /// @dev Reverts if underlyingStart or underlyingEnd are not available
    /// Vault cannot settle when it paused
    function settle(uint256[] calldata _underlyingEndRoundHints) external;

    function mintTo(address _recipient, uint256 _collateralAmount) external;

    /// @notice Mints primary and complement derivative tokens
    /// @dev Checks and switches to the right state and does nothing if vault is not in Live state
    function mint(uint256 _collateralAmount) external;

    /// @notice Refund equal amounts of derivative tokens for collateral at any time
    function refund(uint256 _tokenAmount) external;

    function refundTo(address _recipient, uint256 _tokenAmount) external;

    function redeemTo(
        address _recipient,
        uint256 _primaryTokenAmount,
        uint256 _complementTokenAmount,
        uint256[] calldata _underlyingEndRoundHints
    ) external;

    /// @notice Redeems unequal amounts previously calculated conversions if the vault is in Settled state
    function redeem(
        uint256 _primaryTokenAmount,
        uint256 _complementTokenAmount,
        uint256[] calldata _underlyingEndRoundHints
    ) external;
}

File 6 of 17 : Math.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.7.6;

import "./Num.sol";

contract Math is Bronze, Const, Num {
    /**********************************************************************************************
    // calcSpotPrice                                                                             //
    // sP = spotPrice                                                                            //
    // bI = tokenBalanceIn                 bI          1                                         //
    // bO = tokenBalanceOut         sP =  ----  *  ----------                                    //
    // sF = swapFee                        bO      ( 1 - sF )                                    //
    **********************************************************************************************/
    function calcSpotPrice(
        uint tokenBalanceIn,
        uint tokenBalanceOut,
        uint swapFee
    )
        public pure
        returns (uint spotPrice)
    {
        uint ratio = div(tokenBalanceIn, tokenBalanceOut);
        uint scale = div(BONE, sub(BONE, swapFee));
        spotPrice = mul(ratio, scale);
    }

    /**********************************************************************************************
    // calcOutGivenIn                                                                            //
    // aO = tokenAmountOut                                                                       //
    // bO = tokenBalanceOut                                                                      //
    // bI = tokenBalanceIn              /      /            bI             \   \                 //
    // aI = tokenAmountIn    aO = bO * |  1 - | --------------------------  |  |                 //
    // sF = swapFee                     \      \ ( bI + ( aI * ( 1 - sF )) /   /                 //
    **********************************************************************************************/
    function calcOutGivenIn(
        uint tokenBalanceIn,
        uint tokenBalanceOut,
        uint tokenAmountIn,
        uint swapFee
    )
        public pure
        returns (uint tokenAmountOut)
    {
        uint adjustedIn = sub(BONE, swapFee);
        adjustedIn = mul(tokenAmountIn, adjustedIn);
        uint y = div(tokenBalanceIn, add(tokenBalanceIn, adjustedIn));
        uint bar = sub(BONE, y);
        tokenAmountOut = mul(tokenBalanceOut, bar);
    }

    /**********************************************************************************************
    // calcInGivenOut                                                                            //
    // aI = tokenAmountIn                                                                        //
    // bO = tokenBalanceOut               /  /     bO      \       \                             //
    // bI = tokenBalanceIn          bI * |  | ------------  | - 1  |                             //
    // aO = tokenAmountOut    aI =        \  \ ( bO - aO ) /       /                             //
    // sF = swapFee                 --------------------------------                             //
    //                                              ( 1 - sF )                                   //
    **********************************************************************************************/
    function calcInGivenOut(
        uint tokenBalanceIn,
        uint tokenBalanceOut,
        uint tokenAmountOut,
        uint swapFee
    )
        public pure
        returns (uint tokenAmountIn)
    {
        uint diff = sub(tokenBalanceOut, tokenAmountOut);
        uint y = div(tokenBalanceOut, diff);
        uint foo = sub(y, BONE);
        tokenAmountIn = sub(BONE, swapFee);
        tokenAmountIn = div(mul(tokenBalanceIn, foo), tokenAmountIn);
    }
}

File 7 of 17 : Num.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.7.6;

import "./Const.sol";

contract Num is Const {

    function toi(uint a)
        internal pure
        returns (uint)
    {
        return a / BONE;
    }

    function floor(uint a)
        internal pure
        returns (uint)
    {
        return toi(a) * BONE;
    }

    function add(uint a, uint b)
        internal pure
        returns (uint c)
    {
        c = a + b;
        require(c >= a, "ADD_OVERFLOW");
    }

    function sub(uint a, uint b)
        internal pure
        returns (uint c)
    {
        bool flag;
        (c, flag) = subSign(a, b);
        require(!flag, "SUB_UNDERFLOW");
    }

    function subSign(uint a, uint b)
        internal pure
        returns (uint, bool)
    {
        if (a >= b) {
            return (a - b, false);
        } else {
            return (b - a, true);
        }
    }

    function mul(uint a, uint b)
        internal pure
        returns (uint c)
    {
        uint c0 = a * b;
        require(a == 0 || c0 / a == b, "MUL_OVERFLOW");
        uint c1 = c0 + (BONE / 2);
        require(c1 >= c0, "MUL_OVERFLOW");
        c = c1 / BONE;
    }

    function div(uint a, uint b)
        internal pure
        returns (uint c)
    {
        require(b != 0, "DIV_ZERO");
        uint c0 = a * BONE;
        require(a == 0 || c0 / a == BONE, "DIV_INTERNAL"); // mul overflow
        uint c1 = c0 + (b / 2);
        require(c1 >= c0, "DIV_INTERNAL"); //  add require
        c = c1 / b;
    }

    // DSMath.wpow
    function powi(uint a, uint n)
        internal pure
        returns (uint z)
    {
        z = n % 2 != 0 ? a : BONE;

        for (n /= 2; n != 0; n /= 2) {
            a = mul(a, a);

            if (n % 2 != 0) {
                z = mul(z, a);
            }
        }
    }

    // Compute b^(e.w) by splitting it into (b^e)*(b^0.w).
    // Use `powi` for `b^e` and `powK` for k iterations
    // of approximation of b^0.w
    function pow(uint base, uint exp)
        internal pure
        returns (uint)
    {
        require(base >= MIN_POW_BASE, "POW_BASE_TOO_LOW");
        require(base <= MAX_POW_BASE, "POW_BASE_TOO_HIGH");

        uint whole  = floor(exp);
        uint remain = sub(exp, whole);

        uint wholePow = powi(base, toi(whole));

        if (remain == 0) {
            return wholePow;
        }

        uint partialResult = powApprox(base, remain, POW_PRECISION);
        return mul(wholePow, partialResult);
    }

    function powApprox(uint base, uint exp, uint precision)
        internal pure
        returns (uint sum)
    {
        // term 0:
        uint a     = exp;
        (uint x, bool xneg)  = subSign(base, BONE);
        uint term = BONE;
        sum   = term;
        bool negative = false;


        // term(k) = numer / denom
        //         = (product(a - i - 1, i=1-->k) * x^k) / (k!)
        // each iteration, multiply previous term by (a-(k-1)) * x / k
        // continue until term is less than precision
        for (uint i = 1; term >= precision; i++) {
            uint bigK = i * BONE;
            (uint c, bool cneg) = subSign(a, sub(bigK, BONE));
            term = mul(term, mul(c, x));
            term = div(term, bigK);
            if (term == 0) break;

            if (xneg) negative = !negative;
            if (cneg) negative = !negative;
            if (negative) {
                sum = sub(sum, term);
            } else {
                sum = add(sum, term);
            }
        }
    }

    function min(uint first, uint second)
        internal pure
        returns (uint)
    {
        if(first < second) {
            return first;
        }
        return second;
    }
}

File 8 of 17 : Token.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.7.6;

import "./Num.sol";

// Highly opinionated token implementation

interface IERC20 {

    function totalSupply() external view returns (uint);
    function balanceOf(address whom) external view returns (uint);
    function allowance(address src, address dst) external view returns (uint);

    function approve(address dst, uint amt) external returns (bool);
    function transfer(address dst, uint amt) external returns (bool);
    function transferFrom(
        address src, address dst, uint amt
    ) external returns (bool);
}

contract TokenBase is Num {

    mapping(address => uint)                   internal _balance;
    mapping(address => mapping(address=>uint)) internal _allowance;
    uint internal _totalSupply;

    event Approval(address indexed src, address indexed dst, uint amt);
    event Transfer(address indexed src, address indexed dst, uint amt);

    function _mint(uint amt) internal {
        _balance[address(this)] = add(_balance[address(this)], amt);
        _totalSupply = add(_totalSupply, amt);
        emit Transfer(address(0), address(this), amt);
    }

    function _burn(uint amt) internal {
        require(_balance[address(this)] >= amt, "INSUFFICIENT_BAL");
        _balance[address(this)] = sub(_balance[address(this)], amt);
        _totalSupply = sub(_totalSupply, amt);
        emit Transfer(address(this), address(0), amt);
    }

    function _move(address src, address dst, uint amt) internal {
        require(_balance[src] >= amt, "INSUFFICIENT_BAL");
        _balance[src] = sub(_balance[src], amt);
        _balance[dst] = add(_balance[dst], amt);
        emit Transfer(src, dst, amt);
    }

    function _push(address to, uint amt) internal {
        _move(address(this), to, amt);
    }

    function _pull(address from, uint amt) internal {
        _move(from, address(this), amt);
    }
}

contract Token is TokenBase, IERC20 {

    string  private _name;
    string  private _symbol;
    uint8   private constant _decimals = 18;

    function setName(string memory name) internal {
        _name = name;
    }

    function setSymbol(string memory symbol) internal {
        _symbol = symbol;
    }

    function name() public view returns (string memory) {
        return _name;
    }

    function symbol() public view returns (string memory) {
        return _symbol;
    }

    function decimals() public view returns(uint8) {
        return _decimals;
    }

    function allowance(address src, address dst) external view override returns (uint) {
        return _allowance[src][dst];
    }

    function balanceOf(address whom) external view override returns (uint) {
        return _balance[whom];
    }

    function totalSupply() public view override returns (uint) {
        return _totalSupply;
    }

    function approve(address dst, uint amt) external override returns (bool) {
        _allowance[msg.sender][dst] = amt;
        emit Approval(msg.sender, dst, amt);
        return true;
    }

    function increaseApproval(address dst, uint amt) external returns (bool) {
        _allowance[msg.sender][dst] = add(_allowance[msg.sender][dst], amt);
        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
        return true;
    }

    function decreaseApproval(address dst, uint amt) external returns (bool) {
        uint oldValue = _allowance[msg.sender][dst];
        if (amt > oldValue) {
            _allowance[msg.sender][dst] = 0;
        } else {
            _allowance[msg.sender][dst] = sub(oldValue, amt);
        }
        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
        return true;
    }

    function transfer(address dst, uint amt) external override returns (bool) {
        _move(msg.sender, dst, amt);
        return true;
    }

    function transferFrom(address src, address dst, uint amt) external override returns (bool) {
        uint oldValue = _allowance[src][msg.sender];
        require(msg.sender == src || amt <= oldValue, "TOKEN_BAD_CALLER");
        _move(src, dst, amt);
        if (msg.sender != src && oldValue != uint256(-1)) {
            _allowance[src][msg.sender] = sub(oldValue, amt);
            emit Approval(msg.sender, dst, _allowance[src][msg.sender]);
        }
        return true;
    }
}

File 9 of 17 : IDerivativeSpecification.sol
// "SPDX-License-Identifier: GPL-3.0-or-later"

pragma solidity 0.7.6;

/// @title Derivative Specification interface
/// @notice Immutable collection of derivative attributes
/// @dev Created by the derivative's author and published to the DerivativeSpecificationRegistry
interface IDerivativeSpecification {
    /// @notice Proof of a derivative specification
    /// @dev Verifies that contract is a derivative specification
    /// @return true if contract is a derivative specification
    function isDerivativeSpecification() external pure returns (bool);

    /// @notice Set of oracles that are relied upon to measure changes in the state of the world
    /// between the start and the end of the Live period
    /// @dev Should be resolved through OracleRegistry contract
    /// @return oracle symbols
    function oracleSymbols() external view returns (bytes32[] memory);

    /// @notice Algorithm that, for the type of oracle used by the derivative,
    /// finds the value closest to a given timestamp
    /// @dev Should be resolved through OracleIteratorRegistry contract
    /// @return oracle iterator symbols
    function oracleIteratorSymbols() external view returns (bytes32[] memory);

    /// @notice Type of collateral that users submit to mint the derivative
    /// @dev Should be resolved through CollateralTokenRegistry contract
    /// @return collateral token symbol
    function collateralTokenSymbol() external view returns (bytes32);

    /// @notice Mapping from the change in the underlying variable (as defined by the oracle)
    /// and the initial collateral split to the final collateral split
    /// @dev Should be resolved through CollateralSplitRegistry contract
    /// @return collateral split symbol
    function collateralSplitSymbol() external view returns (bytes32);

    /// @notice Lifecycle parameter that define the length of the derivative's Live period.
    /// @dev Set in seconds
    /// @return live period value
    function livePeriod() external view returns (uint256);

    /// @notice Parameter that determines starting nominal value of primary asset
    /// @dev Units of collateral theoretically swappable for 1 unit of primary asset
    /// @return primary nominal value
    function primaryNominalValue() external view returns (uint256);

    /// @notice Parameter that determines starting nominal value of complement asset
    /// @dev Units of collateral theoretically swappable for 1 unit of complement asset
    /// @return complement nominal value
    function complementNominalValue() external view returns (uint256);

    /// @notice Minting fee rate due to the author of the derivative specification.
    /// @dev Percentage fee multiplied by 10 ^ 12
    /// @return author fee
    function authorFee() external view returns (uint256);

    /// @notice Symbol of the derivative
    /// @dev Should be resolved through DerivativeSpecificationRegistry contract
    /// @return derivative specification symbol
    function symbol() external view returns (string memory);

    /// @notice Return optional long name of the derivative
    /// @dev Isn't used directly in the protocol
    /// @return long name
    function name() external view returns (string memory);

    /// @notice Optional URI to the derivative specs
    /// @dev Isn't used directly in the protocol
    /// @return URI to the derivative specs
    function baseURI() external view returns (string memory);

    /// @notice Derivative spec author
    /// @dev Used to set and receive author's fee
    /// @return address of the author
    function author() external view returns (address);
}

File 10 of 17 : BokkyPooBahsDateTimeLibrary.sol
pragma solidity ^0.7.0;

// ----------------------------------------------------------------------------
// BokkyPooBah's DateTime Library v1.01
//
// A gas-efficient Solidity date and time library
//
// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary
//
// Tested date range 1970/01/01 to 2345/12/31
//
// Conventions:
// Unit      | Range         | Notes
// :-------- |:-------------:|:-----
// timestamp | >= 0          | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC
// year      | 1970 ... 2345 |
// month     | 1 ... 12      |
// day       | 1 ... 31      |
// hour      | 0 ... 23      |
// minute    | 0 ... 59      |
// second    | 0 ... 59      |
// dayOfWeek | 1 ... 7       | 1 = Monday, ..., 7 = Sunday
//
//
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.
// ----------------------------------------------------------------------------

library BokkyPooBahsDateTimeLibrary {
    uint256 constant SECONDS_PER_DAY = 24 * 60 * 60;
    uint256 constant SECONDS_PER_HOUR = 60 * 60;
    uint256 constant SECONDS_PER_MINUTE = 60;
    int256 constant OFFSET19700101 = 2440588;

    uint256 constant DOW_MON = 1;
    uint256 constant DOW_TUE = 2;
    uint256 constant DOW_WED = 3;
    uint256 constant DOW_THU = 4;
    uint256 constant DOW_FRI = 5;
    uint256 constant DOW_SAT = 6;
    uint256 constant DOW_SUN = 7;

    // ------------------------------------------------------------------------
    // Calculate the number of days from 1970/01/01 to year/month/day using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and subtracting the offset 2440588 so that 1970/01/01 is day 0
    //
    // days = day
    //      - 32075
    //      + 1461 * (year + 4800 + (month - 14) / 12) / 4
    //      + 367 * (month - 2 - (month - 14) / 12 * 12) / 12
    //      - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4
    //      - offset
    // ------------------------------------------------------------------------
    function _daysFromDate(
        uint256 year,
        uint256 month,
        uint256 day
    ) internal pure returns (uint256 _days) {
        require(year >= 1970);
        int256 _year = int256(year);
        int256 _month = int256(month);
        int256 _day = int256(day);

        int256 __days =
            _day -
                32075 +
                (1461 * (_year + 4800 + (_month - 14) / 12)) /
                4 +
                (367 * (_month - 2 - ((_month - 14) / 12) * 12)) /
                12 -
                (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) /
                4 -
                OFFSET19700101;

        _days = uint256(__days);
    }

    // ------------------------------------------------------------------------
    // Calculate year/month/day from the number of days since 1970/01/01 using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and adding the offset 2440588 so that 1970/01/01 is day 0
    //
    // int L = days + 68569 + offset
    // int N = 4 * L / 146097
    // L = L - (146097 * N + 3) / 4
    // year = 4000 * (L + 1) / 1461001
    // L = L - 1461 * year / 4 + 31
    // month = 80 * L / 2447
    // dd = L - 2447 * month / 80
    // L = month / 11
    // month = month + 2 - 12 * L
    // year = 100 * (N - 49) + year + L
    // ------------------------------------------------------------------------
    function _daysToDate(uint256 _days)
        internal
        pure
        returns (
            uint256 year,
            uint256 month,
            uint256 day
        )
    {
        int256 __days = int256(_days);

        int256 L = __days + 68569 + OFFSET19700101;
        int256 N = (4 * L) / 146097;
        L = L - (146097 * N + 3) / 4;
        int256 _year = (4000 * (L + 1)) / 1461001;
        L = L - (1461 * _year) / 4 + 31;
        int256 _month = (80 * L) / 2447;
        int256 _day = L - (2447 * _month) / 80;
        L = _month / 11;
        _month = _month + 2 - 12 * L;
        _year = 100 * (N - 49) + _year + L;

        year = uint256(_year);
        month = uint256(_month);
        day = uint256(_day);
    }

    function timestampFromDate(
        uint256 year,
        uint256 month,
        uint256 day
    ) internal pure returns (uint256 timestamp) {
        timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;
    }

    function timestampFromDateTime(
        uint256 year,
        uint256 month,
        uint256 day,
        uint256 hour,
        uint256 minute,
        uint256 second
    ) internal pure returns (uint256 timestamp) {
        timestamp =
            _daysFromDate(year, month, day) *
            SECONDS_PER_DAY +
            hour *
            SECONDS_PER_HOUR +
            minute *
            SECONDS_PER_MINUTE +
            second;
    }

    function timestampToDate(uint256 timestamp)
        internal
        pure
        returns (
            uint256 year,
            uint256 month,
            uint256 day
        )
    {
        (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function timestampToDateTime(uint256 timestamp)
        internal
        pure
        returns (
            uint256 year,
            uint256 month,
            uint256 day,
            uint256 hour,
            uint256 minute,
            uint256 second
        )
    {
        (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        uint256 secs = timestamp % SECONDS_PER_DAY;
        hour = secs / SECONDS_PER_HOUR;
        secs = secs % SECONDS_PER_HOUR;
        minute = secs / SECONDS_PER_MINUTE;
        second = secs % SECONDS_PER_MINUTE;
    }

    function isValidDate(
        uint256 year,
        uint256 month,
        uint256 day
    ) internal pure returns (bool valid) {
        if (year >= 1970 && month > 0 && month <= 12) {
            uint256 daysInMonth = _getDaysInMonth(year, month);
            if (day > 0 && day <= daysInMonth) {
                valid = true;
            }
        }
    }

    function isValidDateTime(
        uint256 year,
        uint256 month,
        uint256 day,
        uint256 hour,
        uint256 minute,
        uint256 second
    ) internal pure returns (bool valid) {
        if (isValidDate(year, month, day)) {
            if (hour < 24 && minute < 60 && second < 60) {
                valid = true;
            }
        }
    }

    function isLeapYear(uint256 timestamp)
        internal
        pure
        returns (bool leapYear)
    {
        (uint256 year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);
        leapYear = _isLeapYear(year);
    }

    function _isLeapYear(uint256 year) internal pure returns (bool leapYear) {
        leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }

    function isWeekDay(uint256 timestamp) internal pure returns (bool weekDay) {
        weekDay = getDayOfWeek(timestamp) <= DOW_FRI;
    }

    function isWeekEnd(uint256 timestamp) internal pure returns (bool weekEnd) {
        weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;
    }

    function getDaysInMonth(uint256 timestamp)
        internal
        pure
        returns (uint256 daysInMonth)
    {
        (uint256 year, uint256 month, ) =
            _daysToDate(timestamp / SECONDS_PER_DAY);
        daysInMonth = _getDaysInMonth(year, month);
    }

    function _getDaysInMonth(uint256 year, uint256 month)
        internal
        pure
        returns (uint256 daysInMonth)
    {
        if (
            month == 1 ||
            month == 3 ||
            month == 5 ||
            month == 7 ||
            month == 8 ||
            month == 10 ||
            month == 12
        ) {
            daysInMonth = 31;
        } else if (month != 2) {
            daysInMonth = 30;
        } else {
            daysInMonth = _isLeapYear(year) ? 29 : 28;
        }
    }

    // 1 = Monday, 7 = Sunday
    function getDayOfWeek(uint256 timestamp)
        internal
        pure
        returns (uint256 dayOfWeek)
    {
        uint256 _days = timestamp / SECONDS_PER_DAY;
        dayOfWeek = ((_days + 3) % 7) + 1;
    }

    function getYear(uint256 timestamp) internal pure returns (uint256 year) {
        (year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getMonth(uint256 timestamp) internal pure returns (uint256 month) {
        (, month, ) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getDay(uint256 timestamp) internal pure returns (uint256 day) {
        (, , day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getHour(uint256 timestamp) internal pure returns (uint256 hour) {
        uint256 secs = timestamp % SECONDS_PER_DAY;
        hour = secs / SECONDS_PER_HOUR;
    }

    function getMinute(uint256 timestamp)
        internal
        pure
        returns (uint256 minute)
    {
        uint256 secs = timestamp % SECONDS_PER_HOUR;
        minute = secs / SECONDS_PER_MINUTE;
    }

    function getSecond(uint256 timestamp)
        internal
        pure
        returns (uint256 second)
    {
        second = timestamp % SECONDS_PER_MINUTE;
    }

    function addYears(uint256 timestamp, uint256 _years)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        (uint256 year, uint256 month, uint256 day) =
            _daysToDate(timestamp / SECONDS_PER_DAY);
        year += _years;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp =
            _daysFromDate(year, month, day) *
            SECONDS_PER_DAY +
            (timestamp % SECONDS_PER_DAY);
        require(newTimestamp >= timestamp);
    }

    function addMonths(uint256 timestamp, uint256 _months)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        (uint256 year, uint256 month, uint256 day) =
            _daysToDate(timestamp / SECONDS_PER_DAY);
        month += _months;
        year += (month - 1) / 12;
        month = ((month - 1) % 12) + 1;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp =
            _daysFromDate(year, month, day) *
            SECONDS_PER_DAY +
            (timestamp % SECONDS_PER_DAY);
        require(newTimestamp >= timestamp);
    }

    function addDays(uint256 timestamp, uint256 _days)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp + _days * SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }

    function addHours(uint256 timestamp, uint256 _hours)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;
        require(newTimestamp >= timestamp);
    }

    function addMinutes(uint256 timestamp, uint256 _minutes)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp >= timestamp);
    }

    function addSeconds(uint256 timestamp, uint256 _seconds)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp + _seconds;
        require(newTimestamp >= timestamp);
    }

    function subYears(uint256 timestamp, uint256 _years)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        (uint256 year, uint256 month, uint256 day) =
            _daysToDate(timestamp / SECONDS_PER_DAY);
        year -= _years;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp =
            _daysFromDate(year, month, day) *
            SECONDS_PER_DAY +
            (timestamp % SECONDS_PER_DAY);
        require(newTimestamp <= timestamp);
    }

    function subMonths(uint256 timestamp, uint256 _months)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        (uint256 year, uint256 month, uint256 day) =
            _daysToDate(timestamp / SECONDS_PER_DAY);
        uint256 yearMonth = year * 12 + (month - 1) - _months;
        year = yearMonth / 12;
        month = (yearMonth % 12) + 1;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp =
            _daysFromDate(year, month, day) *
            SECONDS_PER_DAY +
            (timestamp % SECONDS_PER_DAY);
        require(newTimestamp <= timestamp);
    }

    function subDays(uint256 timestamp, uint256 _days)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp - _days * SECONDS_PER_DAY;
        require(newTimestamp <= timestamp);
    }

    function subHours(uint256 timestamp, uint256 _hours)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;
        require(newTimestamp <= timestamp);
    }

    function subMinutes(uint256 timestamp, uint256 _minutes)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp <= timestamp);
    }

    function subSeconds(uint256 timestamp, uint256 _seconds)
        internal
        pure
        returns (uint256 newTimestamp)
    {
        newTimestamp = timestamp - _seconds;
        require(newTimestamp <= timestamp);
    }

    function diffYears(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 _years)
    {
        require(fromTimestamp <= toTimestamp);
        (uint256 fromYear, , ) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint256 toYear, , ) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _years = toYear - fromYear;
    }

    function diffMonths(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 _months)
    {
        require(fromTimestamp <= toTimestamp);
        (uint256 fromYear, uint256 fromMonth, ) =
            _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint256 toYear, uint256 toMonth, ) =
            _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;
    }

    function diffDays(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 _days)
    {
        require(fromTimestamp <= toTimestamp);
        _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;
    }

    function diffHours(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 _hours)
    {
        require(fromTimestamp <= toTimestamp);
        _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;
    }

    function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 _minutes)
    {
        require(fromTimestamp <= toTimestamp);
        _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;
    }

    function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp)
        internal
        pure
        returns (uint256 _seconds)
    {
        require(fromTimestamp <= toTimestamp);
        _seconds = toTimestamp - fromTimestamp;
    }
}

File 11 of 17 : EIP20NonStandardInterface.sol
// "SPDX-License-Identifier: GPL-3.0-or-later"

pragma solidity 0.7.6;

/// @title EIP20NonStandardInterface
/// @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
/// See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
interface EIP20NonStandardInterface {
    /// @notice Get the total number of tokens in circulation
    /// @return The supply of tokens
    function totalSupply() external view returns (uint256);

    /// @notice Gets the balance of the specified address
    /// @param owner The address from which the balance will be retrieved
    /// @return balance The balance
    function balanceOf(address owner) external view returns (uint256 balance);

    //
    // !!!!!!!!!!!!!!
    // !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
    // !!!!!!!!!!!!!!
    //

    /// @notice Transfer `amount` tokens from `msg.sender` to `dst`
    /// @param dst The address of the destination account
    /// @param amount The number of tokens to transfer
    function transfer(address dst, uint256 amount) external;

    //
    // !!!!!!!!!!!!!!
    // !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
    // !!!!!!!!!!!!!!
    //

    /// @notice Transfer `amount` tokens from `src` to `dst`
    /// @param src The address of the source account
    /// @param dst The address of the destination account
    /// @param amount The number of tokens to transfer
    function transferFrom(
        address src,
        address dst,
        uint256 amount
    ) external;

    /// @notice Approve `spender` to transfer up to `amount` from `src`
    /// @dev This will overwrite the approval amount for `spender`
    ///  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
    /// @param spender The address of the account which may transfer tokens
    /// @param amount The number of tokens that are approved
    /// @return success Whether or not the approval succeeded
    function approve(address spender, uint256 amount)
        external
        returns (bool success);

    /// @notice Get the current allowance from `owner` for `spender`
    /// @param owner The address of the account which owns the tokens to be spent
    /// @param spender The address of the account which may transfer tokens
    /// @return remaining The number of tokens allowed to be spent
    function allowance(address owner, address spender)
        external
        view
        returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 amount
    );
}

File 12 of 17 : IERC20Metadata.sol
// "SPDX-License-Identifier: GPL-3.0-or-later"

pragma solidity 0.7.6;

interface IERC20Metadata {
    function name() external view returns (string memory);

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

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

File 13 of 17 : TokenMetadataGenerator.sol
// "SPDX-License-Identifier: GPL-3.0-or-later"

pragma solidity 0.7.6;

import "../libs/BokkyPooBahsDateTimeLibrary/BokkyPooBahsDateTimeLibrary.sol";

contract TokenMetadataGenerator {
    function formatDate(uint256 _posixDate)
        internal
        view
        returns (string memory)
    {
        uint256 year;
        uint256 month;
        uint256 day;
        (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(
            _posixDate
        );

        return
            concat(
                uint2str(day),
                concat(
                    getMonthShortName(month),
                    uint2str(getCenturyYears(year))
                )
            );
    }

    function formatMeta(
        string memory _prefix,
        string memory _concatenator,
        string memory _date,
        string memory _postfix
    ) internal pure returns (string memory) {
        return concat(_prefix, concat(_concatenator, concat(_date, _postfix)));
    }

    function makeTokenName(
        string memory _baseName,
        string memory _date,
        string memory _postfix
    ) internal pure returns (string memory) {
        return formatMeta(_baseName, " ", _date, _postfix);
    }

    function makeTokenSymbol(
        string memory _baseName,
        string memory _date,
        string memory _postfix
    ) internal pure returns (string memory) {
        return formatMeta(_baseName, "-", _date, _postfix);
    }

    function getCenturyYears(uint256 _year) internal pure returns (uint256) {
        return _year % 100;
    }

    function concat(string memory _a, string memory _b)
        internal
        pure
        returns (string memory)
    {
        return string(abi.encodePacked(bytes(_a), bytes(_b)));
    }

    function uint2str(uint256 _i)
        internal
        pure
        returns (string memory _uintAsString)
    {
        if (_i == 0) {
            return "0";
        }
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len - 1;
        while (_i != 0) {
            bstr[k--] = bytes1(uint8(48 + (_i % 10)));
            _i /= 10;
        }
        return string(bstr);
    }

    function getMonthShortName(uint256 _month)
        internal
        pure
        returns (string memory)
    {
        if (_month == 1) {
            return "Jan";
        }
        if (_month == 2) {
            return "Feb";
        }
        if (_month == 3) {
            return "Mar";
        }
        if (_month == 4) {
            return "Arp";
        }
        if (_month == 5) {
            return "May";
        }
        if (_month == 6) {
            return "Jun";
        }
        if (_month == 7) {
            return "Jul";
        }
        if (_month == 8) {
            return "Aug";
        }
        if (_month == 9) {
            return "Sep";
        }
        if (_month == 10) {
            return "Oct";
        }
        if (_month == 11) {
            return "Nov";
        }
        if (_month == 12) {
            return "Dec";
        }
        return "NaN";
    }
}

File 14 of 17 : IRepricer.sol
// "SPDX-License-Identifier: GNU General Public License v3.0"

pragma solidity 0.7.6;

import "../IVault.sol";

interface IRepricer {

    function isRepricer() external pure returns(bool);

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

    function reprice(
        uint _pMin,
        int _volatility,
        IVault _vault,
        uint[2] memory _primary,
        uint[2] memory _complement,
        int _liveUnderlingValue
    )
    external view returns(
        uint newPrimaryLeverage, uint newComplementLeverage, int estPricePrimary, int estPriceComplement
    );
}

File 15 of 17 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

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

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

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

pragma solidity >=0.6.0 <0.8.0;

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

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 17 of 17 : Pausable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor () internal {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_derivativeVault","type":"address"},{"internalType":"address","name":"_dynamicFee","type":"address"},{"internalType":"address","name":"_repricer","type":"address"},{"internalType":"uint256","name":"_baseFee","type":"uint256"},{"internalType":"uint256","name":"_maxFee","type":"uint256"},{"internalType":"uint256","name":"_feeAmp","type":"uint256"},{"internalType":"address","name":"_controller","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"LOG_CALL","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LOG_EXIT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"name":"LOG_JOIN","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"repricingBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balancePrimary","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balanceComplement","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leveragePrimary","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leverageComplement","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLeveragePrimary","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLeverageComplement","type":"uint256"},{"indexed":false,"internalType":"int256","name":"estPricePrimary","type":"int256"},{"indexed":false,"internalType":"int256","name":"estPriceComplement","type":"int256"},{"indexed":false,"internalType":"int256","name":"liveUnderlingValue","type":"int256"}],"name":"LOG_REPRICE","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenLeverageIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenLeverageOut","type":"uint256"}],"name":"LOG_SWAP","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BOUND_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_IN_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_OUT_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POW_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_POW_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POW_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"whom","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcInGivenOut","outputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcOutGivenIn","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcSpotPrice","outputs":[{"internalType":"uint256","name":"spotPrice","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"decreaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"derivativeVault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicFee","outputs":[{"internalType":"contract IDynamicFee","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256[2]","name":"minAmountsOut","type":"uint256[2]"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exposureLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeAmp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_primaryBalance","type":"uint256"},{"internalType":"uint256","name":"_primaryLeverage","type":"uint256"},{"internalType":"uint256","name":"_complementBalance","type":"uint256"},{"internalType":"uint256","name":"_complementLeverage","type":"uint256"},{"internalType":"uint256","name":"_exposureLimit","type":"uint256"},{"internalType":"uint256","name":"_volatility","type":"uint256"},{"internalType":"uint256","name":"_pMin","type":"uint256"},{"internalType":"uint256","name":"_qMin","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getColor","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getLeverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokens","outputs":[{"internalType":"address[2]","name":"tokens","type":"address[2]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"iBONE","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"increaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isFinalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256[2]","name":"maxAmountsIn","type":"uint256[2]"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"qMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repricer","outputs":[{"internalType":"contract IRepricer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"repricingBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"swapExactAmountIn","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"spotPriceAfter","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"volatility","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506040516200585c3803806200585c833981810160405260e08110156200003757600080fd5b508051602082015160408301516060840151608085015160a086015160c0909601519495939492939192909190600062000070620006b4565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506000805460ff60a01b191690556001600160a01b03871662000111576040805162461bcd60e51b815260206004820152600b60248201526a1393d517d117d59055531560aa1b604482015290519081900360640190fd5b601280546001600160a01b0319166001600160a01b038981169190911790915586166200016f576040805162461bcd60e51b81526020600482015260076024820152664e4f545f46454560c81b604482015290519081900360640190fd5b601380546001600160a01b0319166001600160a01b03888116919091179091558516620001d2576040805162461bcd60e51b815260206004820152600c60248201526b2727aa2fa922a82924a1a2a960a11b604482015290519081900360640190fd5b601480546001600160a01b0319166001600160a01b0387811691909117909155600b859055600c839055600d849055811662000246576040805162461bcd60e51b815260206004820152600e60248201526d2727aa2fa1a7a72a2927a62622a960911b604482015290519081900360640190fd5b600680546001600160a01b0380841661010002610100600160a81b0319909216919091179091556012546040805163198406d960e21b81529051600093620002e49316916366101b64916004808301926020929190829003018186803b158015620002b057600080fd5b505afa158015620002c5573d6000803e3d6000fd5b505050506040513d6020811015620002dc57600080fd5b5051620006b8565b9050620004c6620004c0601260009054906101000a90046001600160a01b03166001600160a01b031663dbcb32bf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200033d57600080fd5b505afa15801562000352573d6000803e3d6000fd5b505050506040513d60208110156200036957600080fd5b5051604080516306fdde0360e01b815290516001600160a01b03909216916306fdde0391600480820192600092909190829003018186803b158015620003ae57600080fd5b505afa158015620003c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015620003ed57600080fd5b81019080805160405193929190846401000000008211156200040e57600080fd5b9083019060208201858111156200042457600080fd5b82516401000000008111828201881017156200043f57600080fd5b82525081516020918201929091019080838360005b838110156200046e57818101518382015260200162000454565b50505050905090810190601f1680156200049c5780820380516001836020036101000a031916815260200191505b506040818101905260038152620204c560ec1b602082015287935091505062000720565b62000757565b620006a6620006a0601260009054906101000a90046001600160a01b03166001600160a01b031663dbcb32bf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200051d57600080fd5b505afa15801562000532573d6000803e3d6000fd5b505050506040513d60208110156200054957600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b1580156200058e57600080fd5b505afa158015620005a3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015620005cd57600080fd5b8101908080516040519392919084640100000000821115620005ee57600080fd5b9083019060208201858111156200060457600080fd5b82516401000000008111828201881017156200061f57600080fd5b82525081516020918201929091019080838360005b838110156200064e57818101518382015260200162000634565b50505050905090810190601f1680156200067c5780820380516001836020036101000a031916815260200191505b5060408181019052600381526202d4c560ec1b602082015287935091505062000770565b6200079f565b505050505050505062000d01565b3390565b60606000806000620006d585620007b460201b62002b241760201c565b9194509250905062000715620006eb82620007d5565b6200070f620006fa85620008b5565b6200070f620007098862000ada565b620007d5565b62000ae1565b93505050505b919050565b60606200074f84604051806040016040528060018152602001600160fd1b815250858562000ba060201b60201c565b949350505050565b80516200076c90600490602084019062000c55565b5050565b60606200074f84604051806040016040528060018152602001602d60f81b815250858562000ba060201b60201c565b80516200076c90600590602084019062000c55565b60008080620007c862015180850462000bbe565b9196909550909350915050565b606081620007fc57506040805180820190915260018152600360fc1b60208201526200071b565b8160005b81156200081657600101600a8204915062000800565b6000816001600160401b03811180156200082f57600080fd5b506040519080825280601f01601f1916602001820160405280156200085b576020820181803683370190505b50905060001982015b8515620008ac57600a860660300160f81b828280600190039350815181106200088957fe5b60200101906001600160f81b031916908160001a905350600a8604955062000864565b50949350505050565b60608160011415620008e257506040805180820190915260038152622530b760e91b60208201526200071b565b81600214156200090d57506040805180820190915260038152622332b160e91b60208201526200071b565b816003141562000938575060408051808201909152600381526226b0b960e91b60208201526200071b565b816004141562000963575060408051808201909152600381526204172760ec1b60208201526200071b565b81600514156200098e57506040805180820190915260038152624d617960e81b60208201526200071b565b8160061415620009b95750604080518082019091526003815262253ab760e91b60208201526200071b565b8160071415620009e45750604080518082019091526003815262129d5b60ea1b60208201526200071b565b816008141562000a0f575060408051808201909152600381526241756760e81b60208201526200071b565b816009141562000a3a575060408051808201909152600381526205365760ec1b60208201526200071b565b81600a141562000a65575060408051808201909152600381526213d8dd60ea1b60208201526200071b565b81600b141562000a9057506040805180820190915260038152622737bb60e91b60208201526200071b565b81600c141562000abb575060408051808201909152600381526244656360e81b60208201526200071b565b50506040805180820190915260038152622730a760e91b602082015290565b6064900690565b606082826040516020018083805190602001908083835b6020831062000b195780518252601f19909201916020918201910162000af8565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831062000b635780518252601f19909201916020918201910162000b42565b6001836020036101000a03801982511681845116808217855250505050505090500192505050604051602081830303815290604052905092915050565b606062000bb5856200070f8681878762000ae1565b95945050505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f846050028162000c1657fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b828054600181600116156101000203166002900490600052602060002090601f01602090048101928262000c8d576000855562000cd8565b82601f1062000ca857805160ff191683800117855562000cd8565b8280016001018555821562000cd8579182015b8281111562000cd857825182559160200191906001019062000cbb565b5062000ce692915062000cea565b5090565b5b8082111562000ce6576000815560010162000ceb565b614b4b8062000d116000396000f3fe608060405234801561001057600080fd5b50600436106103205760003560e01c80638456cb59116101a7578063adab6cfe116100ee578063dd3584e811610097578063ec09302111610071578063ec0930211461085f578063f2fde38b14610867578063f8b2cb4f1461089a57610320565b8063dd3584e814610814578063dd43eb571461081c578063dd62ed3e1461082457610320565b8063cce99230116100c8578063cce99230146107b1578063d73dd623146107b9578063db08a5e3146107f257610320565b8063adab6cfe146107a1578063b20d550b146107a9578063c36596a6146104f857610320565b806395d89b4111610150578063a45de7df1161012a578063a45de7df146106dd578063a9059cbb14610725578063aa6ca8081461075e57610320565b806395d89b41146106c5578063992e2a92146106cd5780639a86139b146106d557610320565b806388f1e0e71161018157806388f1e0e7146106935780638d4e4083146106b55780638da5cb5b146106bd57610320565b80638456cb591461067b57806385272a6e1461068357806387b53b7c1461068b57610320565b806340179d831161026b57806370a082311161021457806373d1747b116101ee57806373d1747b1461063c57806376a38e911461064457806378cebb9b1461067357610320565b806370a08231146105d2578063715018a61461060557806372ee63411461060d57610320565b80635c975abb116102455780635c975abb1461058957806366188463146105915780636ef25c3a146105ca57610320565b806340179d83146104f8578063436f9be41461050057806358f030aa1461052957610320565b806322950746116102cd578063313ce567116102a7578063313ce5671461049d5780633b15a718146104bb5780633f4ba83a146104ee57610320565b8063229507461461044a57806322aa14e71461045257806323b872dd1461045a57610320565b8063095ea7b3116102fe578063095ea7b3146103c457806313c43c931461041157806318160ddd1461044257610320565b806301032adc1461032557806301f59d161461033f57806306fdde0314610347575b600080fd5b61032d6108cd565b60408051918252519081900360200190f35b61032d6108d9565b61034f6108df565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610389578181015183820152602001610371565b50505050905090810190601f1680156103b65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103fd600480360360408110156103da57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610993565b604080519115158252519081900360200190f35b610419610a07565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61032d610a23565b61032d610a29565b61032d610a2f565b6103fd6004803603606081101561047057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610a35565b6104a5610bb8565b6040805160ff9092168252519081900360200190f35b61032d600480360360208110156104d157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610bbd565b6104f6610bf0565b005b61032d610ca2565b61032d6004803603606081101561051657600080fd5b5080359060208101359060400135610cae565b6105706004803603608081101561053f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135169060600135610cf8565b6040805192835260208301919091528051918290030190f35b6103fd61139c565b6103fd600480360360408110156105a757600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356113bd565b61032d6114db565b61032d600480360360208110156105e857600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166114e1565b6104f6611509565b61032d6004803603608081101561062357600080fd5b5080359060208101359060408101359060600135611620565b61032d611681565b61032d6004803603608081101561065a57600080fd5b5080359060208101359060408101359060600135611695565b6104196116ef565b6104f661170b565b61032d6117bb565b61032d6117c1565b6104f6600480360360608110156106a957600080fd5b508035906020016117c7565b6103fd611bf8565b610419611c1a565b61034f611c36565b61032d611cb5565b61032d611cc1565b6104f660048036036101008110156106f457600080fd5b5080359060208101359060408101359060608101359060808101359060a08101359060c08101359060e00135611ce5565b6103fd6004803603604081101561073b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561238b565b6107666123a1565b6040518082600260200280838360005b8381101561078e578181015183820152602001610776565b5050505090500191505060405180910390f35b61032d6123fa565b610419612400565b61032d61241c565b6103fd600480360360408110156107cf57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612422565b6104f66004803603606081101561080857600080fd5b508035906020016124cf565b61032d6128fb565b61032d612900565b61032d6004803603604081101561083a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516612905565b61032d61293d565b6104f66004803603602081101561087d57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661294d565b61032d600480360360208110156108b057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612aee565b671bc16d674ec7ffff81565b600d5481565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109895780601f1061095e57610100808354040283529160200191610989565b820191906000526020600020905b81548152906001019060200180831161096c57829003601f168201915b5050505050905090565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60145473ffffffffffffffffffffffffffffffffffffffff1681565b60035490565b600e5481565b600a5481565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260026020908152604080832033808552925282205491921480610a745750808311155b610adf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f544f4b454e5f4241445f43414c4c455200000000000000000000000000000000604482015290519081900360640190fd5b610aea858585612b43565b3373ffffffffffffffffffffffffffffffffffffffff861614801590610b3057507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114155b15610bad57610b3f8184612cac565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260026020908152604080832033808552908352928190208590558051948552519288169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35b506001949350505050565b601290565b6000610bc7612d32565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090205490565b610bf8612da4565b73ffffffffffffffffffffffffffffffffffffffff16610c16611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614610c9857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610ca0612da8565b565b670de0b6b3a764000081565b600080610cbb8585612e96565b90506000610ce2670de0b6b3a7640000610cdd670de0b6b3a764000087612cac565b612e96565b9050610cee828261301f565b9695505050505050565b60408051602080825236908201819052600092839233927fffffffff000000000000000000000000000000000000000000000000000000008535169285929081908101848480828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2610d88612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610dbb61139c565b15610e2757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b6006547501000000000000000000000000000000000000000000900460ff16610eb157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f46494e414c495a454400000000000000000000000000000000000000604482015290519081900360640190fd5b601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166366101b646040518163ffffffff1660e01b815260040160206040518083038186803b158015610f1957600080fd5b505afa158015610f2d573d6000803e3d6000fd5b505050506040513d6020811015610f4357600080fd5b50514210610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f534554544c454400000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b8373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141561104d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f53414d455f544f4b454e00000000000000000000000000000000000000000000604482015290519081900360640190fd5b600f548510156110be57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d494e5f544f4b454e5f494e0000000000000000000000000000000000000000604482015290519081900360640190fd5b6110c661312d565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152600960208181526040808420815180830183528154815260019182015481850152958a16855292825292839020835180850190945280548452909101549082015261114b61113d611133846134e7565b84602001516134fb565b6706f05b59d3b2000061301f565b8711156111b957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d41585f494e5f524154494f0000000000000000000000000000000000000000604482015290519081900360640190fd5b6111d66111c5836134e7565b6111ce836134e7565b896000611620565b93506000806111e7848a8589613512565b909250905060006112c56111fa866134e7565b611203866134e7565b601354600b54600c54600d54604080517fe91fe030000000000000000000000000000000000000000000000000000000008152600481018b90526024810194909452604484019290925260648301525173ffffffffffffffffffffffffffffffffffffffff9092169163e91fe030916084808201926020929091908290030181600087803b15801561129457600080fd5b505af11580156112a8573d6000803e3d6000fd5b505050506040513d60208110156112be57600080fd5b5051610cae565b90506112e36112d3866134e7565b6112dc866134e7565b8c86611620565b96508787101561135457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4c494d49545f4f55540000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6113628b8b8b8a85886136f0565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055969b969a509598505050505050505050565b60005474010000000000000000000000000000000000000000900460ff1690565b33600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091528120548083111561142c5733600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff88168452909152812055611468565b6114368184612cac565b33600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff891684529091529020555b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff89168085529083529281902054815190815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b600b5481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205490565b611511612da4565b73ffffffffffffffffffffffffffffffffffffffff1661152f611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146115b157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600080611635670de0b6b3a764000084612cac565b9050611641848261301f565b9050600061165387610cdd89856139ca565b90506000611669670de0b6b3a764000083612cac565b9050611675878261301f565b98975050505050505050565b6402540be400670de0b6b3a76400005b0481565b6000806116a28585612cac565b905060006116b08683612e96565b905060006116c682670de0b6b3a7640000612cac565b90506116da670de0b6b3a764000086612cac565b93506116756116e9898361301f565b85612e96565b60125473ffffffffffffffffffffffffffffffffffffffff1681565b611713612da4565b73ffffffffffffffffffffffffffffffffffffffff16611731611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146117b357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610ca0613a3c565b60105481565b600c5481565b3373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2611888612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190557501000000000000000000000000000000000000000000900460ff1661193c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f46494e414c495a454400000000000000000000000000000000000000604482015290519081900360640190fd5b6000611946610a23565b905060006119548483612e96565b9050806119c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d4154485f415050524f58000000000000000000000000000000000000000000604482015290519081900360640190fd5b60005b6002811015611bb6576000600782600281106119dd57fe5b015473ffffffffffffffffffffffffffffffffffffffff1660008181526009602052604090206001015490915080611a7657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f5f42414c414e434500000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000611a82858361301f565b9050868460028110611a9057fe5b6020020135811115611b0357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4c494d49545f494e000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260096020526040902060010154611b3690826139ca565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600960209081526040918290206001019390935580518481529051919233927f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a9281900390910190a3611ba6833383613b18565b5050600190920191506119c59050565b50611bc084613e13565b611bca3385613e1f565b5050600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050565b6006547501000000000000000000000000000000000000000000900460ff1690565b60005473ffffffffffffffffffffffffffffffffffffffff1690565b60058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109895780601f1061095e57610100808354040283529160200191610989565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b3373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2611da6612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055601254604080517f66101b64000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216916366101b6491600480820192602092909190829003018186803b158015611e3c57600080fd5b505afa158015611e50573d6000803e3d6000fd5b505050506040513d6020811015611e6657600080fd5b50514210611ed557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f534554544c454400000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6006547501000000000000000000000000000000000000000000900460ff1615611f6057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f49535f46494e414c495a45440000000000000000000000000000000000000000604482015290519081900360640190fd5b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314611feb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f434f4e54524f4c4c4552000000000000000000000000000000000000604482015290519081900360640190fd5b85881461205957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f53594d4d455452494300000000000000000000000000000000000000604482015290519081900360640190fd5b600e829055600f81905560108490556011839055600680547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000179055601254604080517f91ac094c00000000000000000000000000000000000000000000000000000000815290516121529260009273ffffffffffffffffffffffffffffffffffffffff909116916391ac094c91600480820192602092909190829003018186803b15801561211f57600080fd5b505afa158015612133573d6000803e3d6000fd5b505050506040513d602081101561214957600080fd5b50518a8a613e2d565b6121f26001601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394f973d66040518163ffffffff1660e01b815260040160206040518083038186803b1580156121bf57600080fd5b505afa1580156121d3573d6000803e3d6000fd5b505050506040513d60208110156121e957600080fd5b50518888613e2d565b6000886121fd613fb5565b0290506000601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b15801561226a57600080fd5b505afa15801561227e573d6000803e3d6000fd5b505050506040513d602081101561229457600080fd5b5051604080517f313ce567000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163313ce56791600480820192602092909190829003018186803b1580156122fe57600080fd5b505afa158015612312573d6000803e3d6000fd5b505050506040513d602081101561232857600080fd5b505160ff16905060128110156123445780601203600a0a820291505b61234d82613e13565b6123573383613e1f565b5050600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050505050505050565b6000612398338484612b43565b50600192915050565b6123a9614ad1565b6123b1612d32565b60408051808201918290529060079060029082845b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116123c6575050505050905090565b600f5481565b60135473ffffffffffffffffffffffffffffffffffffffff1681565b60115481565b33600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915281205461245d90836139ca565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff89168085529083529281902085905580519485525191937f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a350600192915050565b3373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2612590612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190557501000000000000000000000000000000000000000000900460ff1661264457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f46494e414c495a454400000000000000000000000000000000000000604482015290519081900360640190fd5b600061264e610a23565b9050600061265c8483612e96565b9050806126ca57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d4154485f415050524f58000000000000000000000000000000000000000000604482015290519081900360640190fd5b6126d43385614211565b6126dd8461421b565b60005b60028110156128cc576000600782600281106126f857fe5b015473ffffffffffffffffffffffffffffffffffffffff166000818152600960205260409020600101549091508061279157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f5f42414c414e434500000000000000000000000000000000000000000000604482015290519081900360640190fd5b600061279d858361301f565b90508684600281106127ab57fe5b602002013581101561281e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4c494d49545f4f55540000000000000000000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600960205260409020600101546128519082612cac565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600960209081526040918290206001019390935580518481529051919233927fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed9281900390910190a36128c1833383614224565b5050506001016126e0565b5050600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055505050565b600281565b600181565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020908152604080832093909416825291909152205490565b6002670de0b6b3a7640000611691565b612955612da4565b73ffffffffffffffffffffffffffffffffffffffff16612973611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146129f557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8116612a61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180614af06026913960400191505060405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000612af8612d32565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090206001015490565b60008080612b3662015180850461436c565b9196909550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054811115612bd757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f494e53554646494349454e545f42414c00000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612c079082612cac565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612c4390826139ca565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080612cb98484614420565b90925090508015612d2b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f5355425f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b5092915050565b60065460ff1615610ca057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f5245454e54525900000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b3390565b612db061139c565b612e1b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612e6c612da4565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190a1565b600081612f0457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4449565f5a45524f000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a76400008302831580612f2c5750670de0b6b3a7640000848281612f2957fe5b04145b612f9757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4449565f494e5445524e414c0000000000000000000000000000000000000000604482015290519081900360640190fd5b6002830481018181101561300c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4449565f494e5445524e414c0000000000000000000000000000000000000000604482015290519081900360640190fd5b83818161301557fe5b0495945050505050565b600082820283158061303957508284828161303657fe5b04145b6130a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d554c5f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b2000081018181101561311e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d554c5f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000081613015565b43600a54141561313c57610ca0565b43600a55600060098161314d614445565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600060096000613197614468565b73ffffffffffffffffffffffffffffffffffffffff90811682526020808301939093526040918201600090812083518085018552600180890154825288548288015285518087018752908301548152825481880152601454600e5460115460125489517fb4ba0231000000000000000000000000000000000000000000000000000000008152600481018990529951969b5094999398969788978897889795831696631a1afbc596909316928d928d92859263b4ba02319260248082019391829003018186803b15801561326a57600080fd5b505afa15801561327e573d6000803e3d6000fd5b505050506040513d602081101561329457600080fd5b5051604080517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b168152600481018881526024820188905273ffffffffffffffffffffffffffffffffffffffff8716604483015291606490910190859080838360005b838110156133145781810151838201526020016132fc565b5050505090500183600260200280838360005b8381101561333f578181015183820152602001613327565b50505050905001828152602001965050505050505060806040518083038186803b15801561336c57600080fd5b505afa158015613380573d6000803e3d6000fd5b505050506040513d608081101561339657600080fd5b508051602080830151604080850151606090950151600a548c518c518e8701518e88015160125487517fb4ba02310000000000000000000000000000000000000000000000000000000081526000600482015297519a9f50979d50999b509399507f20a9a7e8eddd119db42373ce305e5cd9ca3521682c54e58bca672a721dd0281898929791969095939492938d938d938d938d9373ffffffffffffffffffffffffffffffffffffffff169263b4ba02319260248083019392829003018186803b15801561346357600080fd5b505afa158015613477573d6000803e3d6000fd5b505050506040513d602081101561348d57600080fd5b5051604080519a8b5260208b0199909952898901979097526060890195909552608088019390935260a087019190915260c086015260e085015261010084015261012083015251908190036101400190a150509455505055565b6000610a018260200151836000015161301f565b60008183101561350c575081610a01565b50919050565b6000806000601360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a18034d160405180606001604052808a6020015181526020018a600001518152602001898152506040518060600160405280896020015181526020018960000151815260200188815250600b54600c54600d546040518663ffffffff1660e01b81526004018086600360200280838360005b838110156135db5781810151838201526020016135c3565b5050505090500185600360200280838360005b838110156136065781810151838201526020016135ee565b50505050905001848152602001838152602001828152602001955050505050506040805180830381600087803b15801561363f57600080fd5b505af1158015613653573d6000803e3d6000fd5b505050506040513d604081101561366957600080fd5b50805160209091015192509050600081136136e557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4241445f46454500000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152600960205260408082209287168252812090919061372d82898389614473565b613739828983896147e2565b6137478260010154896139ca565b826001018190555061375d816001015487612cac565b60018083019190915560408051808201909152835481529083015460208201526138349061378a906134e7565b6040805180820190915283548152600184015460208201526137ab906134e7565b6013546001868101549086015473ffffffffffffffffffffffffffffffffffffffff9092169163e91fe030916137e091614932565b600b54600c54600d546040518563ffffffff1660e01b815260040180858152602001848152602001838152602001828152602001945050505050602060405180830381600087803b15801561129457600080fd5b9250848310156138a557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d4154485f415050524f58000000000000000000000000000000000000000000604482015290519081900360640190fd5b6138af8887612e96565b85111561391d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4d4154485f415050524f585f4f54484552000000000000000000000000000000604482015290519081900360640190fd5b6001808301549082015483548354604080518d8152602081018c90528082018a90526060810195909552608085019390935260a084019190915260c08301525173ffffffffffffffffffffffffffffffffffffffff808a1692908c169133917f1c5fe691bf1a10c1e6c35d8974514451cd3f40ed1135a0450fe2550e3ebae597919081900360e00190a46139b289338a613b18565b506139be873388614224565b50509695505050505050565b81810182811015610a0157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4144445f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b613a4461139c565b15613ab057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612e6c612da4565b6000808473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613b8257600080fd5b505afa158015613b96573d6000803e3d6000fd5b505050506040513d6020811015613bac57600080fd5b5051604080517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152306024830152604482018790529151929350908716916323b872dd9160648082019260009290919082900301818387803b158015613c2f57600080fd5b505af1158015613c43573d6000803e3d6000fd5b5050505060003d60008114613c5f5760208114613c8757600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9150613c93565b60206000803e60005191505b5080613d0057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b60008673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613d6957600080fd5b505afa158015613d7d573d6000803e3d6000fd5b505050506040513d6020811015613d9357600080fd5b5051905082811015613e0657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b613e1c81614953565b50565b613e2982826149c8565b5050565b600f54821015613e9e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d494e5f42414c414e4345000000000000000000000000000000000000000000604482015290519081900360640190fd5b60008111613f0d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f5a45524f5f4c4556455241474500000000000000000000000000000000000000604482015290519081900360640190fd5b604080518082018252828152602080820185815273ffffffffffffffffffffffffffffffffffffffff8716600090815260099092529290209051815590516001909101558260078560028110613f5f57fe5b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055613fae833384613b18565b5050505050565b601254604080517fdbcb32bf000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163dbcb32bf916004808301926020929190829003018186803b15801561402057600080fd5b505afa158015614034573d6000803e3d6000fd5b505050506040513d602081101561404a57600080fd5b5051604080517fab56c592000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163ab56c59291600480820192602092909190829003018186803b1580156140b457600080fd5b505afa1580156140c8573d6000803e3d6000fd5b505050506040513d60208110156140de57600080fd5b5051601254604080517fdbcb32bf000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163dbcb32bf91600480820192602092909190829003018186803b15801561414b57600080fd5b505afa15801561415f573d6000803e3d6000fd5b505050506040513d602081101561417557600080fd5b5051604080517fc6bb30e2000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163c6bb30e291600480820192602092909190829003018186803b1580156141df57600080fd5b505afa1580156141f3573d6000803e3d6000fd5b505050506040513d602081101561420957600080fd5b505101919050565b613e2982826149d3565b613e1c816149de565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561429557600080fd5b505af11580156142a9573d6000803e3d6000fd5b5050505060003d600081146142c557602081146142ed57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91506142f9565b60206000803e60005191505b508061436657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b50505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f84605002816143c357fe5b0590506000605061098f83020585039050600b82057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf94909401606402929092018301996002600c90940290910392909201975095509350505050565b600080828410614436575050808203600061443e565b505081810360015b9250929050565b60006007815b015473ffffffffffffffffffffffffffffffffffffffff16905090565b60006007600161444b565b600f546040805180820190915283548152600184015460208201526144a19061449b906134e7565b83612cac565b1161450d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f424f554e444152595f4c45564552414745440000000000000000000000000000604482015290519081900360640190fd5b600f5461451e836001015483612cac565b1161458a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f424f554e444152595f4e4f4e5f4c455645524147454400000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a764000061459d613fb5565b02905060006145b4600e54610cdd84600e54612cac565b905060006145cf6145c784600e54612cac565b600e54612e96565b905060006146326146076146018a604051806040016040529081600082015481526020016001820154815250506134e7565b896139ca565b604080518082019091528854815260018901546020820152610cdd9061462c906134e7565b88612cac565b90508083106146a257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f424f554e444152595f4c4f574552000000000000000000000000000000000000604482015290519081900360640190fd5b81811061471057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f424f554e444152595f5550504552000000000000000000000000000000000000604482015290519081900360640190fd5b600061473661472c6147268b600101548b6139ca565b886139ca565b8860010154614420565b5080915050600061475b61462c6147518c600101548c6139ca565b8a600101546139ca565b905060105461476a8383612e96565b106147d657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f424f554e444152595f4558504f53555245000000000000000000000000000000604482015290519081900360640190fd5b50505050505050505050565b6040805180820190915282548152600183015460208201526148199061480b9061449b906134e7565b610cdd846001015484612cac565b80835561488757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5a45524f5f4f55545f4c45564552414745000000000000000000000000000000604482015290519081900360640190fd5b6040805180820190915284548152600185015460208201526148c4906148b6906148b0906134e7565b856139ca565b610cdd8660010154866139ca565b80855561436657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5a45524f5f494e5f4c4556455241474500000000000000000000000000000000604482015290519081900360640190fd5b6000818301670de0b6b3a7640000838503028161494b57fe5b059392505050565b3060009081526001602052604090205461496d90826139ca565b3060009081526001602052604090205560035461498a90826139ca565b60035560408051828152905130916000917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a350565b613e29308383612b43565b613e29823083612b43565b30600090815260016020526040902054811115614a5c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f494e53554646494349454e545f42414c00000000000000000000000000000000604482015290519081900360640190fd5b30600090815260016020526040902054614a769082612cac565b30600090815260016020526040902055600354614a939082612cac565b60035560408051828152905160009130917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a350565b6040518060400160405280600290602082028036833750919291505056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373a26469706673582212203d1d5f5109d6b6fd6706cfca3141555ad03b66bfe251fe16f38afc347192dbf864736f6c63430007060033000000000000000000000000ea5b9650f6c47d112bb008132a86388b594eb849000000000000000000000000db635eebaedef9801653f559e2c859aa81ac1ff4000000000000000000000000ee981eb86df4569b6368d9cb2172ff971bf453de0000000000000000000000000000000000000000000000000011c37937e0800000000000000000000000000000000000000000000000000003782dace9d90000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a596c2d3e0f390a212a8ed47308cf621b5e949c

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103205760003560e01c80638456cb59116101a7578063adab6cfe116100ee578063dd3584e811610097578063ec09302111610071578063ec0930211461085f578063f2fde38b14610867578063f8b2cb4f1461089a57610320565b8063dd3584e814610814578063dd43eb571461081c578063dd62ed3e1461082457610320565b8063cce99230116100c8578063cce99230146107b1578063d73dd623146107b9578063db08a5e3146107f257610320565b8063adab6cfe146107a1578063b20d550b146107a9578063c36596a6146104f857610320565b806395d89b4111610150578063a45de7df1161012a578063a45de7df146106dd578063a9059cbb14610725578063aa6ca8081461075e57610320565b806395d89b41146106c5578063992e2a92146106cd5780639a86139b146106d557610320565b806388f1e0e71161018157806388f1e0e7146106935780638d4e4083146106b55780638da5cb5b146106bd57610320565b80638456cb591461067b57806385272a6e1461068357806387b53b7c1461068b57610320565b806340179d831161026b57806370a082311161021457806373d1747b116101ee57806373d1747b1461063c57806376a38e911461064457806378cebb9b1461067357610320565b806370a08231146105d2578063715018a61461060557806372ee63411461060d57610320565b80635c975abb116102455780635c975abb1461058957806366188463146105915780636ef25c3a146105ca57610320565b806340179d83146104f8578063436f9be41461050057806358f030aa1461052957610320565b806322950746116102cd578063313ce567116102a7578063313ce5671461049d5780633b15a718146104bb5780633f4ba83a146104ee57610320565b8063229507461461044a57806322aa14e71461045257806323b872dd1461045a57610320565b8063095ea7b3116102fe578063095ea7b3146103c457806313c43c931461041157806318160ddd1461044257610320565b806301032adc1461032557806301f59d161461033f57806306fdde0314610347575b600080fd5b61032d6108cd565b60408051918252519081900360200190f35b61032d6108d9565b61034f6108df565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610389578181015183820152602001610371565b50505050905090810190601f1680156103b65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103fd600480360360408110156103da57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610993565b604080519115158252519081900360200190f35b610419610a07565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61032d610a23565b61032d610a29565b61032d610a2f565b6103fd6004803603606081101561047057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610a35565b6104a5610bb8565b6040805160ff9092168252519081900360200190f35b61032d600480360360208110156104d157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610bbd565b6104f6610bf0565b005b61032d610ca2565b61032d6004803603606081101561051657600080fd5b5080359060208101359060400135610cae565b6105706004803603608081101561053f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135169060600135610cf8565b6040805192835260208301919091528051918290030190f35b6103fd61139c565b6103fd600480360360408110156105a757600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356113bd565b61032d6114db565b61032d600480360360208110156105e857600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166114e1565b6104f6611509565b61032d6004803603608081101561062357600080fd5b5080359060208101359060408101359060600135611620565b61032d611681565b61032d6004803603608081101561065a57600080fd5b5080359060208101359060408101359060600135611695565b6104196116ef565b6104f661170b565b61032d6117bb565b61032d6117c1565b6104f6600480360360608110156106a957600080fd5b508035906020016117c7565b6103fd611bf8565b610419611c1a565b61034f611c36565b61032d611cb5565b61032d611cc1565b6104f660048036036101008110156106f457600080fd5b5080359060208101359060408101359060608101359060808101359060a08101359060c08101359060e00135611ce5565b6103fd6004803603604081101561073b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561238b565b6107666123a1565b6040518082600260200280838360005b8381101561078e578181015183820152602001610776565b5050505090500191505060405180910390f35b61032d6123fa565b610419612400565b61032d61241c565b6103fd600480360360408110156107cf57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612422565b6104f66004803603606081101561080857600080fd5b508035906020016124cf565b61032d6128fb565b61032d612900565b61032d6004803603604081101561083a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516612905565b61032d61293d565b6104f66004803603602081101561087d57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661294d565b61032d600480360360208110156108b057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612aee565b671bc16d674ec7ffff81565b600d5481565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109895780601f1061095e57610100808354040283529160200191610989565b820191906000526020600020905b81548152906001019060200180831161096c57829003601f168201915b5050505050905090565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60145473ffffffffffffffffffffffffffffffffffffffff1681565b60035490565b600e5481565b600a5481565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260026020908152604080832033808552925282205491921480610a745750808311155b610adf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f544f4b454e5f4241445f43414c4c455200000000000000000000000000000000604482015290519081900360640190fd5b610aea858585612b43565b3373ffffffffffffffffffffffffffffffffffffffff861614801590610b3057507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114155b15610bad57610b3f8184612cac565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260026020908152604080832033808552908352928190208590558051948552519288169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35b506001949350505050565b601290565b6000610bc7612d32565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090205490565b610bf8612da4565b73ffffffffffffffffffffffffffffffffffffffff16610c16611c1a565b73ffffffffffffffffffffffffffffffffffffffff1614610c9857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610ca0612da8565b565b670de0b6b3a764000081565b600080610cbb8585612e96565b90506000610ce2670de0b6b3a7640000610cdd670de0b6b3a764000087612cac565b612e96565b9050610cee828261301f565b9695505050505050565b60408051602080825236908201819052600092839233927fffffffff000000000000000000000000000000000000000000000000000000008535169285929081908101848480828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2610d88612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610dbb61139c565b15610e2757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b6006547501000000000000000000000000000000000000000000900460ff16610eb157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f46494e414c495a454400000000000000000000000000000000000000604482015290519081900360640190fd5b601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166366101b646040518163ffffffff1660e01b815260040160206040518083038186803b158015610f1957600080fd5b505afa158015610f2d573d6000803e3d6000fd5b505050506040513d6020811015610f4357600080fd5b50514210610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f534554544c454400000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b8373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141561104d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f53414d455f544f4b454e00000000000000000000000000000000000000000000604482015290519081900360640190fd5b600f548510156110be57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d494e5f544f4b454e5f494e0000000000000000000000000000000000000000604482015290519081900360640190fd5b6110c661312d565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152600960208181526040808420815180830183528154815260019182015481850152958a16855292825292839020835180850190945280548452909101549082015261114b61113d611133846134e7565b84602001516134fb565b6706f05b59d3b2000061301f565b8711156111b957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d41585f494e5f524154494f0000000000000000000000000000000000000000604482015290519081900360640190fd5b6111d66111c5836134e7565b6111ce836134e7565b896000611620565b93506000806111e7848a8589613512565b909250905060006112c56111fa866134e7565b611203866134e7565b601354600b54600c54600d54604080517fe91fe030000000000000000000000000000000000000000000000000000000008152600481018b90526024810194909452604484019290925260648301525173ffffffffffffffffffffffffffffffffffffffff9092169163e91fe030916084808201926020929091908290030181600087803b15801561129457600080fd5b505af11580156112a8573d6000803e3d6000fd5b505050506040513d60208110156112be57600080fd5b5051610cae565b90506112e36112d3866134e7565b6112dc866134e7565b8c86611620565b96508787101561135457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4c494d49545f4f55540000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6113628b8b8b8a85886136f0565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055969b969a509598505050505050505050565b60005474010000000000000000000000000000000000000000900460ff1690565b33600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091528120548083111561142c5733600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff88168452909152812055611468565b6114368184612cac565b33600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff891684529091529020555b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff89168085529083529281902054815190815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b600b5481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205490565b611511612da4565b73ffffffffffffffffffffffffffffffffffffffff1661152f611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146115b157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600080611635670de0b6b3a764000084612cac565b9050611641848261301f565b9050600061165387610cdd89856139ca565b90506000611669670de0b6b3a764000083612cac565b9050611675878261301f565b98975050505050505050565b6402540be400670de0b6b3a76400005b0481565b6000806116a28585612cac565b905060006116b08683612e96565b905060006116c682670de0b6b3a7640000612cac565b90506116da670de0b6b3a764000086612cac565b93506116756116e9898361301f565b85612e96565b60125473ffffffffffffffffffffffffffffffffffffffff1681565b611713612da4565b73ffffffffffffffffffffffffffffffffffffffff16611731611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146117b357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610ca0613a3c565b60105481565b600c5481565b3373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2611888612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190557501000000000000000000000000000000000000000000900460ff1661193c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f46494e414c495a454400000000000000000000000000000000000000604482015290519081900360640190fd5b6000611946610a23565b905060006119548483612e96565b9050806119c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d4154485f415050524f58000000000000000000000000000000000000000000604482015290519081900360640190fd5b60005b6002811015611bb6576000600782600281106119dd57fe5b015473ffffffffffffffffffffffffffffffffffffffff1660008181526009602052604090206001015490915080611a7657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f5f42414c414e434500000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000611a82858361301f565b9050868460028110611a9057fe5b6020020135811115611b0357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4c494d49545f494e000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260096020526040902060010154611b3690826139ca565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600960209081526040918290206001019390935580518481529051919233927f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a9281900390910190a3611ba6833383613b18565b5050600190920191506119c59050565b50611bc084613e13565b611bca3385613e1f565b5050600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050565b6006547501000000000000000000000000000000000000000000900460ff1690565b60005473ffffffffffffffffffffffffffffffffffffffff1690565b60058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109895780601f1061095e57610100808354040283529160200191610989565b6704a03ce68d21555681565b7f42524f4e5a45000000000000000000000000000000000000000000000000000090565b3373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2611da6612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055601254604080517f66101b64000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216916366101b6491600480820192602092909190829003018186803b158015611e3c57600080fd5b505afa158015611e50573d6000803e3d6000fd5b505050506040513d6020811015611e6657600080fd5b50514210611ed557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f534554544c454400000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6006547501000000000000000000000000000000000000000000900460ff1615611f6057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f49535f46494e414c495a45440000000000000000000000000000000000000000604482015290519081900360640190fd5b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314611feb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f434f4e54524f4c4c4552000000000000000000000000000000000000604482015290519081900360640190fd5b85881461205957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f53594d4d455452494300000000000000000000000000000000000000604482015290519081900360640190fd5b600e829055600f81905560108490556011839055600680547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000179055601254604080517f91ac094c00000000000000000000000000000000000000000000000000000000815290516121529260009273ffffffffffffffffffffffffffffffffffffffff909116916391ac094c91600480820192602092909190829003018186803b15801561211f57600080fd5b505afa158015612133573d6000803e3d6000fd5b505050506040513d602081101561214957600080fd5b50518a8a613e2d565b6121f26001601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394f973d66040518163ffffffff1660e01b815260040160206040518083038186803b1580156121bf57600080fd5b505afa1580156121d3573d6000803e3d6000fd5b505050506040513d60208110156121e957600080fd5b50518888613e2d565b6000886121fd613fb5565b0290506000601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b15801561226a57600080fd5b505afa15801561227e573d6000803e3d6000fd5b505050506040513d602081101561229457600080fd5b5051604080517f313ce567000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163313ce56791600480820192602092909190829003018186803b1580156122fe57600080fd5b505afa158015612312573d6000803e3d6000fd5b505050506040513d602081101561232857600080fd5b505160ff16905060128110156123445780601203600a0a820291505b61234d82613e13565b6123573383613e1f565b5050600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050505050505050565b6000612398338484612b43565b50600192915050565b6123a9614ad1565b6123b1612d32565b60408051808201918290529060079060029082845b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116123c6575050505050905090565b600f5481565b60135473ffffffffffffffffffffffffffffffffffffffff1681565b60115481565b33600090815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915281205461245d90836139ca565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff89168085529083529281902085905580519485525191937f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a350600192915050565b3373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a2612590612d32565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190557501000000000000000000000000000000000000000000900460ff1661264457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e4f545f46494e414c495a454400000000000000000000000000000000000000604482015290519081900360640190fd5b600061264e610a23565b9050600061265c8483612e96565b9050806126ca57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d4154485f415050524f58000000000000000000000000000000000000000000604482015290519081900360640190fd5b6126d43385614211565b6126dd8461421b565b60005b60028110156128cc576000600782600281106126f857fe5b015473ffffffffffffffffffffffffffffffffffffffff166000818152600960205260409020600101549091508061279157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f5f42414c414e434500000000000000000000000000000000000000000000604482015290519081900360640190fd5b600061279d858361301f565b90508684600281106127ab57fe5b602002013581101561281e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4c494d49545f4f55540000000000000000000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600960205260409020600101546128519082612cac565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600960209081526040918290206001019390935580518481529051919233927fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed9281900390910190a36128c1833383614224565b5050506001016126e0565b5050600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055505050565b600281565b600181565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020908152604080832093909416825291909152205490565b6002670de0b6b3a7640000611691565b612955612da4565b73ffffffffffffffffffffffffffffffffffffffff16612973611c1a565b73ffffffffffffffffffffffffffffffffffffffff16146129f557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8116612a61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180614af06026913960400191505060405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000612af8612d32565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090206001015490565b60008080612b3662015180850461436c565b9196909550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054811115612bd757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f494e53554646494349454e545f42414c00000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612c079082612cac565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612c4390826139ca565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080612cb98484614420565b90925090508015612d2b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f5355425f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b5092915050565b60065460ff1615610ca057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f5245454e54525900000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b3390565b612db061139c565b612e1b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612e6c612da4565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190a1565b600081612f0457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f4449565f5a45524f000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a76400008302831580612f2c5750670de0b6b3a7640000848281612f2957fe5b04145b612f9757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4449565f494e5445524e414c0000000000000000000000000000000000000000604482015290519081900360640190fd5b6002830481018181101561300c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4449565f494e5445524e414c0000000000000000000000000000000000000000604482015290519081900360640190fd5b83818161301557fe5b0495945050505050565b600082820283158061303957508284828161303657fe5b04145b6130a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d554c5f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b6706f05b59d3b2000081018181101561311e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d554c5f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000081613015565b43600a54141561313c57610ca0565b43600a55600060098161314d614445565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600060096000613197614468565b73ffffffffffffffffffffffffffffffffffffffff90811682526020808301939093526040918201600090812083518085018552600180890154825288548288015285518087018752908301548152825481880152601454600e5460115460125489517fb4ba0231000000000000000000000000000000000000000000000000000000008152600481018990529951969b5094999398969788978897889795831696631a1afbc596909316928d928d92859263b4ba02319260248082019391829003018186803b15801561326a57600080fd5b505afa15801561327e573d6000803e3d6000fd5b505050506040513d602081101561329457600080fd5b5051604080517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b168152600481018881526024820188905273ffffffffffffffffffffffffffffffffffffffff8716604483015291606490910190859080838360005b838110156133145781810151838201526020016132fc565b5050505090500183600260200280838360005b8381101561333f578181015183820152602001613327565b50505050905001828152602001965050505050505060806040518083038186803b15801561336c57600080fd5b505afa158015613380573d6000803e3d6000fd5b505050506040513d608081101561339657600080fd5b508051602080830151604080850151606090950151600a548c518c518e8701518e88015160125487517fb4ba02310000000000000000000000000000000000000000000000000000000081526000600482015297519a9f50979d50999b509399507f20a9a7e8eddd119db42373ce305e5cd9ca3521682c54e58bca672a721dd0281898929791969095939492938d938d938d938d9373ffffffffffffffffffffffffffffffffffffffff169263b4ba02319260248083019392829003018186803b15801561346357600080fd5b505afa158015613477573d6000803e3d6000fd5b505050506040513d602081101561348d57600080fd5b5051604080519a8b5260208b0199909952898901979097526060890195909552608088019390935260a087019190915260c086015260e085015261010084015261012083015251908190036101400190a150509455505055565b6000610a018260200151836000015161301f565b60008183101561350c575081610a01565b50919050565b6000806000601360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a18034d160405180606001604052808a6020015181526020018a600001518152602001898152506040518060600160405280896020015181526020018960000151815260200188815250600b54600c54600d546040518663ffffffff1660e01b81526004018086600360200280838360005b838110156135db5781810151838201526020016135c3565b5050505090500185600360200280838360005b838110156136065781810151838201526020016135ee565b50505050905001848152602001838152602001828152602001955050505050506040805180830381600087803b15801561363f57600080fd5b505af1158015613653573d6000803e3d6000fd5b505050506040513d604081101561366957600080fd5b50805160209091015192509050600081136136e557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600760248201527f4241445f46454500000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152600960205260408082209287168252812090919061372d82898389614473565b613739828983896147e2565b6137478260010154896139ca565b826001018190555061375d816001015487612cac565b60018083019190915560408051808201909152835481529083015460208201526138349061378a906134e7565b6040805180820190915283548152600184015460208201526137ab906134e7565b6013546001868101549086015473ffffffffffffffffffffffffffffffffffffffff9092169163e91fe030916137e091614932565b600b54600c54600d546040518563ffffffff1660e01b815260040180858152602001848152602001838152602001828152602001945050505050602060405180830381600087803b15801561129457600080fd5b9250848310156138a557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d4154485f415050524f58000000000000000000000000000000000000000000604482015290519081900360640190fd5b6138af8887612e96565b85111561391d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4d4154485f415050524f585f4f54484552000000000000000000000000000000604482015290519081900360640190fd5b6001808301549082015483548354604080518d8152602081018c90528082018a90526060810195909552608085019390935260a084019190915260c08301525173ffffffffffffffffffffffffffffffffffffffff808a1692908c169133917f1c5fe691bf1a10c1e6c35d8974514451cd3f40ed1135a0450fe2550e3ebae597919081900360e00190a46139b289338a613b18565b506139be873388614224565b50509695505050505050565b81810182811015610a0157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4144445f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b613a4461139c565b15613ab057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612e6c612da4565b6000808473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613b8257600080fd5b505afa158015613b96573d6000803e3d6000fd5b505050506040513d6020811015613bac57600080fd5b5051604080517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152306024830152604482018790529151929350908716916323b872dd9160648082019260009290919082900301818387803b158015613c2f57600080fd5b505af1158015613c43573d6000803e3d6000fd5b5050505060003d60008114613c5f5760208114613c8757600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9150613c93565b60206000803e60005191505b5080613d0057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b60008673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613d6957600080fd5b505afa158015613d7d573d6000803e3d6000fd5b505050506040513d6020811015613d9357600080fd5b5051905082811015613e0657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b613e1c81614953565b50565b613e2982826149c8565b5050565b600f54821015613e9e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d494e5f42414c414e4345000000000000000000000000000000000000000000604482015290519081900360640190fd5b60008111613f0d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f5a45524f5f4c4556455241474500000000000000000000000000000000000000604482015290519081900360640190fd5b604080518082018252828152602080820185815273ffffffffffffffffffffffffffffffffffffffff8716600090815260099092529290209051815590516001909101558260078560028110613f5f57fe5b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055613fae833384613b18565b5050505050565b601254604080517fdbcb32bf000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163dbcb32bf916004808301926020929190829003018186803b15801561402057600080fd5b505afa158015614034573d6000803e3d6000fd5b505050506040513d602081101561404a57600080fd5b5051604080517fab56c592000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163ab56c59291600480820192602092909190829003018186803b1580156140b457600080fd5b505afa1580156140c8573d6000803e3d6000fd5b505050506040513d60208110156140de57600080fd5b5051601254604080517fdbcb32bf000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163dbcb32bf91600480820192602092909190829003018186803b15801561414b57600080fd5b505afa15801561415f573d6000803e3d6000fd5b505050506040513d602081101561417557600080fd5b5051604080517fc6bb30e2000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163c6bb30e291600480820192602092909190829003018186803b1580156141df57600080fd5b505afa1580156141f3573d6000803e3d6000fd5b505050506040513d602081101561420957600080fd5b505101919050565b613e2982826149d3565b613e1c816149de565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561429557600080fd5b505af11580156142a9573d6000803e3d6000fd5b5050505060003d600081146142c557602081146142ed57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91506142f9565b60206000803e60005191505b508061436657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b50505050565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f84605002816143c357fe5b0590506000605061098f83020585039050600b82057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf94909401606402929092018301996002600c90940290910392909201975095509350505050565b600080828410614436575050808203600061443e565b505081810360015b9250929050565b60006007815b015473ffffffffffffffffffffffffffffffffffffffff16905090565b60006007600161444b565b600f546040805180820190915283548152600184015460208201526144a19061449b906134e7565b83612cac565b1161450d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f424f554e444152595f4c45564552414745440000000000000000000000000000604482015290519081900360640190fd5b600f5461451e836001015483612cac565b1161458a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f424f554e444152595f4e4f4e5f4c455645524147454400000000000000000000604482015290519081900360640190fd5b6000670de0b6b3a764000061459d613fb5565b02905060006145b4600e54610cdd84600e54612cac565b905060006145cf6145c784600e54612cac565b600e54612e96565b905060006146326146076146018a604051806040016040529081600082015481526020016001820154815250506134e7565b896139ca565b604080518082019091528854815260018901546020820152610cdd9061462c906134e7565b88612cac565b90508083106146a257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f424f554e444152595f4c4f574552000000000000000000000000000000000000604482015290519081900360640190fd5b81811061471057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f424f554e444152595f5550504552000000000000000000000000000000000000604482015290519081900360640190fd5b600061473661472c6147268b600101548b6139ca565b886139ca565b8860010154614420565b5080915050600061475b61462c6147518c600101548c6139ca565b8a600101546139ca565b905060105461476a8383612e96565b106147d657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f424f554e444152595f4558504f53555245000000000000000000000000000000604482015290519081900360640190fd5b50505050505050505050565b6040805180820190915282548152600183015460208201526148199061480b9061449b906134e7565b610cdd846001015484612cac565b80835561488757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5a45524f5f4f55545f4c45564552414745000000000000000000000000000000604482015290519081900360640190fd5b6040805180820190915284548152600185015460208201526148c4906148b6906148b0906134e7565b856139ca565b610cdd8660010154866139ca565b80855561436657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5a45524f5f494e5f4c4556455241474500000000000000000000000000000000604482015290519081900360640190fd5b6000818301670de0b6b3a7640000838503028161494b57fe5b059392505050565b3060009081526001602052604090205461496d90826139ca565b3060009081526001602052604090205560035461498a90826139ca565b60035560408051828152905130916000917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a350565b613e29308383612b43565b613e29823083612b43565b30600090815260016020526040902054811115614a5c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f494e53554646494349454e545f42414c00000000000000000000000000000000604482015290519081900360640190fd5b30600090815260016020526040902054614a769082612cac565b30600090815260016020526040902055600354614a939082612cac565b60035560408051828152905160009130917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a350565b6040518060400160405280600290602082028036833750919291505056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373a26469706673582212203d1d5f5109d6b6fd6706cfca3141555ad03b66bfe251fe16f38afc347192dbf864736f6c63430007060033

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

000000000000000000000000ea5b9650f6c47d112bb008132a86388b594eb849000000000000000000000000db635eebaedef9801653f559e2c859aa81ac1ff4000000000000000000000000ee981eb86df4569b6368d9cb2172ff971bf453de0000000000000000000000000000000000000000000000000011c37937e0800000000000000000000000000000000000000000000000000003782dace9d90000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a596c2d3e0f390a212a8ed47308cf621b5e949c

-----Decoded View---------------
Arg [0] : _derivativeVault (address): 0xea5b9650f6c47D112Bb008132a86388B594Eb849
Arg [1] : _dynamicFee (address): 0xdB635EEbaEdEF9801653F559E2C859aA81Ac1FF4
Arg [2] : _repricer (address): 0xee981EB86DF4569b6368d9Cb2172Ff971Bf453dE
Arg [3] : _baseFee (uint256): 5000000000000000
Arg [4] : _maxFee (uint256): 250000000000000000
Arg [5] : _feeAmp (uint256): 10
Arg [6] : _controller (address): 0x7A596C2d3e0f390A212a8Ed47308cf621b5E949C

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000ea5b9650f6c47d112bb008132a86388b594eb849
Arg [1] : 000000000000000000000000db635eebaedef9801653f559e2c859aa81ac1ff4
Arg [2] : 000000000000000000000000ee981eb86df4569b6368d9cb2172ff971bf453de
Arg [3] : 0000000000000000000000000000000000000000000000000011c37937e08000
Arg [4] : 00000000000000000000000000000000000000000000000003782dace9d90000
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [6] : 0000000000000000000000007a596c2d3e0f390a212a8ed47308cf621b5e949c


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.