Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 932 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim Balance | 11543970 | 1437 days ago | IN | 0 ETH | 0.00193885 | ||||
Add Liquidity | 11543970 | 1437 days ago | IN | 0 ETH | 0.0046545 | ||||
Transfer Store O... | 11543597 | 1437 days ago | IN | 0 ETH | 0.00874255 | ||||
Add Liquidity | 11543204 | 1437 days ago | IN | 0 ETH | 0.04441166 | ||||
Add Liquidity | 11543088 | 1437 days ago | IN | 0 ETH | 0.09368672 | ||||
Add Liquidity | 11542821 | 1437 days ago | IN | 0 ETH | 0.07748106 | ||||
Add Liquidity | 11542557 | 1437 days ago | IN | 0 ETH | 0.12865123 | ||||
Add Liquidity | 11542377 | 1438 days ago | IN | 0 ETH | 0.05066665 | ||||
Add Liquidity | 11542324 | 1438 days ago | IN | 0 ETH | 0.05334421 | ||||
Add Liquidity | 11542165 | 1438 days ago | IN | 0 ETH | 0.04578714 | ||||
Claim Balance | 11542128 | 1438 days ago | IN | 0 ETH | 0.00446075 | ||||
Add Liquidity | 11542118 | 1438 days ago | IN | 0 ETH | 0.05490485 | ||||
Claim Balance | 11541756 | 1438 days ago | IN | 0 ETH | 0.00225047 | ||||
Remove Liquidity | 11541683 | 1438 days ago | IN | 0 ETH | 0.01857688 | ||||
Remove Liquidity | 11541445 | 1438 days ago | IN | 0 ETH | 0.01569836 | ||||
Remove Liquidity | 11541418 | 1438 days ago | IN | 0 ETH | 0.01647097 | ||||
Remove Liquidity | 11541307 | 1438 days ago | IN | 0 ETH | 0.01169617 | ||||
Add Liquidity | 11541106 | 1438 days ago | IN | 0 ETH | 0.06807434 | ||||
Add Liquidity | 11540884 | 1438 days ago | IN | 0 ETH | 0.02380099 | ||||
Remove Liquidity | 11540810 | 1438 days ago | IN | 0 ETH | 0.01076106 | ||||
Add Liquidity | 11540498 | 1438 days ago | IN | 0 ETH | 0.01477184 | ||||
Remove Liquidity | 11540473 | 1438 days ago | IN | 0 ETH | 0.01665195 | ||||
Add Liquidity | 11540376 | 1438 days ago | IN | 0 ETH | 0.03751407 | ||||
Remove Liquidity | 11540351 | 1438 days ago | IN | 0 ETH | 0.01268048 | ||||
Add Liquidity | 11540314 | 1438 days ago | IN | 0 ETH | 0.02813376 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
11534306 | 1439 days ago | 22.61086941 ETH | ||||
11534306 | 1439 days ago | 22.61086941 ETH | ||||
11526845 | 1440 days ago | 2 ETH | ||||
11526500 | 1440 days ago | 4 ETH | ||||
11525694 | 1440 days ago | 16.95 ETH | ||||
11525072 | 1440 days ago | 2.01424929 ETH | ||||
11525072 | 1440 days ago | 2.01424929 ETH | ||||
11524351 | 1440 days ago | 9.8 ETH | ||||
11522471 | 1441 days ago | 0.7 ETH | ||||
11521566 | 1441 days ago | 16.15731661 ETH | ||||
11521540 | 1441 days ago | 7 ETH | ||||
11520888 | 1441 days ago | 20 ETH | ||||
11520838 | 1441 days ago | 25 ETH | ||||
11519007 | 1441 days ago | 10 ETH | ||||
11516982 | 1441 days ago | 5 ETH | ||||
11516443 | 1441 days ago | 0.9 ETH | ||||
11516135 | 1442 days ago | 5 ETH | ||||
11515518 | 1442 days ago | 105 ETH | ||||
11515343 | 1442 days ago | 4 ETH | ||||
11515185 | 1442 days ago | 185.6940737 ETH | ||||
11515185 | 1442 days ago | 185.6940737 ETH | ||||
11514807 | 1442 days ago | 69 ETH | ||||
11514513 | 1442 days ago | 99.8 ETH | ||||
11514279 | 1442 days ago | 3.01733675 ETH | ||||
11514279 | 1442 days ago | 3.01733675 ETH |
Loading...
Loading
Contract Name:
LiquidityProtection
Compiler Version
v0.6.12+commit.27d51765
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-12-14 */ // File: @openzeppelin/contracts/token/ERC20/IERC20.sol // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @bancor/token-governance/contracts/IClaimable.sol pragma solidity 0.6.12; /// @title Claimable contract interface interface IClaimable { function owner() external view returns (address); function transferOwnership(address newOwner) external; function acceptOwnership() external; } // File: @bancor/token-governance/contracts/IMintableToken.sol pragma solidity 0.6.12; /// @title Mintable Token interface interface IMintableToken is IERC20, IClaimable { function issue(address to, uint256 amount) external; function destroy(address from, uint256 amount) external; } // File: @bancor/token-governance/contracts/ITokenGovernance.sol pragma solidity 0.6.12; /// @title The interface for mintable/burnable token governance. interface ITokenGovernance { // The address of the mintable ERC20 token. function token() external view returns (IMintableToken); /// @dev Mints new tokens. /// /// @param to Account to receive the new amount. /// @param amount Amount to increase the supply by. /// function mint(address to, uint256 amount) external; /// @dev Burns tokens from the caller. /// /// @param amount Amount to decrease the supply by. /// function burn(uint256 amount) external; } // File: solidity/contracts/utility/interfaces/ICheckpointStore.sol pragma solidity 0.6.12; /** * @dev Checkpoint store contract interface */ interface ICheckpointStore { function addCheckpoint(address _address) external; function addPastCheckpoint(address _address, uint256 _time) external; function addPastCheckpoints(address[] calldata _addresses, uint256[] calldata _times) external; function checkpoint(address _address) external view returns (uint256); } // File: solidity/contracts/utility/ReentrancyGuard.sol pragma solidity 0.6.12; /** * @dev This contract provides protection against calling a function * (directly or indirectly) from within itself. */ contract ReentrancyGuard { uint256 private constant UNLOCKED = 1; uint256 private constant LOCKED = 2; // LOCKED while protected code is being executed, UNLOCKED otherwise uint256 private state = UNLOCKED; /** * @dev ensures instantiation only by sub-contracts */ constructor() internal {} // protects a function against reentrancy attacks modifier protected() { _protected(); state = LOCKED; _; state = UNLOCKED; } // error message binary size optimization function _protected() internal view { require(state == UNLOCKED, "ERR_REENTRANCY"); } } // File: solidity/contracts/utility/interfaces/IOwned.sol pragma solidity 0.6.12; /* Owned contract interface */ interface IOwned { // this function isn't since the compiler emits automatically generated getter functions as external function owner() external view returns (address); function transferOwnership(address _newOwner) external; function acceptOwnership() external; } // File: solidity/contracts/utility/Owned.sol pragma solidity 0.6.12; /** * @dev This contract provides support and utilities for contract ownership. */ contract Owned is IOwned { address public override owner; address public newOwner; /** * @dev triggered when the owner is updated * * @param _prevOwner previous owner * @param _newOwner new owner */ event OwnerUpdate(address indexed _prevOwner, address indexed _newOwner); /** * @dev initializes a new Owned instance */ constructor() public { owner = msg.sender; } // allows execution by the owner only modifier ownerOnly { _ownerOnly(); _; } // error message binary size optimization function _ownerOnly() internal view { require(msg.sender == owner, "ERR_ACCESS_DENIED"); } /** * @dev allows transferring the contract ownership * the new owner still needs to accept the transfer * can only be called by the contract owner * * @param _newOwner new contract owner */ function transferOwnership(address _newOwner) public override ownerOnly { require(_newOwner != owner, "ERR_SAME_OWNER"); newOwner = _newOwner; } /** * @dev used by a new owner to accept an ownership transfer */ function acceptOwnership() public override { require(msg.sender == newOwner, "ERR_ACCESS_DENIED"); emit OwnerUpdate(owner, newOwner); owner = newOwner; newOwner = address(0); } } // File: solidity/contracts/utility/SafeMath.sol pragma solidity 0.6.12; /** * @dev This library supports basic math operations with overflow/underflow protection. */ library SafeMath { /** * @dev returns the sum of _x and _y, reverts if the calculation overflows * * @param _x value 1 * @param _y value 2 * * @return sum */ function add(uint256 _x, uint256 _y) internal pure returns (uint256) { uint256 z = _x + _y; require(z >= _x, "ERR_OVERFLOW"); return z; } /** * @dev returns the difference of _x minus _y, reverts if the calculation underflows * * @param _x minuend * @param _y subtrahend * * @return difference */ function sub(uint256 _x, uint256 _y) internal pure returns (uint256) { require(_x >= _y, "ERR_UNDERFLOW"); return _x - _y; } /** * @dev returns the product of multiplying _x by _y, reverts if the calculation overflows * * @param _x factor 1 * @param _y factor 2 * * @return product */ function mul(uint256 _x, uint256 _y) internal pure returns (uint256) { // gas optimization if (_x == 0) return 0; uint256 z = _x * _y; require(z / _x == _y, "ERR_OVERFLOW"); return z; } /** * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. * * @param _x dividend * @param _y divisor * * @return quotient */ function div(uint256 _x, uint256 _y) internal pure returns (uint256) { require(_y > 0, "ERR_DIVIDE_BY_ZERO"); uint256 c = _x / _y; return c; } } // File: solidity/contracts/utility/Math.sol pragma solidity 0.6.12; /** * @dev This library provides a set of complex math operations. */ library Math { /** * @dev returns the largest integer smaller than or equal to the square root of a positive integer * * @param _num a positive integer * * @return the largest integer smaller than or equal to the square root of the positive integer */ function floorSqrt(uint256 _num) internal pure returns (uint256) { uint256 x = _num / 2 + 1; uint256 y = (x + _num / x) / 2; while (x > y) { x = y; y = (x + _num / x) / 2; } return x; } /** * @dev returns the smallest integer larger than or equal to the square root of a positive integer * * @param _num a positive integer * * @return the smallest integer larger than or equal to the square root of the positive integer */ function ceilSqrt(uint256 _num) internal pure returns (uint256) { uint256 x = floorSqrt(_num); return x * x == _num ? x : x + 1; } /** * @dev computes a reduced-scalar ratio * * @param _n ratio numerator * @param _d ratio denominator * @param _max maximum desired scalar * * @return ratio's numerator and denominator */ function reducedRatio( uint256 _n, uint256 _d, uint256 _max ) internal pure returns (uint256, uint256) { (uint256 n, uint256 d) = (_n, _d); if (n > _max || d > _max) { (n, d) = normalizedRatio(n, d, _max); } if (n != d) { return (n, d); } return (1, 1); } /** * @dev computes "scale * a / (a + b)" and "scale * b / (a + b)". */ function normalizedRatio( uint256 _a, uint256 _b, uint256 _scale ) internal pure returns (uint256, uint256) { if (_a <= _b) { return accurateRatio(_a, _b, _scale); } (uint256 y, uint256 x) = accurateRatio(_b, _a, _scale); return (x, y); } /** * @dev computes "scale * a / (a + b)" and "scale * b / (a + b)", assuming that "a <= b". */ function accurateRatio( uint256 _a, uint256 _b, uint256 _scale ) internal pure returns (uint256, uint256) { uint256 maxVal = uint256(-1) / _scale; if (_a > maxVal) { uint256 c = _a / (maxVal + 1) + 1; _a /= c; // we can now safely compute `_a * _scale` _b /= c; } if (_a != _b) { uint256 n = _a * _scale; uint256 d = _a + _b; // can overflow if (d >= _a) { // no overflow in `_a + _b` uint256 x = roundDiv(n, d); // we can now safely compute `_scale - x` uint256 y = _scale - x; return (x, y); } if (n < _b - (_b - _a) / 2) { return (0, _scale); // `_a * _scale < (_a + _b) / 2 < MAX_UINT256 < _a + _b` } return (1, _scale - 1); // `(_a + _b) / 2 < _a * _scale < MAX_UINT256 < _a + _b` } return (_scale / 2, _scale / 2); // allow reduction to `(1, 1)` in the calling function } /** * @dev computes the nearest integer to a given quotient without overflowing or underflowing. */ function roundDiv(uint256 _n, uint256 _d) internal pure returns (uint256) { return _n / _d + (_n % _d) / (_d - _d / 2); } /** * @dev returns the average number of decimal digits in a given list of positive integers * * @param _values list of positive integers * * @return the average number of decimal digits in the given list of positive integers */ function geometricMean(uint256[] memory _values) internal pure returns (uint256) { uint256 numOfDigits = 0; uint256 length = _values.length; for (uint256 i = 0; i < length; i++) { numOfDigits += decimalLength(_values[i]); } return uint256(10)**(roundDivUnsafe(numOfDigits, length) - 1); } /** * @dev returns the number of decimal digits in a given positive integer * * @param _x positive integer * * @return the number of decimal digits in the given positive integer */ function decimalLength(uint256 _x) internal pure returns (uint256) { uint256 y = 0; for (uint256 x = _x; x > 0; x /= 10) { y++; } return y; } /** * @dev returns the nearest integer to a given quotient * the computation is overflow-safe assuming that the input is sufficiently small * * @param _n quotient numerator * @param _d quotient denominator * * @return the nearest integer to the given quotient */ function roundDivUnsafe(uint256 _n, uint256 _d) internal pure returns (uint256) { return (_n + _d / 2) / _d; } /** * @dev returns the larger of two values * * @param _val1 the first value * @param _val2 the second value */ function max(uint256 _val1, uint256 _val2) internal pure returns (uint256) { return _val1 > _val2 ? _val1 : _val2; } } // File: solidity/contracts/token/interfaces/IERC20Token.sol pragma solidity 0.6.12; /* ERC20 Standard Token interface */ interface IERC20Token { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address _owner) external view returns (uint256); function allowance(address _owner, address _spender) external view returns (uint256); function transfer(address _to, uint256 _value) external returns (bool); function transferFrom( address _from, address _to, uint256 _value ) external returns (bool); function approve(address _spender, uint256 _value) external returns (bool); } // File: solidity/contracts/utility/TokenHandler.sol pragma solidity 0.6.12; contract TokenHandler { bytes4 private constant APPROVE_FUNC_SELECTOR = bytes4(keccak256("approve(address,uint256)")); bytes4 private constant TRANSFER_FUNC_SELECTOR = bytes4(keccak256("transfer(address,uint256)")); bytes4 private constant TRANSFER_FROM_FUNC_SELECTOR = bytes4(keccak256("transferFrom(address,address,uint256)")); /** * @dev executes the ERC20 token's `approve` function and reverts upon failure * the main purpose of this function is to prevent a non standard ERC20 token * from failing silently * * @param _token ERC20 token address * @param _spender approved address * @param _value allowance amount */ function safeApprove( IERC20Token _token, address _spender, uint256 _value ) internal { (bool success, bytes memory data) = address(_token).call( abi.encodeWithSelector(APPROVE_FUNC_SELECTOR, _spender, _value) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "ERR_APPROVE_FAILED"); } /** * @dev executes the ERC20 token's `transfer` function and reverts upon failure * the main purpose of this function is to prevent a non standard ERC20 token * from failing silently * * @param _token ERC20 token address * @param _to target address * @param _value transfer amount */ function safeTransfer( IERC20Token _token, address _to, uint256 _value ) internal { (bool success, bytes memory data) = address(_token).call( abi.encodeWithSelector(TRANSFER_FUNC_SELECTOR, _to, _value) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "ERR_TRANSFER_FAILED"); } /** * @dev executes the ERC20 token's `transferFrom` function and reverts upon failure * the main purpose of this function is to prevent a non standard ERC20 token * from failing silently * * @param _token ERC20 token address * @param _from source address * @param _to target address * @param _value transfer amount */ function safeTransferFrom( IERC20Token _token, address _from, address _to, uint256 _value ) internal { (bool success, bytes memory data) = address(_token).call( abi.encodeWithSelector(TRANSFER_FROM_FUNC_SELECTOR, _from, _to, _value) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "ERR_TRANSFER_FROM_FAILED"); } } // File: solidity/contracts/utility/Types.sol pragma solidity 0.6.12; /** * @dev This contract provides types which can be used by various contracts. */ struct Fraction { uint256 n; // numerator uint256 d; // denominator } // File: solidity/contracts/utility/Time.sol pragma solidity 0.6.12; /* Time implementing contract */ contract Time { /** * @dev returns the current time */ function time() internal view virtual returns (uint256) { return block.timestamp; } } // File: solidity/contracts/utility/Utils.sol pragma solidity 0.6.12; /** * @dev Utilities & Common Modifiers */ contract Utils { // verifies that a value is greater than zero modifier greaterThanZero(uint256 _value) { _greaterThanZero(_value); _; } // error message binary size optimization function _greaterThanZero(uint256 _value) internal pure { require(_value > 0, "ERR_ZERO_VALUE"); } // validates an address - currently only checks that it isn't null modifier validAddress(address _address) { _validAddress(_address); _; } // error message binary size optimization function _validAddress(address _address) internal pure { require(_address != address(0), "ERR_INVALID_ADDRESS"); } // verifies that the address is different than this contract address modifier notThis(address _address) { _notThis(_address); _; } // error message binary size optimization function _notThis(address _address) internal view { require(_address != address(this), "ERR_ADDRESS_IS_SELF"); } } // File: solidity/contracts/converter/interfaces/IConverterAnchor.sol pragma solidity 0.6.12; /* Converter Anchor interface */ interface IConverterAnchor is IOwned { } // File: solidity/contracts/token/interfaces/IDSToken.sol pragma solidity 0.6.12; /* DSToken interface */ interface IDSToken is IConverterAnchor, IERC20Token { function issue(address _to, uint256 _amount) external; function destroy(address _from, uint256 _amount) external; } // File: solidity/contracts/liquidity-protection/interfaces/ILiquidityProtectionStore.sol pragma solidity 0.6.12; /* Liquidity Protection Store interface */ interface ILiquidityProtectionStore is IOwned { function withdrawTokens( IERC20Token _token, address _to, uint256 _amount ) external; function protectedLiquidity(uint256 _id) external view returns ( address, IDSToken, IERC20Token, uint256, uint256, uint256, uint256, uint256 ); function addProtectedLiquidity( address _provider, IDSToken _poolToken, IERC20Token _reserveToken, uint256 _poolAmount, uint256 _reserveAmount, uint256 _reserveRateN, uint256 _reserveRateD, uint256 _timestamp ) external returns (uint256); function updateProtectedLiquidityAmounts( uint256 _id, uint256 _poolNewAmount, uint256 _reserveNewAmount ) external; function removeProtectedLiquidity(uint256 _id) external; function lockedBalance(address _provider, uint256 _index) external view returns (uint256, uint256); function lockedBalanceRange( address _provider, uint256 _startIndex, uint256 _endIndex ) external view returns (uint256[] memory, uint256[] memory); function addLockedBalance( address _provider, uint256 _reserveAmount, uint256 _expirationTime ) external returns (uint256); function removeLockedBalance(address _provider, uint256 _index) external; function systemBalance(IERC20Token _poolToken) external view returns (uint256); function incSystemBalance(IERC20Token _poolToken, uint256 _poolAmount) external; function decSystemBalance(IERC20Token _poolToken, uint256 _poolAmount) external; } // File: solidity/contracts/liquidity-protection/interfaces/ILiquidityProtectionSettings.sol pragma solidity 0.6.12; /* Liquidity Protection Store Settings interface */ interface ILiquidityProtectionSettings { function addPoolToWhitelist(IConverterAnchor _poolAnchor) external; function removePoolFromWhitelist(IConverterAnchor _poolAnchor) external; function isPoolWhitelisted(IConverterAnchor _poolAnchor) external view returns (bool); function isPoolSupported(IConverterAnchor _poolAnchor) external view returns (bool); function minNetworkTokenLiquidityForMinting() external view returns (uint256); function defaultNetworkTokenMintingLimit() external view returns (uint256); function networkTokenMintingLimits(IConverterAnchor _poolAnchor) external view returns (uint256); function networkTokensMinted(IConverterAnchor _poolAnchor) external view returns (uint256); function incNetworkTokensMinted(IConverterAnchor _poolAnchor, uint256 _amount) external; function decNetworkTokensMinted(IConverterAnchor _poolAnchor, uint256 _amount) external; function minProtectionDelay() external view returns (uint256); function maxProtectionDelay() external view returns (uint256); function setProtectionDelays(uint256 _minProtectionDelay, uint256 _maxProtectionDelay) external; function minNetworkCompensation() external view returns (uint256); function setMinNetworkCompensation(uint256 _minCompensation) external; function lockDuration() external view returns (uint256); function setLockDuration(uint256 _lockDuration) external; function averageRateMaxDeviation() external view returns (uint32); function setAverageRateMaxDeviation(uint32 _averageRateMaxDeviation) external; } // File: solidity/contracts/converter/interfaces/IConverter.sol pragma solidity 0.6.12; /* Converter interface */ interface IConverter is IOwned { function converterType() external pure returns (uint16); function anchor() external view returns (IConverterAnchor); function isActive() external view returns (bool); function targetAmountAndFee( IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount ) external view returns (uint256, uint256); function convert( IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount, address _trader, address payable _beneficiary ) external payable returns (uint256); function conversionFee() external view returns (uint32); function maxConversionFee() external view returns (uint32); function reserveBalance(IERC20Token _reserveToken) external view returns (uint256); receive() external payable; function transferAnchorOwnership(address _newOwner) external; function acceptAnchorOwnership() external; function setConversionFee(uint32 _conversionFee) external; function withdrawTokens( IERC20Token _token, address _to, uint256 _amount ) external; function withdrawETH(address payable _to) external; function addReserve(IERC20Token _token, uint32 _ratio) external; // deprecated, backward compatibility function token() external view returns (IConverterAnchor); function transferTokenOwnership(address _newOwner) external; function acceptTokenOwnership() external; function connectors(IERC20Token _address) external view returns ( uint256, uint32, bool, bool, bool ); function getConnectorBalance(IERC20Token _connectorToken) external view returns (uint256); function connectorTokens(uint256 _index) external view returns (IERC20Token); function connectorTokenCount() external view returns (uint16); /** * @dev triggered when the converter is activated * * @param _type converter type * @param _anchor converter anchor * @param _activated true if the converter was activated, false if it was deactivated */ event Activation(uint16 indexed _type, IConverterAnchor indexed _anchor, bool indexed _activated); /** * @dev triggered when a conversion between two tokens occurs * * @param _fromToken source ERC20 token * @param _toToken target ERC20 token * @param _trader wallet that initiated the trade * @param _amount input amount in units of the source token * @param _return output amount minus conversion fee in units of the target token * @param _conversionFee conversion fee in units of the target token */ event Conversion( IERC20Token indexed _fromToken, IERC20Token indexed _toToken, address indexed _trader, uint256 _amount, uint256 _return, int256 _conversionFee ); /** * @dev triggered when the rate between two tokens in the converter changes * note that the event might be dispatched for rate updates between any two tokens in the converter * * @param _token1 address of the first token * @param _token2 address of the second token * @param _rateN rate of 1 unit of `_token1` in `_token2` (numerator) * @param _rateD rate of 1 unit of `_token1` in `_token2` (denominator) */ event TokenRateUpdate(IERC20Token indexed _token1, IERC20Token indexed _token2, uint256 _rateN, uint256 _rateD); /** * @dev triggered when the conversion fee is updated * * @param _prevFee previous fee percentage, represented in ppm * @param _newFee new fee percentage, represented in ppm */ event ConversionFeeUpdate(uint32 _prevFee, uint32 _newFee); } // File: solidity/contracts/converter/interfaces/IConverterRegistry.sol pragma solidity 0.6.12; interface IConverterRegistry { function getAnchorCount() external view returns (uint256); function getAnchors() external view returns (address[] memory); function getAnchor(uint256 _index) external view returns (IConverterAnchor); function isAnchor(address _value) external view returns (bool); function getLiquidityPoolCount() external view returns (uint256); function getLiquidityPools() external view returns (address[] memory); function getLiquidityPool(uint256 _index) external view returns (IConverterAnchor); function isLiquidityPool(address _value) external view returns (bool); function getConvertibleTokenCount() external view returns (uint256); function getConvertibleTokens() external view returns (address[] memory); function getConvertibleToken(uint256 _index) external view returns (IERC20Token); function isConvertibleToken(address _value) external view returns (bool); function getConvertibleTokenAnchorCount(IERC20Token _convertibleToken) external view returns (uint256); function getConvertibleTokenAnchors(IERC20Token _convertibleToken) external view returns (address[] memory); function getConvertibleTokenAnchor(IERC20Token _convertibleToken, uint256 _index) external view returns (IConverterAnchor); function isConvertibleTokenAnchor(IERC20Token _convertibleToken, address _value) external view returns (bool); } // File: solidity/contracts/liquidity-protection/LiquidityProtection.sol pragma solidity 0.6.12; interface ILiquidityPoolConverter is IConverter { function addLiquidity( IERC20Token[] memory _reserveTokens, uint256[] memory _reserveAmounts, uint256 _minReturn ) external payable; function removeLiquidity( uint256 _amount, IERC20Token[] memory _reserveTokens, uint256[] memory _reserveMinReturnAmounts ) external; function recentAverageRate(IERC20Token _reserveToken) external view returns (uint256, uint256); } /** * @dev This contract implements the liquidity protection mechanism. */ contract LiquidityProtection is TokenHandler, Utils, Owned, ReentrancyGuard, Time { using SafeMath for uint256; using Math for *; struct ProtectedLiquidity { address provider; // liquidity provider IDSToken poolToken; // pool token address IERC20Token reserveToken; // reserve token address uint256 poolAmount; // pool token amount uint256 reserveAmount; // reserve token amount uint256 reserveRateN; // rate of 1 protected reserve token in units of the other reserve token (numerator) uint256 reserveRateD; // rate of 1 protected reserve token in units of the other reserve token (denominator) uint256 timestamp; // timestamp } // various rates between the two reserve tokens. the rate is of 1 unit of the protected reserve token in units of the other reserve token struct PackedRates { uint128 addSpotRateN; // spot rate of 1 A in units of B when liquidity was added (numerator) uint128 addSpotRateD; // spot rate of 1 A in units of B when liquidity was added (denominator) uint128 removeSpotRateN; // spot rate of 1 A in units of B when liquidity is removed (numerator) uint128 removeSpotRateD; // spot rate of 1 A in units of B when liquidity is removed (denominator) uint128 removeAverageRateN; // average rate of 1 A in units of B when liquidity is removed (numerator) uint128 removeAverageRateD; // average rate of 1 A in units of B when liquidity is removed (denominator) } IERC20Token internal constant ETH_RESERVE_ADDRESS = IERC20Token(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); uint32 internal constant PPM_RESOLUTION = 1000000; uint256 internal constant MAX_UINT128 = 2**128 - 1; uint256 internal constant MAX_UINT256 = uint256(-1); ILiquidityProtectionSettings public immutable settings; ILiquidityProtectionStore public immutable store; IERC20Token public immutable networkToken; ITokenGovernance public immutable networkTokenGovernance; IERC20Token public immutable govToken; ITokenGovernance public immutable govTokenGovernance; ICheckpointStore public immutable lastRemoveCheckpointStore; // true if the contract is currently adding/removing liquidity from a converter, used for accepting ETH bool private updatingLiquidity = false; /** * @dev initializes a new LiquidityProtection contract * * @param _settings liquidity protection settings * @param _store liquidity protection store * @param _networkTokenGovernance network token governance * @param _govTokenGovernance governance token governance * @param _lastRemoveCheckpointStore last liquidity removal/unprotection checkpoints store */ constructor( ILiquidityProtectionSettings _settings, ILiquidityProtectionStore _store, ITokenGovernance _networkTokenGovernance, ITokenGovernance _govTokenGovernance, ICheckpointStore _lastRemoveCheckpointStore ) public validAddress(address(_settings)) validAddress(address(_store)) validAddress(address(_networkTokenGovernance)) validAddress(address(_govTokenGovernance)) notThis(address(_settings)) notThis(address(_store)) notThis(address(_networkTokenGovernance)) notThis(address(_govTokenGovernance)) { settings = _settings; store = _store; networkTokenGovernance = _networkTokenGovernance; networkToken = IERC20Token(address(_networkTokenGovernance.token())); govTokenGovernance = _govTokenGovernance; govToken = IERC20Token(address(_govTokenGovernance.token())); lastRemoveCheckpointStore = _lastRemoveCheckpointStore; } // ensures that the contract is currently removing liquidity from a converter modifier updatingLiquidityOnly() { _updatingLiquidityOnly(); _; } // error message binary size optimization function _updatingLiquidityOnly() internal view { require(updatingLiquidity, "ERR_NOT_UPDATING_LIQUIDITY"); } // ensures that the portion is valid modifier validPortion(uint32 _portion) { _validPortion(_portion); _; } // error message binary size optimization function _validPortion(uint32 _portion) internal pure { require(_portion > 0 && _portion <= PPM_RESOLUTION, "ERR_INVALID_PORTION"); } // ensures that the pool is supported modifier poolSupported(IConverterAnchor _poolAnchor) { _poolSupported(_poolAnchor); _; } // error message binary size optimization function _poolSupported(IConverterAnchor _poolAnchor) internal view { require(settings.isPoolSupported(_poolAnchor), "ERR_POOL_NOT_SUPPORTED"); } // ensures that the pool is whitelisted modifier poolWhitelisted(IConverterAnchor _poolAnchor) { _poolWhitelisted(_poolAnchor); _; } // error message binary size optimization function _poolWhitelisted(IConverterAnchor _poolAnchor) internal view { require(settings.isPoolWhitelisted(_poolAnchor), "ERR_POOL_NOT_WHITELISTED"); } /** * @dev accept ETH * used when removing liquidity from ETH converters */ receive() external payable updatingLiquidityOnly() {} /** * @dev transfers the ownership of the store * can only be called by the contract owner * * @param _newOwner the new owner of the store */ function transferStoreOwnership(address _newOwner) external ownerOnly { store.transferOwnership(_newOwner); } /** * @dev accepts the ownership of the store * can only be called by the contract owner */ function acceptStoreOwnership() external ownerOnly { store.acceptOwnership(); } /** * @dev adds protection to existing pool tokens * also mints new governance tokens for the caller * * @param _poolAnchor anchor of the pool * @param _amount amount of pool tokens to protect */ function protectLiquidity(IConverterAnchor _poolAnchor, uint256 _amount) external protected poolSupported(_poolAnchor) poolWhitelisted(_poolAnchor) greaterThanZero(_amount) { // get the converter IConverter converter = IConverter(payable(ownedBy(_poolAnchor))); // save a local copy of `networkToken` IERC20Token networkTokenLocal = networkToken; // protect both reserves IDSToken poolToken = IDSToken(address(_poolAnchor)); protectLiquidity(poolToken, converter, networkTokenLocal, 0, _amount / 2); protectLiquidity(poolToken, converter, networkTokenLocal, 1, _amount - _amount / 2); // transfer the pool tokens from the caller directly to the store safeTransferFrom(poolToken, msg.sender, address(store), _amount); } /** * @dev cancels the protection and returns the pool tokens to the caller * also burns governance tokens from the caller * must be called with the indices of both the base token and the network token protections * * @param _id1 id in the caller's list of protected liquidity * @param _id2 matching id in the caller's list of protected liquidity */ function unprotectLiquidity(uint256 _id1, uint256 _id2) external protected { require(_id1 != _id2, "ERR_SAME_ID"); ProtectedLiquidity memory liquidity1 = protectedLiquidity(_id1, msg.sender); ProtectedLiquidity memory liquidity2 = protectedLiquidity(_id2, msg.sender); // save a local copy of `networkToken` IERC20Token networkTokenLocal = networkToken; // verify that the two protected liquidities were added together (using `protect`) require( liquidity1.poolToken == liquidity2.poolToken && liquidity1.reserveToken != liquidity2.reserveToken && (liquidity1.reserveToken == networkTokenLocal || liquidity2.reserveToken == networkTokenLocal) && liquidity1.timestamp == liquidity2.timestamp && liquidity1.poolAmount <= liquidity2.poolAmount.add(1) && liquidity2.poolAmount <= liquidity1.poolAmount.add(1), "ERR_PROTECTIONS_MISMATCH" ); // verify that the two protected liquidities are not removed on the same block in which they were added require(liquidity1.timestamp < time(), "ERR_TOO_EARLY"); // burn the governance tokens from the caller. we need to transfer the tokens to the contract itself, since only // token holders can burn their tokens uint256 amount = liquidity1.reserveToken == networkTokenLocal ? liquidity1.reserveAmount : liquidity2.reserveAmount; safeTransferFrom(govToken, msg.sender, address(this), amount); govTokenGovernance.burn(amount); // update last liquidity removal checkpoint lastRemoveCheckpointStore.addCheckpoint(msg.sender); // remove the two protected liquidities from the provider store.removeProtectedLiquidity(_id1); store.removeProtectedLiquidity(_id2); // transfer the pool tokens back to the caller store.withdrawTokens(liquidity1.poolToken, msg.sender, liquidity1.poolAmount.add(liquidity2.poolAmount)); } /** * @dev adds protected liquidity to a pool for a specific recipient * also mints new governance tokens for the caller if the caller adds network tokens * * @param _owner protected liquidity owner * @param _poolAnchor anchor of the pool * @param _reserveToken reserve token to add to the pool * @param _amount amount of tokens to add to the pool * @return new protected liquidity id */ function addLiquidityFor( address _owner, IConverterAnchor _poolAnchor, IERC20Token _reserveToken, uint256 _amount ) external payable protected validAddress(_owner) poolSupported(_poolAnchor) poolWhitelisted(_poolAnchor) greaterThanZero(_amount) returns (uint256) { return addLiquidity(_owner, _poolAnchor, _reserveToken, _amount); } /** * @dev adds protected liquidity to a pool * also mints new governance tokens for the caller if the caller adds network tokens * * @param _poolAnchor anchor of the pool * @param _reserveToken reserve token to add to the pool * @param _amount amount of tokens to add to the pool * @return new protected liquidity id */ function addLiquidity( IConverterAnchor _poolAnchor, IERC20Token _reserveToken, uint256 _amount ) external payable protected poolSupported(_poolAnchor) poolWhitelisted(_poolAnchor) greaterThanZero(_amount) returns (uint256) { return addLiquidity(msg.sender, _poolAnchor, _reserveToken, _amount); } /** * @dev adds protected liquidity to a pool for a specific recipient * also mints new governance tokens for the caller if the caller adds network tokens * * @param _owner protected liquidity owner * @param _poolAnchor anchor of the pool * @param _reserveToken reserve token to add to the pool * @param _amount amount of tokens to add to the pool * @return new protected liquidity id */ function addLiquidity( address _owner, IConverterAnchor _poolAnchor, IERC20Token _reserveToken, uint256 _amount ) private returns (uint256) { // save a local copy of `networkToken` IERC20Token networkTokenLocal = networkToken; if (_reserveToken == networkTokenLocal) { require(msg.value == 0, "ERR_ETH_AMOUNT_MISMATCH"); return addNetworkTokenLiquidity(_owner, _poolAnchor, networkTokenLocal, _amount); } // verify that ETH was passed with the call if needed uint256 val = _reserveToken == ETH_RESERVE_ADDRESS ? _amount : 0; require(msg.value == val, "ERR_ETH_AMOUNT_MISMATCH"); return addBaseTokenLiquidity(_owner, _poolAnchor, _reserveToken, networkTokenLocal, _amount); } /** * @dev adds protected network token liquidity to a pool * also mints new governance tokens for the caller * * @param _owner protected liquidity owner * @param _poolAnchor anchor of the pool * @param _networkToken the network reserve token of the pool * @param _amount amount of tokens to add to the pool * @return new protected liquidity id */ function addNetworkTokenLiquidity( address _owner, IConverterAnchor _poolAnchor, IERC20Token _networkToken, uint256 _amount ) internal returns (uint256) { IDSToken poolToken = IDSToken(address(_poolAnchor)); // get the rate between the pool token and the reserve Fraction memory poolRate = poolTokenRate(poolToken, _networkToken); // calculate the amount of pool tokens based on the amount of reserve tokens uint256 poolTokenAmount = _amount.mul(poolRate.d).div(poolRate.n); // remove the pool tokens from the system's ownership (will revert if not enough tokens are available) store.decSystemBalance(poolToken, poolTokenAmount); // add protected liquidity for the recipient uint256 id = addProtectedLiquidity(_owner, poolToken, _networkToken, poolTokenAmount, _amount); // burns the network tokens from the caller. we need to transfer the tokens to the contract itself, since only // token holders can burn their tokens safeTransferFrom(_networkToken, msg.sender, address(this), _amount); networkTokenGovernance.burn(_amount); settings.decNetworkTokensMinted(_poolAnchor, _amount); // mint governance tokens to the recipient govTokenGovernance.mint(_owner, _amount); return id; } /** * @dev adds protected base token liquidity to a pool * * @param _owner protected liquidity owner * @param _poolAnchor anchor of the pool * @param _baseToken the base reserve token of the pool * @param _networkToken the network reserve token of the pool * @param _amount amount of tokens to add to the pool * @return new protected liquidity id */ function addBaseTokenLiquidity( address _owner, IConverterAnchor _poolAnchor, IERC20Token _baseToken, IERC20Token _networkToken, uint256 _amount ) internal returns (uint256) { IDSToken poolToken = IDSToken(address(_poolAnchor)); // get the reserve balances ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(ownedBy(_poolAnchor))); (uint256 reserveBalanceBase, uint256 reserveBalanceNetwork) = converterReserveBalances(converter, _baseToken, _networkToken); require(reserveBalanceNetwork >= settings.minNetworkTokenLiquidityForMinting(), "ERR_NOT_ENOUGH_LIQUIDITY"); // calculate and mint the required amount of network tokens for adding liquidity uint256 newNetworkLiquidityAmount = _amount.mul(reserveBalanceNetwork).div(reserveBalanceBase); // verify network token minting limit uint256 mintingLimit = settings.networkTokenMintingLimits(_poolAnchor); if (mintingLimit == 0) { mintingLimit = settings.defaultNetworkTokenMintingLimit(); } uint256 newNetworkTokensMinted = settings.networkTokensMinted(_poolAnchor).add(newNetworkLiquidityAmount); require(newNetworkTokensMinted <= mintingLimit, "ERR_MAX_AMOUNT_REACHED"); // issue new network tokens to the system networkTokenGovernance.mint(address(this), newNetworkLiquidityAmount); settings.incNetworkTokensMinted(_poolAnchor, newNetworkLiquidityAmount); // transfer the base tokens from the caller and approve the converter ensureAllowance(_networkToken, address(converter), newNetworkLiquidityAmount); if (_baseToken != ETH_RESERVE_ADDRESS) { safeTransferFrom(_baseToken, msg.sender, address(this), _amount); ensureAllowance(_baseToken, address(converter), _amount); } // add liquidity addLiquidity(converter, _baseToken, _networkToken, _amount, newNetworkLiquidityAmount, msg.value); // transfer the new pool tokens to the store uint256 poolTokenAmount = poolToken.balanceOf(address(this)); safeTransfer(poolToken, address(store), poolTokenAmount); // the system splits the pool tokens with the caller // increase the system's pool token balance and add protected liquidity for the caller store.incSystemBalance(poolToken, poolTokenAmount - poolTokenAmount / 2); // account for rounding errors return addProtectedLiquidity(_owner, poolToken, _baseToken, poolTokenAmount / 2, _amount); } /** * @dev returns the expected/actual amounts the provider will receive for removing liquidity * it's also possible to provide the remove liquidity time to get an estimation * for the return at that given point * * @param _id protected liquidity id * @param _portion portion of liquidity to remove, in PPM * @param _removeTimestamp time at which the liquidity is removed * @return expected return amount in the reserve token * @return actual return amount in the reserve token * @return compensation in the network token */ function removeLiquidityReturn( uint256 _id, uint32 _portion, uint256 _removeTimestamp ) external view validPortion(_portion) returns ( uint256, uint256, uint256 ) { ProtectedLiquidity memory liquidity = protectedLiquidity(_id); // verify input require(liquidity.provider != address(0), "ERR_INVALID_ID"); require(_removeTimestamp >= liquidity.timestamp, "ERR_INVALID_TIMESTAMP"); // calculate the portion of the liquidity to remove if (_portion != PPM_RESOLUTION) { liquidity.poolAmount = liquidity.poolAmount.mul(_portion) / PPM_RESOLUTION; liquidity.reserveAmount = liquidity.reserveAmount.mul(_portion) / PPM_RESOLUTION; } // get the various rates between the reserves upon adding liquidity and now PackedRates memory packedRates = packRates( liquidity.poolToken, liquidity.reserveToken, liquidity.reserveRateN, liquidity.reserveRateD, false ); uint256 targetAmount = removeLiquidityTargetAmount( liquidity.poolToken, liquidity.reserveToken, liquidity.poolAmount, liquidity.reserveAmount, packedRates, liquidity.timestamp, _removeTimestamp ); // for network token, the return amount is identical to the target amount if (liquidity.reserveToken == networkToken) { return (targetAmount, targetAmount, 0); } // handle base token return // calculate the amount of pool tokens required for liquidation // note that the amount is doubled since it's not possible to liquidate one reserve only Fraction memory poolRate = poolTokenRate(liquidity.poolToken, liquidity.reserveToken); uint256 poolAmount = targetAmount.mul(poolRate.d).div(poolRate.n / 2); // limit the amount of pool tokens by the amount the system/caller holds uint256 availableBalance = store.systemBalance(liquidity.poolToken).add(liquidity.poolAmount); poolAmount = poolAmount > availableBalance ? availableBalance : poolAmount; // calculate the base token amount received by liquidating the pool tokens // note that the amount is divided by 2 since the pool amount represents both reserves uint256 baseAmount = poolAmount.mul(poolRate.n / 2).div(poolRate.d); uint256 networkAmount = getNetworkCompensation(targetAmount, baseAmount, packedRates); return (targetAmount, baseAmount, networkAmount); } /** * @dev removes protected liquidity from a pool * also burns governance tokens from the caller if the caller removes network tokens * * @param _id id in the caller's list of protected liquidity * @param _portion portion of liquidity to remove, in PPM */ function removeLiquidity(uint256 _id, uint32 _portion) external validPortion(_portion) protected { ProtectedLiquidity memory liquidity = protectedLiquidity(_id, msg.sender); // save a local copy of `networkToken` IERC20Token networkTokenLocal = networkToken; // verify that the pool is whitelisted _poolWhitelisted(liquidity.poolToken); // verify that the protected liquidity is not removed on the same block in which it was added require(liquidity.timestamp < time(), "ERR_TOO_EARLY"); if (_portion == PPM_RESOLUTION) { // remove the protected liquidity from the provider store.removeProtectedLiquidity(_id); } else { // remove a portion of the protected liquidity from the provider uint256 fullPoolAmount = liquidity.poolAmount; uint256 fullReserveAmount = liquidity.reserveAmount; liquidity.poolAmount = liquidity.poolAmount.mul(_portion) / PPM_RESOLUTION; liquidity.reserveAmount = liquidity.reserveAmount.mul(_portion) / PPM_RESOLUTION; store.updateProtectedLiquidityAmounts( _id, fullPoolAmount - liquidity.poolAmount, fullReserveAmount - liquidity.reserveAmount ); } // update last liquidity removal checkpoint lastRemoveCheckpointStore.addCheckpoint(msg.sender); // add the pool tokens to the system store.incSystemBalance(liquidity.poolToken, liquidity.poolAmount); // if removing network token liquidity, burn the governance tokens from the caller. we need to transfer the // tokens to the contract itself, since only token holders can burn their tokens if (liquidity.reserveToken == networkTokenLocal) { safeTransferFrom(govToken, msg.sender, address(this), liquidity.reserveAmount); govTokenGovernance.burn(liquidity.reserveAmount); } // get the various rates between the reserves upon adding liquidity and now PackedRates memory packedRates = packRates( liquidity.poolToken, liquidity.reserveToken, liquidity.reserveRateN, liquidity.reserveRateD, true ); // get the target token amount uint256 targetAmount = removeLiquidityTargetAmount( liquidity.poolToken, liquidity.reserveToken, liquidity.poolAmount, liquidity.reserveAmount, packedRates, liquidity.timestamp, time() ); // remove network token liquidity if (liquidity.reserveToken == networkTokenLocal) { // mint network tokens for the caller and lock them networkTokenGovernance.mint(address(store), targetAmount); settings.incNetworkTokensMinted(liquidity.poolToken, targetAmount); lockTokens(msg.sender, targetAmount); return; } // remove base token liquidity // calculate the amount of pool tokens required for liquidation // note that the amount is doubled since it's not possible to liquidate one reserve only Fraction memory poolRate = poolTokenRate(liquidity.poolToken, liquidity.reserveToken); uint256 poolAmount = targetAmount.mul(poolRate.d).div(poolRate.n / 2); // limit the amount of pool tokens by the amount the system holds uint256 systemBalance = store.systemBalance(liquidity.poolToken); poolAmount = poolAmount > systemBalance ? systemBalance : poolAmount; // withdraw the pool tokens from the store store.decSystemBalance(liquidity.poolToken, poolAmount); store.withdrawTokens(liquidity.poolToken, address(this), poolAmount); // remove liquidity removeLiquidity(liquidity.poolToken, poolAmount, liquidity.reserveToken, networkTokenLocal); // transfer the base tokens to the caller uint256 baseBalance; if (liquidity.reserveToken == ETH_RESERVE_ADDRESS) { baseBalance = address(this).balance; msg.sender.transfer(baseBalance); } else { baseBalance = liquidity.reserveToken.balanceOf(address(this)); safeTransfer(liquidity.reserveToken, msg.sender, baseBalance); } // compensate the caller with network tokens if still needed uint256 delta = getNetworkCompensation(targetAmount, baseBalance, packedRates); if (delta > 0) { // check if there's enough network token balance, otherwise mint more uint256 networkBalance = networkTokenLocal.balanceOf(address(this)); if (networkBalance < delta) { networkTokenGovernance.mint(address(this), delta - networkBalance); } // lock network tokens for the caller safeTransfer(networkTokenLocal, address(store), delta); lockTokens(msg.sender, delta); } // if the contract still holds network tokens, burn them uint256 networkBalance = networkTokenLocal.balanceOf(address(this)); if (networkBalance > 0) { networkTokenGovernance.burn(networkBalance); settings.decNetworkTokensMinted(liquidity.poolToken, networkBalance); } } /** * @dev returns the amount the provider will receive for removing liquidity * it's also possible to provide the remove liquidity rate & time to get an estimation * for the return at that given point * * @param _poolToken pool token * @param _reserveToken reserve token * @param _poolAmount pool token amount when the liquidity was added * @param _reserveAmount reserve token amount that was added * @param _packedRates see `struct PackedRates` * @param _addTimestamp time at which the liquidity was added * @param _removeTimestamp time at which the liquidity is removed * @return amount received for removing liquidity */ function removeLiquidityTargetAmount( IDSToken _poolToken, IERC20Token _reserveToken, uint256 _poolAmount, uint256 _reserveAmount, PackedRates memory _packedRates, uint256 _addTimestamp, uint256 _removeTimestamp ) internal view returns (uint256) { // get the rate between the pool token and the reserve token Fraction memory poolRate = poolTokenRate(_poolToken, _reserveToken); // get the rate between the reserves upon adding liquidity and now Fraction memory addSpotRate = Fraction({ n: _packedRates.addSpotRateN, d: _packedRates.addSpotRateD }); Fraction memory removeSpotRate = Fraction({ n: _packedRates.removeSpotRateN, d: _packedRates.removeSpotRateD }); Fraction memory removeAverageRate = Fraction({ n: _packedRates.removeAverageRateN, d: _packedRates.removeAverageRateD }); // calculate the protected amount of reserve tokens plus accumulated fee before compensation uint256 total = protectedAmountPlusFee(_poolAmount, poolRate, addSpotRate, removeSpotRate); // calculate the impermanent loss Fraction memory loss = impLoss(addSpotRate, removeAverageRate); // calculate the protection level Fraction memory level = protectionLevel(_addTimestamp, _removeTimestamp); // calculate the compensation amount return compensationAmount(_reserveAmount, Math.max(_reserveAmount, total), loss, level); } /** * @dev allows the caller to claim network token balance that is no longer locked * note that the function can revert if the range is too large * * @param _startIndex start index in the caller's list of locked balances * @param _endIndex end index in the caller's list of locked balances (exclusive) */ function claimBalance(uint256 _startIndex, uint256 _endIndex) external protected { // get the locked balances from the store (uint256[] memory amounts, uint256[] memory expirationTimes) = store.lockedBalanceRange(msg.sender, _startIndex, _endIndex); uint256 totalAmount = 0; uint256 length = amounts.length; assert(length == expirationTimes.length); // reverse iteration since we're removing from the list for (uint256 i = length; i > 0; i--) { uint256 index = i - 1; if (expirationTimes[index] > time()) { continue; } // remove the locked balance item store.removeLockedBalance(msg.sender, _startIndex + index); totalAmount = totalAmount.add(amounts[index]); } if (totalAmount > 0) { // transfer the tokens to the caller in a single call store.withdrawTokens(networkToken, msg.sender, totalAmount); } } /** * @dev returns the ROI for removing liquidity in the current state after providing liquidity with the given args * the function assumes full protection is in effect * return value is in PPM and can be larger than PPM_RESOLUTION for positive ROI, 1M = 0% ROI * * @param _poolToken pool token * @param _reserveToken reserve token * @param _reserveAmount reserve token amount that was added * @param _poolRateN rate of 1 pool token in reserve token units when the liquidity was added (numerator) * @param _poolRateD rate of 1 pool token in reserve token units when the liquidity was added (denominator) * @param _reserveRateN rate of 1 reserve token in the other reserve token units when the liquidity was added (numerator) * @param _reserveRateD rate of 1 reserve token in the other reserve token units when the liquidity was added (denominator) * @return ROI in PPM */ function poolROI( IDSToken _poolToken, IERC20Token _reserveToken, uint256 _reserveAmount, uint256 _poolRateN, uint256 _poolRateD, uint256 _reserveRateN, uint256 _reserveRateD ) external view returns (uint256) { // calculate the amount of pool tokens based on the amount of reserve tokens uint256 poolAmount = _reserveAmount.mul(_poolRateD).div(_poolRateN); // get the various rates between the reserves upon adding liquidity and now PackedRates memory packedRates = packRates(_poolToken, _reserveToken, _reserveRateN, _reserveRateD, false); // get the current return uint256 protectedReturn = removeLiquidityTargetAmount( _poolToken, _reserveToken, poolAmount, _reserveAmount, packedRates, time().sub(settings.maxProtectionDelay()), time() ); // calculate the ROI as the ratio between the current fully protected return and the initial amount return protectedReturn.mul(PPM_RESOLUTION).div(_reserveAmount); } /** * @dev utility to protect existing liquidity * also mints new governance tokens for the caller when protecting the network token reserve * * @param _poolAnchor pool anchor * @param _converter pool converter * @param _networkToken the network reserve token of the pool * @param _reserveIndex index of the reserve to protect * @param _poolAmount amount of pool tokens to protect */ function protectLiquidity( IDSToken _poolAnchor, IConverter _converter, IERC20Token _networkToken, uint256 _reserveIndex, uint256 _poolAmount ) internal { // get the reserves token IERC20Token reserveToken = _converter.connectorTokens(_reserveIndex); // get the pool token rate IDSToken poolToken = IDSToken(address(_poolAnchor)); Fraction memory poolRate = poolTokenRate(poolToken, reserveToken); // calculate the reserve balance based on the amount provided and the pool token rate uint256 reserveAmount = _poolAmount.mul(poolRate.n).div(poolRate.d); // protect the liquidity addProtectedLiquidity(msg.sender, poolToken, reserveToken, _poolAmount, reserveAmount); // for network token liquidity, mint governance tokens to the caller if (reserveToken == _networkToken) { govTokenGovernance.mint(msg.sender, reserveAmount); } } /** * @dev adds protected liquidity for the caller to the store * * @param _provider protected liquidity provider * @param _poolToken pool token * @param _reserveToken reserve token * @param _poolAmount amount of pool tokens to protect * @param _reserveAmount amount of reserve tokens to protect * @return new protected liquidity id */ function addProtectedLiquidity( address _provider, IDSToken _poolToken, IERC20Token _reserveToken, uint256 _poolAmount, uint256 _reserveAmount ) internal returns (uint256) { Fraction memory rate = reserveTokenAverageRate(_poolToken, _reserveToken, true); return store.addProtectedLiquidity( _provider, _poolToken, _reserveToken, _poolAmount, _reserveAmount, rate.n, rate.d, time() ); } /** * @dev locks network tokens for the provider and emits the tokens locked event * * @param _provider tokens provider * @param _amount amount of network tokens */ function lockTokens(address _provider, uint256 _amount) internal { uint256 expirationTime = time().add(settings.lockDuration()); store.addLockedBalance(_provider, _amount, expirationTime); } /** * @dev returns the rate of 1 pool token in reserve token units * * @param _poolToken pool token * @param _reserveToken reserve token */ function poolTokenRate(IDSToken _poolToken, IERC20Token _reserveToken) internal view virtual returns (Fraction memory) { // get the pool token supply uint256 poolTokenSupply = _poolToken.totalSupply(); // get the reserve balance IConverter converter = IConverter(payable(ownedBy(_poolToken))); uint256 reserveBalance = converter.getConnectorBalance(_reserveToken); // for standard pools, 50% of the pool supply value equals the value of each reserve return Fraction({ n: reserveBalance.mul(2), d: poolTokenSupply }); } /** * @dev returns the average rate of 1 reserve token in the other reserve token units * * @param _poolToken pool token * @param _reserveToken reserve token * @param _validateAverageRate true to validate the average rate; false otherwise */ function reserveTokenAverageRate( IDSToken _poolToken, IERC20Token _reserveToken, bool _validateAverageRate ) internal view returns (Fraction memory) { (, , uint256 averageRateN, uint256 averageRateD) = reserveTokenRates(_poolToken, _reserveToken, _validateAverageRate); return Fraction(averageRateN, averageRateD); } /** * @dev returns the spot rate and average rate of 1 reserve token in the other reserve token units * * @param _poolToken pool token * @param _reserveToken reserve token * @param _validateAverageRate true to validate the average rate; false otherwise */ function reserveTokenRates( IDSToken _poolToken, IERC20Token _reserveToken, bool _validateAverageRate ) internal view returns ( uint256, uint256, uint256, uint256 ) { ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(ownedBy(_poolToken))); IERC20Token otherReserve = converter.connectorTokens(0); if (otherReserve == _reserveToken) { otherReserve = converter.connectorTokens(1); } (uint256 spotRateN, uint256 spotRateD) = converterReserveBalances(converter, otherReserve, _reserveToken); (uint256 averageRateN, uint256 averageRateD) = converter.recentAverageRate(_reserveToken); require( !_validateAverageRate || averageRateInRange( spotRateN, spotRateD, averageRateN, averageRateD, settings.averageRateMaxDeviation() ), "ERR_INVALID_RATE" ); return (spotRateN, spotRateD, averageRateN, averageRateD); } /** * @dev returns the various rates between the reserves * * @param _poolToken pool token * @param _reserveToken reserve token * @param _addSpotRateN add spot rate numerator * @param _addSpotRateD add spot rate denominator * @param _validateAverageRate true to validate the average rate; false otherwise * @return see `struct PackedRates` */ function packRates( IDSToken _poolToken, IERC20Token _reserveToken, uint256 _addSpotRateN, uint256 _addSpotRateD, bool _validateAverageRate ) internal view returns (PackedRates memory) { (uint256 removeSpotRateN, uint256 removeSpotRateD, uint256 removeAverageRateN, uint256 removeAverageRateD) = reserveTokenRates(_poolToken, _reserveToken, _validateAverageRate); require( (_addSpotRateN <= MAX_UINT128 && _addSpotRateD <= MAX_UINT128) && (removeSpotRateN <= MAX_UINT128 && removeSpotRateD <= MAX_UINT128) && (removeAverageRateN <= MAX_UINT128 && removeAverageRateD <= MAX_UINT128), "ERR_INVALID_RATE" ); return PackedRates({ addSpotRateN: uint128(_addSpotRateN), addSpotRateD: uint128(_addSpotRateD), removeSpotRateN: uint128(removeSpotRateN), removeSpotRateD: uint128(removeSpotRateD), removeAverageRateN: uint128(removeAverageRateN), removeAverageRateD: uint128(removeAverageRateD) }); } /** * @dev returns whether or not the deviation of the average rate from the spot rate is within range * for example, if the maximum permitted deviation is 5%, then return `95/100 <= average/spot <= 100/95` * * @param _spotRateN spot rate numerator * @param _spotRateD spot rate denominator * @param _averageRateN average rate numerator * @param _averageRateD average rate denominator * @param _maxDeviation the maximum permitted deviation of the average rate from the spot rate */ function averageRateInRange( uint256 _spotRateN, uint256 _spotRateD, uint256 _averageRateN, uint256 _averageRateD, uint32 _maxDeviation ) internal pure returns (bool) { uint256 min = _spotRateN.mul(_averageRateD).mul(PPM_RESOLUTION - _maxDeviation).mul(PPM_RESOLUTION - _maxDeviation); uint256 mid = _spotRateD.mul(_averageRateN).mul(PPM_RESOLUTION - _maxDeviation).mul(PPM_RESOLUTION); uint256 max = _spotRateN.mul(_averageRateD).mul(PPM_RESOLUTION).mul(PPM_RESOLUTION); return min <= mid && mid <= max; } /** * @dev utility to add liquidity to a converter * * @param _converter converter * @param _reserveToken1 reserve token 1 * @param _reserveToken2 reserve token 2 * @param _reserveAmount1 reserve amount 1 * @param _reserveAmount2 reserve amount 2 * @param _value ETH amount to add */ function addLiquidity( ILiquidityPoolConverter _converter, IERC20Token _reserveToken1, IERC20Token _reserveToken2, uint256 _reserveAmount1, uint256 _reserveAmount2, uint256 _value ) internal { // ensure that the contract can receive ETH updatingLiquidity = true; IERC20Token[] memory reserveTokens = new IERC20Token[](2); uint256[] memory amounts = new uint256[](2); reserveTokens[0] = _reserveToken1; reserveTokens[1] = _reserveToken2; amounts[0] = _reserveAmount1; amounts[1] = _reserveAmount2; _converter.addLiquidity{ value: _value }(reserveTokens, amounts, 1); // ensure that the contract can receive ETH updatingLiquidity = false; } /** * @dev utility to remove liquidity from a converter * * @param _poolToken pool token of the converter * @param _poolAmount amount of pool tokens to remove * @param _reserveToken1 reserve token 1 * @param _reserveToken2 reserve token 2 */ function removeLiquidity( IDSToken _poolToken, uint256 _poolAmount, IERC20Token _reserveToken1, IERC20Token _reserveToken2 ) internal { ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(ownedBy(_poolToken))); // ensure that the contract can receive ETH updatingLiquidity = true; IERC20Token[] memory reserveTokens = new IERC20Token[](2); uint256[] memory minReturns = new uint256[](2); reserveTokens[0] = _reserveToken1; reserveTokens[1] = _reserveToken2; minReturns[0] = 1; minReturns[1] = 1; converter.removeLiquidity(_poolAmount, reserveTokens, minReturns); // ensure that the contract can receive ETH updatingLiquidity = false; } /** * @dev returns a protected liquidity from the store * * @param _id protected liquidity id * @return protected liquidity */ function protectedLiquidity(uint256 _id) internal view returns (ProtectedLiquidity memory) { ProtectedLiquidity memory liquidity; ( liquidity.provider, liquidity.poolToken, liquidity.reserveToken, liquidity.poolAmount, liquidity.reserveAmount, liquidity.reserveRateN, liquidity.reserveRateD, liquidity.timestamp ) = store.protectedLiquidity(_id); return liquidity; } /** * @dev returns a protected liquidity from the store * * @param _id protected liquidity id * @param _provider authorized provider * @return protected liquidity */ function protectedLiquidity(uint256 _id, address _provider) internal view returns (ProtectedLiquidity memory) { ProtectedLiquidity memory liquidity = protectedLiquidity(_id); require(liquidity.provider == _provider, "ERR_ACCESS_DENIED"); return liquidity; } /** * @dev returns the protected amount of reserve tokens plus accumulated fee before compensation * * @param _poolAmount pool token amount when the liquidity was added * @param _poolRate rate of 1 pool token in the related reserve token units * @param _addRate rate of 1 reserve token in the other reserve token units when the liquidity was added * @param _removeRate rate of 1 reserve token in the other reserve token units when the liquidity is removed * @return protected amount of reserve tokens plus accumulated fee = sqrt(_removeRate / _addRate) * _poolRate * _poolAmount */ function protectedAmountPlusFee( uint256 _poolAmount, Fraction memory _poolRate, Fraction memory _addRate, Fraction memory _removeRate ) internal pure returns (uint256) { uint256 n = Math.ceilSqrt(_addRate.d.mul(_removeRate.n)).mul(_poolRate.n); uint256 d = Math.floorSqrt(_addRate.n.mul(_removeRate.d)).mul(_poolRate.d); uint256 x = n * _poolAmount; if (x / n == _poolAmount) { return x / d; } (uint256 hi, uint256 lo) = n > _poolAmount ? (n, _poolAmount) : (_poolAmount, n); (uint256 p, uint256 q) = Math.reducedRatio(hi, d, MAX_UINT256 / lo); uint256 min = (hi / d).mul(lo); if (q > 0) { return Math.max(min, p * lo / q); } return min; } /** * @dev returns the impermanent loss incurred due to the change in rates between the reserve tokens * * @param _prevRate previous rate between the reserves * @param _newRate new rate between the reserves * @return impermanent loss (as a ratio) */ function impLoss(Fraction memory _prevRate, Fraction memory _newRate) internal pure returns (Fraction memory) { uint256 ratioN = _newRate.n.mul(_prevRate.d); uint256 ratioD = _newRate.d.mul(_prevRate.n); uint256 prod = ratioN * ratioD; uint256 root = prod / ratioN == ratioD ? Math.floorSqrt(prod) : Math.floorSqrt(ratioN) * Math.floorSqrt(ratioD); uint256 sum = ratioN.add(ratioD); // the arithmetic below is safe because `x + y >= sqrt(x * y) * 2` if (sum % 2 == 0) { sum /= 2; return Fraction({ n: sum - root, d: sum }); } return Fraction({ n: sum - root * 2, d: sum }); } /** * @dev returns the protection level based on the timestamp and protection delays * * @param _addTimestamp time at which the liquidity was added * @param _removeTimestamp time at which the liquidity is removed * @return protection level (as a ratio) */ function protectionLevel(uint256 _addTimestamp, uint256 _removeTimestamp) internal view returns (Fraction memory) { uint256 timeElapsed = _removeTimestamp.sub(_addTimestamp); uint256 minProtectionDelay = settings.minProtectionDelay(); uint256 maxProtectionDelay = settings.maxProtectionDelay(); if (timeElapsed < minProtectionDelay) { return Fraction({ n: 0, d: 1 }); } if (timeElapsed >= maxProtectionDelay) { return Fraction({ n: 1, d: 1 }); } return Fraction({ n: timeElapsed, d: maxProtectionDelay }); } /** * @dev returns the compensation amount based on the impermanent loss and the protection level * * @param _amount protected amount in units of the reserve token * @param _total amount plus fee in units of the reserve token * @param _loss protection level (as a ratio between 0 and 1) * @param _level impermanent loss (as a ratio between 0 and 1) * @return compensation amount */ function compensationAmount( uint256 _amount, uint256 _total, Fraction memory _loss, Fraction memory _level ) internal pure returns (uint256) { uint256 levelN = _level.n.mul(_amount); uint256 levelD = _level.d; uint256 maxVal = Math.max(Math.max(levelN, levelD), _total); (uint256 lossN, uint256 lossD) = Math.reducedRatio(_loss.n, _loss.d, MAX_UINT256 / maxVal); return _total.mul(lossD.sub(lossN)).div(lossD).add(lossN.mul(levelN).div(lossD.mul(levelD))); } function getNetworkCompensation( uint256 _targetAmount, uint256 _baseAmount, PackedRates memory _packedRates ) internal view returns (uint256) { if (_targetAmount <= _baseAmount) { return 0; } // calculate the delta in network tokens uint256 delta = (_targetAmount - _baseAmount).mul(_packedRates.removeAverageRateN).div(_packedRates.removeAverageRateD); // the delta might be very small due to precision loss // in which case no compensation will take place (gas optimization) if (delta >= settings.minNetworkCompensation()) { return delta; } return 0; } /** * @dev utility, checks whether allowance for the given spender exists and approves one if it doesn't. * note that we use the non standard erc-20 interface in which `approve` has no return value so that * this function will work for both standard and non standard tokens * * @param _token token to check the allowance in * @param _spender approved address * @param _value allowance amount */ function ensureAllowance( IERC20Token _token, address _spender, uint256 _value ) private { uint256 allowance = _token.allowance(address(this), _spender); if (allowance < _value) { if (allowance > 0) safeApprove(_token, _spender, 0); safeApprove(_token, _spender, _value); } } // utility to get the reserve balances function converterReserveBalances( IConverter _converter, IERC20Token _reserveToken1, IERC20Token _reserveToken2 ) private view returns (uint256, uint256) { return (_converter.getConnectorBalance(_reserveToken1), _converter.getConnectorBalance(_reserveToken2)); } // utility to get the owner function ownedBy(IOwned _owned) private view returns (address) { return _owned.owner(); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ILiquidityProtectionSettings","name":"_settings","type":"address"},{"internalType":"contract ILiquidityProtectionStore","name":"_store","type":"address"},{"internalType":"contract ITokenGovernance","name":"_networkTokenGovernance","type":"address"},{"internalType":"contract ITokenGovernance","name":"_govTokenGovernance","type":"address"},{"internalType":"contract ICheckpointStore","name":"_lastRemoveCheckpointStore","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnerUpdate","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptStoreOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor","name":"_poolAnchor","type":"address"},{"internalType":"contract IERC20Token","name":"_reserveToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"contract IConverterAnchor","name":"_poolAnchor","type":"address"},{"internalType":"contract IERC20Token","name":"_reserveToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addLiquidityFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startIndex","type":"uint256"},{"internalType":"uint256","name":"_endIndex","type":"uint256"}],"name":"claimBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"govToken","outputs":[{"internalType":"contract IERC20Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"govTokenGovernance","outputs":[{"internalType":"contract ITokenGovernance","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRemoveCheckpointStore","outputs":[{"internalType":"contract ICheckpointStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"networkToken","outputs":[{"internalType":"contract IERC20Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"networkTokenGovernance","outputs":[{"internalType":"contract ITokenGovernance","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IDSToken","name":"_poolToken","type":"address"},{"internalType":"contract IERC20Token","name":"_reserveToken","type":"address"},{"internalType":"uint256","name":"_reserveAmount","type":"uint256"},{"internalType":"uint256","name":"_poolRateN","type":"uint256"},{"internalType":"uint256","name":"_poolRateD","type":"uint256"},{"internalType":"uint256","name":"_reserveRateN","type":"uint256"},{"internalType":"uint256","name":"_reserveRateD","type":"uint256"}],"name":"poolROI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor","name":"_poolAnchor","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"protectLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint32","name":"_portion","type":"uint32"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint32","name":"_portion","type":"uint32"},{"internalType":"uint256","name":"_removeTimestamp","type":"uint256"}],"name":"removeLiquidityReturn","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"settings","outputs":[{"internalType":"contract ILiquidityProtectionSettings","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"store","outputs":[{"internalType":"contract ILiquidityProtectionStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferStoreOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id1","type":"uint256"},{"internalType":"uint256","name":"_id2","type":"uint256"}],"name":"unprotectLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
61016060405260016002556003805460ff191690553480156200002157600080fd5b506040516200531538038062005315833981810160405260a08110156200004757600080fd5b508051602082015160408301516060840151608090940151600080546001600160a01b031916331790559293919290919084620000848162000225565b84620000908162000225565b846200009c8162000225565b84620000a88162000225565b88620000b48162000284565b88620000c08162000284565b88620000cc8162000284565b88620000d88162000284565b6001600160601b031960608e811b82166080528d811b821660a0528c901b1660e05260408051637e062a3560e11b815290516001600160a01b038d169163fc0c546a916004808301926020929190829003018186803b1580156200013b57600080fd5b505afa15801562000150573d6000803e3d6000fd5b505050506040513d60208110156200016757600080fd5b50516001600160601b0319606091821b811660c052908b901b166101205260408051637e062a3560e11b815290516001600160a01b038c169163fc0c546a916004808301926020929190829003018186803b158015620001c657600080fd5b505afa158015620001db573d6000803e3d6000fd5b505050506040513d6020811015620001f257600080fd5b50516001600160601b0319606091821b81166101005299901b9098166101405250620002e39a5050505050505050505050565b6001600160a01b03811662000281576040805162461bcd60e51b815260206004820152601360248201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b50565b6001600160a01b03811630141562000281576040805162461bcd60e51b815260206004820152601360248201527f4552525f414444524553535f49535f53454c4600000000000000000000000000604482015290519081900360640190fd5b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c614ea26200047360003980610f505280611a6c52806120115250806110965280611c7a5280611f7752806126585280613fd452508061050e52806110695280611f4e525080610532528061118d52806116c252806117de5280613ec7528061438e52508061058d528061091e52806109bd5280610b565280610d2d5280611d8352806134e75250806105d8528061064b528061085452806108ef5280610bfe5280610dbd5280610ece5280610fb152806111bc528061131552806113c55280611458528061172852806119c45280611a485280611a98528061207452806120f2528061217052806129045280613005528061362e5280613e1b5280614553528061458252508061123c528061185c5280611b5a5280611c9e52806122dc52806123c25280612e535280612f7052806138e55280613bb75280613c5a5280613f455280614091528061417e528061421e52806142ac52806143ef5250614ea26000f3fe60806040526004361061012e5760003560e01c8063975057e7116100ab578063d4ee1d901161006f578063d4ee1d90146103db578063d79dabae146103f0578063e06174e414610405578063e4a767261461041a578063f04ef41f14610450578063f2fde38b146104805761013d565b8063975057e7146102d5578063c21fe133146102ea578063c2250a99146102ff578063c83df66314610332578063caee4c8f1461039f5761013d565b80636d533e9b116100f25780636d533e9b14610206578063782ed90c1461026057806379ba50971461029657806389d94b46146102ab5780638da5cb5b146102c05761013d565b806305268cff146101425780630529fa3d1461017357806315ee207d14610188578063630d8c63146101c15780636ca95a4e146101f15761013d565b3661013d5761013b6104b3565b005b600080fd5b34801561014e57600080fd5b5061015761050c565b604080516001600160a01b039092168252519081900360200190f35b34801561017f57600080fd5b50610157610530565b34801561019457600080fd5b5061013b600480360360408110156101ab57600080fd5b506001600160a01b038135169060200135610554565b3480156101cd57600080fd5b5061013b600480360360408110156101e457600080fd5b508035906020013561060c565b3480156101fd57600080fd5b506101576109bb565b34801561021257600080fd5b506102426004803603606081101561022957600080fd5b5080359063ffffffff60208201351690604001356109df565b60408051938452602084019290925282820152519081900360600190f35b34801561026c57600080fd5b5061013b6004803603604081101561028357600080fd5b508035906020013563ffffffff16610cff565b3480156102a257600080fd5b5061013b611903565b3480156102b757600080fd5b5061013b6119ba565b3480156102cc57600080fd5b50610157611a37565b3480156102e157600080fd5b50610157611a46565b3480156102f657600080fd5b50610157611a6a565b34801561030b57600080fd5b5061013b6004803603602081101561032257600080fd5b50356001600160a01b0316611a8e565b34801561033e57600080fd5b5061038d600480360360e081101561035557600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a08101359060c00135611b20565b60408051918252519081900360200190f35b61038d600480360360808110156103b557600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135611c15565b3480156103e757600080fd5b50610157611c69565b3480156103fc57600080fd5b50610157611c78565b34801561041157600080fd5b50610157611c9c565b61038d6004803603606081101561043057600080fd5b506001600160a01b03813581169160208101359091169060400135611cc0565b34801561045c57600080fd5b5061013b6004803603604081101561047357600080fd5b5080359060200135611d08565b34801561048c57600080fd5b5061013b600480360360208110156104a357600080fd5b50356001600160a01b0316612214565b60035460ff1661050a576040805162461bcd60e51b815260206004820152601a60248201527f4552525f4e4f545f5550444154494e475f4c4951554944495459000000000000604482015290519081900360640190fd5b565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b61055c612292565b600280558161056a816122da565b82610574816123c0565b8261057e816124aa565b6000610589866124f0565b90507f0000000000000000000000000000000000000000000000000000000000000000866105be818484600060028c0461255d565b6105d1818484600160028c048c0361255d565b6105fd81337f00000000000000000000000000000000000000000000000000000000000000008a6126c3565b50506001600255505050505050565b610614612292565b6002805560408051637a1036f560e11b81523360048201526024810184905260448101839052905160609182916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163f4206dea916064808301926000929190829003018186803b15801561069157600080fd5b505afa1580156106a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160409081528110156106ce57600080fd5b81019080805160405193929190846401000000008211156106ee57600080fd5b90830190602082018581111561070357600080fd5b825186602082028301116401000000008211171561072057600080fd5b82525081516020918201928201910280838360005b8381101561074d578181015183820152602001610735565b505050509050016040526020018051604051939291908464010000000082111561077657600080fd5b90830190602082018581111561078b57600080fd5b82518660208202830111640100000000821117156107a857600080fd5b82525081516020918201928201910280838360005b838110156107d55781810151838201526020016107bd565b505050509050016040525050509150915060008083519050825181146107f757fe5b805b80156108e657600019810161080c612836565b85828151811061081857fe5b6020026020010151111561082c57506108dd565b604080516390e0661b60e01b8152336004820152898301602482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916390e0661b91604480830192600092919082900301818387803b15801561089b57600080fd5b505af11580156108af573d6000803e3d6000fd5b505050506108d98682815181106108c257fe5b60200260200101518561283a90919063ffffffff16565b9350505b600019016107f9565b5081156109ae577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635e35359e7f000000000000000000000000000000000000000000000000000000000000000033856040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b15801561099557600080fd5b505af11580156109a9573d6000803e3d6000fd5b505050505b5050600160025550505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806000846109ee8161288c565b6109f6614dbd565b6109ff886128f2565b80519091506001600160a01b0316610a4f576040805162461bcd60e51b815260206004820152600e60248201526d11549497d253959053125117d25160921b604482015290519081900360640190fd5b8060e00151861015610aa0576040805162461bcd60e51b815260206004820152601560248201527404552525f494e56414c49445f54494d455354414d5605c1b604482015290519081900360640190fd5b63ffffffff8716620f424014610b05576060810151620f424090610acd9063ffffffff8a8116906129fc16565b81610ad457fe5b0460608201526080810151620f424090610af79063ffffffff8a8116906129fc16565b81610afe57fe5b0460808201525b610b0d614e1d565b610b2b826020015183604001518460a001518560c001516000612a5a565b90506000610b528360200151846040015185606001518660800151868860e001518e612b6f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031683604001516001600160a01b03161415610ba357955085945060009350610cf5915050565b610bab614e52565b610bbd84602001518560400151612c85565b90506000610bf06002836000015181610bd257fe5b04610bea8460200151866129fc90919063ffffffff16565b90612daa565b90506000610c9f86606001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635121220c89602001516040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610c6d57600080fd5b505afa158015610c81573d6000803e3d6000fd5b505050506040513d6020811015610c9757600080fd5b50519061283a565b9050808211610cae5781610cb0565b805b91506000610cd68460200151610bea6002876000015181610ccd57fe5b879190046129fc565b90506000610ce5868389612e09565b959b509099509397505050505050505b5093509350939050565b80610d098161288c565b610d11612292565b60028055610d1d614dbd565b610d278433612ef0565b905060007f00000000000000000000000000000000000000000000000000000000000000009050610d5b82602001516123c0565b610d63612836565b8260e0015110610daa576040805162461bcd60e51b815260206004820152600d60248201526c4552525f544f4f5f4541524c5960981b604482015290519081900360640190fd5b63ffffffff8416620f42401415610e3e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636f366b71866040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610e2157600080fd5b505af1158015610e35573d6000803e3d6000fd5b50505050610f30565b60608201516080830151620f4240610e5f8363ffffffff898116906129fc16565b81610e6657fe5b0460608501526080840151620f424090610e899063ffffffff898116906129fc16565b81610e9057fe5b046080850181905260608501516040805163161139bd60e31b8152600481018b90529185036024830152918303604482015290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163b089cde891606480830192600092919082900301818387803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b5050505050505b60408051631d092adf60e01b815233600482015290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691631d092adf91602480830192600092919082900301818387803b158015610f9757600080fd5b505af1158015610fab573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663332100fa836020015184606001516040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561102e57600080fd5b505af1158015611042573d6000803e3d6000fd5b50505050806001600160a01b031682604001516001600160a01b03161415611117576110947f0000000000000000000000000000000000000000000000000000000000000000333085608001516126c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166342966c6883608001516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156110fe57600080fd5b505af1158015611112573d6000803e3d6000fd5b505050505b61111f614e1d565b61113d836020015184604001518560a001518660c001516001612a5a565b9050600061116b8460200151856040015186606001518760800151868960e00151611166612836565b612b6f565b9050826001600160a01b031684604001516001600160a01b031614156112e0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c10f197f0000000000000000000000000000000000000000000000000000000000000000836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663deacd84e8560200151836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156112b557600080fd5b505af11580156112c9573d6000803e3d6000fd5b505050506112d73382612f69565b505050506118f9565b6112e8614e52565b6112fa85602001518660400151612c85565b9050600061130f6002836000015181610bd257fe5b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635121220c88602001516040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d60208110156113ae57600080fd5b505190508082116113bf57816113c1565b805b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166319c6a5e48860200151846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561143e57600080fd5b505af1158015611452573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635e35359e886020015130856040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b1580156114e257600080fd5b505af11580156114f6573d6000803e3d6000fd5b5050505061150e8760200151838960400151896130ac565b60408701516000906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561157057506040514790339082156108fc029083906000818181858888f1935050505015801561156a573d6000803e3d6000fd5b50611600565b87604001516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156115c157600080fd5b505afa1580156115d5573d6000803e3d6000fd5b505050506040513d60208110156115eb57600080fd5b50516040890151909150611600903383613299565b600061160d868389612e09565b90508015611759576000886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561166457600080fd5b505afa158015611678573d6000803e3d6000fd5b505050506040513d602081101561168e57600080fd5b505190508181101561172257604080516340c10f1960e01b8152306004820152828403602482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916340c10f1991604480830192600092919082900301818387803b15801561170957600080fd5b505af115801561171d573d6000803e3d6000fd5b505050505b61174d897f000000000000000000000000000000000000000000000000000000000000000084613299565b6117573383612f69565b505b6000886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156117a857600080fd5b505afa1580156117bc573d6000803e3d6000fd5b505050506040513d60208110156117d257600080fd5b5051905080156118ee577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166342966c68826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561184257600080fd5b505af1158015611856573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663802fa3ba8b60200151836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156118d557600080fd5b505af11580156118e9573d6000803e3d6000fd5b505050505b505050505050505050505b5050600160025550565b6001546001600160a01b03163314611956576040805162461bcd60e51b815260206004820152601160248201527011549497d050d0d154d4d7d11153925151607a1b604482015290519081900360640190fd5b600154600080546040516001600160a01b0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6119c26133f2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a1d57600080fd5b505af1158015611a31573d6000803e3d6000fd5b50505050565b6000546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b611a966133f2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f2fde38b826040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050600060405180830381600087803b158015611b0557600080fd5b505af1158015611b19573d6000803e3d6000fd5b5050505050565b600080611b3186610bea89886129fc565b9050611b3b614e1d565b611b498a8a87876000612a5a565b90506000611bf38b8b858c86611beb7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ce3f3adb6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bb157600080fd5b505afa158015611bc5573d6000803e3d6000fd5b505050506040513d6020811015611bdb57600080fd5b5051611be5612836565b90613445565b611166612836565b9050611c0689610bea83620f42406129fc565b9b9a5050505050505050505050565b6000611c1f612292565b6002805584611c2d81613492565b84611c37816122da565b85611c41816123c0565b84611c4b816124aa565b611c57898989896134e3565b60016002559998505050505050505050565b6001546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611cca612292565b6002805583611cd8816122da565b84611ce2816123c0565b83611cec816124aa565b611cf8338888886134e3565b6001600255979650505050505050565b611d10612292565b6002805581811415611d57576040805162461bcd60e51b815260206004820152600b60248201526a11549497d4d0535157d25160aa1b604482015290519081900360640190fd5b611d5f614dbd565b611d698333612ef0565b9050611d73614dbd565b611d7d8333612ef0565b905060007f0000000000000000000000000000000000000000000000000000000000000000905081602001516001600160a01b031683602001516001600160a01b0316148015611de7575081604001516001600160a01b031683604001516001600160a01b031614155b8015611e275750806001600160a01b031683604001516001600160a01b03161480611e275750806001600160a01b031682604001516001600160a01b0316145b8015611e3a57508160e001518360e00151145b8015611e5957506060820151611e5190600161283a565b836060015111155b8015611e7857506060830151611e7090600161283a565b826060015111155b611ec9576040805162461bcd60e51b815260206004820152601860248201527f4552525f50524f54454354494f4e535f4d49534d415443480000000000000000604482015290519081900360640190fd5b611ed1612836565b8360e0015110611f18576040805162461bcd60e51b815260206004820152600d60248201526c4552525f544f4f5f4541524c5960981b604482015290519081900360640190fd5b6000816001600160a01b031684604001516001600160a01b031614611f41578260800151611f47565b83608001515b9050611f757f00000000000000000000000000000000000000000000000000000000000000003330846126c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166342966c68826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611fdb57600080fd5b505af1158015611fef573d6000803e3d6000fd5b505060408051631d092adf60e01b815233600482015290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169350631d092adf9250602480830192600092919082900301818387803b15801561205a57600080fd5b505af115801561206e573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636f366b71876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120d857600080fd5b505af11580156120ec573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636f366b71866040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561215657600080fd5b505af115801561216a573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635e35359e8560200151336121be8760600151896060015161283a90919063ffffffff16565b6040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b15801561099557600080fd5b61221c6133f2565b6000546001600160a01b0382811691161415612270576040805162461bcd60e51b815260206004820152600e60248201526d22a9292fa9a0a6a2afa7aba722a960911b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60016002541461050a576040805162461bcd60e51b815260206004820152600e60248201526d4552525f5245454e5452414e435960901b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d4f63148826040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561234757600080fd5b505afa15801561235b573d6000803e3d6000fd5b505050506040513d602081101561237157600080fd5b50516123bd576040805162461bcd60e51b815260206004820152601660248201527511549497d413d3d317d393d517d4d5541413d495115160521b604482015290519081900360640190fd5b50565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632b26a982826040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561242d57600080fd5b505afa158015612441573d6000803e3d6000fd5b505050506040513d602081101561245757600080fd5b50516123bd576040805162461bcd60e51b815260206004820152601860248201527f4552525f504f4f4c5f4e4f545f57484954454c49535445440000000000000000604482015290519081900360640190fd5b600081116123bd576040805162461bcd60e51b815260206004820152600e60248201526d4552525f5a45524f5f56414c554560901b604482015290519081900360640190fd5b6000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561252b57600080fd5b505afa15801561253f573d6000803e3d6000fd5b505050506040513d602081101561255557600080fd5b505192915050565b6000846001600160a01b03166319b64015846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156125a357600080fd5b505afa1580156125b7573d6000803e3d6000fd5b505050506040513d60208110156125cd57600080fd5b50519050856125da614e52565b6125e48284612c85565b905060006126078260200151610bea8460000151886129fc90919063ffffffff16565b90506126163384868885613614565b50866001600160a01b0316846001600160a01b031614156126b857604080516340c10f1960e01b81523360048201526024810183905290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916340c10f1991604480830192600092919082900301818387803b15801561269f57600080fd5b505af11580156126b3573d6000803e3d6000fd5b505050505b505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17815292518251600094606094938a169392918291908083835b602083106127485780518252601f199092019160209182019101612729565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146127aa576040519150601f19603f3d011682016040523d82523d6000602084013e6127af565b606091505b50915091508180156127dd5750805115806127dd57508080602001905160208110156127da57600080fd5b50515b61282e576040805162461bcd60e51b815260206004820152601860248201527f4552525f5452414e534645525f46524f4d5f4641494c45440000000000000000604482015290519081900360640190fd5b505050505050565b4290565b600082820183811015612883576040805162461bcd60e51b815260206004820152600c60248201526b4552525f4f564552464c4f5760a01b604482015290519081900360640190fd5b90505b92915050565b60008163ffffffff161180156128ab5750620f424063ffffffff821611155b6123bd576040805162461bcd60e51b815260206004820152601360248201527222a9292fa4a72b20a624a22fa827a92a24a7a760691b604482015290519081900360640190fd5b6128fa614dbd565b612902614dbd565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635290ffbb846040518263ffffffff1660e01b8152600401808281526020019150506101006040518083038186803b15801561296757600080fd5b505afa15801561297b573d6000803e3d6000fd5b505050506040513d61010081101561299257600080fd5b50805160208083015160408085015160608087015160808089015160a0808b015160c0808d015160e09d8e01519d8f019d909d528d019b909b528b01999099528901979097528701959095526001600160a01b039485169086015283169084015216815292915050565b600082612a0b57506000612886565b82820282848281612a1857fe5b0414612883576040805162461bcd60e51b815260206004820152600c60248201526b4552525f4f564552464c4f5760a01b604482015290519081900360640190fd5b612a62614e1d565b600080600080612a738a8a8861372b565b93509350935093506001600160801b038811158015612a9957506001600160801b038711155b8015612abe57506001600160801b038411158015612abe57506001600160801b038311155b8015612ae357506001600160801b038211158015612ae357506001600160801b038111155b612b27576040805162461bcd60e51b815260206004820152601060248201526f4552525f494e56414c49445f5241544560801b604482015290519081900360640190fd5b6040805160c0810182526001600160801b03998a16815297891660208901529388169387019390935290861660608601528516608085015290931660a0830152509392505050565b6000612b79614e52565b612b838989612c85565b9050612b8d614e52565b604051806040016040528087600001516001600160801b0316815260200187602001516001600160801b03168152509050612bc6614e52565b50604080518082018252908701516001600160801b0390811682526060880151166020820152612bf4614e52565b604051806040016040528089608001516001600160801b031681526020018960a001516001600160801b031681525090506000612c338b8686866139c4565b9050612c3d614e52565b612c478584613acf565b9050612c51614e52565b612c5b8a8a613b9d565b9050612c728c612c6b8e86613d39565b8484613d4f565b9f9e505050505050505050505050505050565b612c8d614e52565b6000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612cc857600080fd5b505afa158015612cdc573d6000803e3d6000fd5b505050506040513d6020811015612cf257600080fd5b505190506000612d01856124f0565b90506000816001600160a01b031663d8959512866040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015612d5257600080fd5b505afa158015612d66573d6000803e3d6000fd5b505050506040513d6020811015612d7c57600080fd5b50516040805180820190915290915080612d978360026129fc565b8152602001939093525090949350505050565b6000808211612df5576040805162461bcd60e51b81526020600482015260126024820152714552525f4449564944455f42595f5a45524f60701b604482015290519081900360640190fd5b6000828481612e0057fe5b04949350505050565b6000828411612e1a57506000612ee9565b6000612e4f8360a001516001600160801b0316610bea85608001516001600160801b03168789036129fc90919063ffffffff16565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a80c76ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015612eaa57600080fd5b505afa158015612ebe573d6000803e3d6000fd5b505050506040513d6020811015612ed457600080fd5b50518110612ee3579050612ee9565b60009150505b9392505050565b612ef8614dbd565b612f00614dbd565b612f09846128f2565b9050826001600160a01b031681600001516001600160a01b031614612883576040805162461bcd60e51b815260206004820152601160248201527011549497d050d0d154d4d7d11153925151607a1b604482015290519081900360640190fd5b60006130017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663045544436040518163ffffffff1660e01b815260040160206040518083038186803b158015612fc757600080fd5b505afa158015612fdb573d6000803e3d6000fd5b505050506040513d6020811015612ff157600080fd5b5051612ffb612836565b9061283a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dbae3a5d8484846040518463ffffffff1660e01b815260040180846001600160a01b031681526020018381526020018281526020019350505050602060405180830381600087803b15801561308257600080fd5b505af1158015613096573d6000803e3d6000fd5b505050506040513d6020811015611b1957600080fd5b60006130b7856124f0565b6003805460ff1916600117905560408051600280825260608083018452939450909160208301908036833750506040805160028082526060808301845294955090925090602083019080368337019050509050848260008151811061311857fe5b60200260200101906001600160a01b031690816001600160a01b031681525050838260018151811061314657fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060018160008151811061317557fe5b60200260200101818152505060018160018151811061319057fe5b602002602001018181525050826001600160a01b031663b127c0a58784846040518463ffffffff1660e01b8152600401808481526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156132075781810151838201526020016131ef565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561324657818101518382015260200161322e565b5050505090500195505050505050600060405180830381600087803b15801561326e57600080fd5b505af1158015613282573d6000803e3d6000fd5b50506003805460ff19169055505050505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b178152925182516000946060949389169392918291908083835b602083106133165780518252601f1990920191602091820191016132f7565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613378576040519150601f19603f3d011682016040523d82523d6000602084013e61337d565b606091505b50915091508180156133ab5750805115806133ab57508080602001905160208110156133a857600080fd5b50515b611b19576040805162461bcd60e51b815260206004820152601360248201527211549497d514905394d1915497d19052531151606a1b604482015290519081900360640190fd5b6000546001600160a01b0316331461050a576040805162461bcd60e51b815260206004820152601160248201527011549497d050d0d154d4d7d11153925151607a1b604482015290519081900360640190fd5b60008183101561348c576040805162461bcd60e51b815260206004820152600d60248201526c4552525f554e444552464c4f5760981b604482015290519081900360640190fd5b50900390565b6001600160a01b0381166123bd576040805162461bcd60e51b81526020600482015260136024820152724552525f494e56414c49445f4144445245535360681b604482015290519081900360640190fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03848116908216141561357b573415613567576040805162461bcd60e51b815260206004820152601760248201527608aa4a4be8aa890be829a9eaa9ca8be9a92a69a82a8869604b1b604482015290519081900360640190fd5b61357386868386613ddf565b91505061360c565b60006001600160a01b03851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146135a85760006135aa565b835b90508034146135fa576040805162461bcd60e51b815260206004820152601760248201527608aa4a4be8aa890be829a9eaa9ca8be9a92a69a82a8869604b1b604482015290519081900360640190fd5b613607878787858861406e565b925050505b949350505050565b600061361e614e52565b61362a86866001614635565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d5f087888888888887600001518860200151613672612836565b6040518963ffffffff1660e01b815260040180896001600160a01b03168152602001886001600160a01b03168152602001876001600160a01b0316815260200186815260200185815260200184815260200183815260200182815260200198505050505050505050602060405180830381600087803b1580156136f457600080fd5b505af1158015613708573d6000803e3d6000fd5b505050506040513d602081101561371e57600080fd5b5051979650505050505050565b600080600080600061373c886124f0565b90506000816001600160a01b03166319b6401560006040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561378557600080fd5b505afa158015613799573d6000803e3d6000fd5b505050506040513d60208110156137af57600080fd5b505190506001600160a01b03808216908916141561383b57816001600160a01b03166319b6401560016040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561380c57600080fd5b505afa158015613820573d6000803e3d6000fd5b505050506040513d602081101561383657600080fd5b505190505b60008061384984848c614669565b91509150600080856001600160a01b0316631f0181bc8d6040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050604080518083038186803b15801561389c57600080fd5b505afa1580156138b0573d6000803e3d6000fd5b505050506040513d60408110156138c657600080fd5b50805160209091015190925090508a158061396d575061396d848484847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166324a088686040518163ffffffff1660e01b815260040160206040518083038186803b15801561393c57600080fd5b505afa158015613950573d6000803e3d6000fd5b505050506040513d602081101561396657600080fd5b5051614769565b6139b1576040805162461bcd60e51b815260206004820152601060248201526f4552525f494e56414c49445f5241544560801b604482015290519081900360640190fd5b929c919b50995090975095505050505050565b82518151602084015160009283926139ef926139e9916139e491906129fc565b614806565b906129fc565b90506000613a1e86602001516139e9613a19876020015189600001516129fc90919063ffffffff16565b614826565b905081870287838281613a2d57fe5b041415613a4857818181613a3d57fe5b04935050505061360c565b600080898511613a59578985613a5c565b848a5b91509150600080613a7984878560001981613a7357fe5b0461487c565b915091506000613a9384888781613a8c57fe5b04906129fc565b90508115613abf57613ab0818386860281613aaa57fe5b04613d39565b9850505050505050505061360c565b9c9b505050505050505050505050565b613ad7614e52565b60208301518251600091613aeb91906129fc565b84516020850151919250600091613b01916129fc565b9050818102600082848381613b1257fe5b0414613b3057613b2183614826565b613b2a85614826565b02613b39565b613b3982614826565b90506000613b47858561283a565b905060028106613b7a57600281049050604051806040016040528083830381526020018281525095505050505050612886565b604080518082019091526002909202810382526020820152935050505092915050565b613ba5614e52565b6000613bb18385613445565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632c560f896040518163ffffffff1660e01b815260040160206040518083038186803b158015613c0e57600080fd5b505afa158015613c22573d6000803e3d6000fd5b505050506040513d6020811015613c3857600080fd5b50516040805163ce3f3adb60e01b815290519192506000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163ce3f3adb916004808301926020929190829003018186803b158015613ca057600080fd5b505afa158015613cb4573d6000803e3d6000fd5b505050506040513d6020811015613cca57600080fd5b5051905081831015613cf75760405180604001604052806000815260200160018152509350505050612886565b808310613d1f5760405180604001604052806001815260200160018152509350505050612886565b604080518082019091529283526020830152509392505050565b6000818311613d485781612883565b5090919050565b80516000908190613d6090876129fc565b60208401519091506000613d7d613d778484613d39565b88613d39565b9050600080613d9a886000015189602001518560001981613a7357fe5b9092509050613dd1613db9613daf83876129fc565b610bea85896129fc565b612ffb83610bea613dca8288613445565b8e906129fc565b9a9950505050505050505050565b600083613dea614e52565b613df48286612c85565b90506000613e178260000151610bea8460200151886129fc90919063ffffffff16565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166319c6a5e484836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613e9057600080fd5b505af1158015613ea4573d6000803e3d6000fd5b505050506000613eb7898589858a613614565b9050613ec5873330896126c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166342966c68876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613f2b57600080fd5b505af1158015613f3f573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663802fa3ba89886040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613fba57600080fd5b505af1158015613fce573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c10f198a886040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561404957600080fd5b505af115801561405d573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000848161407b826124f0565b905060008061408b838989614669565b915091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166312588d0e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156140e857600080fd5b505afa1580156140fc573d6000803e3d6000fd5b505050506040513d602081101561411257600080fd5b5051811015614168576040805162461bcd60e51b815260206004820152601860248201527f4552525f4e4f545f454e4f5547485f4c49515549444954590000000000000000604482015290519081900360640190fd5b600061417883610bea89856129fc565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663943fd08a8c6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156141e957600080fd5b505afa1580156141fd573d6000803e3d6000fd5b505050506040513d602081101561421357600080fd5b50519050806142a4577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b97b55ce6040518163ffffffff1660e01b815260040160206040518083038186803b15801561427557600080fd5b505afa158015614289573d6000803e3d6000fd5b505050506040513d602081101561429f57600080fd5b505190505b6000614317837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663350ed8e78f6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610c6d57600080fd5b905081811115614367576040805162461bcd60e51b815260206004820152601660248201527511549497d3505617d05353d5539517d4915050d2115160521b604482015290519081900360640190fd5b604080516340c10f1960e01b81523060048201526024810185905290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916340c10f1991604480830192600092919082900301818387803b1580156143d557600080fd5b505af11580156143e9573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663deacd84e8d856040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561446457600080fd5b505af1158015614478573d6000803e3d6000fd5b505050506144878a87856148c4565b6001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146144c2576144b78b33308c6126c3565b6144c28b878b6148c4565b6144d0868c8c8c8734614968565b6000876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561451f57600080fd5b505afa158015614533573d6000803e3d6000fd5b505050506040513d602081101561454957600080fd5b50519050614578887f000000000000000000000000000000000000000000000000000000000000000083613299565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663332100fa896002840484036040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156145f457600080fd5b505af1158015614608573d6000803e3d6000fd5b505050506146238e898e6002858161461c57fe5b048e613614565b9e9d5050505050505050505050505050565b61463d614e52565b60008061464b86868661372b565b60408051808201909152918252602082015298975050505050505050565b600080846001600160a01b031663d8959512856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156146b957600080fd5b505afa1580156146cd573d6000803e3d6000fd5b505050506040513d60208110156146e357600080fd5b505160408051636c4aca8960e11b81526001600160a01b03868116600483015291519188169163d895951291602480820192602092909190829003018186803b15801561472f57600080fd5b505afa158015614743573d6000803e3d6000fd5b505050506040513d602081101561475957600080fd5b505190925090505b935093915050565b60008061479d83620f42400363ffffffff166139e985620f42400363ffffffff166139e9888c6129fc90919063ffffffff16565b905060006147d0620f424063ffffffff166139e986620f42400363ffffffff166139e98a8c6129fc90919063ffffffff16565b905060006147e7620f42406139e981818d8b6129fc565b90508183111580156147f95750808211155b9998505050505050505050565b60008061481283614826565b905082818202146128865780600101612ee9565b6000806002830460010190506000600282858161483f57fe5b0483018161484957fe5b0490505b8082111561487557809150600282858161486357fe5b0483018161486d57fe5b04905061484d565b5092915050565b60008084848482118061488e57508481115b156148a45761489e828287614b47565b90925090505b8082146148b5579092509050614761565b50600196879650945050505050565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561491557600080fd5b505afa158015614929573d6000803e3d6000fd5b505050506040513d602081101561493f57600080fd5b5051905081811015611a3157801561495d5761495d84846000614b80565b611a31848484614b80565b6003805460ff1916600117905560408051600280825260608083018452926020830190803683375050604080516002808252606080830184529495509092509060208301908036833701905050905086826000815181106149c557fe5b60200260200101906001600160a01b031690816001600160a01b03168152505085826001815181106149f357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508481600081518110614a2157fe5b6020026020010181815250508381600181518110614a3b57fe5b602002602001018181525050876001600160a01b0316637d8916bd84848460016040518563ffffffff1660e01b8152600401808060200180602001848152602001838103835286818151815260200191508051906020019060200280838360005b83811015614ab4578181015183820152602001614a9c565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015614af3578181015183820152602001614adb565b50505050905001955050505050506000604051808303818588803b158015614b1a57600080fd5b505af1158015614b2e573d6000803e3d6000fd5b50506003805460ff191690555050505050505050505050565b600080838511614b6557614b5c858585614cd8565b91509150614761565b600080614b73868887614cd8565b9890975095505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b178152925182516000946060949389169392918291908083835b60208310614bfd5780518252601f199092019160209182019101614bde565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614c5f576040519150601f19603f3d011682016040523d82523d6000602084013e614c64565b606091505b5091509150818015614c92575080511580614c925750808060200190516020811015614c8f57600080fd5b50515b611b19576040805162461bcd60e51b815260206004820152601260248201527111549497d054141493d59157d1905253115160721b604482015290519081900360640190fd5b60008060008360001981614ce857fe5b04905080861115614d21576000816001018781614d0157fe5b046001019050808781614d1057fe5b049650808681614d1c57fe5b049550505b848614614d8157858402858701878110614d52576000614d418383614d91565b955050508385039250614761915050565b6002888803048703821015614d705760008694509450505050614761565b600180870394509450505050614761565b5050600290910493849350915050565b6000600282048203828481614da257fe5b0681614daa57fe5b04828481614db457fe5b04019392505050565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60405180604001604052806000815260200160008152509056fea26469706673582212200b0235110436240d15a64b82ece6b9e600dccbb988885efc5c5e63d964f6343d64736f6c634300060c0033000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da9000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2440000000000000000000000000887ae1251e180d7d453aedebee26e1639f20113000000000000000000000000f8a2fb650e25a26ce839d64be8a0abbcb0b87b32
Deployed Bytecode
0x60806040526004361061012e5760003560e01c8063975057e7116100ab578063d4ee1d901161006f578063d4ee1d90146103db578063d79dabae146103f0578063e06174e414610405578063e4a767261461041a578063f04ef41f14610450578063f2fde38b146104805761013d565b8063975057e7146102d5578063c21fe133146102ea578063c2250a99146102ff578063c83df66314610332578063caee4c8f1461039f5761013d565b80636d533e9b116100f25780636d533e9b14610206578063782ed90c1461026057806379ba50971461029657806389d94b46146102ab5780638da5cb5b146102c05761013d565b806305268cff146101425780630529fa3d1461017357806315ee207d14610188578063630d8c63146101c15780636ca95a4e146101f15761013d565b3661013d5761013b6104b3565b005b600080fd5b34801561014e57600080fd5b5061015761050c565b604080516001600160a01b039092168252519081900360200190f35b34801561017f57600080fd5b50610157610530565b34801561019457600080fd5b5061013b600480360360408110156101ab57600080fd5b506001600160a01b038135169060200135610554565b3480156101cd57600080fd5b5061013b600480360360408110156101e457600080fd5b508035906020013561060c565b3480156101fd57600080fd5b506101576109bb565b34801561021257600080fd5b506102426004803603606081101561022957600080fd5b5080359063ffffffff60208201351690604001356109df565b60408051938452602084019290925282820152519081900360600190f35b34801561026c57600080fd5b5061013b6004803603604081101561028357600080fd5b508035906020013563ffffffff16610cff565b3480156102a257600080fd5b5061013b611903565b3480156102b757600080fd5b5061013b6119ba565b3480156102cc57600080fd5b50610157611a37565b3480156102e157600080fd5b50610157611a46565b3480156102f657600080fd5b50610157611a6a565b34801561030b57600080fd5b5061013b6004803603602081101561032257600080fd5b50356001600160a01b0316611a8e565b34801561033e57600080fd5b5061038d600480360360e081101561035557600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a08101359060c00135611b20565b60408051918252519081900360200190f35b61038d600480360360808110156103b557600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135611c15565b3480156103e757600080fd5b50610157611c69565b3480156103fc57600080fd5b50610157611c78565b34801561041157600080fd5b50610157611c9c565b61038d6004803603606081101561043057600080fd5b506001600160a01b03813581169160208101359091169060400135611cc0565b34801561045c57600080fd5b5061013b6004803603604081101561047357600080fd5b5080359060200135611d08565b34801561048c57600080fd5b5061013b600480360360208110156104a357600080fd5b50356001600160a01b0316612214565b60035460ff1661050a576040805162461bcd60e51b815260206004820152601a60248201527f4552525f4e4f545f5550444154494e475f4c4951554944495459000000000000604482015290519081900360640190fd5b565b7f00000000000000000000000048fb253446873234f2febbf9bdeaa72d9d387f9481565b7f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc24481565b61055c612292565b600280558161056a816122da565b82610574816123c0565b8261057e816124aa565b6000610589866124f0565b90507f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c866105be818484600060028c0461255d565b6105d1818484600160028c048c0361255d565b6105fd81337f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb558a6126c3565b50506001600255505050505050565b610614612292565b6002805560408051637a1036f560e11b81523360048201526024810184905260448101839052905160609182916001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55169163f4206dea916064808301926000929190829003018186803b15801561069157600080fd5b505afa1580156106a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160409081528110156106ce57600080fd5b81019080805160405193929190846401000000008211156106ee57600080fd5b90830190602082018581111561070357600080fd5b825186602082028301116401000000008211171561072057600080fd5b82525081516020918201928201910280838360005b8381101561074d578181015183820152602001610735565b505050509050016040526020018051604051939291908464010000000082111561077657600080fd5b90830190602082018581111561078b57600080fd5b82518660208202830111640100000000821117156107a857600080fd5b82525081516020918201928201910280838360005b838110156107d55781810151838201526020016107bd565b505050509050016040525050509150915060008083519050825181146107f757fe5b805b80156108e657600019810161080c612836565b85828151811061081857fe5b6020026020010151111561082c57506108dd565b604080516390e0661b60e01b8152336004820152898301602482015290516001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb5516916390e0661b91604480830192600092919082900301818387803b15801561089b57600080fd5b505af11580156108af573d6000803e3d6000fd5b505050506108d98682815181106108c257fe5b60200260200101518561283a90919063ffffffff16565b9350505b600019016107f9565b5081156109ae577f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316635e35359e7f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c33856040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b15801561099557600080fd5b505af11580156109a9573d6000803e3d6000fd5b505050505b5050600160025550505050565b7f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c81565b6000806000846109ee8161288c565b6109f6614dbd565b6109ff886128f2565b80519091506001600160a01b0316610a4f576040805162461bcd60e51b815260206004820152600e60248201526d11549497d253959053125117d25160921b604482015290519081900360640190fd5b8060e00151861015610aa0576040805162461bcd60e51b815260206004820152601560248201527404552525f494e56414c49445f54494d455354414d5605c1b604482015290519081900360640190fd5b63ffffffff8716620f424014610b05576060810151620f424090610acd9063ffffffff8a8116906129fc16565b81610ad457fe5b0460608201526080810151620f424090610af79063ffffffff8a8116906129fc16565b81610afe57fe5b0460808201525b610b0d614e1d565b610b2b826020015183604001518460a001518560c001516000612a5a565b90506000610b528360200151846040015185606001518660800151868860e001518e612b6f565b90507f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c6001600160a01b031683604001516001600160a01b03161415610ba357955085945060009350610cf5915050565b610bab614e52565b610bbd84602001518560400151612c85565b90506000610bf06002836000015181610bd257fe5b04610bea8460200151866129fc90919063ffffffff16565b90612daa565b90506000610c9f86606001517f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316635121220c89602001516040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610c6d57600080fd5b505afa158015610c81573d6000803e3d6000fd5b505050506040513d6020811015610c9757600080fd5b50519061283a565b9050808211610cae5781610cb0565b805b91506000610cd68460200151610bea6002876000015181610ccd57fe5b879190046129fc565b90506000610ce5868389612e09565b959b509099509397505050505050505b5093509350939050565b80610d098161288c565b610d11612292565b60028055610d1d614dbd565b610d278433612ef0565b905060007f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c9050610d5b82602001516123c0565b610d63612836565b8260e0015110610daa576040805162461bcd60e51b815260206004820152600d60248201526c4552525f544f4f5f4541524c5960981b604482015290519081900360640190fd5b63ffffffff8416620f42401415610e3e577f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316636f366b71866040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610e2157600080fd5b505af1158015610e35573d6000803e3d6000fd5b50505050610f30565b60608201516080830151620f4240610e5f8363ffffffff898116906129fc16565b81610e6657fe5b0460608501526080840151620f424090610e899063ffffffff898116906129fc16565b81610e9057fe5b046080850181905260608501516040805163161139bd60e31b8152600481018b90529185036024830152918303604482015290516001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55169163b089cde891606480830192600092919082900301818387803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b5050505050505b60408051631d092adf60e01b815233600482015290516001600160a01b037f000000000000000000000000f8a2fb650e25a26ce839d64be8a0abbcb0b87b321691631d092adf91602480830192600092919082900301818387803b158015610f9757600080fd5b505af1158015610fab573d6000803e3d6000fd5b505050507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b031663332100fa836020015184606001516040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561102e57600080fd5b505af1158015611042573d6000803e3d6000fd5b50505050806001600160a01b031682604001516001600160a01b03161415611117576110947f00000000000000000000000048fb253446873234f2febbf9bdeaa72d9d387f94333085608001516126c3565b7f0000000000000000000000000887ae1251e180d7d453aedebee26e1639f201136001600160a01b03166342966c6883608001516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156110fe57600080fd5b505af1158015611112573d6000803e3d6000fd5b505050505b61111f614e1d565b61113d836020015184604001518560a001518660c001516001612a5a565b9050600061116b8460200151856040015186606001518760800151868960e00151611166612836565b612b6f565b9050826001600160a01b031684604001516001600160a01b031614156112e0577f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2446001600160a01b03166340c10f197f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505050507f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663deacd84e8560200151836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156112b557600080fd5b505af11580156112c9573d6000803e3d6000fd5b505050506112d73382612f69565b505050506118f9565b6112e8614e52565b6112fa85602001518660400151612c85565b9050600061130f6002836000015181610bd257fe5b905060007f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316635121220c88602001516040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d60208110156113ae57600080fd5b505190508082116113bf57816113c1565b805b91507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b03166319c6a5e48860200151846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561143e57600080fd5b505af1158015611452573d6000803e3d6000fd5b505050507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316635e35359e886020015130856040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b1580156114e257600080fd5b505af11580156114f6573d6000803e3d6000fd5b5050505061150e8760200151838960400151896130ac565b60408701516000906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561157057506040514790339082156108fc029083906000818181858888f1935050505015801561156a573d6000803e3d6000fd5b50611600565b87604001516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156115c157600080fd5b505afa1580156115d5573d6000803e3d6000fd5b505050506040513d60208110156115eb57600080fd5b50516040890151909150611600903383613299565b600061160d868389612e09565b90508015611759576000886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561166457600080fd5b505afa158015611678573d6000803e3d6000fd5b505050506040513d602081101561168e57600080fd5b505190508181101561172257604080516340c10f1960e01b8152306004820152828403602482015290516001600160a01b037f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc24416916340c10f1991604480830192600092919082900301818387803b15801561170957600080fd5b505af115801561171d573d6000803e3d6000fd5b505050505b61174d897f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb5584613299565b6117573383612f69565b505b6000886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156117a857600080fd5b505afa1580156117bc573d6000803e3d6000fd5b505050506040513d60208110156117d257600080fd5b5051905080156118ee577f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2446001600160a01b03166342966c68826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561184257600080fd5b505af1158015611856573d6000803e3d6000fd5b505050507f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663802fa3ba8b60200151836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156118d557600080fd5b505af11580156118e9573d6000803e3d6000fd5b505050505b505050505050505050505b5050600160025550565b6001546001600160a01b03163314611956576040805162461bcd60e51b815260206004820152601160248201527011549497d050d0d154d4d7d11153925151607a1b604482015290519081900360640190fd5b600154600080546040516001600160a01b0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6119c26133f2565b7f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a1d57600080fd5b505af1158015611a31573d6000803e3d6000fd5b50505050565b6000546001600160a01b031681565b7f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb5581565b7f000000000000000000000000f8a2fb650e25a26ce839d64be8a0abbcb0b87b3281565b611a966133f2565b7f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b031663f2fde38b826040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050600060405180830381600087803b158015611b0557600080fd5b505af1158015611b19573d6000803e3d6000fd5b5050505050565b600080611b3186610bea89886129fc565b9050611b3b614e1d565b611b498a8a87876000612a5a565b90506000611bf38b8b858c86611beb7f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663ce3f3adb6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bb157600080fd5b505afa158015611bc5573d6000803e3d6000fd5b505050506040513d6020811015611bdb57600080fd5b5051611be5612836565b90613445565b611166612836565b9050611c0689610bea83620f42406129fc565b9b9a5050505050505050505050565b6000611c1f612292565b6002805584611c2d81613492565b84611c37816122da565b85611c41816123c0565b84611c4b816124aa565b611c57898989896134e3565b60016002559998505050505050505050565b6001546001600160a01b031681565b7f0000000000000000000000000887ae1251e180d7d453aedebee26e1639f2011381565b7f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da981565b6000611cca612292565b6002805583611cd8816122da565b84611ce2816123c0565b83611cec816124aa565b611cf8338888886134e3565b6001600255979650505050505050565b611d10612292565b6002805581811415611d57576040805162461bcd60e51b815260206004820152600b60248201526a11549497d4d0535157d25160aa1b604482015290519081900360640190fd5b611d5f614dbd565b611d698333612ef0565b9050611d73614dbd565b611d7d8333612ef0565b905060007f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c905081602001516001600160a01b031683602001516001600160a01b0316148015611de7575081604001516001600160a01b031683604001516001600160a01b031614155b8015611e275750806001600160a01b031683604001516001600160a01b03161480611e275750806001600160a01b031682604001516001600160a01b0316145b8015611e3a57508160e001518360e00151145b8015611e5957506060820151611e5190600161283a565b836060015111155b8015611e7857506060830151611e7090600161283a565b826060015111155b611ec9576040805162461bcd60e51b815260206004820152601860248201527f4552525f50524f54454354494f4e535f4d49534d415443480000000000000000604482015290519081900360640190fd5b611ed1612836565b8360e0015110611f18576040805162461bcd60e51b815260206004820152600d60248201526c4552525f544f4f5f4541524c5960981b604482015290519081900360640190fd5b6000816001600160a01b031684604001516001600160a01b031614611f41578260800151611f47565b83608001515b9050611f757f00000000000000000000000048fb253446873234f2febbf9bdeaa72d9d387f943330846126c3565b7f0000000000000000000000000887ae1251e180d7d453aedebee26e1639f201136001600160a01b03166342966c68826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611fdb57600080fd5b505af1158015611fef573d6000803e3d6000fd5b505060408051631d092adf60e01b815233600482015290516001600160a01b037f000000000000000000000000f8a2fb650e25a26ce839d64be8a0abbcb0b87b32169350631d092adf9250602480830192600092919082900301818387803b15801561205a57600080fd5b505af115801561206e573d6000803e3d6000fd5b505050507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316636f366b71876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120d857600080fd5b505af11580156120ec573d6000803e3d6000fd5b505050507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316636f366b71866040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561215657600080fd5b505af115801561216a573d6000803e3d6000fd5b505050507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316635e35359e8560200151336121be8760600151896060015161283a90919063ffffffff16565b6040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050600060405180830381600087803b15801561099557600080fd5b61221c6133f2565b6000546001600160a01b0382811691161415612270576040805162461bcd60e51b815260206004820152600e60248201526d22a9292fa9a0a6a2afa7aba722a960911b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60016002541461050a576040805162461bcd60e51b815260206004820152600e60248201526d4552525f5245454e5452414e435960901b604482015290519081900360640190fd5b7f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663d4f63148826040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561234757600080fd5b505afa15801561235b573d6000803e3d6000fd5b505050506040513d602081101561237157600080fd5b50516123bd576040805162461bcd60e51b815260206004820152601660248201527511549497d413d3d317d393d517d4d5541413d495115160521b604482015290519081900360640190fd5b50565b7f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b0316632b26a982826040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561242d57600080fd5b505afa158015612441573d6000803e3d6000fd5b505050506040513d602081101561245757600080fd5b50516123bd576040805162461bcd60e51b815260206004820152601860248201527f4552525f504f4f4c5f4e4f545f57484954454c49535445440000000000000000604482015290519081900360640190fd5b600081116123bd576040805162461bcd60e51b815260206004820152600e60248201526d4552525f5a45524f5f56414c554560901b604482015290519081900360640190fd5b6000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561252b57600080fd5b505afa15801561253f573d6000803e3d6000fd5b505050506040513d602081101561255557600080fd5b505192915050565b6000846001600160a01b03166319b64015846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156125a357600080fd5b505afa1580156125b7573d6000803e3d6000fd5b505050506040513d60208110156125cd57600080fd5b50519050856125da614e52565b6125e48284612c85565b905060006126078260200151610bea8460000151886129fc90919063ffffffff16565b90506126163384868885613614565b50866001600160a01b0316846001600160a01b031614156126b857604080516340c10f1960e01b81523360048201526024810183905290516001600160a01b037f0000000000000000000000000887ae1251e180d7d453aedebee26e1639f2011316916340c10f1991604480830192600092919082900301818387803b15801561269f57600080fd5b505af11580156126b3573d6000803e3d6000fd5b505050505b505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17815292518251600094606094938a169392918291908083835b602083106127485780518252601f199092019160209182019101612729565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146127aa576040519150601f19603f3d011682016040523d82523d6000602084013e6127af565b606091505b50915091508180156127dd5750805115806127dd57508080602001905160208110156127da57600080fd5b50515b61282e576040805162461bcd60e51b815260206004820152601860248201527f4552525f5452414e534645525f46524f4d5f4641494c45440000000000000000604482015290519081900360640190fd5b505050505050565b4290565b600082820183811015612883576040805162461bcd60e51b815260206004820152600c60248201526b4552525f4f564552464c4f5760a01b604482015290519081900360640190fd5b90505b92915050565b60008163ffffffff161180156128ab5750620f424063ffffffff821611155b6123bd576040805162461bcd60e51b815260206004820152601360248201527222a9292fa4a72b20a624a22fa827a92a24a7a760691b604482015290519081900360640190fd5b6128fa614dbd565b612902614dbd565b7f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b0316635290ffbb846040518263ffffffff1660e01b8152600401808281526020019150506101006040518083038186803b15801561296757600080fd5b505afa15801561297b573d6000803e3d6000fd5b505050506040513d61010081101561299257600080fd5b50805160208083015160408085015160608087015160808089015160a0808b015160c0808d015160e09d8e01519d8f019d909d528d019b909b528b01999099528901979097528701959095526001600160a01b039485169086015283169084015216815292915050565b600082612a0b57506000612886565b82820282848281612a1857fe5b0414612883576040805162461bcd60e51b815260206004820152600c60248201526b4552525f4f564552464c4f5760a01b604482015290519081900360640190fd5b612a62614e1d565b600080600080612a738a8a8861372b565b93509350935093506001600160801b038811158015612a9957506001600160801b038711155b8015612abe57506001600160801b038411158015612abe57506001600160801b038311155b8015612ae357506001600160801b038211158015612ae357506001600160801b038111155b612b27576040805162461bcd60e51b815260206004820152601060248201526f4552525f494e56414c49445f5241544560801b604482015290519081900360640190fd5b6040805160c0810182526001600160801b03998a16815297891660208901529388169387019390935290861660608601528516608085015290931660a0830152509392505050565b6000612b79614e52565b612b838989612c85565b9050612b8d614e52565b604051806040016040528087600001516001600160801b0316815260200187602001516001600160801b03168152509050612bc6614e52565b50604080518082018252908701516001600160801b0390811682526060880151166020820152612bf4614e52565b604051806040016040528089608001516001600160801b031681526020018960a001516001600160801b031681525090506000612c338b8686866139c4565b9050612c3d614e52565b612c478584613acf565b9050612c51614e52565b612c5b8a8a613b9d565b9050612c728c612c6b8e86613d39565b8484613d4f565b9f9e505050505050505050505050505050565b612c8d614e52565b6000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612cc857600080fd5b505afa158015612cdc573d6000803e3d6000fd5b505050506040513d6020811015612cf257600080fd5b505190506000612d01856124f0565b90506000816001600160a01b031663d8959512866040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015612d5257600080fd5b505afa158015612d66573d6000803e3d6000fd5b505050506040513d6020811015612d7c57600080fd5b50516040805180820190915290915080612d978360026129fc565b8152602001939093525090949350505050565b6000808211612df5576040805162461bcd60e51b81526020600482015260126024820152714552525f4449564944455f42595f5a45524f60701b604482015290519081900360640190fd5b6000828481612e0057fe5b04949350505050565b6000828411612e1a57506000612ee9565b6000612e4f8360a001516001600160801b0316610bea85608001516001600160801b03168789036129fc90919063ffffffff16565b90507f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663a80c76ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015612eaa57600080fd5b505afa158015612ebe573d6000803e3d6000fd5b505050506040513d6020811015612ed457600080fd5b50518110612ee3579050612ee9565b60009150505b9392505050565b612ef8614dbd565b612f00614dbd565b612f09846128f2565b9050826001600160a01b031681600001516001600160a01b031614612883576040805162461bcd60e51b815260206004820152601160248201527011549497d050d0d154d4d7d11153925151607a1b604482015290519081900360640190fd5b60006130017f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663045544436040518163ffffffff1660e01b815260040160206040518083038186803b158015612fc757600080fd5b505afa158015612fdb573d6000803e3d6000fd5b505050506040513d6020811015612ff157600080fd5b5051612ffb612836565b9061283a565b90507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b031663dbae3a5d8484846040518463ffffffff1660e01b815260040180846001600160a01b031681526020018381526020018281526020019350505050602060405180830381600087803b15801561308257600080fd5b505af1158015613096573d6000803e3d6000fd5b505050506040513d6020811015611b1957600080fd5b60006130b7856124f0565b6003805460ff1916600117905560408051600280825260608083018452939450909160208301908036833750506040805160028082526060808301845294955090925090602083019080368337019050509050848260008151811061311857fe5b60200260200101906001600160a01b031690816001600160a01b031681525050838260018151811061314657fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060018160008151811061317557fe5b60200260200101818152505060018160018151811061319057fe5b602002602001018181525050826001600160a01b031663b127c0a58784846040518463ffffffff1660e01b8152600401808481526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156132075781810151838201526020016131ef565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561324657818101518382015260200161322e565b5050505090500195505050505050600060405180830381600087803b15801561326e57600080fd5b505af1158015613282573d6000803e3d6000fd5b50506003805460ff19169055505050505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b178152925182516000946060949389169392918291908083835b602083106133165780518252601f1990920191602091820191016132f7565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613378576040519150601f19603f3d011682016040523d82523d6000602084013e61337d565b606091505b50915091508180156133ab5750805115806133ab57508080602001905160208110156133a857600080fd5b50515b611b19576040805162461bcd60e51b815260206004820152601360248201527211549497d514905394d1915497d19052531151606a1b604482015290519081900360640190fd5b6000546001600160a01b0316331461050a576040805162461bcd60e51b815260206004820152601160248201527011549497d050d0d154d4d7d11153925151607a1b604482015290519081900360640190fd5b60008183101561348c576040805162461bcd60e51b815260206004820152600d60248201526c4552525f554e444552464c4f5760981b604482015290519081900360640190fd5b50900390565b6001600160a01b0381166123bd576040805162461bcd60e51b81526020600482015260136024820152724552525f494e56414c49445f4144445245535360681b604482015290519081900360640190fd5b60007f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c6001600160a01b03848116908216141561357b573415613567576040805162461bcd60e51b815260206004820152601760248201527608aa4a4be8aa890be829a9eaa9ca8be9a92a69a82a8869604b1b604482015290519081900360640190fd5b61357386868386613ddf565b91505061360c565b60006001600160a01b03851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146135a85760006135aa565b835b90508034146135fa576040805162461bcd60e51b815260206004820152601760248201527608aa4a4be8aa890be829a9eaa9ca8be9a92a69a82a8869604b1b604482015290519081900360640190fd5b613607878787858861406e565b925050505b949350505050565b600061361e614e52565b61362a86866001614635565b90507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b03166361d5f087888888888887600001518860200151613672612836565b6040518963ffffffff1660e01b815260040180896001600160a01b03168152602001886001600160a01b03168152602001876001600160a01b0316815260200186815260200185815260200184815260200183815260200182815260200198505050505050505050602060405180830381600087803b1580156136f457600080fd5b505af1158015613708573d6000803e3d6000fd5b505050506040513d602081101561371e57600080fd5b5051979650505050505050565b600080600080600061373c886124f0565b90506000816001600160a01b03166319b6401560006040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561378557600080fd5b505afa158015613799573d6000803e3d6000fd5b505050506040513d60208110156137af57600080fd5b505190506001600160a01b03808216908916141561383b57816001600160a01b03166319b6401560016040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561380c57600080fd5b505afa158015613820573d6000803e3d6000fd5b505050506040513d602081101561383657600080fd5b505190505b60008061384984848c614669565b91509150600080856001600160a01b0316631f0181bc8d6040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050604080518083038186803b15801561389c57600080fd5b505afa1580156138b0573d6000803e3d6000fd5b505050506040513d60408110156138c657600080fd5b50805160209091015190925090508a158061396d575061396d848484847f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b03166324a088686040518163ffffffff1660e01b815260040160206040518083038186803b15801561393c57600080fd5b505afa158015613950573d6000803e3d6000fd5b505050506040513d602081101561396657600080fd5b5051614769565b6139b1576040805162461bcd60e51b815260206004820152601060248201526f4552525f494e56414c49445f5241544560801b604482015290519081900360640190fd5b929c919b50995090975095505050505050565b82518151602084015160009283926139ef926139e9916139e491906129fc565b614806565b906129fc565b90506000613a1e86602001516139e9613a19876020015189600001516129fc90919063ffffffff16565b614826565b905081870287838281613a2d57fe5b041415613a4857818181613a3d57fe5b04935050505061360c565b600080898511613a59578985613a5c565b848a5b91509150600080613a7984878560001981613a7357fe5b0461487c565b915091506000613a9384888781613a8c57fe5b04906129fc565b90508115613abf57613ab0818386860281613aaa57fe5b04613d39565b9850505050505050505061360c565b9c9b505050505050505050505050565b613ad7614e52565b60208301518251600091613aeb91906129fc565b84516020850151919250600091613b01916129fc565b9050818102600082848381613b1257fe5b0414613b3057613b2183614826565b613b2a85614826565b02613b39565b613b3982614826565b90506000613b47858561283a565b905060028106613b7a57600281049050604051806040016040528083830381526020018281525095505050505050612886565b604080518082019091526002909202810382526020820152935050505092915050565b613ba5614e52565b6000613bb18385613445565b905060007f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b0316632c560f896040518163ffffffff1660e01b815260040160206040518083038186803b158015613c0e57600080fd5b505afa158015613c22573d6000803e3d6000fd5b505050506040513d6020811015613c3857600080fd5b50516040805163ce3f3adb60e01b815290519192506000916001600160a01b037f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da9169163ce3f3adb916004808301926020929190829003018186803b158015613ca057600080fd5b505afa158015613cb4573d6000803e3d6000fd5b505050506040513d6020811015613cca57600080fd5b5051905081831015613cf75760405180604001604052806000815260200160018152509350505050612886565b808310613d1f5760405180604001604052806001815260200160018152509350505050612886565b604080518082019091529283526020830152509392505050565b6000818311613d485781612883565b5090919050565b80516000908190613d6090876129fc565b60208401519091506000613d7d613d778484613d39565b88613d39565b9050600080613d9a886000015189602001518560001981613a7357fe5b9092509050613dd1613db9613daf83876129fc565b610bea85896129fc565b612ffb83610bea613dca8288613445565b8e906129fc565b9a9950505050505050505050565b600083613dea614e52565b613df48286612c85565b90506000613e178260000151610bea8460200151886129fc90919063ffffffff16565b90507f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b03166319c6a5e484836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613e9057600080fd5b505af1158015613ea4573d6000803e3d6000fd5b505050506000613eb7898589858a613614565b9050613ec5873330896126c3565b7f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2446001600160a01b03166342966c68876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613f2b57600080fd5b505af1158015613f3f573d6000803e3d6000fd5b505050507f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663802fa3ba89886040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613fba57600080fd5b505af1158015613fce573d6000803e3d6000fd5b505050507f0000000000000000000000000887ae1251e180d7d453aedebee26e1639f201136001600160a01b03166340c10f198a886040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561404957600080fd5b505af115801561405d573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000848161407b826124f0565b905060008061408b838989614669565b915091507f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b03166312588d0e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156140e857600080fd5b505afa1580156140fc573d6000803e3d6000fd5b505050506040513d602081101561411257600080fd5b5051811015614168576040805162461bcd60e51b815260206004820152601860248201527f4552525f4e4f545f454e4f5547485f4c49515549444954590000000000000000604482015290519081900360640190fd5b600061417883610bea89856129fc565b905060007f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663943fd08a8c6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156141e957600080fd5b505afa1580156141fd573d6000803e3d6000fd5b505050506040513d602081101561421357600080fd5b50519050806142a4577f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663b97b55ce6040518163ffffffff1660e01b815260040160206040518083038186803b15801561427557600080fd5b505afa158015614289573d6000803e3d6000fd5b505050506040513d602081101561429f57600080fd5b505190505b6000614317837f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663350ed8e78f6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610c6d57600080fd5b905081811115614367576040805162461bcd60e51b815260206004820152601660248201527511549497d3505617d05353d5539517d4915050d2115160521b604482015290519081900360640190fd5b604080516340c10f1960e01b81523060048201526024810185905290516001600160a01b037f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc24416916340c10f1991604480830192600092919082900301818387803b1580156143d557600080fd5b505af11580156143e9573d6000803e3d6000fd5b505050507f000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da96001600160a01b031663deacd84e8d856040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561446457600080fd5b505af1158015614478573d6000803e3d6000fd5b505050506144878a87856148c4565b6001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146144c2576144b78b33308c6126c3565b6144c28b878b6148c4565b6144d0868c8c8c8734614968565b6000876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561451f57600080fd5b505afa158015614533573d6000803e3d6000fd5b505050506040513d602081101561454957600080fd5b50519050614578887f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb5583613299565b6001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb551663332100fa896002840484036040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156145f457600080fd5b505af1158015614608573d6000803e3d6000fd5b505050506146238e898e6002858161461c57fe5b048e613614565b9e9d5050505050505050505050505050565b61463d614e52565b60008061464b86868661372b565b60408051808201909152918252602082015298975050505050505050565b600080846001600160a01b031663d8959512856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156146b957600080fd5b505afa1580156146cd573d6000803e3d6000fd5b505050506040513d60208110156146e357600080fd5b505160408051636c4aca8960e11b81526001600160a01b03868116600483015291519188169163d895951291602480820192602092909190829003018186803b15801561472f57600080fd5b505afa158015614743573d6000803e3d6000fd5b505050506040513d602081101561475957600080fd5b505190925090505b935093915050565b60008061479d83620f42400363ffffffff166139e985620f42400363ffffffff166139e9888c6129fc90919063ffffffff16565b905060006147d0620f424063ffffffff166139e986620f42400363ffffffff166139e98a8c6129fc90919063ffffffff16565b905060006147e7620f42406139e981818d8b6129fc565b90508183111580156147f95750808211155b9998505050505050505050565b60008061481283614826565b905082818202146128865780600101612ee9565b6000806002830460010190506000600282858161483f57fe5b0483018161484957fe5b0490505b8082111561487557809150600282858161486357fe5b0483018161486d57fe5b04905061484d565b5092915050565b60008084848482118061488e57508481115b156148a45761489e828287614b47565b90925090505b8082146148b5579092509050614761565b50600196879650945050505050565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561491557600080fd5b505afa158015614929573d6000803e3d6000fd5b505050506040513d602081101561493f57600080fd5b5051905081811015611a3157801561495d5761495d84846000614b80565b611a31848484614b80565b6003805460ff1916600117905560408051600280825260608083018452926020830190803683375050604080516002808252606080830184529495509092509060208301908036833701905050905086826000815181106149c557fe5b60200260200101906001600160a01b031690816001600160a01b03168152505085826001815181106149f357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508481600081518110614a2157fe5b6020026020010181815250508381600181518110614a3b57fe5b602002602001018181525050876001600160a01b0316637d8916bd84848460016040518563ffffffff1660e01b8152600401808060200180602001848152602001838103835286818151815260200191508051906020019060200280838360005b83811015614ab4578181015183820152602001614a9c565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015614af3578181015183820152602001614adb565b50505050905001955050505050506000604051808303818588803b158015614b1a57600080fd5b505af1158015614b2e573d6000803e3d6000fd5b50506003805460ff191690555050505050505050505050565b600080838511614b6557614b5c858585614cd8565b91509150614761565b600080614b73868887614cd8565b9890975095505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b178152925182516000946060949389169392918291908083835b60208310614bfd5780518252601f199092019160209182019101614bde565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614c5f576040519150601f19603f3d011682016040523d82523d6000602084013e614c64565b606091505b5091509150818015614c92575080511580614c925750808060200190516020811015614c8f57600080fd5b50515b611b19576040805162461bcd60e51b815260206004820152601260248201527111549497d054141493d59157d1905253115160721b604482015290519081900360640190fd5b60008060008360001981614ce857fe5b04905080861115614d21576000816001018781614d0157fe5b046001019050808781614d1057fe5b049650808681614d1c57fe5b049550505b848614614d8157858402858701878110614d52576000614d418383614d91565b955050508385039250614761915050565b6002888803048703821015614d705760008694509450505050614761565b600180870394509450505050614761565b5050600290910493849350915050565b6000600282048203828481614da257fe5b0681614daa57fe5b04828481614db457fe5b04019392505050565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60405180604001604052806000815260200160008152509056fea26469706673582212200b0235110436240d15a64b82ece6b9e600dccbb988885efc5c5e63d964f6343d64736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da9000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2440000000000000000000000000887ae1251e180d7d453aedebee26e1639f20113000000000000000000000000f8a2fb650e25a26ce839d64be8a0abbcb0b87b32
-----Decoded View---------------
Arg [0] : _settings (address): 0xd444ec18952c7cAf09636f21807683DaCC1d7dA9
Arg [1] : _store (address): 0xf5FAB5DBD2f3bf675dE4cB76517d4767013cfB55
Arg [2] : _networkTokenGovernance (address): 0xa489C2b5b36835A327851Ab917A80562B5AFC244
Arg [3] : _govTokenGovernance (address): 0x0887ae1251E180d7D453aeDEBee26e1639f20113
Arg [4] : _lastRemoveCheckpointStore (address): 0xF8a2FB650e25a26CE839D64bE8a0aBbCb0b87B32
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000d444ec18952c7caf09636f21807683dacc1d7da9
Arg [1] : 000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55
Arg [2] : 000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc244
Arg [3] : 0000000000000000000000000887ae1251e180d7d453aedebee26e1639f20113
Arg [4] : 000000000000000000000000f8a2fb650e25a26ce839d64be8a0abbcb0b87b32
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.