ETH Price: $3,413.38 (+1.19%)

Contract

0x12B2BbBfAB2CE6789DF5659E9AC27A4A91C96C5C
 
Transaction Hash
Method
Block
From
To
Unstake193086862024-02-26 2:11:59275 days ago1708913519IN
0x12B2BbBf...A91C96C5C
0 ETH0.0064062526.63823601
Intend To Unstak...193059512024-02-25 17:00:35275 days ago1708880435IN
0x12B2BbBf...A91C96C5C
0 ETH0.0017508737.08462159
Unstake192713182024-02-20 20:33:47280 days ago1708461227IN
0x12B2BbBf...A91C96C5C
0 ETH0.0114354855.43053716
Intend To Unstak...192639662024-02-19 19:50:47281 days ago1708372247IN
0x12B2BbBf...A91C96C5C
0 ETH0.0024805452.5393929
Unstake179717772023-08-22 17:35:23462 days ago1692725723IN
0x12B2BbBf...A91C96C5C
0 ETH0.0125980448.29207024
Intend To Unstak...179655812023-08-21 20:47:47463 days ago1692650867IN
0x12B2BbBf...A91C96C5C
0 ETH0.0014776931.29855153
Unstake170931442023-04-21 6:59:35586 days ago1682060375IN
0x12B2BbBf...A91C96C5C
0 ETH0.0082896942.40189509
Intend To Unstak...170895682023-04-20 18:50:11586 days ago1682016611IN
0x12B2BbBf...A91C96C5C
0 ETH0.0020295967.39944492
Intend To Unstak...170397462023-04-13 16:52:59593 days ago1681404779IN
0x12B2BbBf...A91C96C5C
0 ETH0.0009149230.38317765
Intend To Unstak...170354872023-04-13 0:53:59594 days ago1681347239IN
0x12B2BbBf...A91C96C5C
0 ETH0.0006588121.8780355
Intend To Unstak...169732792023-04-04 4:46:59603 days ago1680583619IN
0x12B2BbBf...A91C96C5C
0 ETH0.0005867119.48376695
Intend To Unstak...168156142023-03-13 0:51:11625 days ago1678668671IN
0x12B2BbBf...A91C96C5C
0 ETH0.0017522537.11372162
Withdraw Funds167834432023-03-08 12:09:35629 days ago1678277375IN
0x12B2BbBf...A91C96C5C
0 ETH0.0025345223.44281883
Intend To Unstak...167834372023-03-08 12:08:23629 days ago1678277303IN
0x12B2BbBf...A91C96C5C
0 ETH0.0007262624.11807977
Intend To Unstak...167004602023-02-24 20:07:35641 days ago1677269255IN
0x12B2BbBf...A91C96C5C
0 ETH0.0008109626.93086092
Withdraw Funds165147902023-01-29 20:13:47667 days ago1675023227IN
0x12B2BbBf...A91C96C5C
0 ETH0.0009999621.36870371
Intend To Unstak...165140412023-01-29 17:43:11667 days ago1675014191IN
0x12B2BbBf...A91C96C5C
0 ETH0.000558218.53704815
Unstake165014572023-01-27 23:33:47669 days ago1674862427IN
0x12B2BbBf...A91C96C5C
0 ETH0.0031653716.19090894
Intend To Unstak...165014352023-01-27 23:29:11669 days ago1674862151IN
0x12B2BbBf...A91C96C5C
0 ETH0.0004772415.84857492
Unstake163831102023-01-11 10:55:35685 days ago1673434535IN
0x12B2BbBf...A91C96C5C
0 ETH0.0026848115.05120975
Intend To Unstak...163705842023-01-09 16:57:23687 days ago1673283443IN
0x12B2BbBf...A91C96C5C
0 ETH0.0011895539.50315422
Withdraw Funds163704432023-01-09 16:29:11687 days ago1673281751IN
0x12B2BbBf...A91C96C5C
0 ETH0.0039905436.91021666
Intend To Unstak...162830512022-12-28 11:48:23699 days ago1672228103IN
0x12B2BbBf...A91C96C5C
0 ETH0.0004018513.34501968
Unstake162277452022-12-20 18:37:59707 days ago1671561479IN
0x12B2BbBf...A91C96C5C
0 ETH0.0061821431.62172007
Withdraw Funds162276952022-12-20 18:27:59707 days ago1671560879IN
0x12B2BbBf...A91C96C5C
0 ETH0.0031181628.8412001
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
124623762021-05-19 3:15:091288 days ago1621394109  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StakeLocker

Compiler Version
v0.6.11+commit.5ef660b1

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-05-19
*/

// SPDX-License-Identifier:  AGPL-3.0-or-later // hevm: flattened sources of contracts/StakeLocker.sol
pragma solidity =0.6.11 >=0.6.0 <0.8.0 >=0.6.2 <0.8.0;

////// contracts/interfaces/IMapleGlobals.sol
/* pragma solidity 0.6.11; */

interface IMapleGlobals {

    function pendingGovernor() external view returns (address);

    function governor() external view returns (address);

    function globalAdmin() external view returns (address);

    function mpl() external view returns (address);

    function mapleTreasury() external view returns (address);

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

    function treasuryFee() external view returns (uint256);

    function investorFee() external view returns (uint256);

    function defaultGracePeriod() external view returns (uint256);

    function fundingPeriod() external view returns (uint256);

    function swapOutRequired() external view returns (uint256);

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

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

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

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

    function isValidCalc(address, uint8) external view returns (bool);

    function getLpCooldownParams() external view returns (uint256, uint256);

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

    function isValidSubFactory(address, address, uint8) external view returns (bool);

    function isValidPoolFactory(address) external view returns (bool);
    
    function getLatestPrice(address) external view returns (uint256);
    
    function defaultUniswapPath(address, address) external view returns (address);

    function minLoanEquity() external view returns (uint256);
    
    function maxSwapSlippage() external view returns (uint256);

    function protocolPaused() external view returns (bool);

    function stakerCooldownPeriod() external view returns (uint256);

    function lpCooldownPeriod() external view returns (uint256);

    function stakerUnstakeWindow() external view returns (uint256);

    function lpWithdrawWindow() external view returns (uint256);

    function oracleFor(address) external view returns (address);

    function validSubFactories(address, address) external view returns (bool);

    function setStakerCooldownPeriod(uint256) external;

    function setLpCooldownPeriod(uint256) external;

    function setStakerUnstakeWindow(uint256) external;

    function setLpWithdrawWindow(uint256) external;

    function setMaxSwapSlippage(uint256) external;

    function setGlobalAdmin(address) external;

    function setValidBalancerPool(address, bool) external;

    function setProtocolPause(bool) external;

    function setValidPoolFactory(address, bool) external;

    function setValidLoanFactory(address, bool) external;

    function setValidSubFactory(address, address, bool) external;

    function setDefaultUniswapPath(address, address, address) external;

    function setPoolDelegateAllowlist(address, bool) external;

    function setCollateralAsset(address, bool) external;

    function setLiquidityAsset(address, bool) external;

    function setCalc(address, bool) external;

    function setInvestorFee(uint256) external;

    function setTreasuryFee(uint256) external;

    function setMapleTreasury(address) external;

    function setDefaultGracePeriod(uint256) external;

    function setMinLoanEquity(uint256) external;

    function setFundingPeriod(uint256) external;

    function setSwapOutRequired(uint256) external;

    function setPriceOracle(address, address) external;

    function setPendingGovernor(address) external;

    function acceptGovernor() external;

}

////// contracts/token/interfaces/IBaseFDT.sol
/* pragma solidity 0.6.11; */

interface IBaseFDT {

    /**
        @dev    Returns the total amount of funds a given address is able to withdraw currently.
        @param  owner Address of FDT holder.
        @return A uint256 representing the available funds for a given account.
    */
    function withdrawableFundsOf(address owner) external view returns (uint256);

    /**
        @dev Withdraws all available funds for a FDT holder.
    */
    function withdrawFunds() external;

    /**
        @dev   This event emits when new funds are distributed.
        @param by               The address of the sender that distributed funds.
        @param fundsDistributed The amount of funds received for distribution.
    */
    event FundsDistributed(address indexed by, uint256 fundsDistributed);

    /**
        @dev   This event emits when distributed funds are withdrawn by a token holder.
        @param by             The address of the receiver of funds.
        @param fundsWithdrawn The amount of funds that were withdrawn.
        @param totalWithdrawn The total amount of funds that were withdrawn.
    */
    event FundsWithdrawn(address indexed by, uint256 fundsWithdrawn, uint256 totalWithdrawn);

}

////// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
/* pragma solidity >=0.6.0 <0.8.0; */

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

////// contracts/token/interfaces/IBasicFDT.sol
/* pragma solidity 0.6.11; */

/* import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; */

/* import "./IBaseFDT.sol"; */

interface IBasicFDT is IBaseFDT, IERC20 {

    event PointsPerShareUpdated(uint256);

    event PointsCorrectionUpdated(address indexed, int256);

    function withdrawnFundsOf(address) external view returns (uint256);

    function accumulativeFundsOf(address) external view returns (uint256);

    function updateFundsReceived() external;

}

////// contracts/token/interfaces/IExtendedFDT.sol
/* pragma solidity 0.6.11; */

/* import "./IBasicFDT.sol"; */

interface IExtendedFDT is IBasicFDT {

    event LossesPerShareUpdated(uint256);

    event LossesCorrectionUpdated(address indexed, int256);

    event LossesDistributed(address indexed, uint256);

    event LossesRecognized(address indexed, uint256, uint256);

    function lossesPerShare() external view returns (uint256);

    function recognizableLossesOf(address) external view returns (uint256);

    function recognizedLossesOf(address) external view returns (uint256);

    function accumulativeLossesOf(address) external view returns (uint256);

    function updateLossesReceived() external;

}

////// contracts/token/interfaces/IPoolFDT.sol
/* pragma solidity 0.6.11; */

/* import "./IExtendedFDT.sol"; */

interface IPoolFDT is IExtendedFDT {

    function interestSum() external view returns (uint256);

    function poolLosses() external view returns (uint256);

    function interestBalance() external view returns (uint256);

    function lossesBalance() external view returns (uint256);

}

////// contracts/interfaces/IPool.sol
/* pragma solidity 0.6.11; */

/* import "../token/interfaces/IPoolFDT.sol"; */

interface IPool is IPoolFDT {

    function poolDelegate() external view returns (address);

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

    function deposit(uint256) external;

    function increaseCustodyAllowance(address, uint256) external;

    function transferByCustodian(address, address, uint256) external;

    function poolState() external view returns (uint256);

    function deactivate() external;

    function finalize() external;

    function claim(address, address) external returns (uint256[7] memory);

    function setLockupPeriod(uint256) external;
    
    function setStakingFee(uint256) external;

    function setPoolAdmin(address, bool) external;

    function fundLoan(address, address, uint256) external;

    function withdraw(uint256) external;

    function superFactory() external view returns (address);

    function triggerDefault(address, address) external;

    function isPoolFinalized() external view returns (bool);

    function setOpenToPublic(bool) external;

    function setAllowList(address, bool) external;

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

    function openToPublic() external view returns (bool);

    function intendToWithdraw() external;

    function DL_FACTORY() external view returns (uint8);

    function liquidityAsset() external view returns (address);

    function liquidityLocker() external view returns (address);

    function stakeAsset() external view returns (address);

    function stakeLocker() external view returns (address);

    function stakingFee() external view returns (uint256);

    function delegateFee() external view returns (uint256);

    function principalOut() external view returns (uint256);

    function liquidityCap() external view returns (uint256);

    function lockupPeriod() external view returns (uint256);

    function depositDate(address) external view returns (uint256);

    function debtLockers(address, address) external view returns (address);

    function withdrawCooldown(address) external view returns (uint256);

    function setLiquidityCap(uint256) external;

    function cancelWithdraw() external;

    function reclaimERC20(address) external;

    function BPTVal(address, address, address, address) external view returns (uint256);

    function isDepositAllowed(uint256) external view returns (bool);

    function getInitialStakeRequirements() external view returns (uint256, uint256, bool, uint256, uint256);

}

////// contracts/interfaces/IPoolFactory.sol
/* pragma solidity 0.6.11; */

interface IPoolFactory {

    function LL_FACTORY() external view returns (uint8);

    function SL_FACTORY() external view returns (uint8);

    function poolsCreated() external view returns (uint256);

    function globals() external view returns (address);

    function pools(uint256) external view returns (address);

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

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

    function setGlobals(address) external;

    function createPool(address, address, address, address, uint256, uint256, uint256) external returns (address);

    function setPoolFactoryAdmin(address, bool) external;

    function pause() external;

    function unpause() external;

}

////// contracts/math/SafeMathInt.sol
/* pragma solidity 0.6.11; */

library SafeMathInt {
    function toUint256Safe(int256 a) internal pure returns (uint256) {
        require(a >= 0, "SMI:NEG");
        return uint256(a);
    }
}

////// contracts/math/SafeMathUint.sol
/* pragma solidity 0.6.11; */

library SafeMathUint {
    function toInt256Safe(uint256 a) internal pure returns (int256 b) {
        b = int256(a);
        require(b >= 0, "SMU:OOB");
    }
}

////// lib/openzeppelin-contracts/contracts/math/SafeMath.sol
/* pragma solidity >=0.6.0 <0.8.0; */

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

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

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

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

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

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

        return c;
    }

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

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

////// lib/openzeppelin-contracts/contracts/math/SignedSafeMath.sol
/* pragma solidity >=0.6.0 <0.8.0; */

/**
 * @title SignedSafeMath
 * @dev Signed math operations with safety checks that revert on error.
 */
library SignedSafeMath {
    int256 constant private _INT256_MIN = -2**255;

    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");

        int256 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");

        int256 c = a / b;

        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
}

////// lib/openzeppelin-contracts/contracts/GSN/Context.sol
/* 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;
    }
}

////// lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol
/* pragma solidity >=0.6.0 <0.8.0; */

/* import "../../GSN/Context.sol"; */
/* import "./IERC20.sol"; */
/* import "../../math/SafeMath.sol"; */

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name_, string memory symbol_) public {
        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}

////// contracts/token/BasicFDT.sol
/* pragma solidity 0.6.11; */

/* import "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; */
/* import "lib/openzeppelin-contracts/contracts/math/SafeMath.sol"; */
/* import "lib/openzeppelin-contracts/contracts/math/SignedSafeMath.sol"; */
/* import "./interfaces/IBaseFDT.sol"; */
/* import "../math/SafeMathUint.sol"; */
/* import "../math/SafeMathInt.sol"; */

/// @title BasicFDT implements base level FDT functionality for accounting for revenues.
abstract contract BasicFDT is IBaseFDT, ERC20 {
    using SafeMath       for uint256;
    using SafeMathUint   for uint256;
    using SignedSafeMath for  int256;
    using SafeMathInt    for  int256;

    uint256 internal constant pointsMultiplier = 2 ** 128;
    uint256 internal pointsPerShare;

    mapping(address => int256)  internal pointsCorrection;
    mapping(address => uint256) internal withdrawnFunds;

    event   PointsPerShareUpdated(uint256 pointsPerShare);
    event PointsCorrectionUpdated(address indexed account, int256 pointsCorrection);

    constructor(string memory name, string memory symbol) ERC20(name, symbol) public { }

    /**
        @dev Distributes funds to token holders.
        @dev It reverts if the total supply of tokens is 0.
        @dev It emits a `FundsDistributed` event if the amount of received funds is greater than 0.
        @dev It emits a `PointsPerShareUpdated` event if the amount of received funds is greater than 0.
             About undistributed funds:
                In each distribution, there is a small amount of funds which do not get distributed,
                   which is `(value  pointsMultiplier) % totalSupply()`.
                With a well-chosen `pointsMultiplier`, the amount funds that are not getting distributed
                   in a distribution can be less than 1 (base unit).
                We can actually keep track of the undistributed funds in a distribution
                   and try to distribute it in the next distribution.
    */
    function _distributeFunds(uint256 value) internal {
        require(totalSupply() > 0, "FDT:ZERO_SUPPLY");

        if (value == 0) return;

        pointsPerShare = pointsPerShare.add(value.mul(pointsMultiplier) / totalSupply());
        emit FundsDistributed(msg.sender, value);
        emit PointsPerShareUpdated(pointsPerShare);
    }

    /**
        @dev    Prepares the withdrawal of funds.
        @dev    It emits a `FundsWithdrawn` event if the amount of withdrawn funds is greater than 0.
        @return withdrawableDividend The amount of dividend funds that can be withdrawn.
    */
    function _prepareWithdraw() internal returns (uint256 withdrawableDividend) {
        withdrawableDividend       = withdrawableFundsOf(msg.sender);
        uint256 _withdrawnFunds    = withdrawnFunds[msg.sender].add(withdrawableDividend);
        withdrawnFunds[msg.sender] = _withdrawnFunds;

        emit FundsWithdrawn(msg.sender, withdrawableDividend, _withdrawnFunds);
    }

    /**
        @dev    Returns the amount of funds that an account can withdraw.
        @param  _owner The address of a token holder.
        @return The amount funds that `_owner` can withdraw.
    */
    function withdrawableFundsOf(address _owner) public view override returns (uint256) {
        return accumulativeFundsOf(_owner).sub(withdrawnFunds[_owner]);
    }

    /**
        @dev    Returns the amount of funds that an account has withdrawn.
        @param  _owner The address of a token holder.
        @return The amount of funds that `_owner` has withdrawn.
    */
    function withdrawnFundsOf(address _owner) external view returns (uint256) {
        return withdrawnFunds[_owner];
    }

    /**
        @dev    Returns the amount of funds that an account has earned in total.
        @dev    accumulativeFundsOf(_owner) = withdrawableFundsOf(_owner) + withdrawnFundsOf(_owner)
                                         = (pointsPerShare * balanceOf(_owner) + pointsCorrection[_owner]) / pointsMultiplier
        @param  _owner The address of a token holder.
        @return The amount of funds that `_owner` has earned in total.
    */
    function accumulativeFundsOf(address _owner) public view returns (uint256) {
        return
            pointsPerShare
                .mul(balanceOf(_owner))
                .toInt256Safe()
                .add(pointsCorrection[_owner])
                .toUint256Safe() / pointsMultiplier;
    }

    /**
        @dev   Transfers tokens from one account to another. Updates pointsCorrection to keep funds unchanged.
        @dev   It emits two `PointsCorrectionUpdated` events, one for the sender and one for the receiver.
        @param from  The address to transfer from.
        @param to    The address to transfer to.
        @param value The amount to be transferred.
    */
    function _transfer(
        address from,
        address to,
        uint256 value
    ) internal virtual override {
        super._transfer(from, to, value);

        int256 _magCorrection       = pointsPerShare.mul(value).toInt256Safe();
        int256 pointsCorrectionFrom = pointsCorrection[from].add(_magCorrection);
        pointsCorrection[from]      = pointsCorrectionFrom;
        int256 pointsCorrectionTo   = pointsCorrection[to].sub(_magCorrection);
        pointsCorrection[to]        = pointsCorrectionTo;

        emit PointsCorrectionUpdated(from, pointsCorrectionFrom);
        emit PointsCorrectionUpdated(to,   pointsCorrectionTo);
    }

    /**
        @dev   Mints tokens to an account. Updates pointsCorrection to keep funds unchanged.
        @param account The account that will receive the created tokens.
        @param value   The amount that will be created.
    */
    function _mint(address account, uint256 value) internal virtual override {
        super._mint(account, value);

        int256 _pointsCorrection = pointsCorrection[account].sub(
            (pointsPerShare.mul(value)).toInt256Safe()
        );

        pointsCorrection[account] = _pointsCorrection;

        emit PointsCorrectionUpdated(account, _pointsCorrection);
    }

    /**
        @dev   Burns an amount of the token of a given account. Updates pointsCorrection to keep funds unchanged.
        @dev   It emits a `PointsCorrectionUpdated` event.
        @param account The account whose tokens will be burnt.
        @param value   The amount that will be burnt.
    */
    function _burn(address account, uint256 value) internal virtual override {
        super._burn(account, value);

        int256 _pointsCorrection = pointsCorrection[account].add(
            (pointsPerShare.mul(value)).toInt256Safe()
        );

        pointsCorrection[account] = _pointsCorrection;

        emit PointsCorrectionUpdated(account, _pointsCorrection);
    }

    /**
        @dev Withdraws all available funds for a token holder.
    */
    function withdrawFunds() public virtual override {}

    /**
        @dev    Updates the current `fundsToken` balance and returns the difference of the new and previous `fundsToken` balance.
        @return A int256 representing the difference of the new and previous `fundsToken` balance.
    */
    function _updateFundsTokenBalance() internal virtual returns (int256) {}

    /**
        @dev Registers a payment of funds in tokens. May be called directly after a deposit is made.
        @dev Calls _updateFundsTokenBalance(), whereby the contract computes the delta of the new and previous
             `fundsToken` balance and increments the total received funds (cumulative), by delta, by calling _distributeFunds().
    */
    function updateFundsReceived() public virtual {
        int256 newFunds = _updateFundsTokenBalance();

        if (newFunds <= 0) return;

        _distributeFunds(newFunds.toUint256Safe());
    }
}

////// contracts/token/ExtendedFDT.sol
/* pragma solidity 0.6.11; */

/* import "./BasicFDT.sol"; */

/// @title ExtendedFDT implements FDT functionality for accounting for losses.
abstract contract ExtendedFDT is BasicFDT {
    using SafeMath       for uint256;
    using SafeMathUint   for uint256;
    using SignedSafeMath for  int256;
    using SafeMathInt    for  int256;

    uint256 internal lossesPerShare;

    mapping(address => int256)  internal lossesCorrection;
    mapping(address => uint256) internal recognizedLosses;

    event   LossesPerShareUpdated(uint256 lossesPerShare);
    event LossesCorrectionUpdated(address indexed account, int256 lossesCorrection);

    /**
        @dev   This event emits when new losses are distributed.
        @param by                The address of the account that has distributed losses.
        @param lossesDistributed The amount of losses received for distribution.
    */
    event LossesDistributed(address indexed by, uint256 lossesDistributed);

    /**
        @dev   This event emits when distributed losses are recognized by a token holder.
        @param by                    The address of the receiver of losses.
        @param lossesRecognized      The amount of losses that were recognized.
        @param totalLossesRecognized The total amount of losses that are recognized.
    */
    event LossesRecognized(address indexed by, uint256 lossesRecognized, uint256 totalLossesRecognized);

    constructor(string memory name, string memory symbol) BasicFDT(name, symbol) public { }

    /**
        @dev Distributes losses to token holders.
        @dev It reverts if the total supply of tokens is 0.
        @dev It emits a `LossesDistributed` event if the amount of received losses is greater than 0.
        @dev It emits a `LossesPerShareUpdated` event if the amount of received losses is greater than 0.
             About undistributed losses:
                In each distribution, there is a small amount of losses which do not get distributed,
                which is `(value * pointsMultiplier) % totalSupply()`.
             With a well-chosen `pointsMultiplier`, the amount losses that are not getting distributed
                in a distribution can be less than 1 (base unit).
             We can actually keep track of the undistributed losses in a distribution
                and try to distribute it in the next distribution.
    */
    function _distributeLosses(uint256 value) internal {
        require(totalSupply() > 0, "FDT:ZERO_SUPPLY");

        if (value == 0) return;

        uint256 _lossesPerShare = lossesPerShare.add(value.mul(pointsMultiplier) / totalSupply());
        lossesPerShare          = _lossesPerShare;

        emit LossesDistributed(msg.sender, value);
        emit LossesPerShareUpdated(_lossesPerShare);
    }

    /**
        @dev    Prepares losses for a withdrawal.
        @dev    It emits a `LossesWithdrawn` event if the amount of withdrawn losses is greater than 0.
        @return recognizableDividend The amount of dividend losses that can be recognized.
    */
    function _prepareLossesWithdraw() internal returns (uint256 recognizableDividend) {
        recognizableDividend = recognizableLossesOf(msg.sender);

        uint256 _recognizedLosses    = recognizedLosses[msg.sender].add(recognizableDividend);
        recognizedLosses[msg.sender] = _recognizedLosses;

        emit LossesRecognized(msg.sender, recognizableDividend, _recognizedLosses);
    }

    /**
        @dev    Returns the amount of losses that an address can withdraw.
        @param  _owner The address of a token holder.
        @return The amount of losses that `_owner` can withdraw.
    */
    function recognizableLossesOf(address _owner) public view returns (uint256) {
        return accumulativeLossesOf(_owner).sub(recognizedLosses[_owner]);
    }

    /**
        @dev    Returns the amount of losses that an address has recognized.
        @param  _owner The address of a token holder
        @return The amount of losses that `_owner` has recognized
    */
    function recognizedLossesOf(address _owner) external view returns (uint256) {
        return recognizedLosses[_owner];
    }

    /**
        @dev    Returns the amount of losses that an address has earned in total.
        @dev    accumulativeLossesOf(_owner) = recognizableLossesOf(_owner) + recognizedLossesOf(_owner)
                = (lossesPerShare * balanceOf(_owner) + lossesCorrection[_owner]) / pointsMultiplier
        @param  _owner The address of a token holder
        @return The amount of losses that `_owner` has earned in total
    */
    function accumulativeLossesOf(address _owner) public view returns (uint256) {
        return
            lossesPerShare
                .mul(balanceOf(_owner))
                .toInt256Safe()
                .add(lossesCorrection[_owner])
                .toUint256Safe() / pointsMultiplier;
    }

    /**
        @dev   Transfers tokens from one account to another. Updates pointsCorrection to keep funds unchanged.
        @dev         It emits two `LossesCorrectionUpdated` events, one for the sender and one for the receiver.
        @param from  The address to transfer from.
        @param to    The address to transfer to.
        @param value The amount to be transferred.
    */
    function _transfer(
        address from,
        address to,
        uint256 value
    ) internal virtual override {
        super._transfer(from, to, value);

        int256 _lossesCorrection    = lossesPerShare.mul(value).toInt256Safe();
        int256 lossesCorrectionFrom = lossesCorrection[from].add(_lossesCorrection);
        lossesCorrection[from]      = lossesCorrectionFrom;
        int256 lossesCorrectionTo   = lossesCorrection[to].sub(_lossesCorrection);
        lossesCorrection[to]        = lossesCorrectionTo;

        emit LossesCorrectionUpdated(from, lossesCorrectionFrom);
        emit LossesCorrectionUpdated(to,   lossesCorrectionTo);
    }

    /**
        @dev   Mints tokens to an account. Updates lossesCorrection to keep losses unchanged.
        @dev   It emits a `LossesCorrectionUpdated` event.
        @param account The account that will receive the created tokens.
        @param value   The amount that will be created.
    */
    function _mint(address account, uint256 value) internal virtual override {
        super._mint(account, value);

        int256 _lossesCorrection = lossesCorrection[account].sub(
            (lossesPerShare.mul(value)).toInt256Safe()
        );

        lossesCorrection[account] = _lossesCorrection;

        emit LossesCorrectionUpdated(account, _lossesCorrection);
    }

    /**
        @dev   Burns an amount of the token of a given account. Updates lossesCorrection to keep losses unchanged.
        @dev   It emits a `LossesCorrectionUpdated` event.
        @param account The account from which tokens will be burnt.
        @param value   The amount that will be burnt.
    */
    function _burn(address account, uint256 value) internal virtual override {
        super._burn(account, value);

        int256 _lossesCorrection = lossesCorrection[account].add(
            (lossesPerShare.mul(value)).toInt256Safe()
        );

        lossesCorrection[account] = _lossesCorrection;

        emit LossesCorrectionUpdated(account, _lossesCorrection);
    }

    /**
        @dev Registers a loss. May be called directly after a shortfall after BPT burning occurs.
        @dev Calls _updateLossesTokenBalance(), whereby the contract computes the delta of the new and previous
             losses balance and increments the total losses (cumulative), by delta, by calling _distributeLosses().
    */
    function updateLossesReceived() public virtual {
        int256 newLosses = _updateLossesBalance();

        if (newLosses <= 0) return;

        _distributeLosses(newLosses.toUint256Safe());
    }

    /**
        @dev Recognizes all recognizable losses for an account using loss accounting.
    */
    function _recognizeLosses() internal virtual returns (uint256 losses) { }

    /**
        @dev    Updates the current losses balance and returns the difference of the new and previous losses balance.
        @return A int256 representing the difference of the new and previous losses balance.
    */
    function _updateLossesBalance() internal virtual returns (int256) { }
}

////// contracts/token/StakeLockerFDT.sol
/* pragma solidity 0.6.11; */

/* import "./ExtendedFDT.sol"; */

/// @title StakeLockerFDT inherits ExtendedFDT and accounts for gains/losses for Stakers.
abstract contract StakeLockerFDT is ExtendedFDT {
    using SafeMath       for uint256;
    using SafeMathUint   for uint256;
    using SignedSafeMath for  int256;
    using SafeMathInt    for  int256;

    IERC20 public immutable fundsToken;

    uint256 public bptLosses;          // Sum of all unrecognized losses.
    uint256 public lossesBalance;      // The amount of losses present and accounted for in this contract.
    uint256 public fundsTokenBalance;  // The amount of `fundsToken` (Liquidity Asset) currently present and accounted for in this contract.

    constructor(string memory name, string memory symbol, address _fundsToken) ExtendedFDT(name, symbol) public {
        fundsToken = IERC20(_fundsToken);
    }

    /**
        @dev    Updates loss accounting for `msg.sender`, recognizing losses.
        @return losses Amount to be subtracted from a withdraw amount.
    */
    function _recognizeLosses() internal override returns (uint256 losses) {
        losses = _prepareLossesWithdraw();

        bptLosses = bptLosses.sub(losses);

        _updateLossesBalance();
    }

    /**
        @dev    Updates the current losses balance and returns the difference of the new and previous losses balance.
        @return A int256 representing the difference of the new and previous losses balance.
    */
    function _updateLossesBalance() internal override returns (int256) {
        uint256 _prevLossesTokenBalance = lossesBalance;

        lossesBalance = bptLosses;

        return int256(lossesBalance).sub(int256(_prevLossesTokenBalance));
    }

    /**
        @dev    Updates the current interest balance and returns the difference of the new and previous interest balance.
        @return A int256 representing the difference of the new and previous interest balance.
    */
    function _updateFundsTokenBalance() internal virtual override returns (int256) {
        uint256 _prevFundsTokenBalance = fundsTokenBalance;

        fundsTokenBalance = fundsToken.balanceOf(address(this));

        return int256(fundsTokenBalance).sub(int256(_prevFundsTokenBalance));
    }
}

////// lib/openzeppelin-contracts/contracts/utils/Address.sol
/* pragma solidity >=0.6.2 <0.8.0; */

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

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

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

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

////// lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol
/* pragma solidity >=0.6.0 <0.8.0; */

/* import "./IERC20.sol"; */
/* import "../../math/SafeMath.sol"; */
/* import "../../utils/Address.sol"; */

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

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

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

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

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

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

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

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

////// lib/openzeppelin-contracts/contracts/utils/Pausable.sol
/* pragma solidity >=0.6.0 <0.8.0; */

/* import "../GSN/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 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());
    }
}

////// contracts/StakeLocker.sol
/* pragma solidity 0.6.11; */

/* import "lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol"; */
/* import "lib/openzeppelin-contracts/contracts/utils/Pausable.sol"; */

/* import "./interfaces/IMapleGlobals.sol"; */
/* import "./interfaces/IPool.sol"; */
/* import "./interfaces/IPoolFactory.sol"; */

/* import "./token/StakeLockerFDT.sol"; */

/// @title StakeLocker holds custody of stakeAsset tokens for a given Pool and earns revenue from interest.
contract StakeLocker is StakeLockerFDT, Pausable {

    using SafeMathInt    for int256;
    using SignedSafeMath for int256;
    using SafeERC20      for IERC20;

    uint256 constant WAD = 10 ** 18;  // Scaling factor for synthetic float division.

    IERC20  public immutable stakeAsset;  // The asset deposited by Stakers into this contract, for liquidation during defaults.

    address public immutable liquidityAsset;  // The Liquidity Asset for the Pool as well as the dividend token for StakeLockerFDT interest.
    address public immutable pool;            // The parent Pool.

    uint256 public lockupPeriod;  // Number of seconds for which unstaking is not allowed.

    mapping(address => uint256)                     public stakeDate;              // Map of account addresses to effective stake date.
    mapping(address => uint256)                     public unstakeCooldown;        // The timestamp of when a Staker called `cooldown()`.
    mapping(address => bool)                        public allowed;                // Map of addresses to allowed status.
    mapping(address => mapping(address => uint256)) public custodyAllowance;       // Amount of StakeLockerFDTs that are "locked" at a certain address.
    mapping(address => uint256)                     public totalCustodyAllowance;  // Total amount of StakeLockerFDTs that are "locked" for a given account, cannot be greater than balance.

    bool public openToPublic;  // Boolean opening StakeLocker to public for staking BPTs

    event            StakeLockerOpened();
    event               BalanceUpdated(address indexed staker, address indexed token, uint256 balance);
    event             AllowListUpdated(address indexed staker, bool status);
    event             StakeDateUpdated(address indexed staker, uint256 stakeDate);
    event          LockupPeriodUpdated(uint256 lockupPeriod);
    event                     Cooldown(address indexed staker, uint256 cooldown);
    event                        Stake(address indexed staker, uint256 amount);
    event                      Unstake(address indexed staker, uint256 amount);
    event              CustodyTransfer(address indexed custodian, address indexed from, address indexed to, uint256 amount);
    event      CustodyAllowanceChanged(address indexed staker, address indexed custodian, uint256 oldAllowance, uint256 newAllowance);
    event TotalCustodyAllowanceUpdated(address indexed staker, uint256 newTotalAllowance);

    constructor(
        address _stakeAsset,
        address _liquidityAsset,
        address _pool
    ) StakeLockerFDT("Maple StakeLocker", "MPLSTAKE", _liquidityAsset) public {
        liquidityAsset = _liquidityAsset;
        stakeAsset     = IERC20(_stakeAsset);
        pool           = _pool;
        lockupPeriod   = 180 days;
    }

    /*****************/
    /*** Modifiers ***/
    /*****************/

    /**
        @dev Checks that an account can unstake given the following conditions:
                 1. The Account is not the Pool Delegate and the Pool is in Finalized state.
                 2. The Pool is in Initialized or Deactivated state.
    */
    modifier canUnstake(address from) {
        IPool _pool = IPool(pool);

        // The Pool cannot be finalized, but if it is, account cannot be the Pool Delegate.
        require(!_pool.isPoolFinalized() || from != _pool.poolDelegate(), "SL:STAKE_LOCKED");
        _;
    }

    /**
        @dev Checks that `msg.sender` is the Governor.
    */
    modifier isGovernor() {
        require(msg.sender == _globals().governor(), "SL:NOT_GOV");
        _;
    }

    /**
        @dev Checks that `msg.sender` is the Pool.
    */
    modifier isPool() {
        require(msg.sender == pool, "SL:NOT_P");
        _;
    }

    /**********************/
    /*** Pool Functions ***/
    /**********************/

    /**
        @dev   Updates Staker status on the allowlist. Only the Pool Delegate can call this function.
        @dev   It emits an `AllowListUpdated` event.
        @param staker The address of the Staker to set status for.
        @param status The status of the Staker on allowlist.
    */
    function setAllowlist(address staker, bool status) public {
        _whenProtocolNotPaused();
        _isValidPoolDelegate();
        allowed[staker] = status;
        emit AllowListUpdated(staker, status);
    }

    /**
        @dev Sets the StakeLocker as open to the public. Only the Pool Delegate can call this function.
        @dev It emits a `StakeLockerOpened` event.
    */
    function openStakeLockerToPublic() external {
        _whenProtocolNotPaused();
        _isValidPoolDelegate();
        openToPublic = true;
        emit StakeLockerOpened();
    }

    /**
        @dev   Sets the lockup period. Only the Pool Delegate can call this function.
        @dev   It emits a `LockupPeriodUpdated` event.
        @param newLockupPeriod New lockup period used to restrict unstaking.
    */
    function setLockupPeriod(uint256 newLockupPeriod) external {
        _whenProtocolNotPaused();
        _isValidPoolDelegate();
        require(newLockupPeriod <= lockupPeriod, "SL:INVALID_VALUE");
        lockupPeriod = newLockupPeriod;
        emit LockupPeriodUpdated(newLockupPeriod);
    }

    /**
        @dev   Transfers an amount of Stake Asset to a destination account. Only the Pool can call this function.
        @param dst Destination to transfer Stake Asset to.
        @param amt Amount of Stake Asset to transfer.
    */
    function pull(address dst, uint256 amt) isPool external {
        stakeAsset.safeTransfer(dst, amt);
    }

    /**
        @dev   Updates loss accounting for StakeLockerFDTs after BPTs have been burned. Only the Pool can call this function.
        @param bptsBurned Amount of BPTs that have been burned.
    */
    function updateLosses(uint256 bptsBurned) isPool external {
        bptLosses = bptLosses.add(bptsBurned);
        updateLossesReceived();
    }

    /************************/
    /*** Staker Functions ***/
    /************************/

    /**
        @dev   Handles a Staker's depositing of an amount of Stake Asset, minting them StakeLockerFDTs.
        @dev   It emits a `StakeDateUpdated` event.
        @dev   It emits a `Stake` event.
        @dev   It emits a `Cooldown` event.
        @dev   It emits a `BalanceUpdated` event.
        @param amt Amount of Stake Asset (BPTs) to deposit.
    */
    function stake(uint256 amt) whenNotPaused external {
        _whenProtocolNotPaused();
        _isAllowed(msg.sender);

        unstakeCooldown[msg.sender] = uint256(0);  // Reset account's unstake cooldown if Staker had previously intended to unstake.

        _updateStakeDate(msg.sender, amt);

        stakeAsset.safeTransferFrom(msg.sender, address(this), amt);
        _mint(msg.sender, amt);

        emit Stake(msg.sender, amt);
        emit Cooldown(msg.sender, uint256(0));
        emit BalanceUpdated(address(this), address(stakeAsset), stakeAsset.balanceOf(address(this)));
    }

    /**
        @dev   Updates information used to calculate unstake delay.
        @dev   It emits a `StakeDateUpdated` event.
        @param account The Staker that deposited BPTs.
        @param amt     Amount of BPTs the Staker has deposited.
    */
    function _updateStakeDate(address account, uint256 amt) internal {
        uint256 prevDate = stakeDate[account];
        uint256 balance = balanceOf(account);

        // stakeDate + (now - stakeDate) * (amt / (balance + amt))
        // NOTE: prevDate = 0 implies balance = 0, and equation reduces to now.
        uint256 newDate = (balance + amt) > 0
            ? prevDate.add(block.timestamp.sub(prevDate).mul(amt).div(balance + amt))
            : prevDate;

        stakeDate[account] = newDate;
        emit StakeDateUpdated(account, newDate);
    }

    /**
        @dev Activates the cooldown period to unstake. It can't be called if the account is not staking.
        @dev It emits a `Cooldown` event.
    **/
    function intendToUnstake() external {
        require(balanceOf(msg.sender) != uint256(0), "SL:ZERO_BALANCE");
        unstakeCooldown[msg.sender] = block.timestamp;
        emit Cooldown(msg.sender, block.timestamp);
    }

    /**
        @dev Cancels an initiated unstake by resetting the calling account's unstake cooldown.
        @dev It emits a `Cooldown` event.
    */
    function cancelUnstake() external {
        require(unstakeCooldown[msg.sender] != uint256(0), "SL:NOT_UNSTAKING");
        unstakeCooldown[msg.sender] = 0;
        emit Cooldown(msg.sender, uint256(0));
    }

    /**
        @dev   Handles a Staker's withdrawing of an amount of Stake Asset, minus any losses. It also claims interest and burns StakeLockerFDTs for the calling account.
        @dev   It emits an `Unstake` event.
        @dev   It emits a `BalanceUpdated` event.
        @param amt Amount of Stake Asset (BPTs) to withdraw.
    */
    function unstake(uint256 amt) external canUnstake(msg.sender) {
        _whenProtocolNotPaused();

        require(balanceOf(msg.sender).sub(amt) >= totalCustodyAllowance[msg.sender], "SL:INSUF_UNSTAKEABLE_BAL");  // Account can only unstake tokens that aren't custodied
        require(isUnstakeAllowed(msg.sender),                                        "SL:OUTSIDE_COOLDOWN");
        require(stakeDate[msg.sender].add(lockupPeriod) <= block.timestamp,          "SL:FUNDS_LOCKED");

        updateFundsReceived();   // Account for any funds transferred into contract since last call.
        _burn(msg.sender, amt);  // Burn the corresponding StakeLockerFDTs balance.
        withdrawFunds();         // Transfer the full entitled Liquidity Asset interest.

        stakeAsset.safeTransfer(msg.sender, amt.sub(_recognizeLosses()));  // Unstake amount minus losses.

        emit Unstake(msg.sender, amt);
        emit BalanceUpdated(address(this), address(stakeAsset), stakeAsset.balanceOf(address(this)));
    }

    /**
        @dev Withdraws all claimable interest earned from the StakeLocker for an account.
        @dev It emits a `BalanceUpdated` event if there are withdrawable funds.
    */
    function withdrawFunds() public override {
        _whenProtocolNotPaused();

        uint256 withdrawableFunds = _prepareWithdraw();

        if (withdrawableFunds == uint256(0)) return;

        fundsToken.safeTransfer(msg.sender, withdrawableFunds);
        emit BalanceUpdated(address(this), address(fundsToken), fundsToken.balanceOf(address(this)));

        _updateFundsTokenBalance();
    }

    /**
        @dev   Increases the custody allowance for a given Custodian corresponding to the account (`msg.sender`).
        @dev   It emits a `CustodyAllowanceChanged` event.
        @dev   It emits a `TotalCustodyAllowanceUpdated` event.
        @param custodian Address which will act as Custodian of a given amount for an account.
        @param amount    Number of additional FDTs to be custodied by the Custodian.
    */
    function increaseCustodyAllowance(address custodian, uint256 amount) external {
        uint256 oldAllowance      = custodyAllowance[msg.sender][custodian];
        uint256 newAllowance      = oldAllowance.add(amount);
        uint256 newTotalAllowance = totalCustodyAllowance[msg.sender].add(amount);

        require(custodian != address(0),                    "SL:INVALID_CUSTODIAN");
        require(amount    != uint256(0),                    "SL:INVALID_AMT");
        require(newTotalAllowance <= balanceOf(msg.sender), "SL:INSUF_BALANCE");

        custodyAllowance[msg.sender][custodian] = newAllowance;
        totalCustodyAllowance[msg.sender]       = newTotalAllowance;
        emit CustodyAllowanceChanged(msg.sender, custodian, oldAllowance, newAllowance);
        emit TotalCustodyAllowanceUpdated(msg.sender, newTotalAllowance);
    }

    /**
        @dev   Transfers custodied StakeLockerFDTs back to the account.
        @dev   `from` and `to` should always be equal in this implementation.
        @dev   This means that the Custodian can only decrease their own allowance and unlock funds for the original owner.
        @dev   It emits a `CustodyTransfer` event.
        @dev   It emits a `CustodyAllowanceChanged` event.
        @dev   It emits a `TotalCustodyAllowanceUpdated` event.
        @param from   Address which holds the StakeLockerFDTs.
        @param to     Address which will be the new owner of the amount of StakeLockerFDTs.
        @param amount Amount of StakeLockerFDTs transferred.
    */
    function transferByCustodian(address from, address to, uint256 amount) external {
        uint256 oldAllowance = custodyAllowance[from][msg.sender];
        uint256 newAllowance = oldAllowance.sub(amount);

        require(to == from,             "SL:INVALID_RECEIVER");
        require(amount != uint256(0),   "SL:INVALID_AMT");

        custodyAllowance[from][msg.sender] = newAllowance;
        uint256 newTotalAllowance          = totalCustodyAllowance[from].sub(amount);
        totalCustodyAllowance[from]        = newTotalAllowance;
        emit CustodyTransfer(msg.sender, from, to, amount);
        emit CustodyAllowanceChanged(from, msg.sender, oldAllowance, newAllowance);
        emit TotalCustodyAllowanceUpdated(msg.sender, newTotalAllowance);
    }

    /**
        @dev   Transfers StakeLockerFDTs.
        @param from Address sending   StakeLockerFDTs.
        @param to   Address receiving StakeLockerFDTs.
        @param wad  Amount of StakeLockerFDTs to transfer.
    */
    function _transfer(address from, address to, uint256 wad) internal override canUnstake(from) {
        _whenProtocolNotPaused();
        require(stakeDate[from].add(lockupPeriod) <= block.timestamp,    "SL:FUNDS_LOCKED");            // Restrict withdrawal during lockup period
        require(balanceOf(from).sub(wad) >= totalCustodyAllowance[from], "SL:INSUF_TRANSFERABLE_BAL");  // Account can only transfer tokens that aren't custodied
        require(isReceiveAllowed(unstakeCooldown[to]),                   "SL:RECIPIENT_NOT_ALLOWED");   // Recipient must not be currently unstaking
        require(recognizableLossesOf(from) == uint256(0),                "SL:RECOG_LOSSES");            // If a staker has unrecognized losses, they must recognize losses through unstake
        _updateStakeDate(to, wad);                                                                      // Update stake date of recipient
        super._transfer(from, to, wad);
    }

    /***********************/
    /*** Admin Functions ***/
    /***********************/

    /**
        @dev Triggers paused state. Halts functionality for certain functions. Only the Pool Delegate or a Pool Admin can call this function.
    */
    function pause() external {
        _isValidPoolDelegateOrPoolAdmin();
        super._pause();
    }

    /**
        @dev Triggers unpaused state. Restores functionality for certain functions. Only the Pool Delegate or a Pool Admin can call this function.
    */
    function unpause() external {
        _isValidPoolDelegateOrPoolAdmin();
        super._unpause();
    }

    /************************/
    /*** Helper Functions ***/
    /************************/

    /**
        @dev Returns if the unstake cooldown period has passed for `msg.sender` and if they are in the unstake window.
    */
    function isUnstakeAllowed(address from) public view returns (bool) {
        IMapleGlobals globals = _globals();
        return (block.timestamp - (unstakeCooldown[from] + globals.stakerCooldownPeriod())) <= globals.stakerUnstakeWindow();
    }

    /**
        @dev Returns if an account is allowed to receive a transfer.
             This is only possible if they have zero cooldown or they are past their unstake window.
    */
    function isReceiveAllowed(uint256 _unstakeCooldown) public view returns (bool) {
        IMapleGlobals globals = _globals();
        return block.timestamp > (_unstakeCooldown + globals.stakerCooldownPeriod() + globals.stakerUnstakeWindow());
    }

    /**
        @dev Checks that `msg.sender` is the Pool Delegate or a Pool Admin.
    */
    function _isValidPoolDelegateOrPoolAdmin() internal view {
        require(msg.sender == IPool(pool).poolDelegate() || IPool(pool).poolAdmins(msg.sender), "SL:NOT_DELEGATE_OR_ADMIN");
    }

    /**
        @dev Checks that `msg.sender` is the Pool Delegate.
    */
    function _isValidPoolDelegate() internal view {
        require(msg.sender == IPool(pool).poolDelegate(), "SL:NOT_DELEGATE");
    }

    /**
        @dev Checks that `msg.sender` is allowed to stake.
    */
    function _isAllowed(address account) internal view {
        require(
            openToPublic || allowed[account] || account == IPool(pool).poolDelegate(),
            "SL:NOT_ALLOWED"
        );
    }

    /**
        @dev Returns the MapleGlobals instance.
    */
    function _globals() internal view returns (IMapleGlobals) {
        return IMapleGlobals(IPoolFactory(IPool(pool).superFactory()).globals());
    }

    /**
        @dev Checks that the protocol is not in a paused state.
    */
    function _whenProtocolNotPaused() internal view {
        require(!_globals().protocolPaused(), "SL:PROTO_PAUSED");
    }

}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_stakeAsset","type":"address"},{"internalType":"address","name":"_liquidityAsset","type":"address"},{"internalType":"address","name":"_pool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"AllowListUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"BalanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"cooldown","type":"uint256"}],"name":"Cooldown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"custodian","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldAllowance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAllowance","type":"uint256"}],"name":"CustodyAllowanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"custodian","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CustodyTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundsDistributed","type":"uint256"}],"name":"FundsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundsWithdrawn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalWithdrawn","type":"uint256"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lockupPeriod","type":"uint256"}],"name":"LockupPeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"int256","name":"lossesCorrection","type":"int256"}],"name":"LossesCorrectionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"lossesDistributed","type":"uint256"}],"name":"LossesDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lossesPerShare","type":"uint256"}],"name":"LossesPerShareUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"lossesRecognized","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalLossesRecognized","type":"uint256"}],"name":"LossesRecognized","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":"account","type":"address"},{"indexed":false,"internalType":"int256","name":"pointsCorrection","type":"int256"}],"name":"PointsCorrectionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pointsPerShare","type":"uint256"}],"name":"PointsPerShareUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeDate","type":"uint256"}],"name":"StakeDateUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"StakeLockerOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"newTotalAllowance","type":"uint256"}],"name":"TotalCustodyAllowanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstake","type":"event"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"accumulativeFundsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"accumulativeLossesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bptLosses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"custodyAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundsToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundsTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"custodian","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseCustodyAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"intendToUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unstakeCooldown","type":"uint256"}],"name":"isReceiveAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"isUnstakeAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockupPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossesBalance","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":"openStakeLockerToPublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"openToPublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"recognizableLossesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"recognizedLossesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLockupPeriod","type":"uint256"}],"name":"setLockupPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeAsset","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakeDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalCustodyAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferByCustodian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"unstakeCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateFundsReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bptsBurned","type":"uint256"}],"name":"updateLosses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateLossesReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"withdrawableFundsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"withdrawnFundsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6101006040523480156200001257600080fd5b50604051620040fb380380620040fb833981810160405260608110156200003857600080fd5b50805160208083015160409384015184518086018652601181527026b0b836329029ba30b5b2a637b1b5b2b960791b818501908152865180880190975260088752674d504c5354414b4560c01b9487019490945280519495929491939092918591849184918391839183918391620000b4916003919062000124565b508051620000ca90600490602084019062000124565b50506005805460ff199081166012179091556001600160601b0319606097881b8116608052600f805490921690915599861b8a1660c052505050505094851b841660a052505090911b1660e05262ed4e00601055620001c9565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200016757805160ff191683800117855562000197565b8280016001018555821562000197579182015b82811115620001975782518255916020019190600101906200017a565b50620001a5929150620001a9565b5090565b620001c691905b80821115620001a55760008155600101620001b0565b90565b60805160601c60a05160601c60c05160601c60e05160601c613e9b62000260600039806109cd5280610fcb5280611bac5280611d5552806120915280612167528061281a52806128ce5280612cf55280612e1c525080610a005250806112915280611316528061164f52806119725280611a395280611dbf525080610adc5280610b2b52806115ea52806126185250613e9b6000f3fe608060405234801561001057600080fd5b50600436106102d55760003560e01c806370a0823111610182578063af6d5571116100e9578063d63a8e11116100a2578063f2d5d56b1161007c578063f2d5d56b14610839578063fab1107814610865578063fec984e314610882578063ff8871301461088a576102d5565b8063d63a8e11146107dd578063dd62ed3e14610803578063ee947a7c14610831576102d5565b8063af6d557114610719578063b12527f81461073f578063bcd01be71461076d578063c771c3901461078a578063c965b548146107a7578063cc0fef02146107d5576102d5565b8063a457c2d71161013b578063a457c2d71461066e578063a694fc3a1461069a578063a9059cbb146106b7578063a9691f3f146106e3578063aed4966a146106eb578063aedc78c314610711576102d5565b806370a082311461060257806380cd916d146106285780638456cb591461063057806386bf1da3146106385780638a10555c1461065e57806395d89b4114610666576102d5565b80632e17de781161024157806346c162de116101fa5780635190bbaf116101d45780635190bbaf146105a65780635c975abb146105cc57806363f04b15146105d457806366967791146105dc576102d5565b806346c162de146105705780634ab17969146105785780634e97415f14610580576102d5565b80632e17de78146104b5578063313ce567146104d257806339509351146104f05780633f4ba83a1461051c57806340bde09814610524578063443bb2931461054a576102d5565b80631831ccf2116102935780631831ccf214610405578063209b2bca1461040d57806323b872dd1461041557806324600fc31461044b57806327f91856146104535780632ac04ac81461047f576102d5565b806241c52c146102da57806306fdde0314610312578063095ea7b31461038f5780630e754e86146103cf57806316f0115b146103d957806318160ddd146103fd575b600080fd5b610300600480360360208110156102f057600080fd5b50356001600160a01b03166108b0565b60408051918252519081900360200190f35b61031a6108cf565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561035457818101518382015260200161033c565b50505050905090810190601f1680156103815780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103bb600480360360408110156103a557600080fd5b506001600160a01b038135169060200135610965565b604080519115158252519081900360200190f35b6103d7610983565b005b6103e16109cb565b604080516001600160a01b039092168252519081900360200190f35b6103006109ef565b6103bb6109f5565b6103e16109fe565b6103bb6004803603606081101561042b57600080fd5b506001600160a01b03813581169160208101359091169060400135610a22565b6103d7610ab0565b6103d76004803603604081101561046957600080fd5b506001600160a01b038135169060200135610be0565b6103d76004803603606081101561049557600080fd5b506001600160a01b03813581169160208101359091169060400135610dcd565b6103d7600480360360208110156104cb57600080fd5b5035610fc6565b6104da6113c3565b6040805160ff9092168252519081900360200190f35b6103bb6004803603604081101561050657600080fd5b506001600160a01b0381351690602001356113cc565b6103d7611420565b6103006004803603602081101561053a57600080fd5b50356001600160a01b0316611430565b6103006004803603602081101561056057600080fd5b50356001600160a01b0316611499565b6103d76114bf565b6103d76114ed565b6103006004803603602081101561059657600080fd5b50356001600160a01b0316611588565b610300600480360360208110156105bc57600080fd5b50356001600160a01b03166115cd565b6103bb6115df565b6103e16115e8565b610300600480360360208110156105f257600080fd5b50356001600160a01b031661160c565b6103006004803603602081101561061857600080fd5b50356001600160a01b0316611632565b6103e161164d565b6103d7611671565b6103bb6004803603602081101561064e57600080fd5b50356001600160a01b0316611681565b6103d7611785565b61031a611820565b6103bb6004803603604081101561068457600080fd5b506001600160a01b038135169060200135611881565b6103d7600480360360208110156106b057600080fd5b50356118ef565b6103bb600480360360408110156106cd57600080fd5b506001600160a01b038135169060200135611ae4565b610300611af8565b6103006004803603602081101561070157600080fd5b50356001600160a01b0316611afe565b610300611b19565b6103006004803603602081101561072f57600080fd5b50356001600160a01b0316611b1f565b6103d76004803603604081101561075557600080fd5b506001600160a01b0381351690602001351515611b31565b6103d76004803603602081101561078357600080fd5b5035611ba1565b6103d7600480360360208110156107a057600080fd5b5035611c27565b610300600480360360408110156107bd57600080fd5b506001600160a01b0381358116916020013516611cbc565b6103d7611cd9565b6103bb600480360360208110156107f357600080fd5b50356001600160a01b0316611d04565b6103006004803603604081101561081957600080fd5b506001600160a01b0381358116916020013516611d19565b610300611d44565b6103d76004803603604081101561084f57600080fd5b506001600160a01b038135169060200135611d4a565b6103bb6004803603602081101561087b57600080fd5b5035611dec565b610300611ed7565b610300600480360360208110156108a057600080fd5b50356001600160a01b0316611edd565b6001600160a01b0381166000908152600860205260409020545b919050565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561095b5780601f106109305761010080835404028352916020019161095b565b820191906000526020600020905b81548152906001019060200180831161093e57829003601f168201915b5050505050905090565b6000610979610972611eef565b8484611ef3565b5060015b92915050565b61098b611fdf565b61099361208f565b6016805460ff191660011790556040517fd33782a61f25b663946a975c2c1799d6e6d2dc636024b8980789f9e9671abb7890600090a1565b7f000000000000000000000000000000000000000000000000000000000000000081565b60025490565b60165460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610a2f848484612162565b610aa584610a3b611eef565b610aa085604051806060016040528060288152602001613d61602891396001600160a01b038a16600090815260016020526040812090610a79611eef565b6001600160a01b03168152602081019190915260400160002054919063ffffffff61247e16565b611ef3565b5060015b9392505050565b610ab8611fdf565b6000610ac2612515565b905080610acf5750610bde565b610b096001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016338363ffffffff61259a16565b604080516370a0823160e01b8152306004820181905291516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692917f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a29184916370a08231916024808301926020929190829003018186803b158015610b9657600080fd5b505afa158015610baa573d6000803e3d6000fd5b505050506040513d6020811015610bc057600080fd5b505160408051918252519081900360200190a3610bdb6125f1565b50505b565b3360009081526014602090815260408083206001600160a01b038616845290915281205490610c15828463ffffffff6126a616565b3360009081526015602052604081205491925090610c39908563ffffffff6126a616565b90506001600160a01b038516610c8d576040805162461bcd60e51b815260206004820152601460248201527329a61d24a72b20a624a22fa1aaa9aa27a224a0a760611b604482015290519081900360640190fd5b83610cd0576040805162461bcd60e51b815260206004820152600e60248201526d14d30e9253959053125117d0535560921b604482015290519081900360640190fd5b610cd933611632565b811115610d20576040805162461bcd60e51b815260206004820152601060248201526f534c3a494e5355465f42414c414e434560801b604482015290519081900360640190fd5b3360008181526014602090815260408083206001600160a01b038a168085529083528184208790558484526015835292819020859055805187815291820186905280519293927f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e89281900390910190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a25050505050565b6001600160a01b038316600090815260146020908152604080832033845290915281205490610e02828463ffffffff61270016565b9050846001600160a01b0316846001600160a01b031614610e60576040805162461bcd60e51b815260206004820152601360248201527229a61d24a72b20a624a22fa922a1a2a4ab22a960691b604482015290519081900360640190fd5b82610ea3576040805162461bcd60e51b815260206004820152600e60248201526d14d30e9253959053125117d0535560921b604482015290519081900360640190fd5b6001600160a01b038516600081815260146020908152604080832033845282528083208590559282526015905290812054610ee4908563ffffffff61270016565b6001600160a01b038088166000818152601560209081526040918290208590558151898152915194955092891693919233927ffaa022ea2cd7f14157070896fabadafe96cc4d4714eef7ae6a992a5084493ed59281900390910190a46040805184815260208101849052815133926001600160a01b038a16927f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e8929081900390910190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a2505050505050565b3360007f00000000000000000000000000000000000000000000000000000000000000009050806001600160a01b0316634f85221a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561102557600080fd5b505afa158015611039573d6000803e3d6000fd5b505050506040513d602081101561104f57600080fd5b505115806110cd5750806001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561109157600080fd5b505afa1580156110a5573d6000803e3d6000fd5b505050506040513d60208110156110bb57600080fd5b50516001600160a01b03838116911614155b611110576040805162461bcd60e51b815260206004820152600f60248201526e14d30e94d51052d157d313d0d2d151608a1b604482015290519081900360640190fd5b611118611fdf565b336000818152601560205260409020549061114490859061113890611632565b9063ffffffff61270016565b1015611197576040805162461bcd60e51b815260206004820152601860248201527f534c3a494e5355465f554e5354414b4541424c455f42414c0000000000000000604482015290519081900360640190fd5b6111a033611681565b6111e7576040805162461bcd60e51b815260206004820152601360248201527229a61d27aaaa29a4a222afa1a7a7a62227aba760691b604482015290519081900360640190fd5b60105433600090815260116020526040902054429161120c919063ffffffff6126a616565b1115611251576040805162461bcd60e51b815260206004820152600f60248201526e14d30e9195539114d7d313d0d2d151608a1b604482015290519081900360640190fd5b6112596114bf565b6112633384612742565b61126b610ab0565b6112be3361128761127a6127e9565b869063ffffffff61270016565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919063ffffffff61259a16565b60408051848152905133917f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd919081900360200190a2604080516370a0823160e01b8152306004820181905291516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692917f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a29184916370a08231916024808301926020929190829003018186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d60208110156113ab57600080fd5b505160408051918252519081900360200190a3505050565b60055460ff1690565b60006109796113d9611eef565b84610aa085600160006113ea611eef565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff6126a616565b611428612818565b610bde612992565b6001600160a01b0381166000908152600a6020526040812054600160801b9061148b906114869061147a61147561146688611632565b6009549063ffffffff612a3016565b612a89565b9063ffffffff612aca16565b612b2f565b8161149257fe5b0492915050565b6001600160a01b03811660009081526008602052604081205461097d9061113884611588565b60006114c96125f1565b9050600081136114d95750610bde565b6114ea6114e582612b2f565b612b70565b50565b33600090815260126020526040902054611541576040805162461bcd60e51b815260206004820152601060248201526f534c3a4e4f545f554e5354414b494e4760801b604482015290519081900360640190fd5b3360008181526012602090815260408083208390558051928352517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b6001600160a01b038116600090815260076020526040812054600160801b9061148b906114869061147a6114756115be88611632565b6006549063ffffffff612a3016565b60116020526000908152604090205481565b600f5460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000081565b6001600160a01b0381166000908152600b602052604081205461097d9061113884611430565b6001600160a01b031660009081526020819052604090205490565b7f000000000000000000000000000000000000000000000000000000000000000081565b611679612818565b610bde612c70565b60008061168c612cf1565b9050806001600160a01b0316632018b8706040518163ffffffff1660e01b815260040160206040518083038186803b1580156116c757600080fd5b505afa1580156116db573d6000803e3d6000fd5b505050506040513d60208110156116f157600080fd5b50516040805163a965d6b560e01b815290516001600160a01b0384169163a965d6b5916004808301926020929190829003018186803b15801561173357600080fd5b505afa158015611747573d6000803e3d6000fd5b505050506040513d602081101561175d57600080fd5b50516001600160a01b0385166000908152601260205260409020540142031115915050919050565b600061179033611632565b14156117d5576040805162461bcd60e51b815260206004820152600f60248201526e534c3a5a45524f5f42414c414e434560881b604482015290519081900360640190fd5b336000818152601260209081526040918290204290819055825190815291517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561095b5780601f106109305761010080835404028352916020019161095b565b600061097961188e611eef565b84610aa085604051806060016040528060258152602001613e4160259139600160006118b8611eef565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61247e16565b600f5460ff161561193a576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b611942611fdf565b61194b33612deb565b336000818152601260205260408120556119659082612ef0565b6119a06001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308463ffffffff612fc516565b6119aa3382613025565b60408051828152905133917febedb8b3c678666e7f36970bc8f57abf6d8fa2e828c0da91ea5b75bf68ed101a919081900360200190a26040805160008152905133917f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d65919081900360200190a2604080516370a0823160e01b8152306004820181905291516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692917f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a29184916370a08231916024808301926020929190829003018186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d6020811015611ace57600080fd5b505160408051918252519081900360200190a350565b6000610979611af1611eef565b8484612162565b600e5481565b6001600160a01b03166000908152600b602052604090205490565b600c5481565b60156020526000908152604090205481565b611b39611fdf565b611b4161208f565b6001600160a01b038216600081815260136020908152604091829020805460ff1916851515908117909155825190815291517f73121574a4eadb4cfdeb2ba56a6a88067b03edd1f0a0dfcac0a5a95682a243679281900390910190a25050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611c09576040805162461bcd60e51b81526020600482015260086024820152670534c3a4e4f545f560c41b604482015290519081900360640190fd5b600c54611c1c908263ffffffff6126a616565b600c556114ea611cd9565b611c2f611fdf565b611c3761208f565b601054811115611c81576040805162461bcd60e51b815260206004820152601060248201526f534c3a494e56414c49445f56414c554560801b604482015290519081900360640190fd5b60108190556040805182815290517fcc67306c5d19f79a73208a1270ca19eb367b4bd5258eac096e974365d18e432c9181900360200190a150565b601460209081526000928352604080842090915290825290205481565b6000611ce3613071565b905060008113611cf35750610bde565b6114ea611cff82612b2f565b61308f565b60136020526000908152604090205460ff1681565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60105481565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611db2576040805162461bcd60e51b81526020600482015260086024820152670534c3a4e4f545f560c41b604482015290519081900360640190fd5b610bdb6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016838363ffffffff61259a16565b600080611df7612cf1565b9050806001600160a01b0316632018b8706040518163ffffffff1660e01b815260040160206040518083038186803b158015611e3257600080fd5b505afa158015611e46573d6000803e3d6000fd5b505050506040513d6020811015611e5c57600080fd5b50516040805163a965d6b560e01b815290516001600160a01b0384169163a965d6b5916004808301926020929190829003018186803b158015611e9e57600080fd5b505afa158015611eb2573d6000803e3d6000fd5b505050506040513d6020811015611ec857600080fd5b50518401014211915050919050565b600d5481565b60126020526000908152604090205481565b3390565b6001600160a01b038316611f385760405162461bcd60e51b8152600401808060200182810382526024815260200180613dcf6024913960400191505060405180910390fd5b6001600160a01b038216611f7d5760405162461bcd60e51b8152600401808060200182810382526022815260200180613cb16022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b611fe7612cf1565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561201f57600080fd5b505afa158015612033573d6000803e3d6000fd5b505050506040513d602081101561204957600080fd5b505115610bde576040805162461bcd60e51b815260206004820152600f60248201526e14d30e941493d513d7d4105554d151608a1b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120e857600080fd5b505afa1580156120fc573d6000803e3d6000fd5b505050506040513d602081101561211257600080fd5b50516001600160a01b03163314610bde576040805162461bcd60e51b815260206004820152600f60248201526e534c3a4e4f545f44454c454741544560881b604482015290519081900360640190fd5b8260007f00000000000000000000000000000000000000000000000000000000000000009050806001600160a01b0316634f85221a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156121c157600080fd5b505afa1580156121d5573d6000803e3d6000fd5b505050506040513d60208110156121eb57600080fd5b505115806122695750806001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561222d57600080fd5b505afa158015612241573d6000803e3d6000fd5b505050506040513d602081101561225757600080fd5b50516001600160a01b03838116911614155b6122ac576040805162461bcd60e51b815260206004820152600f60248201526e14d30e94d51052d157d313d0d2d151608a1b604482015290519081900360640190fd5b6122b4611fdf565b6010546001600160a01b03861660009081526011602052604090205442916122e2919063ffffffff6126a616565b1115612327576040805162461bcd60e51b815260206004820152600f60248201526e14d30e9195539114d7d313d0d2d151608a1b604482015290519081900360640190fd5b6001600160a01b03851660009081526015602052604090205461234d8461113888611632565b10156123a0576040805162461bcd60e51b815260206004820152601960248201527f534c3a494e5355465f5452414e5346455241424c455f42414c00000000000000604482015290519081900360640190fd5b6001600160a01b0384166000908152601260205260409020546123c290611dec565b612413576040805162461bcd60e51b815260206004820152601860248201527f534c3a524543495049454e545f4e4f545f414c4c4f5745440000000000000000604482015290519081900360640190fd5b600061241e8661160c565b14612462576040805162461bcd60e51b815260206004820152600f60248201526e534c3a5245434f475f4c4f5353455360881b604482015290519081900360640190fd5b61246c8484612ef0565b612477858585613194565b5050505050565b6000818484111561250d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156124d25781810151838201526020016124ba565b50505050905090810190601f1680156124ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061252033611499565b3360009081526008602052604081205491925090612544908363ffffffff6126a616565b336000818152600860209081526040918290208490558151868152908101849052815193945091927ffbc3a599b784fe88772fc5abcc07223f64ca0b13acc341f4fb1e46bef0510eb49281900390910190a25090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526125ec9084906132c0565b505050565b600e54604080516370a0823160e01b81523060048201529051600092916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b15801561265f57600080fd5b505afa158015612673573d6000803e3d6000fd5b505050506040513d602081101561268957600080fd5b5051600e8190556126a0908263ffffffff61337116565b91505090565b600082820183811015610aa9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610aa983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061247e565b61274c82826133d6565b600061278e61276961147584600954612a3090919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff612aca16565b6001600160a01b0384166000818152600a60209081526040918290208490558151848152915193945091927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a2505050565b60006127f361347d565b600c54909150612809908263ffffffff61270016565b600c55612814613071565b5090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561287157600080fd5b505afa158015612885573d6000803e3d6000fd5b505050506040513d602081101561289b57600080fd5b50516001600160a01b0316331480612941575060408051633099c27960e11b815233600482015290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163613384f2916024808301926020929190829003018186803b15801561291457600080fd5b505afa158015612928573d6000803e3d6000fd5b505050506040513d602081101561293e57600080fd5b50515b610bde576040805162461bcd60e51b815260206004820152601860248201527f534c3a4e4f545f44454c45474154455f4f525f41444d494e0000000000000000604482015290519081900360640190fd5b600f5460ff166129e0576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b600f805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612a13611eef565b604080516001600160a01b039092168252519081900360200190a1565b600082612a3f5750600061097d565b82820282848281612a4c57fe5b0414610aa95760405162461bcd60e51b8152600401808060200182810382526021815260200180613d406021913960400191505060405180910390fd5b8060008112156108ca576040805162461bcd60e51b815260206004820152600760248201526629a6aa9d27a7a160c91b604482015290519081900360640190fd5b6000828201818312801590612adf5750838112155b80612af45750600083128015612af457508381125b610aa95760405162461bcd60e51b8152600401808060200182810382526021815260200180613cf96021913960400191505060405180910390fd5b600080821215612814576040805162461bcd60e51b8152602060048201526007602482015266534d493a4e454760c81b604482015290519081900360640190fd5b6000612b7a6109ef565b11612bbe576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b80612bc8576114ea565b612bff612bd36109ef565b612be783600160801b63ffffffff612a3016565b81612bee57fe5b60065491900463ffffffff6126a616565b60065560408051828152905133917f26536799ace2c3dbe12e638ec3ade6b4173dcf1289be0a58d51a5003015649bd919081900360200190a260065460408051918252517f1f8d7705f31c3337a080803a8ad7e71946fb88d84738879be2bf402f97156e969181900360200190a150565b600f5460ff1615612cbb576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b600f805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a13611eef565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630d49b38c6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4c57600080fd5b505afa158015612d60573d6000803e3d6000fd5b505050506040513d6020811015612d7657600080fd5b50516040805163c312452560e01b815290516001600160a01b039092169163c312452591600480820192602092909190829003018186803b158015612dba57600080fd5b505afa158015612dce573d6000803e3d6000fd5b505050506040513d6020811015612de457600080fd5b5051905090565b60165460ff1680612e1457506001600160a01b03811660009081526013602052604090205460ff165b80612eae57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b158015612e7357600080fd5b505afa158015612e87573d6000803e3d6000fd5b505050506040513d6020811015612e9d57600080fd5b50516001600160a01b038281169116145b6114ea576040805162461bcd60e51b815260206004820152600e60248201526d14d30e9393d517d0531313d5d15160921b604482015290519081900360640190fd5b6001600160a01b03821660009081526011602052604081205490612f1384611632565b905060008084830111612f265782612f68565b612f68612f5b838601612f4f87612f43428963ffffffff61270016565b9063ffffffff612a3016565b9063ffffffff61350216565b849063ffffffff6126a616565b6001600160a01b0386166000818152601160209081526040918290208490558151848152915193945091927f09686619568b9bd7c4faea3ba0efbeab967ec977167b97405ad208f1a9ccea69929181900390910190a25050505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261301f9085906132c0565b50505050565b61302f8282613544565b600061278e61304c61147584600954612a3090919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff61337116565b600d8054600c54918290556000916126a0908263ffffffff61337116565b60006130996109ef565b116130dd576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b806130e7576114ea565b60006131206130f46109ef565b61310884600160801b63ffffffff612a3016565b8161310f57fe5b60095491900463ffffffff6126a616565b600981905560408051848152905191925033917ff88156a8032a0d2c65df18fafaf84e0bea647b3d94a0f7fc6ab14c97dec2bf749181900360200190a26040805182815290517f240ce2b5ce9e9e5a70010c7f8034c233d89b7ce2d60f3a38d9bc3ca01a36f88c9181900360200190a15050565b61319f838383613590565b60006131b961147583600954612a3090919063ffffffff16565b6001600160a01b0385166000908152600a6020526040812054919250906131e6908363ffffffff612aca16565b6001600160a01b038087166000908152600a602052604080822084905591871681529081205491925090613220908463ffffffff61337116565b6001600160a01b038087166000908152600a602090815260409182902084905581518681529151939450918916927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a26040805182815290516001600160a01b038716917fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3919081900360200190a2505050505050565b6060613315826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166136bc9092919063ffffffff16565b8051909150156125ec5780806020019051602081101561333457600080fd5b50516125ec5760405162461bcd60e51b815260040180806020018281038252602a815260200180613e17602a913960400191505060405180910390fd5b60008183038183128015906133865750838113155b8061339b575060008312801561339b57508381135b610aa95760405162461bcd60e51b8152600401808060200182810382526024815260200180613df36024913960400191505060405180910390fd5b6133e082826136d3565b60006134226133fd61147584600654612a3090919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff612aca16565b6001600160a01b0384166000818152600760209081526040918290208490558151848152915193945091927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a2505050565b60006134883361160c565b336000908152600b6020526040812054919250906134ac908363ffffffff6126a616565b336000818152600b60209081526040918290208490558151868152908101849052815193945091927f814eba35782909dbbaeefb8104073dfca45de43173f7077970c1584b3cf918b59281900390910190a25090565b6000610aa983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506137db565b61354e8282613840565b600061342261356b61147584600654612a3090919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff61337116565b61359b83838361393c565b60006135b561147583600654612a3090919063ffffffff16565b6001600160a01b038516600090815260076020526040812054919250906135e2908363ffffffff612aca16565b6001600160a01b038087166000908152600760205260408082208490559187168152908120549192509061361c908463ffffffff61337116565b6001600160a01b0380871660009081526007602090815260409182902084905581518681529151939450918916927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a26040805182815290516001600160a01b038716917ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773919081900360200190a2505050505050565b60606136cb8484600085613aa3565b949350505050565b6001600160a01b0382166137185760405162461bcd60e51b8152600401808060200182810382526021815260200180613d896021913960400191505060405180910390fd5b613724826000836125ec565b61376781604051806060016040528060228152602001613c8f602291396001600160a01b038516600090815260208190526040902054919063ffffffff61247e16565b6001600160a01b038316600090815260208190526040902055600254613793908263ffffffff61270016565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6000818361382a5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156124d25781810151838201526020016124ba565b50600083858161383657fe5b0495945050505050565b6001600160a01b03821661389b576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6138a7600083836125ec565b6002546138ba908263ffffffff6126a616565b6002556001600160a01b0382166000908152602081905260409020546138e6908263ffffffff6126a616565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b0383166139815760405162461bcd60e51b8152600401808060200182810382526025815260200180613daa6025913960400191505060405180910390fd5b6001600160a01b0382166139c65760405162461bcd60e51b8152600401808060200182810382526023815260200180613c6c6023913960400191505060405180910390fd5b6139d18383836125ec565b613a1481604051806060016040528060268152602001613cd3602691396001600160a01b038616600090815260208190526040902054919063ffffffff61247e16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054613a49908263ffffffff6126a616565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b606082471015613ae45760405162461bcd60e51b8152600401808060200182810382526026815260200180613d1a6026913960400191505060405180910390fd5b613aed85613bff565b613b3e576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613b7d5780518252601f199092019160209182019101613b5e565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613bdf576040519150601f19603f3d011682016040523d82523d6000602084013e613be4565b606091505b5091509150613bf4828286613c05565b979650505050505050565b3b151590565b60608315613c14575081610aa9565b825115613c245782518084602001fd5b60405162461bcd60e51b81526020600482018181528451602484015284518593919283926044019190850190808383600083156124d25781810151838201526020016124ba56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63655369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122048f517b477c459d5376e0cc0cd024aca11f8214b1affb8111823a449ec0c5e9564736f6c634300060b0033000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c27

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102d55760003560e01c806370a0823111610182578063af6d5571116100e9578063d63a8e11116100a2578063f2d5d56b1161007c578063f2d5d56b14610839578063fab1107814610865578063fec984e314610882578063ff8871301461088a576102d5565b8063d63a8e11146107dd578063dd62ed3e14610803578063ee947a7c14610831576102d5565b8063af6d557114610719578063b12527f81461073f578063bcd01be71461076d578063c771c3901461078a578063c965b548146107a7578063cc0fef02146107d5576102d5565b8063a457c2d71161013b578063a457c2d71461066e578063a694fc3a1461069a578063a9059cbb146106b7578063a9691f3f146106e3578063aed4966a146106eb578063aedc78c314610711576102d5565b806370a082311461060257806380cd916d146106285780638456cb591461063057806386bf1da3146106385780638a10555c1461065e57806395d89b4114610666576102d5565b80632e17de781161024157806346c162de116101fa5780635190bbaf116101d45780635190bbaf146105a65780635c975abb146105cc57806363f04b15146105d457806366967791146105dc576102d5565b806346c162de146105705780634ab17969146105785780634e97415f14610580576102d5565b80632e17de78146104b5578063313ce567146104d257806339509351146104f05780633f4ba83a1461051c57806340bde09814610524578063443bb2931461054a576102d5565b80631831ccf2116102935780631831ccf214610405578063209b2bca1461040d57806323b872dd1461041557806324600fc31461044b57806327f91856146104535780632ac04ac81461047f576102d5565b806241c52c146102da57806306fdde0314610312578063095ea7b31461038f5780630e754e86146103cf57806316f0115b146103d957806318160ddd146103fd575b600080fd5b610300600480360360208110156102f057600080fd5b50356001600160a01b03166108b0565b60408051918252519081900360200190f35b61031a6108cf565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561035457818101518382015260200161033c565b50505050905090810190601f1680156103815780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103bb600480360360408110156103a557600080fd5b506001600160a01b038135169060200135610965565b604080519115158252519081900360200190f35b6103d7610983565b005b6103e16109cb565b604080516001600160a01b039092168252519081900360200190f35b6103006109ef565b6103bb6109f5565b6103e16109fe565b6103bb6004803603606081101561042b57600080fd5b506001600160a01b03813581169160208101359091169060400135610a22565b6103d7610ab0565b6103d76004803603604081101561046957600080fd5b506001600160a01b038135169060200135610be0565b6103d76004803603606081101561049557600080fd5b506001600160a01b03813581169160208101359091169060400135610dcd565b6103d7600480360360208110156104cb57600080fd5b5035610fc6565b6104da6113c3565b6040805160ff9092168252519081900360200190f35b6103bb6004803603604081101561050657600080fd5b506001600160a01b0381351690602001356113cc565b6103d7611420565b6103006004803603602081101561053a57600080fd5b50356001600160a01b0316611430565b6103006004803603602081101561056057600080fd5b50356001600160a01b0316611499565b6103d76114bf565b6103d76114ed565b6103006004803603602081101561059657600080fd5b50356001600160a01b0316611588565b610300600480360360208110156105bc57600080fd5b50356001600160a01b03166115cd565b6103bb6115df565b6103e16115e8565b610300600480360360208110156105f257600080fd5b50356001600160a01b031661160c565b6103006004803603602081101561061857600080fd5b50356001600160a01b0316611632565b6103e161164d565b6103d7611671565b6103bb6004803603602081101561064e57600080fd5b50356001600160a01b0316611681565b6103d7611785565b61031a611820565b6103bb6004803603604081101561068457600080fd5b506001600160a01b038135169060200135611881565b6103d7600480360360208110156106b057600080fd5b50356118ef565b6103bb600480360360408110156106cd57600080fd5b506001600160a01b038135169060200135611ae4565b610300611af8565b6103006004803603602081101561070157600080fd5b50356001600160a01b0316611afe565b610300611b19565b6103006004803603602081101561072f57600080fd5b50356001600160a01b0316611b1f565b6103d76004803603604081101561075557600080fd5b506001600160a01b0381351690602001351515611b31565b6103d76004803603602081101561078357600080fd5b5035611ba1565b6103d7600480360360208110156107a057600080fd5b5035611c27565b610300600480360360408110156107bd57600080fd5b506001600160a01b0381358116916020013516611cbc565b6103d7611cd9565b6103bb600480360360208110156107f357600080fd5b50356001600160a01b0316611d04565b6103006004803603604081101561081957600080fd5b506001600160a01b0381358116916020013516611d19565b610300611d44565b6103d76004803603604081101561084f57600080fd5b506001600160a01b038135169060200135611d4a565b6103bb6004803603602081101561087b57600080fd5b5035611dec565b610300611ed7565b610300600480360360208110156108a057600080fd5b50356001600160a01b0316611edd565b6001600160a01b0381166000908152600860205260409020545b919050565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561095b5780601f106109305761010080835404028352916020019161095b565b820191906000526020600020905b81548152906001019060200180831161093e57829003601f168201915b5050505050905090565b6000610979610972611eef565b8484611ef3565b5060015b92915050565b61098b611fdf565b61099361208f565b6016805460ff191660011790556040517fd33782a61f25b663946a975c2c1799d6e6d2dc636024b8980789f9e9671abb7890600090a1565b7f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c2781565b60025490565b60165460ff1681565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6000610a2f848484612162565b610aa584610a3b611eef565b610aa085604051806060016040528060288152602001613d61602891396001600160a01b038a16600090815260016020526040812090610a79611eef565b6001600160a01b03168152602081019190915260400160002054919063ffffffff61247e16565b611ef3565b5060015b9392505050565b610ab8611fdf565b6000610ac2612515565b905080610acf5750610bde565b610b096001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816338363ffffffff61259a16565b604080516370a0823160e01b8152306004820181905291516001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481692917f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a29184916370a08231916024808301926020929190829003018186803b158015610b9657600080fd5b505afa158015610baa573d6000803e3d6000fd5b505050506040513d6020811015610bc057600080fd5b505160408051918252519081900360200190a3610bdb6125f1565b50505b565b3360009081526014602090815260408083206001600160a01b038616845290915281205490610c15828463ffffffff6126a616565b3360009081526015602052604081205491925090610c39908563ffffffff6126a616565b90506001600160a01b038516610c8d576040805162461bcd60e51b815260206004820152601460248201527329a61d24a72b20a624a22fa1aaa9aa27a224a0a760611b604482015290519081900360640190fd5b83610cd0576040805162461bcd60e51b815260206004820152600e60248201526d14d30e9253959053125117d0535560921b604482015290519081900360640190fd5b610cd933611632565b811115610d20576040805162461bcd60e51b815260206004820152601060248201526f534c3a494e5355465f42414c414e434560801b604482015290519081900360640190fd5b3360008181526014602090815260408083206001600160a01b038a168085529083528184208790558484526015835292819020859055805187815291820186905280519293927f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e89281900390910190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a25050505050565b6001600160a01b038316600090815260146020908152604080832033845290915281205490610e02828463ffffffff61270016565b9050846001600160a01b0316846001600160a01b031614610e60576040805162461bcd60e51b815260206004820152601360248201527229a61d24a72b20a624a22fa922a1a2a4ab22a960691b604482015290519081900360640190fd5b82610ea3576040805162461bcd60e51b815260206004820152600e60248201526d14d30e9253959053125117d0535560921b604482015290519081900360640190fd5b6001600160a01b038516600081815260146020908152604080832033845282528083208590559282526015905290812054610ee4908563ffffffff61270016565b6001600160a01b038088166000818152601560209081526040918290208590558151898152915194955092891693919233927ffaa022ea2cd7f14157070896fabadafe96cc4d4714eef7ae6a992a5084493ed59281900390910190a46040805184815260208101849052815133926001600160a01b038a16927f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e8929081900390910190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a2505050505050565b3360007f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c279050806001600160a01b0316634f85221a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561102557600080fd5b505afa158015611039573d6000803e3d6000fd5b505050506040513d602081101561104f57600080fd5b505115806110cd5750806001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561109157600080fd5b505afa1580156110a5573d6000803e3d6000fd5b505050506040513d60208110156110bb57600080fd5b50516001600160a01b03838116911614155b611110576040805162461bcd60e51b815260206004820152600f60248201526e14d30e94d51052d157d313d0d2d151608a1b604482015290519081900360640190fd5b611118611fdf565b336000818152601560205260409020549061114490859061113890611632565b9063ffffffff61270016565b1015611197576040805162461bcd60e51b815260206004820152601860248201527f534c3a494e5355465f554e5354414b4541424c455f42414c0000000000000000604482015290519081900360640190fd5b6111a033611681565b6111e7576040805162461bcd60e51b815260206004820152601360248201527229a61d27aaaa29a4a222afa1a7a7a62227aba760691b604482015290519081900360640190fd5b60105433600090815260116020526040902054429161120c919063ffffffff6126a616565b1115611251576040805162461bcd60e51b815260206004820152600f60248201526e14d30e9195539114d7d313d0d2d151608a1b604482015290519081900360640190fd5b6112596114bf565b6112633384612742565b61126b610ab0565b6112be3361128761127a6127e9565b869063ffffffff61270016565b6001600160a01b037f000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef16919063ffffffff61259a16565b60408051848152905133917f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd919081900360200190a2604080516370a0823160e01b8152306004820181905291516001600160a01b037f000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef1692917f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a29184916370a08231916024808301926020929190829003018186803b15801561138157600080fd5b505afa158015611395573d6000803e3d6000fd5b505050506040513d60208110156113ab57600080fd5b505160408051918252519081900360200190a3505050565b60055460ff1690565b60006109796113d9611eef565b84610aa085600160006113ea611eef565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff6126a616565b611428612818565b610bde612992565b6001600160a01b0381166000908152600a6020526040812054600160801b9061148b906114869061147a61147561146688611632565b6009549063ffffffff612a3016565b612a89565b9063ffffffff612aca16565b612b2f565b8161149257fe5b0492915050565b6001600160a01b03811660009081526008602052604081205461097d9061113884611588565b60006114c96125f1565b9050600081136114d95750610bde565b6114ea6114e582612b2f565b612b70565b50565b33600090815260126020526040902054611541576040805162461bcd60e51b815260206004820152601060248201526f534c3a4e4f545f554e5354414b494e4760801b604482015290519081900360640190fd5b3360008181526012602090815260408083208390558051928352517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b6001600160a01b038116600090815260076020526040812054600160801b9061148b906114869061147a6114756115be88611632565b6006549063ffffffff612a3016565b60116020526000908152604090205481565b600f5460ff1690565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6001600160a01b0381166000908152600b602052604081205461097d9061113884611430565b6001600160a01b031660009081526020819052604090205490565b7f000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef81565b611679612818565b610bde612c70565b60008061168c612cf1565b9050806001600160a01b0316632018b8706040518163ffffffff1660e01b815260040160206040518083038186803b1580156116c757600080fd5b505afa1580156116db573d6000803e3d6000fd5b505050506040513d60208110156116f157600080fd5b50516040805163a965d6b560e01b815290516001600160a01b0384169163a965d6b5916004808301926020929190829003018186803b15801561173357600080fd5b505afa158015611747573d6000803e3d6000fd5b505050506040513d602081101561175d57600080fd5b50516001600160a01b0385166000908152601260205260409020540142031115915050919050565b600061179033611632565b14156117d5576040805162461bcd60e51b815260206004820152600f60248201526e534c3a5a45524f5f42414c414e434560881b604482015290519081900360640190fd5b336000818152601260209081526040918290204290819055825190815291517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561095b5780601f106109305761010080835404028352916020019161095b565b600061097961188e611eef565b84610aa085604051806060016040528060258152602001613e4160259139600160006118b8611eef565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61247e16565b600f5460ff161561193a576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b611942611fdf565b61194b33612deb565b336000818152601260205260408120556119659082612ef0565b6119a06001600160a01b037f000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef1633308463ffffffff612fc516565b6119aa3382613025565b60408051828152905133917febedb8b3c678666e7f36970bc8f57abf6d8fa2e828c0da91ea5b75bf68ed101a919081900360200190a26040805160008152905133917f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d65919081900360200190a2604080516370a0823160e01b8152306004820181905291516001600160a01b037f000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef1692917f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a29184916370a08231916024808301926020929190829003018186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d6020811015611ace57600080fd5b505160408051918252519081900360200190a350565b6000610979611af1611eef565b8484612162565b600e5481565b6001600160a01b03166000908152600b602052604090205490565b600c5481565b60156020526000908152604090205481565b611b39611fdf565b611b4161208f565b6001600160a01b038216600081815260136020908152604091829020805460ff1916851515908117909155825190815291517f73121574a4eadb4cfdeb2ba56a6a88067b03edd1f0a0dfcac0a5a95682a243679281900390910190a25050565b336001600160a01b037f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c271614611c09576040805162461bcd60e51b81526020600482015260086024820152670534c3a4e4f545f560c41b604482015290519081900360640190fd5b600c54611c1c908263ffffffff6126a616565b600c556114ea611cd9565b611c2f611fdf565b611c3761208f565b601054811115611c81576040805162461bcd60e51b815260206004820152601060248201526f534c3a494e56414c49445f56414c554560801b604482015290519081900360640190fd5b60108190556040805182815290517fcc67306c5d19f79a73208a1270ca19eb367b4bd5258eac096e974365d18e432c9181900360200190a150565b601460209081526000928352604080842090915290825290205481565b6000611ce3613071565b905060008113611cf35750610bde565b6114ea611cff82612b2f565b61308f565b60136020526000908152604090205460ff1681565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60105481565b336001600160a01b037f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c271614611db2576040805162461bcd60e51b81526020600482015260086024820152670534c3a4e4f545f560c41b604482015290519081900360640190fd5b610bdb6001600160a01b037f000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef16838363ffffffff61259a16565b600080611df7612cf1565b9050806001600160a01b0316632018b8706040518163ffffffff1660e01b815260040160206040518083038186803b158015611e3257600080fd5b505afa158015611e46573d6000803e3d6000fd5b505050506040513d6020811015611e5c57600080fd5b50516040805163a965d6b560e01b815290516001600160a01b0384169163a965d6b5916004808301926020929190829003018186803b158015611e9e57600080fd5b505afa158015611eb2573d6000803e3d6000fd5b505050506040513d6020811015611ec857600080fd5b50518401014211915050919050565b600d5481565b60126020526000908152604090205481565b3390565b6001600160a01b038316611f385760405162461bcd60e51b8152600401808060200182810382526024815260200180613dcf6024913960400191505060405180910390fd5b6001600160a01b038216611f7d5760405162461bcd60e51b8152600401808060200182810382526022815260200180613cb16022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b611fe7612cf1565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561201f57600080fd5b505afa158015612033573d6000803e3d6000fd5b505050506040513d602081101561204957600080fd5b505115610bde576040805162461bcd60e51b815260206004820152600f60248201526e14d30e941493d513d7d4105554d151608a1b604482015290519081900360640190fd5b7f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c276001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120e857600080fd5b505afa1580156120fc573d6000803e3d6000fd5b505050506040513d602081101561211257600080fd5b50516001600160a01b03163314610bde576040805162461bcd60e51b815260206004820152600f60248201526e534c3a4e4f545f44454c454741544560881b604482015290519081900360640190fd5b8260007f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c279050806001600160a01b0316634f85221a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156121c157600080fd5b505afa1580156121d5573d6000803e3d6000fd5b505050506040513d60208110156121eb57600080fd5b505115806122695750806001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561222d57600080fd5b505afa158015612241573d6000803e3d6000fd5b505050506040513d602081101561225757600080fd5b50516001600160a01b03838116911614155b6122ac576040805162461bcd60e51b815260206004820152600f60248201526e14d30e94d51052d157d313d0d2d151608a1b604482015290519081900360640190fd5b6122b4611fdf565b6010546001600160a01b03861660009081526011602052604090205442916122e2919063ffffffff6126a616565b1115612327576040805162461bcd60e51b815260206004820152600f60248201526e14d30e9195539114d7d313d0d2d151608a1b604482015290519081900360640190fd5b6001600160a01b03851660009081526015602052604090205461234d8461113888611632565b10156123a0576040805162461bcd60e51b815260206004820152601960248201527f534c3a494e5355465f5452414e5346455241424c455f42414c00000000000000604482015290519081900360640190fd5b6001600160a01b0384166000908152601260205260409020546123c290611dec565b612413576040805162461bcd60e51b815260206004820152601860248201527f534c3a524543495049454e545f4e4f545f414c4c4f5745440000000000000000604482015290519081900360640190fd5b600061241e8661160c565b14612462576040805162461bcd60e51b815260206004820152600f60248201526e534c3a5245434f475f4c4f5353455360881b604482015290519081900360640190fd5b61246c8484612ef0565b612477858585613194565b5050505050565b6000818484111561250d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156124d25781810151838201526020016124ba565b50505050905090810190601f1680156124ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061252033611499565b3360009081526008602052604081205491925090612544908363ffffffff6126a616565b336000818152600860209081526040918290208490558151868152908101849052815193945091927ffbc3a599b784fe88772fc5abcc07223f64ca0b13acc341f4fb1e46bef0510eb49281900390910190a25090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526125ec9084906132c0565b505050565b600e54604080516370a0823160e01b81523060048201529051600092916001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816916370a0823191602480820192602092909190829003018186803b15801561265f57600080fd5b505afa158015612673573d6000803e3d6000fd5b505050506040513d602081101561268957600080fd5b5051600e8190556126a0908263ffffffff61337116565b91505090565b600082820183811015610aa9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610aa983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061247e565b61274c82826133d6565b600061278e61276961147584600954612a3090919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff612aca16565b6001600160a01b0384166000818152600a60209081526040918290208490558151848152915193945091927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a2505050565b60006127f361347d565b600c54909150612809908263ffffffff61270016565b600c55612814613071565b5090565b7f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c276001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561287157600080fd5b505afa158015612885573d6000803e3d6000fd5b505050506040513d602081101561289b57600080fd5b50516001600160a01b0316331480612941575060408051633099c27960e11b815233600482015290516001600160a01b037f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c27169163613384f2916024808301926020929190829003018186803b15801561291457600080fd5b505afa158015612928573d6000803e3d6000fd5b505050506040513d602081101561293e57600080fd5b50515b610bde576040805162461bcd60e51b815260206004820152601860248201527f534c3a4e4f545f44454c45474154455f4f525f41444d494e0000000000000000604482015290519081900360640190fd5b600f5460ff166129e0576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b600f805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612a13611eef565b604080516001600160a01b039092168252519081900360200190a1565b600082612a3f5750600061097d565b82820282848281612a4c57fe5b0414610aa95760405162461bcd60e51b8152600401808060200182810382526021815260200180613d406021913960400191505060405180910390fd5b8060008112156108ca576040805162461bcd60e51b815260206004820152600760248201526629a6aa9d27a7a160c91b604482015290519081900360640190fd5b6000828201818312801590612adf5750838112155b80612af45750600083128015612af457508381125b610aa95760405162461bcd60e51b8152600401808060200182810382526021815260200180613cf96021913960400191505060405180910390fd5b600080821215612814576040805162461bcd60e51b8152602060048201526007602482015266534d493a4e454760c81b604482015290519081900360640190fd5b6000612b7a6109ef565b11612bbe576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b80612bc8576114ea565b612bff612bd36109ef565b612be783600160801b63ffffffff612a3016565b81612bee57fe5b60065491900463ffffffff6126a616565b60065560408051828152905133917f26536799ace2c3dbe12e638ec3ade6b4173dcf1289be0a58d51a5003015649bd919081900360200190a260065460408051918252517f1f8d7705f31c3337a080803a8ad7e71946fb88d84738879be2bf402f97156e969181900360200190a150565b600f5460ff1615612cbb576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b600f805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a13611eef565b60007f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c276001600160a01b0316630d49b38c6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4c57600080fd5b505afa158015612d60573d6000803e3d6000fd5b505050506040513d6020811015612d7657600080fd5b50516040805163c312452560e01b815290516001600160a01b039092169163c312452591600480820192602092909190829003018186803b158015612dba57600080fd5b505afa158015612dce573d6000803e3d6000fd5b505050506040513d6020811015612de457600080fd5b5051905090565b60165460ff1680612e1457506001600160a01b03811660009081526013602052604090205460ff165b80612eae57507f000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c276001600160a01b0316634046af2b6040518163ffffffff1660e01b815260040160206040518083038186803b158015612e7357600080fd5b505afa158015612e87573d6000803e3d6000fd5b505050506040513d6020811015612e9d57600080fd5b50516001600160a01b038281169116145b6114ea576040805162461bcd60e51b815260206004820152600e60248201526d14d30e9393d517d0531313d5d15160921b604482015290519081900360640190fd5b6001600160a01b03821660009081526011602052604081205490612f1384611632565b905060008084830111612f265782612f68565b612f68612f5b838601612f4f87612f43428963ffffffff61270016565b9063ffffffff612a3016565b9063ffffffff61350216565b849063ffffffff6126a616565b6001600160a01b0386166000818152601160209081526040918290208490558151848152915193945091927f09686619568b9bd7c4faea3ba0efbeab967ec977167b97405ad208f1a9ccea69929181900390910190a25050505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261301f9085906132c0565b50505050565b61302f8282613544565b600061278e61304c61147584600954612a3090919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff61337116565b600d8054600c54918290556000916126a0908263ffffffff61337116565b60006130996109ef565b116130dd576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b806130e7576114ea565b60006131206130f46109ef565b61310884600160801b63ffffffff612a3016565b8161310f57fe5b60095491900463ffffffff6126a616565b600981905560408051848152905191925033917ff88156a8032a0d2c65df18fafaf84e0bea647b3d94a0f7fc6ab14c97dec2bf749181900360200190a26040805182815290517f240ce2b5ce9e9e5a70010c7f8034c233d89b7ce2d60f3a38d9bc3ca01a36f88c9181900360200190a15050565b61319f838383613590565b60006131b961147583600954612a3090919063ffffffff16565b6001600160a01b0385166000908152600a6020526040812054919250906131e6908363ffffffff612aca16565b6001600160a01b038087166000908152600a602052604080822084905591871681529081205491925090613220908463ffffffff61337116565b6001600160a01b038087166000908152600a602090815260409182902084905581518681529151939450918916927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a26040805182815290516001600160a01b038716917fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3919081900360200190a2505050505050565b6060613315826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166136bc9092919063ffffffff16565b8051909150156125ec5780806020019051602081101561333457600080fd5b50516125ec5760405162461bcd60e51b815260040180806020018281038252602a815260200180613e17602a913960400191505060405180910390fd5b60008183038183128015906133865750838113155b8061339b575060008312801561339b57508381135b610aa95760405162461bcd60e51b8152600401808060200182810382526024815260200180613df36024913960400191505060405180910390fd5b6133e082826136d3565b60006134226133fd61147584600654612a3090919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff612aca16565b6001600160a01b0384166000818152600760209081526040918290208490558151848152915193945091927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a2505050565b60006134883361160c565b336000908152600b6020526040812054919250906134ac908363ffffffff6126a616565b336000818152600b60209081526040918290208490558151868152908101849052815193945091927f814eba35782909dbbaeefb8104073dfca45de43173f7077970c1584b3cf918b59281900390910190a25090565b6000610aa983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506137db565b61354e8282613840565b600061342261356b61147584600654612a3090919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff61337116565b61359b83838361393c565b60006135b561147583600654612a3090919063ffffffff16565b6001600160a01b038516600090815260076020526040812054919250906135e2908363ffffffff612aca16565b6001600160a01b038087166000908152600760205260408082208490559187168152908120549192509061361c908463ffffffff61337116565b6001600160a01b0380871660009081526007602090815260409182902084905581518681529151939450918916927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a26040805182815290516001600160a01b038716917ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773919081900360200190a2505050505050565b60606136cb8484600085613aa3565b949350505050565b6001600160a01b0382166137185760405162461bcd60e51b8152600401808060200182810382526021815260200180613d896021913960400191505060405180910390fd5b613724826000836125ec565b61376781604051806060016040528060228152602001613c8f602291396001600160a01b038516600090815260208190526040902054919063ffffffff61247e16565b6001600160a01b038316600090815260208190526040902055600254613793908263ffffffff61270016565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6000818361382a5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156124d25781810151838201526020016124ba565b50600083858161383657fe5b0495945050505050565b6001600160a01b03821661389b576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6138a7600083836125ec565b6002546138ba908263ffffffff6126a616565b6002556001600160a01b0382166000908152602081905260409020546138e6908263ffffffff6126a616565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b0383166139815760405162461bcd60e51b8152600401808060200182810382526025815260200180613daa6025913960400191505060405180910390fd5b6001600160a01b0382166139c65760405162461bcd60e51b8152600401808060200182810382526023815260200180613c6c6023913960400191505060405180910390fd5b6139d18383836125ec565b613a1481604051806060016040528060268152602001613cd3602691396001600160a01b038616600090815260208190526040902054919063ffffffff61247e16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054613a49908263ffffffff6126a616565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b606082471015613ae45760405162461bcd60e51b8152600401808060200182810382526026815260200180613d1a6026913960400191505060405180910390fd5b613aed85613bff565b613b3e576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613b7d5780518252601f199092019160209182019101613b5e565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613bdf576040519150601f19603f3d011682016040523d82523d6000602084013e613be4565b606091505b5091509150613bf4828286613c05565b979650505050505050565b3b151590565b60608315613c14575081610aa9565b825115613c245782518084602001fd5b60405162461bcd60e51b81526020600482018181528451602484015284518593919283926044019190850190808383600083156124d25781810151838201526020016124ba56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63655369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122048f517b477c459d5376e0cc0cd024aca11f8214b1affb8111823a449ec0c5e9564736f6c634300060b0033

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

000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c27

-----Decoded View---------------
Arg [0] : _stakeAsset (address): 0xc1b10e536CD611aCFf7a7c32A9E29cE6A02Ef6ef
Arg [1] : _liquidityAsset (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [2] : _pool (address): 0xFeBd6F15Df3B73DC4307B1d7E65D46413e710C27

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000c1b10e536cd611acff7a7c32a9e29ce6a02ef6ef
Arg [1] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [2] : 000000000000000000000000febd6f15df3b73dc4307b1d7e65d46413e710c27


Deployed Bytecode Sourcemap

66822:17607:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37818:122;;;;;;;;;;;;;;;;-1:-1:-1;37818:122:0;-1:-1:-1;;;;;37818:122:0;;:::i;:::-;;;;;;;;;;;;;;;;25316:83;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27422:169;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;27422:169:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;71465:185;;;:::i;:::-;;67359:29;;;:::i;:::-;;;;-1:-1:-1;;;;;67359:29:0;;;;;;;;;;;;;;26391:100;;;:::i;68266:24::-;;;:::i;67217:39::-;;;:::i;28073:321::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;28073:321:0;;;;;;;;;;;;;;;;;:::i;77202:408::-;;;:::i;78057:863::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;78057:863:0;;;;;;;;:::i;79618:776::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;79618:776:0;;;;;;;;;;;;;;;;;:::i;75975:1030::-;;;;;;;;;;;;;;;;-1:-1:-1;75975:1030:0;;:::i;26243:83::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;28803:218;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;28803:218:0;;;;;;;;:::i;82139:107::-;;;:::i;46892:304::-;;;;;;;;;;;;;;;;-1:-1:-1;46892:304:0;-1:-1:-1;;;;;46892:304:0;;:::i;37431:165::-;;;;;;;;;;;;;;;;-1:-1:-1;37431:165:0;-1:-1:-1;;;;;37431:165:0;;:::i;41949:202::-;;;:::i;75410:213::-;;;:::i;38403:303::-;;;;;;;;;;;;;;;;-1:-1:-1;38403:303:0;-1:-1:-1;;;;;38403:303:0;;:::i;67522:64::-;;;;;;;;;;;;;;;;-1:-1:-1;67522:64:0;-1:-1:-1;;;;;67522:64:0;;:::i;65132:78::-;;;:::i;51154:34::-;;;:::i;45940:160::-;;;;;;;;;;;;;;;;-1:-1:-1;45940:160:0;-1:-1:-1;;;;;45940:160:0;;:::i;26554:119::-;;;;;;;;;;;;;;;;-1:-1:-1;26554:119:0;-1:-1:-1;;;;;26554:119:0;;:::i;67085:35::-;;;:::i;81863:103::-;;;:::i;82489:247::-;;;;;;;;;;;;;;;;-1:-1:-1;82489:247:0;-1:-1:-1;;;;;82489:247:0;;:::i;75019:227::-;;;:::i;25518:87::-;;;:::i;29524:269::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;29524:269:0;;;;;;;;:::i;73402:605::-;;;;;;;;;;;;;;;;-1:-1:-1;73402:605:0;;:::i;26886:175::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;26886:175:0;;;;;;;;:::i;51380:32::-;;;:::i;46324:126::-;;;;;;;;;;;;;;;;-1:-1:-1;46324:126:0;-1:-1:-1;;;;;46324:126:0;;:::i;51197:24::-;;;:::i;68074:76::-;;;;;;;;;;;;;;;;-1:-1:-1;68074:76:0;-1:-1:-1;;;;;68074:76:0;;:::i;71066:217::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;71066:217:0;;;;;;;;;;:::i;72775:147::-;;;;;;;;;;;;;;;;-1:-1:-1;72775:147:0;;:::i;71896:299::-;;;;;;;;;;;;;;;;-1:-1:-1;71896:299:0;;:::i;67921:71::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;67921:71:0;;;;;;;;;;:::i;50035:203::-;;;:::i;67798:62::-;;;;;;;;;;;;;;;;-1:-1:-1;67798:62:0;-1:-1:-1;;;;;67798:62:0;;:::i;27124:151::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;27124:151:0;;;;;;;;;;:::i;67428:27::-;;;:::i;72450:108::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;72450:108:0;;;;;;;;:::i;82933:251::-;;;;;;;;;;;;;;;;-1:-1:-1;82933:251:0;;:::i;51272:28::-;;;:::i;67659:70::-;;;;;;;;;;;;;;;;-1:-1:-1;67659:70:0;-1:-1:-1;;;;;67659:70:0;;:::i;37818:122::-;-1:-1:-1;;;;;37910:22:0;;37883:7;37910:22;;;:14;:22;;;;;;37818:122;;;;:::o;25316:83::-;25386:5;25379:12;;;;;;;;-1:-1:-1;;25379:12:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25353:13;;25379:12;;25386:5;;25379:12;;25386:5;25379:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25316:83;:::o;27422:169::-;27505:4;27522:39;27531:12;:10;:12::i;:::-;27545:7;27554:6;27522:8;:39::i;:::-;-1:-1:-1;27579:4:0;27422:169;;;;;:::o;71465:185::-;71520:24;:22;:24::i;:::-;71555:22;:20;:22::i;:::-;71588:12;:19;;-1:-1:-1;;71588:19:0;71603:4;71588:19;;;71623;;;;71588:12;;71623:19;71465:185::o;67359:29::-;;;:::o;26391:100::-;26471:12;;26391:100;:::o;68266:24::-;;;;;;:::o;67217:39::-;;;:::o;28073:321::-;28179:4;28196:36;28206:6;28214:9;28225:6;28196:9;:36::i;:::-;28243:121;28252:6;28260:12;:10;:12::i;:::-;28274:89;28312:6;28274:89;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;28274:19:0;;;;;;:11;:19;;;;;;28294:12;:10;:12::i;:::-;-1:-1:-1;;;;;28274:33:0;;;;;;;;;;;;-1:-1:-1;28274:33:0;;;:89;;:37;:89;:::i;:::-;28243:8;:121::i;:::-;-1:-1:-1;28382:4:0;28073:321;;;;;;:::o;77202:408::-;77254:24;:22;:24::i;:::-;77291:25;77319:18;:16;:18::i;:::-;77291:46;-1:-1:-1;77354:31:0;77350:44;;77387:7;;;77350:44;77406:54;-1:-1:-1;;;;;77406:10:0;:23;77430:10;77442:17;77406:54;:23;:54;:::i;:::-;77527:35;;;-1:-1:-1;;;77527:35:0;;77499:4;77527:35;;;;;;;;-1:-1:-1;;;;;77514:10:0;77476:87;;77499:4;77476:87;;;;77527:20;;:35;;;;;;;;;;;;;;77476:87;77527:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;77527:35:0;77476:87;;;;;;;;;;;77527:35;77476:87;;;77576:26;:24;:26::i;:::-;;77202:408;;:::o;78057:863::-;78191:10;78146:20;78174:28;;;:16;:28;;;;;;;;-1:-1:-1;;;;;78174:39:0;;;;;;;;;;;78252:24;78174:39;78269:6;78252:24;:16;:24;:::i;:::-;78337:10;78287:25;78315:33;;;:21;:33;;;;;;78224:52;;-1:-1:-1;78287:25:0;78315:45;;78353:6;78315:45;:37;:45;:::i;:::-;78287:73;-1:-1:-1;;;;;;78381:23:0;;78373:75;;;;;-1:-1:-1;;;78373:75:0;;;;;;;;;;;;-1:-1:-1;;;78373:75:0;;;;;;;;;;;;;;;78467:23;78459:69;;;;;-1:-1:-1;;;78459:69:0;;;;;;;;;;;;-1:-1:-1;;;78459:69:0;;;;;;;;;;;;;;;78568:21;78578:10;78568:9;:21::i;:::-;78547:17;:42;;78539:71;;;;;-1:-1:-1;;;78539:71:0;;;;;;;;;;;;-1:-1:-1;;;78539:71:0;;;;;;;;;;;;;;;78640:10;78623:28;;;;:16;:28;;;;;;;;-1:-1:-1;;;;;78623:39:0;;;;;;;;;;;:54;;;78688:33;;;:21;:33;;;;;;:59;;;78763:74;;;;;;;;;;;;;78623:39;;78640:10;78763:74;;;;;;;;;;78853:59;;;;;;;;78882:10;;78853:59;;;;;;;;;;78057:863;;;;;:::o;79618:776::-;-1:-1:-1;;;;;79732:22:0;;79709:20;79732:22;;;:16;:22;;;;;;;;79755:10;79732:34;;;;;;;;;79800:24;79732:34;79817:6;79800:24;:16;:24;:::i;:::-;79777:47;;79851:4;-1:-1:-1;;;;;79845:10:0;:2;-1:-1:-1;;;;;79845:10:0;;79837:54;;;;;-1:-1:-1;;;79837:54:0;;;;;;;;;;;;-1:-1:-1;;;79837:54:0;;;;;;;;;;;;;;;79910:20;79902:49;;;;;-1:-1:-1;;;79902:49:0;;;;;;;;;;;;-1:-1:-1;;;79902:49:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;79964:22:0;;;;;;:16;:22;;;;;;;;79987:10;79964:34;;;;;;;:49;;;80061:27;;;:21;:27;;;;;;:39;;80093:6;80061:39;:31;:39;:::i;:::-;-1:-1:-1;;;;;80111:27:0;;;;;;;:21;:27;;;;;;;;;:54;;;80181:45;;;;;;;80024:76;;-1:-1:-1;80181:45:0;;;;80111:27;;80197:10;;80181:45;;;;;;;;;;80242:69;;;;;;;;;;;;;;80272:10;;-1:-1:-1;;;;;80242:69:0;;;;;;;;;;;;;;80327:59;;;;;;;;80356:10;;80327:59;;;;;;;;;;79618:776;;;;;;:::o;75975:1030::-;76025:10;70070:11;70090:4;70070:25;;70210:5;-1:-1:-1;;;;;70210:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;70210:23:0;70209:24;;:56;;;70245:5;-1:-1:-1;;;;;70245:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;70245:20:0;-1:-1:-1;;;;;70237:28:0;;;;;;;70209:56;70201:84;;;;;-1:-1:-1;;;70201:84:0;;;;;;;;;;;;-1:-1:-1;;;70201:84:0;;;;;;;;;;;;;;;76048:24:::1;:22;:24::i;:::-;76149:10;76127:33;::::0;;;:21:::1;:33;::::0;;;;;;76093:30:::1;::::0;76119:3;;76093:21:::1;::::0;:9:::1;:21::i;:::-;:25:::0;:30:::1;:25;:30;:::i;:::-;:67;;76085:104;;;::::0;;-1:-1:-1;;;76085:104:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;76266:28;76283:10;76266:16;:28::i;:::-;76258:99;;;::::0;;-1:-1:-1;;;76258:99:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;76258:99:0;;;;;;;;;;;;;::::1;;76402:12;::::0;76386:10:::1;76376:21;::::0;;;:9:::1;:21;::::0;;;;;76419:15:::1;::::0;76376:39:::1;::::0;:21;:39:::1;:25;:39;:::i;:::-;:58;;76368:95;;;::::0;;-1:-1:-1;;;76368:95:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;76368:95:0;;;;;;;;;;;;;::::1;;76476:21;:19;:21::i;:::-;76578:22;76584:10;76596:3;76578:5;:22::i;:::-;76663:15;:13;:15::i;:::-;76755:64;76779:10;76791:27;76799:18;:16;:18::i;:::-;76791:3:::0;;:27:::1;:7;:27;:::i;:::-;-1:-1:-1::0;;;;;76755:10:0::1;:23;::::0;:64;::::1;:23;:64;:::i;:::-;76870:24;::::0;;;;;;;76878:10:::1;::::0;76870:24:::1;::::0;;;;;::::1;::::0;;::::1;76961:35;::::0;;-1:-1:-1;;;76961:35:0;;76933:4:::1;76961:35;::::0;::::1;::::0;;;;;-1:-1:-1;;;;;76948:10:0::1;76910:87;::::0;76933:4;76910:87:::1;::::0;;;76961:20:::1;::::0;:35;;;;;::::1;::::0;;;;;;;;76910:87;76961:35;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;76961:35:0;76910:87:::1;::::0;;;;;;;;;;76961:35:::1;76910:87:::0;;::::1;75975:1030:::0;;;:::o;26243:83::-;26309:9;;;;26243:83;:::o;28803:218::-;28891:4;28908:83;28917:12;:10;:12::i;:::-;28931:7;28940:50;28979:10;28940:11;:25;28952:12;:10;:12::i;:::-;-1:-1:-1;;;;;28940:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;28940:25:0;;;:34;;;;;;;;;;;:50;:38;:50;:::i;82139:107::-;82178:33;:31;:33::i;:::-;82222:16;:14;:16::i;46892:304::-;-1:-1:-1;;;;;47110:24:0;;46959:7;47110:24;;;:16;:24;;;;;;-1:-1:-1;;;34911:8:0;46999:170;;:136;;:88;:55;47036:17;47127:6;47036:9;:17::i;:::-;46999:14;;;:55;:36;:55;:::i;:::-;:86;:88::i;:::-;:110;:136;:110;:136;:::i;:::-;:168;:170::i;:::-;:189;;;;;;;46892:304;-1:-1:-1;;46892:304:0:o;37431:165::-;-1:-1:-1;;;;;37565:22:0;;37506:7;37565:22;;;:14;:22;;;;;;37533:55;;:27;37580:6;37533:19;:27::i;41949:202::-;42006:15;42024:26;:24;:26::i;:::-;42006:44;;42079:1;42067:8;:13;42063:26;;42082:7;;;42063:26;42101:42;42118:24;:8;:22;:24::i;:::-;42101:16;:42::i;:::-;41949:202;:::o;75410:213::-;75479:10;75502:1;75463:27;;;:15;:27;;;;;;75455:70;;;;;-1:-1:-1;;;75455:70:0;;;;;;;;;;;;-1:-1:-1;;;75455:70:0;;;;;;;;;;;;;;;75552:10;75566:1;75536:27;;;:15;:27;;;;;;;;:31;;;75583:32;;;;;;;;;;;;;;;;75410:213::o;38403:303::-;-1:-1:-1;;;;;38620:24:0;;38469:7;38620:24;;;:16;:24;;;;;;-1:-1:-1;;;34911:8:0;38509:170;;:136;;:88;:55;38546:17;38637:6;38546:9;:17::i;:::-;38509:14;;;:55;:36;:55;:::i;67522:64::-;;;;;;;;;;;;;:::o;65132:78::-;65195:7;;;;65132:78;:::o;51154:34::-;;;:::o;45940:160::-;-1:-1:-1;;;;;46067:24:0;;46007:7;46067:24;;;:16;:24;;;;;;46034:58;;:28;46084:6;46034:20;:28::i;26554:119::-;-1:-1:-1;;;;;26647:18:0;26620:7;26647:18;;;;;;;;;;;;26554:119::o;67085:35::-;;;:::o;81863:103::-;81900:33;:31;:33::i;:::-;81944:14;:12;:14::i;82489:247::-;82550:4;82567:21;82591:10;:8;:10::i;:::-;82567:34;;82699:7;-1:-1:-1;;;;;82699:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;82699:29:0;82663:30;;;-1:-1:-1;;;82663:30:0;;;;-1:-1:-1;;;;;82663:28:0;;;;;:30;;;;;82699:29;;82663:30;;;;;;;:28;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;82663:30:0;-1:-1:-1;;;;;82639:21:0;;;;;;:15;82663:30;82639:21;;;;;:54;82620:15;:74;82619:109;;;-1:-1:-1;;82489:247:0;;;:::o;75019:227::-;75107:1;75074:21;75084:10;75074:9;:21::i;:::-;:35;;75066:63;;;;;-1:-1:-1;;;75066:63:0;;;;;;;;;;;;-1:-1:-1;;;75066:63:0;;;;;;;;;;;;;;;75156:10;75140:27;;;;:15;:27;;;;;;;;;75170:15;75140:45;;;;75201:37;;;;;;;;;;;;;;;;;75019:227::o;25518:87::-;25590:7;25583:14;;;;;;;;-1:-1:-1;;25583:14:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25557:13;;25583:14;;25590:7;;25583:14;;25590:7;25583:14;;;;;;;;;;;;;;;;;;;;;;;;29524:269;29617:4;29634:129;29643:12;:10;:12::i;:::-;29657:7;29666:96;29705:15;29666:96;;;;;;;;;;;;;;;;;:11;:25;29678:12;:10;:12::i;:::-;-1:-1:-1;;;;;29666:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;29666:25:0;;;:34;;;;;;;;;;;:96;;:38;:96;:::i;73402:605::-;65450:7;;;;65449:8;65441:37;;;;;-1:-1:-1;;;65441:37:0;;;;;;;;;;;;-1:-1:-1;;;65441:37:0;;;;;;;;;;;;;;;73464:24:::1;:22;:24::i;:::-;73499:22;73510:10;73499;:22::i;:::-;73550:10;73572:1;73534:27:::0;;;:15:::1;:27;::::0;;;;:40;73670:33:::1;::::0;73699:3;73670:16:::1;:33::i;:::-;73716:59;-1:-1:-1::0;;;;;73716:10:0::1;:27;73744:10;73764:4;73771:3:::0;73716:59:::1;:27;:59;:::i;:::-;73786:22;73792:10;73804:3;73786:5;:22::i;:::-;73826;::::0;;;;;;;73832:10:::1;::::0;73826:22:::1;::::0;;;;;::::1;::::0;;::::1;73864:32;::::0;;73893:1:::1;73864:32:::0;;;;73873:10:::1;::::0;73864:32:::1;::::0;;;;;::::1;::::0;;::::1;73963:35;::::0;;-1:-1:-1;;;73963:35:0;;73935:4:::1;73963:35;::::0;::::1;::::0;;;;;-1:-1:-1;;;;;73950:10:0::1;73912:87;::::0;73935:4;73912:87:::1;::::0;;;73963:20:::1;::::0;:35;;;;;::::1;::::0;;;;;;;;73912:87;73963:35;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;73963:35:0;73912:87:::1;::::0;;;;;;;;;;73963:35:::1;73912:87:::0;;::::1;73402:605:::0;:::o;26886:175::-;26972:4;26989:42;26999:12;:10;:12::i;:::-;27013:9;27024:6;26989:9;:42::i;51380:32::-;;;;:::o;46324:126::-;-1:-1:-1;;;;;46418:24:0;46391:7;46418:24;;;:16;:24;;;;;;;46324:126::o;51197:24::-;;;;:::o;68074:76::-;;;;;;;;;;;;;:::o;71066:217::-;71135:24;:22;:24::i;:::-;71170:22;:20;:22::i;:::-;-1:-1:-1;;;;;71203:15:0;;;;;;:7;:15;;;;;;;;;:24;;-1:-1:-1;;71203:24:0;;;;;;;;;;71243:32;;;;;;;;;;;;;;;;;71066:217;;:::o;72775:147::-;70611:10;-1:-1:-1;;;;;70625:4:0;70611:18;;70603:39;;;;;-1:-1:-1;;;70603:39:0;;;;;;;;;;;;-1:-1:-1;;;70603:39:0;;;;;;;;;;;;;;;72856:9:::1;::::0;:25:::1;::::0;72870:10;72856:25:::1;:13;:25;:::i;:::-;72844:9;:37:::0;72892:22:::1;:20;:22::i;71896:299::-:0;71966:24;:22;:24::i;:::-;72001:22;:20;:22::i;:::-;72061:12;;72042:15;:31;;72034:60;;;;;-1:-1:-1;;;72034:60:0;;;;;;;;;;;;-1:-1:-1;;;72034:60:0;;;;;;;;;;;;;;;72105:12;:30;;;72151:36;;;;;;;;;;;;;;;;;71896:299;:::o;67921:71::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;50035:203::-;50093:16;50112:22;:20;:22::i;:::-;50093:41;;50164:1;50151:9;:14;50147:27;;50167:7;;;50147:27;50186:44;50204:25;:9;:23;:25::i;:::-;50186:17;:44::i;67798:62::-;;;;;;;;;;;;;;;:::o;27124:151::-;-1:-1:-1;;;;;27240:18:0;;;27213:7;27240:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;27124:151::o;67428:27::-;;;;:::o;72450:108::-;70611:10;-1:-1:-1;;;;;70625:4:0;70611:18;;70603:39;;;;;-1:-1:-1;;;70603:39:0;;;;;;;;;;;;-1:-1:-1;;;70603:39:0;;;;;;;;;;;;;;;72517:33:::1;-1:-1:-1::0;;;;;72517:10:0::1;:23;72541:3:::0;72546;72517:33:::1;:23;:33;:::i;82933:251::-:0;83006:4;83023:21;83047:10;:8;:10::i;:::-;83023:34;;83146:7;-1:-1:-1;;;;;83146:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83146:29:0;83113:30;;;-1:-1:-1;;;83113:30:0;;;;-1:-1:-1;;;;;83113:28:0;;;;;:30;;;;;83146:29;;83113:30;;;;;;;:28;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83113:30:0;83094:49;;:81;83075:15;:101;;-1:-1:-1;;82933:251:0;;;:::o;51272:28::-;;;;:::o;67659:70::-;;;;;;;;;;;;;:::o;22677:106::-;22765:10;22677:106;:::o;32671:346::-;-1:-1:-1;;;;;32773:19:0;;32765:68;;;;-1:-1:-1;;;32765:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;32852:21:0;;32844:68;;;;-1:-1:-1;;;32844:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;32925:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;32977:32;;;;;;;;;;;;;;;;;32671:346;;;:::o;84301:123::-;84369:10;:8;:10::i;:::-;-1:-1:-1;;;;;84369:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84369:27:0;84368:28;84360:56;;;;;-1:-1:-1;;;84360:56:0;;;;;;;;;;;;-1:-1:-1;;;84360:56:0;;;;;;;;;;;;;;83563:133;83648:4;-1:-1:-1;;;;;83642:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83642:26:0;-1:-1:-1;;;;;83628:40:0;:10;:40;83620:68;;;;;-1:-1:-1;;;83620:68:0;;;;;;;;;;;;-1:-1:-1;;;83620:68:0;;;;;;;;;;;;;;80634:966;80721:4;70070:11;70090:4;70070:25;;70210:5;-1:-1:-1;;;;;70210:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;70210:23:0;70209:24;;:56;;;70245:5;-1:-1:-1;;;;;70245:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;70245:20:0;-1:-1:-1;;;;;70237:28:0;;;;;;;70209:56;70201:84;;;;;-1:-1:-1;;;70201:84:0;;;;;;;;;;;;-1:-1:-1;;;70201:84:0;;;;;;;;;;;;;;;80738:24:::1;:22;:24::i;:::-;80801:12;::::0;-1:-1:-1;;;;;80781:15:0;::::1;;::::0;;;:9:::1;:15;::::0;;;;;80818::::1;::::0;80781:33:::1;::::0;:15;:33:::1;:19;:33;:::i;:::-;:52;;80773:83;;;::::0;;-1:-1:-1;;;80773:83:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;80773:83:0;;;;;;;;;;;;;::::1;;-1:-1:-1::0;;;;;80958:27:0;::::1;;::::0;;;:21:::1;:27;::::0;;;;;80930:24:::1;80950:3:::0;80930:15:::1;80980:4:::0;80930:9:::1;:15::i;:24::-;:55;;80922:93;;;::::0;;-1:-1:-1;;;80922:93:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;-1:-1:-1::0;;;;;81110:19:0;::::1;;::::0;;;:15:::1;:19;::::0;;;;;81093:37:::1;::::0;:16:::1;:37::i;:::-;81085:92;;;::::0;;-1:-1:-1;;;81085:92:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;81281:1;81243:26;81264:4;81243:20;:26::i;:::-;:40;81235:83;;;::::0;;-1:-1:-1;;;81235:83:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;81235:83:0;;;;;;;;;;;;;::::1;;81423:25;81440:2;81444:3;81423:16;:25::i;:::-;81562:30;81578:4;81584:2;81588:3;81562:15;:30::i;:::-;80634:966:::0;;;;;:::o;15674:192::-;15760:7;15796:12;15788:6;;;;15780:29;;;;-1:-1:-1;;;15780:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;15832:5:0;;;15674:192::o;36829:385::-;36875:28;36945:31;36965:10;36945:19;:31::i;:::-;37031:10;36987:23;37016:26;;;:14;:26;;;;;;36916:60;;-1:-1:-1;36987:23:0;37016:52;;36916:60;37016:52;:30;:52;:::i;:::-;37094:10;37079:26;;;;:14;:26;;;;;;;;;:44;;;37141:65;;;;;;;;;;;;;36987:81;;-1:-1:-1;37094:10:0;;37141:65;;;;;;;;;;36829:385;;:::o;60923:177::-;61033:58;;;-1:-1:-1;;;;;61033:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;61033:58:0;-1:-1:-1;;;61033:58:0;;;61006:86;;61026:5;;61006:19;:86::i;:::-;60923:177;;;:::o;52794:297::-;52917:17;;52967:35;;;-1:-1:-1;;;52967:35:0;;52996:4;52967:35;;;;;;52865:6;;52917:17;-1:-1:-1;;;;;52967:10:0;:20;;;;:35;;;;;;;;;;;;;;;:20;:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52967:35:0;52947:17;:55;;;53022:61;;53059:22;53022:61;:29;:61;:::i;:::-;53015:68;;;52794:297;:::o;14771:181::-;14829:7;14861:5;;;14885:6;;;;14877:46;;;;;-1:-1:-1;;;14877:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;15235:136;15293:7;15320:43;15324:1;15327;15320:43;;;;;;;;;;;;;;;;;:3;:43::i;49298:383::-;49382:27;49394:7;49403:5;49382:11;:27::i;:::-;49422:24;49449:97;49493:42;49494:25;49513:5;49494:14;;:18;;:25;;;;:::i;49493:42::-;-1:-1:-1;;;;;49449:25:0;;;;;;:16;:25;;;;;;;:97;:29;:97;:::i;:::-;-1:-1:-1;;;;;49559:25:0;;;;;;:16;:25;;;;;;;;;:45;;;49622:51;;;;;;;49422:124;;-1:-1:-1;49559:25:0;;49622:51;;;;;;;;;;;49298:383;;;:::o;51859:204::-;51914:14;51950:24;:22;:24::i;:::-;51999:9;;51941:33;;-1:-1:-1;51999:21:0;;51941:33;51999:21;:13;:21;:::i;:::-;51987:9;:33;52033:22;:20;:22::i;:::-;;51859:204;:::o;83286:191::-;83382:4;-1:-1:-1;;;;;83376:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83376:26:0;-1:-1:-1;;;;;83362:40:0;:10;:40;;:78;;-1:-1:-1;83406:34:0;;;-1:-1:-1;;;83406:34:0;;83429:10;83406:34;;;;;;-1:-1:-1;;;;;83412:4:0;83406:22;;;;:34;;;;;;;;;;;;;;:22;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83406:34:0;83362:78;83354:115;;;;;-1:-1:-1;;;83354:115:0;;;;;;;;;;;;;;;;;;;;;;;;;;;66181:120;65726:7;;;;65718:40;;;;;-1:-1:-1;;;65718:40:0;;;;;;;;;;;;-1:-1:-1;;;65718:40:0;;;;;;;;;;;;;;;66240:7:::1;:15:::0;;-1:-1:-1;;66240:15:0::1;::::0;;66271:22:::1;66280:12;:10;:12::i;:::-;66271:22;::::0;;-1:-1:-1;;;;;66271:22:0;;::::1;::::0;;;;;;;::::1;::::0;;::::1;66181:120::o:0;16125:471::-;16183:7;16428:6;16424:47;;-1:-1:-1;16458:1:0;16451:8;;16424:47;16495:5;;;16499:1;16495;:5;:1;16519:5;;;;;:10;16511:56;;;;-1:-1:-1;;;16511:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13685:135;13773:1;13741:8;13794:6;;;13786:26;;;;;-1:-1:-1;;;13786:26:0;;;;;;;;;;;;-1:-1:-1;;;13786:26:0;;;;;;;;;;;;;;21810:215;21866:6;21896:5;;;21921:6;;;;;;:16;;;21936:1;21931;:6;;21921:16;21920:38;;;;21947:1;21943;:5;:14;;;;;21956:1;21952;:5;21943:14;21912:84;;;;-1:-1:-1;;;21912:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13439:138;13495:7;13528:1;13523;:6;;13515:26;;;;;-1:-1:-1;;;13515:26:0;;;;;;;;;;;;-1:-1:-1;;;13515:26:0;;;;;;;;;;;;;;36214:346;36299:1;36283:13;:11;:13::i;:::-;:17;36275:45;;;;;-1:-1:-1;;;36275:45:0;;;;;;;;;;;;-1:-1:-1;;;36275:45:0;;;;;;;;;;;;;;;36337:10;36333:23;;36349:7;;36333:23;36385:63;36434:13;:11;:13::i;:::-;36404:27;:5;-1:-1:-1;;;36404:27:0;:9;:27;:::i;:::-;:43;;;;;36385:14;;;36404:43;;36385:63;:18;:63;:::i;:::-;36368:14;:80;36464:35;;;;;;;;36481:10;;36464:35;;;;;;;;;;36537:14;;36515:37;;;;;;;;;;;;;;;;36214:346;:::o;65922:118::-;65450:7;;;;65449:8;65441:37;;;;;-1:-1:-1;;;65441:37:0;;;;;;;;;;;;-1:-1:-1;;;65441:37:0;;;;;;;;;;;;;;;65982:7:::1;:14:::0;;-1:-1:-1;;65982:14:0::1;65992:4;65982:14;::::0;;66012:20:::1;66019:12;:10;:12::i;84062:149::-:0;84105:13;84171:4;-1:-1:-1;;;;;84165:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84165:26:0;84152:50;;;-1:-1:-1;;;84152:50:0;;;;-1:-1:-1;;;;;84152:48:0;;;;;;:50;;;;;84165:26;;84152:50;;;;;;;;:48;:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84152:50:0;;-1:-1:-1;84062:149:0;:::o;83781:207::-;83865:12;;;;;:32;;-1:-1:-1;;;;;;83881:16:0;;;;;;:7;:16;;;;;;;;83865:32;:73;;;;83918:4;-1:-1:-1;;;;;83912:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83912:26:0;-1:-1:-1;;;;;83901:37:0;;;;;;83865:73;83843:137;;;;;-1:-1:-1;;;83843:137:0;;;;;;;;;;;;-1:-1:-1;;;83843:137:0;;;;;;;;;;;;;;74275:569;-1:-1:-1;;;;;74370:18:0;;74351:16;74370:18;;;:9;:18;;;;;;;74417;74380:7;74417:9;:18::i;:::-;74399:36;;74597:15;74633:1;74626:3;74616:7;:13;74615:19;:130;;74737:8;74615:130;;;74650:71;74663:57;74706:13;;;74663:38;74716:3;74663:29;:15;74683:8;74663:29;:19;:29;:::i;:::-;:33;:38;:33;:38;:::i;:::-;:42;:57;:42;:57;:::i;:::-;74650:8;;:71;:12;:71;:::i;:::-;-1:-1:-1;;;;;74758:18:0;;;;;;:9;:18;;;;;;;;;:28;;;74802:34;;;;;;;74597:148;;-1:-1:-1;74758:18:0;;74802:34;;;;;;;;;;;74275:569;;;;;:::o;61108:205::-;61236:68;;;-1:-1:-1;;;;;61236:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;61236:68:0;-1:-1:-1;;;61236:68:0;;;61209:96;;61229:5;;61209:19;:96::i;:::-;61108:205;;;;:::o;48590:383::-;48674:27;48686:7;48695:5;48674:11;:27::i;:::-;48714:24;48741:97;48785:42;48786:25;48805:5;48786:14;;:18;;:25;;;;:::i;48785:42::-;-1:-1:-1;;;;;48741:25:0;;;;;;:16;:25;;;;;;;:97;:29;:97;:::i;52301:249::-;52413:13;;;52455:9;;52439:25;;;;52360:6;;52484:58;;52413:13;52484:58;:25;:58;:::i;44633:412::-;44719:1;44703:13;:11;:13::i;:::-;:17;44695:45;;;;;-1:-1:-1;;;44695:45:0;;;;;;;;;;;;-1:-1:-1;;;44695:45:0;;;;;;;;;;;;;;;44757:10;44753:23;;44769:7;;44753:23;44788;44814:63;44863:13;:11;:13::i;:::-;44833:27;:5;-1:-1:-1;;;44833:27:0;:9;:27;:::i;:::-;:43;;;;;44814:14;;;44833:43;;44814:63;:18;:63;:::i;:::-;44888:14;:41;;;44947:36;;;;;;;;44788:89;;-1:-1:-1;44965:10:0;;44947:36;;;;;;;;;44999:38;;;;;;;;;;;;;;;;;44633:412;;:::o;47601:678::-;47732:32;47748:4;47754:2;47758:5;47732:15;:32::i;:::-;47777:24;47807:40;:25;47826:5;47807:14;;:18;;:25;;;;:::i;:40::-;-1:-1:-1;;;;;47888:22:0;;47858:27;47888:22;;;:16;:22;;;;;;47777:70;;-1:-1:-1;47858:27:0;47888:45;;47777:70;47888:45;:26;:45;:::i;:::-;-1:-1:-1;;;;;47944:22:0;;;;;;;:16;:22;;;;;;:50;;;48035:20;;;;;;;;;47858:75;;-1:-1:-1;47944:22:0;48035:43;;48060:17;48035:43;:24;:43;:::i;:::-;-1:-1:-1;;;;;48089:20:0;;;;;;;:16;:20;;;;;;;;;:48;;;48155:51;;;;;;;48005:73;;-1:-1:-1;48155:51:0;;;;;;;;;;;;;;;48222:49;;;;;;;;-1:-1:-1;;;;;48222:49:0;;;;;;;;;;;;;47601:678;;;;;;:::o;63228:761::-;63652:23;63678:69;63706:4;63678:69;;;;;;;;;;;;;;;;;63686:5;-1:-1:-1;;;;;63678:27:0;;;:69;;;;;:::i;:::-;63762:17;;63652:95;;-1:-1:-1;63762:21:0;63758:224;;63904:10;63893:30;;;;;;;;;;;;;;;-1:-1:-1;63893:30:0;63885:85;;;;-1:-1:-1;;;63885:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21347:218;21403:6;21433:5;;;21458:6;;;;;;:16;;;21473:1;21468;:6;;21458:16;21457:38;;;;21484:1;21480;:5;:14;;;;;21493:1;21489;:5;21480:14;21449:87;;;;-1:-1:-1;;;21449:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40729:383;40813:27;40825:7;40834:5;40813:11;:27::i;:::-;40853:24;40880:97;40924:42;40925:25;40944:5;40925:14;;:18;;:25;;;;:::i;40924:42::-;-1:-1:-1;;;;;40880:25:0;;;;;;:16;:25;;;;;;;:97;:29;:97;:::i;:::-;-1:-1:-1;;;;;40990:25:0;;;;;;:16;:25;;;;;;;;;:45;;;41053:51;;;;;;;40853:124;;-1:-1:-1;40990:25:0;;41053:51;;;;;;;;;;;40729:383;;;:::o;45318:400::-;45370:28;45434:32;45455:10;45434:20;:32::i;:::-;45527:10;45479:25;45510:28;;;:16;:28;;;;;;45411:55;;-1:-1:-1;45479:25:0;45510:54;;45411:55;45510:54;:32;:54;:::i;:::-;45592:10;45575:28;;;;:16;:28;;;;;;;;;:48;;;45641:69;;;;;;;;;;;;;45479:85;;-1:-1:-1;45592:10:0;;45641:69;;;;;;;;;;45318:400;;:::o;17072:132::-;17130:7;17157:39;17161:1;17164;17157:39;;;;;;;;;;;;;;;;;:3;:39::i;40027:383::-;40111:27;40123:7;40132:5;40111:11;:27::i;:::-;40151:24;40178:97;40222:42;40223:25;40242:5;40223:14;;:18;;:25;;;;:::i;40222:42::-;-1:-1:-1;;;;;40178:25:0;;;;;;:16;:25;;;;;;;:97;:29;:97;:::i;39105:672::-;39236:32;39252:4;39258:2;39262:5;39236:15;:32::i;:::-;39281:21;39311:40;:25;39330:5;39311:14;;:18;;:25;;;;:::i;:40::-;-1:-1:-1;;;;;39392:22:0;;39362:27;39392:22;;;:16;:22;;;;;;39281:70;;-1:-1:-1;39362:27:0;39392:42;;39281:70;39392:42;:26;:42;:::i;:::-;-1:-1:-1;;;;;39445:22:0;;;;;;;:16;:22;;;;;;:50;;;39536:20;;;;;;;;;39362:72;;-1:-1:-1;39445:22:0;39536:40;;39561:14;39536:40;:24;:40;:::i;:::-;-1:-1:-1;;;;;39587:20:0;;;;;;;:16;:20;;;;;;;;;:48;;;39653:51;;;;;;;39506:70;;-1:-1:-1;39653:51:0;;;;;;;;;;;;;;;39720:49;;;;;;;;-1:-1:-1;;;;;39720:49:0;;;;;;;;;;;;;39105:672;;;;;;:::o;56801:195::-;56904:12;56936:52;56958:6;56966:4;56972:1;56975:12;56936:21;:52::i;:::-;56929:59;56801:195;-1:-1:-1;;;;56801:195:0:o;31815:418::-;-1:-1:-1;;;;;31899:21:0;;31891:67;;;;-1:-1:-1;;;31891:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31971:49;31992:7;32009:1;32013:6;31971:20;:49::i;:::-;32054:68;32077:6;32054:68;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;32054:18:0;;:9;:18;;;;;;;;;;;;:68;;:22;:68;:::i;:::-;-1:-1:-1;;;;;32033:18:0;;:9;:18;;;;;;;;;;:89;32148:12;;:24;;32165:6;32148:24;:16;:24;:::i;:::-;32133:12;:39;32188:37;;;;;;;;32214:1;;-1:-1:-1;;;;;32188:37:0;;;;;;;;;;;;31815:418;;:::o;17700:278::-;17786:7;17821:12;17814:5;17806:28;;;;-1:-1:-1;;;17806:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17845:9;17861:1;17857;:5;;;;;;;17700:278;-1:-1:-1;;;;;17700:278:0:o;31104:378::-;-1:-1:-1;;;;;31188:21:0;;31180:65;;;;;-1:-1:-1;;;31180:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;31258:49;31287:1;31291:7;31300:6;31258:20;:49::i;:::-;31335:12;;:24;;31352:6;31335:24;:16;:24;:::i;:::-;31320:12;:39;-1:-1:-1;;;;;31391:18:0;;:9;:18;;;;;;;;;;;:30;;31414:6;31391:30;:22;:30;:::i;:::-;-1:-1:-1;;;;;31370:18:0;;:9;:18;;;;;;;;;;;:51;;;;31437:37;;;;;;;31370:18;;:9;;31437:37;;;;;;;;;;31104:378;;:::o;30283:539::-;-1:-1:-1;;;;;30389:20:0;;30381:70;;;;-1:-1:-1;;;30381:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;30470:23:0;;30462:71;;;;-1:-1:-1;;;30462:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30546:47;30567:6;30575:9;30586:6;30546:20;:47::i;:::-;30626:71;30648:6;30626:71;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;30626:17:0;;:9;:17;;;;;;;;;;;;:71;;:21;:71;:::i;:::-;-1:-1:-1;;;;;30606:17:0;;;:9;:17;;;;;;;;;;;:91;;;;30731:20;;;;;;;:32;;30756:6;30731:32;:24;:32;:::i;:::-;-1:-1:-1;;;;;30708:20:0;;;:9;:20;;;;;;;;;;;;:55;;;;30779:35;;;;;;;30708:20;;30779:35;;;;;;;;;;;;;30283:539;;;:::o;57853:530::-;57980:12;58038:5;58013:21;:30;;58005:81;;;;-1:-1:-1;;;58005:81:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58105:18;58116:6;58105:10;:18::i;:::-;58097:60;;;;;-1:-1:-1;;;58097:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;58231:12;58245:23;58272:6;-1:-1:-1;;;;;58272:11:0;58292:5;58300:4;58272:33;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;58272:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58230:75;;;;58323:52;58341:7;58350:10;58362:12;58323:17;:52::i;:::-;58316:59;57853:530;-1:-1:-1;;;;;;;57853:530:0:o;53883:422::-;54250:20;54289:8;;;53883:422::o;59389:742::-;59504:12;59533:7;59529:595;;;-1:-1:-1;59564:10:0;59557:17;;59529:595;59678:17;;:21;59674:439;;59941:10;59935:17;60002:15;59989:10;59985:2;59981:19;59974:44;59889:148;60077:20;;-1:-1:-1;;;60077:20:0;;;;;;;;;;;;;;;;;60084:12;;60077:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Swarm Source

ipfs://48f517b477c459d5376e0cc0cd024aca11f8214b1affb8111823a449ec0c5e95

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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