Source Code
Latest 25 from a total of 6,806 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Remove Liquidity | 16767863 | 949 days ago | IN | 0 ETH | 0.00119008 | ||||
Migrate Position... | 15845591 | 1078 days ago | IN | 0 ETH | 0.00099504 | ||||
Migrate Position... | 15299945 | 1159 days ago | IN | 0 ETH | 0.00119501 | ||||
Add Liquidity | 15197087 | 1175 days ago | IN | 0 ETH | 0.00052737 | ||||
Migrate Position... | 15100144 | 1190 days ago | IN | 0 ETH | 0.00164651 | ||||
Migrate Position... | 15052149 | 1198 days ago | IN | 0 ETH | 0.0040392 | ||||
Remove Liquidity | 15052149 | 1198 days ago | IN | 0 ETH | 0.00212891 | ||||
Remove Liquidity | 14998886 | 1208 days ago | IN | 0 ETH | 0.00406727 | ||||
Migrate Position... | 14996051 | 1208 days ago | IN | 0 ETH | 0.00143267 | ||||
Remove Liquidity | 14993653 | 1209 days ago | IN | 0 ETH | 0.0010018 | ||||
Transfer Wallet ... | 14992781 | 1209 days ago | IN | 0 ETH | 0.00255815 | ||||
Transfer Store O... | 14992776 | 1209 days ago | IN | 0 ETH | 0.00266726 | ||||
Claim Balance | 14992722 | 1209 days ago | IN | 0 ETH | 0.00211096 | ||||
Migrate Position... | 14992682 | 1209 days ago | IN | 0 ETH | 0.01307867 | ||||
Migrate Position... | 14992627 | 1209 days ago | IN | 0 ETH | 0.02068955 | ||||
Migrate Position... | 14992625 | 1209 days ago | IN | 0 ETH | 0.02180641 | ||||
Remove Liquidity | 14992521 | 1209 days ago | IN | 0 ETH | 0.01095359 | ||||
Remove Liquidity | 14992521 | 1209 days ago | IN | 0 ETH | 0.01125613 | ||||
Remove Liquidity | 14992484 | 1209 days ago | IN | 0 ETH | 0.01492037 | ||||
Claim Balance | 14992261 | 1209 days ago | IN | 0 ETH | 0.00196173 | ||||
Claim Balance | 14992223 | 1209 days ago | IN | 0 ETH | 0.00180259 | ||||
Migrate Position... | 14992092 | 1209 days ago | IN | 0 ETH | 0.0079067 | ||||
Migrate Position... | 14992030 | 1209 days ago | IN | 0 ETH | 0.00755426 | ||||
Migrate Position... | 14992014 | 1209 days ago | IN | 0 ETH | 0.00789248 | ||||
Migrate Position... | 14991960 | 1209 days ago | IN | 0 ETH | 0.01013714 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
- | 14991797 | 1209 days ago | 1.00896717 ETH | ||||
- | 14991797 | 1209 days ago | 1.00896717 ETH | ||||
- | 14991266 | 1209 days ago | 0.49268748 ETH | ||||
- | 14991266 | 1209 days ago | 0.49268748 ETH | ||||
- | 14991139 | 1209 days ago | 3.07846844 ETH | ||||
- | 14991139 | 1209 days ago | 3.07846844 ETH | ||||
- | 14990160 | 1209 days ago | 1.00535202 ETH | ||||
- | 14990160 | 1209 days ago | 1.00535202 ETH | ||||
- | 14989965 | 1209 days ago | 2.20147802 ETH | ||||
- | 14989965 | 1209 days ago | 2.20147802 ETH | ||||
- | 14989965 | 1209 days ago | 5.14861823 ETH | ||||
- | 14989965 | 1209 days ago | 5.14861823 ETH | ||||
- | 14989642 | 1209 days ago | 0.18194403 ETH | ||||
- | 14989642 | 1209 days ago | 0.18194403 ETH | ||||
- | 14988103 | 1209 days ago | 50.760708 ETH | ||||
- | 14988103 | 1209 days ago | 50.760708 ETH | ||||
- | 14987052 | 1210 days ago | 74.99938002 ETH | ||||
- | 14987052 | 1210 days ago | 74.99938002 ETH | ||||
- | 14986428 | 1210 days ago | 1.82343978 ETH | ||||
- | 14986428 | 1210 days ago | 1.82343978 ETH | ||||
- | 14985874 | 1210 days ago | 3.02460485 ETH | ||||
- | 14985874 | 1210 days ago | 3.02460485 ETH | ||||
- | 14985368 | 1210 days ago | 67.99983314 ETH | ||||
- | 14985368 | 1210 days ago | 67.99983314 ETH | ||||
- | 14984691 | 1210 days ago | 3.56120992 ETH |
Cross-Chain Transactions
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 Standard Json-Input format)
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/Math.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@bancor/token-governance/contracts/ITokenGovernance.sol"; import "../utility/MathEx.sol"; import "../utility/Types.sol"; import "../utility/Time.sol"; import "../utility/Utils.sol"; import "../utility/Owned.sol"; import "../token/interfaces/IDSToken.sol"; import "../token/ReserveToken.sol"; import "../converter/interfaces/IConverterAnchor.sol"; import "../converter/interfaces/IConverter.sol"; import "../converter/interfaces/IConverterRegistry.sol"; import "./interfaces/ILiquidityProtection.sol"; interface ILiquidityPoolConverter is IConverter { function addLiquidity( IReserveToken[] memory reserveTokens, uint256[] memory reserveAmounts, uint256 minReturn ) external payable; function removeLiquidity( uint256 amount, IReserveToken[] memory reserveTokens, uint256[] memory reserveMinReturnAmounts ) external returns (uint256[] memory); function recentAverageRate(IReserveToken reserveToken) external view returns (uint256, uint256); } interface IBancorNetworkV3 { function migrateLiquidity( IReserveToken reserveToken, address provider, uint256 amount, uint256 availableAmount, uint256 originalAmount ) external payable; } /** * @dev This contract implements the liquidity protection mechanism. */ contract LiquidityProtection is ILiquidityProtection, Utils, Owned, ReentrancyGuard, Time { using Math for uint256; using SafeMath for uint256; using ReserveToken for IReserveToken; using SafeERC20 for IERC20; using SafeERC20 for IDSToken; using SafeERC20Ex for IERC20; using Address for address payable; struct Position { address provider; // liquidity provider IDSToken poolToken; // pool token address IReserveToken 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) } struct PositionList { IDSToken poolToken; // pool token address IReserveToken reserveToken; // reserve token address uint256[] positionIds; // position ids } uint256 internal constant MAX_UINT128 = 2**128 - 1; uint256 internal constant MAX_UINT256 = uint256(-1); IBancorNetworkV3 private immutable _networkV3; address payable private immutable _vaultV3; ILiquidityProtectionSettings private immutable _settings; ILiquidityProtectionStore private immutable _store; ILiquidityProtectionStats private immutable _stats; ILiquidityProtectionSystemStore private immutable _systemStore; ITokenHolder private immutable _wallet; IERC20 private immutable _networkToken; ITokenGovernance private immutable _networkTokenGovernance; IERC20 private immutable _govToken; ITokenGovernance private immutable _govTokenGovernance; /** * @dev initializes a new LiquidityProtection contract */ constructor( IBancorNetworkV3 networkV3, address payable vaultV3, ILiquidityProtectionSettings settings, ILiquidityProtectionStore store, ILiquidityProtectionStats stats, ILiquidityProtectionSystemStore systemStore, ITokenHolder wallet, ITokenGovernance networkTokenGovernance, ITokenGovernance govTokenGovernance ) public { _validAddress(address(networkV3)); _validAddress(address(vaultV3)); _validAddress(address(settings)); _validAddress(address(store)); _validAddress(address(stats)); _validAddress(address(systemStore)); _validAddress(address(wallet)); _networkV3 = networkV3; _vaultV3 = vaultV3; _settings = settings; _store = store; _stats = stats; _systemStore = systemStore; _wallet = wallet; _networkTokenGovernance = networkTokenGovernance; _govTokenGovernance = govTokenGovernance; _networkToken = networkTokenGovernance.token(); _govToken = govTokenGovernance.token(); } // ensures that the pool is supported and whitelisted modifier poolSupportedAndWhitelisted(IConverterAnchor poolAnchor) { _poolSupported(poolAnchor); _poolWhitelisted(poolAnchor); _; } // ensures that add liquidity is enabled modifier addLiquidityEnabled(IConverterAnchor poolAnchor, IReserveToken reserveToken) { _addLiquidityEnabled(poolAnchor, reserveToken); _; } // error message binary size optimization function _poolSupported(IConverterAnchor poolAnchor) internal view { require(_settings.isPoolSupported(poolAnchor), "ERR_POOL_NOT_SUPPORTED"); } // error message binary size optimization function _poolWhitelisted(IConverterAnchor poolAnchor) internal view { require(_settings.isPoolWhitelisted(poolAnchor), "ERR_POOL_NOT_WHITELISTED"); } // error message binary size optimization function _addLiquidityEnabled(IConverterAnchor poolAnchor, IReserveToken reserveToken) internal view { require(!_settings.addLiquidityDisabled(poolAnchor, reserveToken), "ERR_ADD_LIQUIDITY_DISABLED"); } // error message binary size optimization function _verifyEthAmount(uint256 value) internal view { require(msg.value == value, "ERR_ETH_AMOUNT_MISMATCH"); } /** * @dev returns the LP store */ function store() external view override returns (ILiquidityProtectionStore) { return _store; } /** * @dev returns the LP stats */ function stats() external view override returns (ILiquidityProtectionStats) { return _stats; } /** * @dev returns the LP settings */ function settings() external view override returns (ILiquidityProtectionSettings) { return _settings; } /** * @dev accept ETH */ receive() external payable {} /** * @dev transfers the ownership of the store * * Requirements: * * - the caller must be the owner of the contract */ function transferStoreOwnership(address newOwner) external ownerOnly { _store.transferOwnership(newOwner); } /** * @dev accepts the ownership of the store * * Requirements: * * - the caller must be the owner of the contract */ function acceptStoreOwnership() external ownerOnly { _store.acceptOwnership(); } /** * @dev transfers the ownership of the wallet * * Requirements: * * - the caller must be the owner of the contract */ function transferWalletOwnership(address newOwner) external ownerOnly { _wallet.transferOwnership(newOwner); } /** * @dev accepts the ownership of the wallet * * Requirements: * * - the caller must be the owner of the contract */ function acceptWalletOwnership() external ownerOnly { _wallet.acceptOwnership(); } /** * @dev adds protected liquidity to a pool for a specific recipient, mints new governance tokens for the caller * if the caller adds network tokens, and returns the new position id */ function addLiquidityFor( address owner, IConverterAnchor poolAnchor, IReserveToken reserveToken, uint256 amount ) external payable override nonReentrant validAddress(owner) poolSupportedAndWhitelisted(poolAnchor) addLiquidityEnabled(poolAnchor, reserveToken) greaterThanZero(amount) returns (uint256) { return _addLiquidity(owner, poolAnchor, reserveToken, amount); } /** * @dev adds protected liquidity to a pool, mints new governance tokens for the caller if the caller adds network * tokens, and returns the new position id */ function addLiquidity( IConverterAnchor poolAnchor, IReserveToken reserveToken, uint256 amount ) external payable override nonReentrant poolSupportedAndWhitelisted(poolAnchor) addLiquidityEnabled(poolAnchor, reserveToken) greaterThanZero(amount) returns (uint256) { return _addLiquidity(msg.sender, poolAnchor, reserveToken, amount); } /** * @dev adds protected liquidity to a pool for a specific recipient, mints new governance tokens for the caller if * the caller adds network tokens, and returns the new position id */ function _addLiquidity( address owner, IConverterAnchor poolAnchor, IReserveToken reserveToken, uint256 amount ) private returns (uint256) { if (_isNetworkToken(reserveToken)) { _verifyEthAmount(0); return _addNetworkTokenLiquidity(owner, poolAnchor, amount); } // verify that ETH was passed with the call if needed _verifyEthAmount(reserveToken.isNativeToken() ? amount : 0); return _addBaseTokenLiquidity(owner, poolAnchor, reserveToken, amount); } /** * @dev adds network token liquidity to a pool, mints new governance tokens for the caller, and returns the new ] * position id */ function _addNetworkTokenLiquidity( address owner, IConverterAnchor poolAnchor, uint256 amount ) internal returns (uint256) { IDSToken poolToken = IDSToken(address(poolAnchor)); IReserveToken networkToken = IReserveToken(address(_networkToken)); // 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 = _mulDivF(amount, poolRate.d, poolRate.n); // remove the pool tokens from the system's ownership (will revert if not enough tokens are available) _systemStore.decSystemBalance(poolToken, poolTokenAmount); // add the position for the recipient uint256 id = _addPosition(owner, poolToken, networkToken, poolTokenAmount, amount, _time()); // 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 _networkToken.safeTransferFrom(msg.sender, address(this), amount); _burnNetworkTokens(poolAnchor, amount); // mint governance tokens to the recipient _govTokenGovernance.mint(owner, amount); return id; } /** * @dev adds base token liquidity to a pool */ function _addBaseTokenLiquidity( address owner, IConverterAnchor poolAnchor, IReserveToken baseToken, uint256 amount ) internal returns (uint256) { IDSToken poolToken = IDSToken(address(poolAnchor)); IReserveToken networkToken = IReserveToken(address(_networkToken)); // 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 = _mulDivF(amount, reserveBalanceNetwork, reserveBalanceBase); // get network token minting limit uint256 mintingLimit = _networkTokenMintingLimit(poolAnchor); uint256 newNetworkTokensMinted = _systemStore.networkTokensMinted(poolAnchor).add(newNetworkLiquidityAmount); require(newNetworkTokensMinted <= mintingLimit, "ERR_MAX_AMOUNT_REACHED"); // issue new network tokens to the system _mintNetworkTokens(address(this), poolAnchor, newNetworkLiquidityAmount); // transfer the base tokens from the caller and approve the converter networkToken.ensureApprove(address(converter), newNetworkLiquidityAmount); if (!baseToken.isNativeToken()) { baseToken.safeTransferFrom(msg.sender, address(this), amount); baseToken.ensureApprove(address(converter), amount); } // add the liquidity to the converter _addLiquidity(converter, baseToken, networkToken, amount, newNetworkLiquidityAmount, msg.value); // transfer the new pool tokens to the wallet uint256 poolTokenAmount = poolToken.balanceOf(address(this)); poolToken.safeTransfer(address(_wallet), poolTokenAmount); // the system splits the pool tokens with the caller // increase the system's pool token balance and add the position for the caller _systemStore.incSystemBalance(poolToken, poolTokenAmount - poolTokenAmount / 2); // account for rounding errors return _addPosition(owner, poolToken, baseToken, poolTokenAmount / 2, amount, _time()); } /** * @dev returns the single-side staking base and network token limits of a given pool */ function poolAvailableSpace(IConverterAnchor poolAnchor) external view poolSupportedAndWhitelisted(poolAnchor) returns (uint256, uint256) { return (_baseTokenAvailableSpace(poolAnchor), _networkTokenAvailableSpace(poolAnchor)); } /** * @dev returns the base token staking limits of a given pool */ function _baseTokenAvailableSpace(IConverterAnchor poolAnchor) internal view returns (uint256) { // get the pool converter ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolAnchor))); // get the base token IReserveToken networkToken = IReserveToken(address(_networkToken)); IReserveToken baseToken = _converterOtherReserve(converter, networkToken); // get the reserve balances (uint256 reserveBalanceBase, uint256 reserveBalanceNetwork) = _converterReserveBalances( converter, baseToken, networkToken ); // get the network token minting limit uint256 mintingLimit = _networkTokenMintingLimit(poolAnchor); // get the amount of network tokens already minted for the pool uint256 networkTokensMinted = _systemStore.networkTokensMinted(poolAnchor); // get the amount of network tokens which can minted for the pool uint256 networkTokensCanBeMinted = Math.max(mintingLimit, networkTokensMinted) - networkTokensMinted; // return the maximum amount of base token liquidity that can be single-sided staked in the pool return _mulDivF(networkTokensCanBeMinted, reserveBalanceBase, reserveBalanceNetwork); } /** * @dev returns the network token staking limits of a given pool */ function _networkTokenAvailableSpace(IConverterAnchor poolAnchor) internal view returns (uint256) { // get the pool token IDSToken poolToken = IDSToken(address(poolAnchor)); IReserveToken networkToken = IReserveToken(address(_networkToken)); // get the pool token rate Fraction memory poolRate = _poolTokenRate(poolToken, networkToken); // return the maximum amount of network token liquidity that can be single-sided staked in the pool return _systemStore.systemBalance(poolToken).mul(poolRate.n).add(poolRate.n).sub(1).div(poolRate.d); } /** * @dev returns the expected, actual, and network token compensation amounts the provider will receive for removing * liquidity * * note that it's also possible to provide the remove liquidity time to get an estimation for the return at that * given point */ function removeLiquidityReturn( uint256 id, uint32 portion, uint256 removeTimestamp ) external view validPortion(portion) returns ( uint256, uint256, uint256 ) { Position memory pos = _position(id); require(pos.provider != address(0), "ERR_INVALID_ID"); require(removeTimestamp >= pos.timestamp, "ERR_INVALID_TIMESTAMP"); // calculate the portion of the liquidity to remove if (portion != PPM_RESOLUTION) { (pos.poolAmount, pos.reserveAmount) = _portionAmounts(pos.poolAmount, pos.reserveAmount, portion); } // get the various rates between the reserves upon adding liquidity and now PackedRates memory packedRates = _packRates( pos.poolToken, pos.reserveToken, pos.reserveRateN, pos.reserveRateD ); uint256 targetAmount = _removeLiquidityTargetAmount( pos.poolToken, pos.reserveToken, pos.poolAmount, pos.reserveAmount, packedRates, pos.timestamp, removeTimestamp ); // for network token, the return amount is identical to the target amount if (_isNetworkToken(pos.reserveToken)) { 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(pos.poolToken, pos.reserveToken); uint256 poolAmount = _liquidationAmount(targetAmount, poolRate, pos.poolToken, pos.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 = _mulDivF(poolAmount, poolRate.n, poolRate.d.mul(2)); uint256 networkAmount = _networkCompensation(targetAmount, baseAmount, packedRates); return (targetAmount, baseAmount, networkAmount); } /** * @dev removes protected liquidity from a pool and also burns governance tokens from the caller if the caller * removes network tokens */ function removeLiquidity(uint256 id, uint32 portion) external override nonReentrant validPortion(portion) { _removeLiquidity(msg.sender, id, portion); } /** * @dev removes a position from a pool and burns governance tokens from the caller if the caller removes network tokens */ function _removeLiquidity( address payable provider, uint256 id, uint32 portion ) internal { // remove the position from the store and update the stats Position memory removedPos = _removePosition(provider, id, portion); // add the pool tokens to the system _systemStore.incSystemBalance(removedPos.poolToken, removedPos.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 (_isNetworkToken(removedPos.reserveToken)) { _govToken.safeTransferFrom(provider, address(this), removedPos.reserveAmount); _govTokenGovernance.burn(removedPos.reserveAmount); } // get the various rates between the reserves upon adding liquidity and now PackedRates memory packedRates = _packRates( removedPos.poolToken, removedPos.reserveToken, removedPos.reserveRateN, removedPos.reserveRateD ); // verify rate deviation as early as possible in order to reduce gas-cost for failing transactions _verifyRateDeviation( packedRates.removeSpotRateN, packedRates.removeSpotRateD, packedRates.removeAverageRateN, packedRates.removeAverageRateD ); // get the target token amount uint256 targetAmount = _removeLiquidityTargetAmount( removedPos.poolToken, removedPos.reserveToken, removedPos.poolAmount, removedPos.reserveAmount, packedRates, removedPos.timestamp, _time() ); // remove network token liquidity if (_isNetworkToken(removedPos.reserveToken)) { // mint network tokens for the caller and lock them _mintNetworkTokens(address(_wallet), removedPos.poolToken, targetAmount); _lockTokens(provider, 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(removedPos.poolToken, removedPos.reserveToken); uint256 poolAmount = _liquidationAmount(targetAmount, poolRate, removedPos.poolToken, 0); // withdraw the pool tokens from the wallet _withdrawPoolTokens(removedPos.poolToken, poolAmount); // remove liquidity _removeLiquidity( removedPos.poolToken, poolAmount, removedPos.reserveToken, IReserveToken(address(_networkToken)) ); // transfer the base tokens to the caller uint256 baseBalance = removedPos.reserveToken.balanceOf(address(this)); removedPos.reserveToken.safeTransfer(provider, baseBalance); // compensate the caller with network tokens if still needed uint256 delta = _networkCompensation(targetAmount, baseBalance, packedRates); if (delta > 0) { // check if there's enough network token balance, otherwise mint more uint256 networkBalance = _networkToken.balanceOf(address(this)); if (networkBalance < delta) { _networkTokenGovernance.mint(address(this), delta - networkBalance); } // lock network tokens for the caller _networkToken.safeTransfer(address(_wallet), delta); _lockTokens(provider, delta); } // if the contract still holds network tokens, burn them uint256 networkBalance = _networkToken.balanceOf(address(this)); if (networkBalance > 0) { _burnNetworkTokens(removedPos.poolToken, networkBalance); } } /** * @dev migrates a set of position lists to v3 * * Requirements: * * - the caller must be the owner of all of the positions */ function migratePositions(PositionList[] calldata positionLists) external nonReentrant { uint256 length = positionLists.length; for (uint256 i = 0; i < length; ++i) { _migratePositions(positionLists[i]); } } /** * @dev migrates a list of positions to v3 * * Requirements: * * - the caller must be the owner of all of the positions */ function _migratePositions(PositionList calldata positionList) internal { IDSToken poolToken = positionList.poolToken; IReserveToken reserveToken = positionList.reserveToken; Fraction memory poolRate = _poolTokenRate(poolToken, reserveToken); (Fraction memory removeSpotRate, Fraction memory removeAverageRate) = _reserveTokenRates( poolToken, reserveToken ); // verify rate deviation as early as possible in order to reduce gas-cost for failing transactions _verifyRateDeviation(removeSpotRate.n, removeSpotRate.d, removeAverageRate.n, removeAverageRate.d); uint256 poolTokenAmount = 0; uint256 originalAmount = 0; uint256 fullyProtectedAmount = 0; uint256 length = positionList.positionIds.length; for (uint256 i = 0; i < length; ++i) { Position memory removedPos = _removePosition(msg.sender, positionList.positionIds[i], PPM_RESOLUTION); require( removedPos.poolToken == poolToken && removedPos.reserveToken == reserveToken, "ERR_INVALID_POSITION_LIST" ); // collect pool token amounts poolTokenAmount = poolTokenAmount.add(removedPos.poolAmount); // collect originally provided amounts originalAmount = originalAmount.add(removedPos.reserveAmount); // get the various rates between the reserves upon adding liquidity and now PackedRates memory packedRates = _packRates( removedPos.reserveRateN, removedPos.reserveRateD, removeSpotRate, removeAverageRate ); // get the fully protected amount (+ fees) fullyProtectedAmount = fullyProtectedAmount.add( _removeLiquidityTargetAmount( poolRate, removedPos.poolAmount, removedPos.reserveAmount, packedRates, Fraction({ n: 1, d: 1 }) ) ); } // add the pool tokens to the system _systemStore.incSystemBalance(poolToken, poolTokenAmount); // remove network token liquidity if (_isNetworkToken(reserveToken)) { // mint the fully protected amount (+ fees) and migrate it _mintNetworkTokens(address(this), poolToken, fullyProtectedAmount); _networkToken.approve(address(_networkV3), fullyProtectedAmount); _networkV3.migrateLiquidity( IReserveToken(address(_networkToken)), msg.sender, fullyProtectedAmount, fullyProtectedAmount, originalAmount ); 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 uint256 poolLiquidationAmount = _liquidationAmount(fullyProtectedAmount, poolRate, poolToken, 0); // withdraw the pool tokens from the wallet _withdrawPoolTokens(poolToken, poolLiquidationAmount); // remove liquidity _removeLiquidity(poolToken, poolLiquidationAmount, reserveToken, IReserveToken(address(_networkToken))); // migrate the received tokens uint256 removedAmount = reserveToken.balanceOf(address(this)); uint256 value; if (reserveToken.isNativeToken()) { value = removedAmount; } else { IERC20(address(reserveToken)).safeApprove(address(_networkV3), removedAmount); } _networkV3.migrateLiquidity{ value: value }( reserveToken, msg.sender, fullyProtectedAmount, removedAmount, originalAmount ); // if the contract still holds network tokens, burn them uint256 networkBalance = _networkToken.balanceOf(address(this)); if (networkBalance > 0) { _burnNetworkTokens(poolToken, networkBalance); } } /** * @dev returns the amount the provider will receive for removing liquidity */ function _removeLiquidityTargetAmount( IDSToken poolToken, IReserveToken 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); // calculate the protection level Fraction memory level = _protectionLevel(addTimestamp, removeTimestamp); return _removeLiquidityTargetAmount(poolRate, poolAmount, reserveAmount, packedRates, level); } /** * @dev returns the amount the provider will receive for removing liquidity */ function _removeLiquidityTargetAmount( Fraction memory poolRate, uint256 poolAmount, uint256 reserveAmount, PackedRates memory packedRates, Fraction memory level ) internal pure returns (uint256) { // 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 compensation amount return _compensationAmount(reserveAmount, Math.max(reserveAmount, total), loss, level); } /** * @dev transfers a position to a new provider * * Requirements: * * - the caller must be the owner of the position */ function transferPosition(uint256 id, address newProvider) external override nonReentrant validAddress(newProvider) returns (uint256) { return _transferPosition(msg.sender, id, newProvider); } /** * @dev transfers a position to a new provider and optionally notifies another contract * * Requirements: * * - the caller must be the owner of the position */ function transferPositionAndNotify( uint256 id, address newProvider, ITransferPositionCallback callback, bytes calldata data ) external override nonReentrant validAddress(newProvider) validAddress(address(callback)) returns (uint256) { uint256 newId = _transferPosition(msg.sender, id, newProvider); callback.onTransferPosition(newId, msg.sender, data); return newId; } /** * @dev migrates system pool tokens to v3 * * Requirements: * * - the caller must be the owner of this contract */ function migrateSystemPoolTokens(IConverterAnchor[] calldata poolAnchors) external nonReentrant ownerOnly { uint256 length = poolAnchors.length; for (uint256 i = 0; i < length; i++) { IDSToken poolToken = IDSToken(address(poolAnchors[i])); uint256 poolAmount = _systemStore.systemBalance(poolToken); _withdrawPoolTokens(poolToken, poolAmount); ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolToken))); (IReserveToken[] memory reserveTokens, uint256[] memory minReturns) = _removeLiquidityInput( IReserveToken(address(_networkToken)), _converterOtherReserve(converter, IReserveToken(address(_networkToken))) ); uint256[] memory reserveAmounts = converter.removeLiquidity(poolAmount, reserveTokens, minReturns); _burnNetworkTokens(poolAnchors[i], reserveAmounts[0]); if (reserveTokens[1].isNativeToken()) { _vaultV3.sendValue(reserveAmounts[1]); } else { reserveTokens[1].safeTransfer(_vaultV3, reserveAmounts[1]); } } } /** * @dev transfers a position to a new provider */ function _transferPosition( address provider, uint256 id, address newProvider ) internal returns (uint256) { // remove the position from the store and update the stats Position memory removedPos = _removePosition(provider, id, PPM_RESOLUTION); // add the position to the store, update the stats, and return the new id return _addPosition( newProvider, removedPos.poolToken, removedPos.reserveToken, removedPos.poolAmount, removedPos.reserveAmount, removedPos.timestamp ); } /** * @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 */ function claimBalance(uint256 startIndex, uint256 endIndex) external nonReentrant { // 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 _wallet.withdrawTokens(IReserveToken(address(_networkToken)), msg.sender, totalAmount); } } /** * @dev returns the ROI for removing liquidity in the current state after providing liquidity with the given args * * note that the function assumes full protection is in effect and that the return value is in PPM and can be * larger than PPM_RESOLUTION for positive ROI, 1M = 0% ROI */ function poolROI( IDSToken poolToken, IReserveToken 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 = _mulDivF(reserveAmount, poolRateD, poolRateN); // get the various rates between the reserves upon adding liquidity and now PackedRates memory packedRates = _packRates(poolToken, reserveToken, reserveRateN, reserveRateD); // 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 _mulDivF(protectedReturn, PPM_RESOLUTION, reserveAmount); } /** * @dev adds the position to the store and updates the stats */ function _addPosition( address provider, IDSToken poolToken, IReserveToken reserveToken, uint256 poolAmount, uint256 reserveAmount, uint256 timestamp ) internal returns (uint256) { // verify rate deviation as early as possible in order to reduce gas-cost for failing transactions (Fraction memory spotRate, Fraction memory averageRate) = _reserveTokenRates(poolToken, reserveToken); _verifyRateDeviation(spotRate.n, spotRate.d, averageRate.n, averageRate.d); _stats.increaseTotalAmounts(provider, poolToken, reserveToken, poolAmount, reserveAmount); _stats.addProviderPool(provider, poolToken); return _store.addProtectedLiquidity( provider, poolToken, reserveToken, poolAmount, reserveAmount, spotRate.n, spotRate.d, timestamp ); } /** * @dev removes the position from the store and updates the stats */ function _removePosition( address provider, uint256 id, uint32 portion ) private returns (Position memory) { Position memory pos = _providerPosition(id, provider); // verify that the pool is whitelisted _poolWhitelisted(pos.poolToken); // verify that the position is not removed on the same block in which it was added require(pos.timestamp < _time(), "ERR_TOO_EARLY"); if (portion == PPM_RESOLUTION) { // remove the position from the provider _store.removeProtectedLiquidity(id); } else { // remove a portion of the position from the provider uint256 fullPoolAmount = pos.poolAmount; uint256 fullReserveAmount = pos.reserveAmount; (pos.poolAmount, pos.reserveAmount) = _portionAmounts(pos.poolAmount, pos.reserveAmount, portion); _store.updateProtectedLiquidityAmounts( id, fullPoolAmount - pos.poolAmount, fullReserveAmount - pos.reserveAmount ); } // update the statistics _stats.decreaseTotalAmounts(pos.provider, pos.poolToken, pos.reserveToken, pos.poolAmount, pos.reserveAmount); return pos; } /** * @dev locks network tokens for the provider and emits the tokens locked event */ 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 */ function _poolTokenRate(IDSToken poolToken, IReserveToken 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 spot rate and average rate of 1 reserve token in the other reserve token units */ function _reserveTokenRates(IDSToken poolToken, IReserveToken reserveToken) internal view returns (Fraction memory, Fraction memory) { ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolToken))); IReserveToken otherReserve = _converterOtherReserve(converter, reserveToken); (uint256 spotRateN, uint256 spotRateD) = _converterReserveBalances(converter, otherReserve, reserveToken); (uint256 averageRateN, uint256 averageRateD) = converter.recentAverageRate(reserveToken); return (Fraction({ n: spotRateN, d: spotRateD }), Fraction({ n: averageRateN, d: averageRateD })); } /** * @dev returns the various rates between the reserves */ function _packRates( IDSToken poolToken, IReserveToken reserveToken, uint256 addSpotRateN, uint256 addSpotRateD ) internal view returns (PackedRates memory) { (Fraction memory removeSpotRate, Fraction memory removeAverageRate) = _reserveTokenRates( poolToken, reserveToken ); assert((removeSpotRate.n | removeSpotRate.d | removeAverageRate.n | removeAverageRate.d) <= MAX_UINT128); return _packRates(addSpotRateN, addSpotRateD, removeSpotRate, removeAverageRate); } /** * @dev returns the various rates between the reserves */ function _packRates( uint256 addSpotRateN, uint256 addSpotRateD, Fraction memory removeSpotRate, Fraction memory removeAverageRate ) internal pure returns (PackedRates memory) { assert((addSpotRateN | addSpotRateD) <= MAX_UINT128); return PackedRates({ addSpotRateN: uint128(addSpotRateN), addSpotRateD: uint128(addSpotRateD), removeSpotRateN: uint128(removeSpotRate.n), removeSpotRateD: uint128(removeSpotRate.d), removeAverageRateN: uint128(removeAverageRate.n), removeAverageRateD: uint128(removeAverageRate.d) }); } /** * @dev verifies that the deviation of the average rate from the spot rate is within the permitted range * * for example, if the maximum permitted deviation is 5%, then verify `95/100 <= average/spot <= 100/95` */ function _verifyRateDeviation( uint256 spotRateN, uint256 spotRateD, uint256 averageRateN, uint256 averageRateD ) internal view { uint256 ppmDelta = PPM_RESOLUTION - _settings.averageRateMaxDeviation(); uint256 min = spotRateN.mul(averageRateD).mul(ppmDelta).mul(ppmDelta); uint256 mid = spotRateD.mul(averageRateN).mul(ppmDelta).mul(PPM_RESOLUTION); uint256 max = spotRateN.mul(averageRateD).mul(PPM_RESOLUTION).mul(PPM_RESOLUTION); require(min <= mid && mid <= max, "ERR_INVALID_RATE"); } /** * @dev utility to add liquidity to a converter */ function _addLiquidity( ILiquidityPoolConverter converter, IReserveToken reserveToken1, IReserveToken reserveToken2, uint256 reserveAmount1, uint256 reserveAmount2, uint256 value ) internal { IReserveToken[] memory reserveTokens = new IReserveToken[](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); } /** * @dev utility to remove liquidity from a converter */ function _removeLiquidity( IDSToken poolToken, uint256 poolAmount, IReserveToken reserveToken1, IReserveToken reserveToken2 ) internal { ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolToken))); (IReserveToken[] memory reserveTokens, uint256[] memory minReturns) = _removeLiquidityInput( reserveToken1, reserveToken2 ); converter.removeLiquidity(poolAmount, reserveTokens, minReturns); } /** * @dev returns a position from the store */ function _position(uint256 id) internal view returns (Position memory) { Position memory pos; ( pos.provider, pos.poolToken, pos.reserveToken, pos.poolAmount, pos.reserveAmount, pos.reserveRateN, pos.reserveRateD, pos.timestamp ) = _store.protectedLiquidity(id); return pos; } /** * @dev returns a position from the store */ function _providerPosition(uint256 id, address provider) internal view returns (Position memory) { Position memory pos = _position(id); require(pos.provider == provider, "ERR_ACCESS_DENIED"); return pos; } /** * @dev returns the protected amount of reserve tokens plus accumulated fee before compensation */ function _protectedAmountPlusFee( uint256 poolAmount, Fraction memory poolRate, Fraction memory addRate, Fraction memory removeRate ) internal pure returns (uint256) { uint256 n = MathEx.ceilSqrt(addRate.d.mul(removeRate.n)).mul(poolRate.n); uint256 d = MathEx.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) = MathEx.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 */ 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 ? MathEx.floorSqrt(prod) : MathEx.floorSqrt(ratioN) * MathEx.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 */ 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 */ 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) = MathEx.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 _networkCompensation( uint256 targetAmount, uint256 baseAmount, PackedRates memory packedRates ) internal view returns (uint256) { if (targetAmount <= baseAmount) { return 0; } // calculate the delta in network tokens uint256 delta = _mulDivF( targetAmount - baseAmount, packedRates.removeAverageRateN, 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 to mint network tokens */ function _mintNetworkTokens( address owner, IConverterAnchor poolAnchor, uint256 amount ) private { _systemStore.incNetworkTokensMinted(poolAnchor, amount); _networkTokenGovernance.mint(owner, amount); } /** * @dev utility to burn network tokens */ function _burnNetworkTokens(IConverterAnchor poolAnchor, uint256 amount) private { _systemStore.decNetworkTokensMinted(poolAnchor, amount); _networkTokenGovernance.burn(amount); } /** * @dev utility to get the reserve balances */ function _converterReserveBalances( IConverter converter, IReserveToken reserveToken1, IReserveToken reserveToken2 ) private view returns (uint256, uint256) { return (converter.getConnectorBalance(reserveToken1), converter.getConnectorBalance(reserveToken2)); } /** * @dev utility to get the other reserve */ function _converterOtherReserve(IConverter converter, IReserveToken thisReserve) private view returns (IReserveToken) { IReserveToken otherReserve = converter.connectorTokens(0); return otherReserve != thisReserve ? otherReserve : converter.connectorTokens(1); } /** * @dev utility to get the owner */ function _ownedBy(IOwned owned) private view returns (address) { return owned.owner(); } /** * @dev returns whether the provided reserve token is the network token */ function _isNetworkToken(IReserveToken reserveToken) private view returns (bool) { return address(reserveToken) == address(_networkToken); } /** * @dev returns custom input for the `removeLiquidity` converter function */ function _removeLiquidityInput(IReserveToken reserveToken1, IReserveToken reserveToken2) private pure returns (IReserveToken[] memory, uint256[] memory) { IReserveToken[] memory reserveTokens = new IReserveToken[](2); uint256[] memory minReturns = new uint256[](2); reserveTokens[0] = reserveToken1; reserveTokens[1] = reserveToken2; minReturns[0] = 1; minReturns[1] = 1; return (reserveTokens, minReturns); } /** * @dev returns the relative position amounts */ function _portionAmounts( uint256 poolAmount, uint256 reserveAmount, uint256 portion ) private pure returns (uint256, uint256) { return (_mulDivF(poolAmount, portion, PPM_RESOLUTION), _mulDivF(reserveAmount, portion, PPM_RESOLUTION)); } /** * @dev returns the network token minting limit */ function _networkTokenMintingLimit(IConverterAnchor poolAnchor) private view returns (uint256) { uint256 mintingLimit = _settings.networkTokenMintingLimits(poolAnchor); return mintingLimit > 0 ? mintingLimit : _settings.defaultNetworkTokenMintingLimit(); } /** * @dev returns the amount of pool tokens required for liquidation */ function _liquidationAmount( uint256 targetAmount, Fraction memory poolRate, IDSToken poolToken, uint256 additionalAmount ) private view returns (uint256) { // note that the amount is doubled since it's not possible to liquidate one reserve only uint256 poolAmount = _mulDivF(targetAmount, poolRate.d.mul(2), poolRate.n); // limit the amount of pool tokens by the amount the system/caller holds return Math.min(poolAmount, _systemStore.systemBalance(poolToken).add(additionalAmount)); } /** * @dev withdraw pool tokens from the wallet */ function _withdrawPoolTokens(IDSToken poolToken, uint256 poolAmount) private { _systemStore.decSystemBalance(poolToken, poolAmount); _wallet.withdrawTokens(IReserveToken(address(poolToken)), address(this), poolAmount); } /** * @dev returns `x * y / z` */ function _mulDivF( uint256 x, uint256 y, uint256 z ) private pure returns (uint256) { return x.mul(y).div(z); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; import "./IMintableToken.sol"; /// @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; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; /** * @dev This library provides a set of complex math operations. */ library MathEx { uint256 private constant MAX_EXP_BIT_LEN = 4; uint256 private constant MAX_EXP = 2**MAX_EXP_BIT_LEN - 1; uint256 private constant MAX_UINT256 = uint256(-1); /** * @dev returns the largest integer smaller than or equal to the square root of a 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 */ function ceilSqrt(uint256 num) internal pure returns (uint256) { uint256 x = floorSqrt(num); return x * x == num ? x : x + 1; } /** * @dev computes the product of two given ratios */ function productRatio( uint256 xn, uint256 yn, uint256 xd, uint256 yd ) internal pure returns (uint256, uint256) { uint256 n = mulDivC(xn, yn, MAX_UINT256); uint256 d = mulDivC(xd, yd, MAX_UINT256); uint256 z = n > d ? n : d; if (z > 1) { return (mulDivC(xn, yn, z), mulDivC(xd, yd, z)); } return (xn * yn, xd * yd); } /** * @dev computes a reduced-scalar ratio */ function reducedRatio( uint256 n, uint256 d, uint256 max ) internal pure returns (uint256, uint256) { (uint256 newN, uint256 newD) = (n, d); if (newN > max || newD > max) { (newN, newD) = normalizedRatio(newN, newD, max); } if (newN != newD) { return (newN, newD); } 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 = MAX_UINT256 / 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 newN = a * scale; uint256 newD = unsafeAdd(a, b); // can overflow if (newD >= a) { // no overflow in `a + b` uint256 x = roundDiv(newN, newD); // we can now safely compute `scale - x` uint256 y = scale - x; return (x, y); } if (newN < 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 */ 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 */ function decimalLength(uint256 x) internal pure returns (uint256) { uint256 y = 0; for (uint256 tmpX = x; tmpX > 0; tmpX /= 10) { ++y; } return y; } /** * @dev returns the nearest integer to a given quotient * * note the computation is overflow-safe assuming that the input is sufficiently small */ function roundDivUnsafe(uint256 n, uint256 d) internal pure returns (uint256) { return (n + d / 2) / d; } /** * @dev returns the largest integer smaller than or equal to `x * y / z` */ function mulDivF( uint256 x, uint256 y, uint256 z ) internal pure returns (uint256) { (uint256 xyh, uint256 xyl) = mul512(x, y); // if `x * y < 2 ^ 256` if (xyh == 0) { return xyl / z; } // assert `x * y / z < 2 ^ 256` require(xyh < z, "ERR_OVERFLOW"); uint256 m = mulMod(x, y, z); // `m = x * y % z` (uint256 nh, uint256 nl) = sub512(xyh, xyl, m); // `n = x * y - m` hence `n / z = floor(x * y / z)` // if `n < 2 ^ 256` if (nh == 0) { return nl / z; } uint256 p = unsafeSub(0, z) & z; // `p` is the largest power of 2 which `z` is divisible by uint256 q = div512(nh, nl, p); // `n` is divisible by `p` because `n` is divisible by `z` and `z` is divisible by `p` uint256 r = inv256(z / p); // `z / p = 1 mod 2` hence `inverse(z / p) = 1 mod 2 ^ 256` return unsafeMul(q, r); // `q * r = (n / p) * inverse(z / p) = n / z` } /** * @dev returns the smallest integer larger than or equal to `x * y / z` */ function mulDivC( uint256 x, uint256 y, uint256 z ) internal pure returns (uint256) { uint256 w = mulDivF(x, y, z); if (mulMod(x, y, z) > 0) { require(w < MAX_UINT256, "ERR_OVERFLOW"); return w + 1; } return w; } /** * @dev returns the value of `x * y` as a pair of 256-bit values */ function mul512(uint256 x, uint256 y) private pure returns (uint256, uint256) { uint256 p = mulModMax(x, y); uint256 q = unsafeMul(x, y); if (p >= q) { return (p - q, q); } return (unsafeSub(p, q) - 1, q); } /** * @dev returns the value of `2 ^ 256 * xh + xl - y`, where `2 ^ 256 * xh + xl >= y` */ function sub512( uint256 xh, uint256 xl, uint256 y ) private pure returns (uint256, uint256) { if (xl >= y) { return (xh, xl - y); } return (xh - 1, unsafeSub(xl, y)); } /** * @dev returns the value of `(2 ^ 256 * xh + xl) / pow2n`, where `xl` is divisible by `pow2n` */ function div512( uint256 xh, uint256 xl, uint256 pow2n ) private pure returns (uint256) { uint256 pow2nInv = unsafeAdd(unsafeSub(0, pow2n) / pow2n, 1); // `1 << (256 - n)` return unsafeMul(xh, pow2nInv) | (xl / pow2n); // `(xh << (256 - n)) | (xl >> n)` } /** * @dev returns the inverse of `d` modulo `2 ^ 256`, where `d` is congruent to `1` modulo `2` */ function inv256(uint256 d) private pure returns (uint256) { // approximate the root of `f(x) = 1 / x - d` using the newton–raphson convergence method uint256 x = 1; for (uint256 i = 0; i < 8; ++i) { x = unsafeMul(x, unsafeSub(2, unsafeMul(x, d))); // `x = x * (2 - x * d) mod 2 ^ 256` } return x; } /** * @dev returns `(x + y) % 2 ^ 256` */ function unsafeAdd(uint256 x, uint256 y) private pure returns (uint256) { return x + y; } /** * @dev returns `(x - y) % 2 ^ 256` */ function unsafeSub(uint256 x, uint256 y) private pure returns (uint256) { return x - y; } /** * @dev returns `(x * y) % 2 ^ 256` */ function unsafeMul(uint256 x, uint256 y) private pure returns (uint256) { return x * y; } /** * @dev returns `x * y % (2 ^ 256 - 1)` */ function mulModMax(uint256 x, uint256 y) private pure returns (uint256) { return mulmod(x, y, MAX_UINT256); } /** * @dev returns `x * y % z` */ function mulMod( uint256 x, uint256 y, uint256 z ) private pure returns (uint256) { return mulmod(x, y, z); } }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE 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 }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE 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; } }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @dev Utilities & Common Modifiers */ contract Utils { uint32 internal constant PPM_RESOLUTION = 1000000; // 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 addr) { _validAddress(addr); _; } // error message binary size optimization function _validAddress(address addr) internal pure { require(addr != address(0), "ERR_INVALID_ADDRESS"); } // 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"); } // validates an external address - currently only checks that it isn't null or this modifier validExternalAddress(address addr) { _validExternalAddress(addr); _; } // error message binary size optimization function _validExternalAddress(address addr) internal view { require(addr != address(0) && addr != address(this), "ERR_INVALID_EXTERNAL_ADDRESS"); } // ensures that the fee is valid modifier validFee(uint32 fee) { _validFee(fee); _; } // error message binary size optimization function _validFee(uint32 fee) internal pure { require(fee <= PPM_RESOLUTION, "ERR_INVALID_FEE"); } }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "./interfaces/IOwned.sol"; /** * @dev This contract provides support and utilities for contract ownership. */ contract Owned is IOwned { address private _owner; address private _newOwner; /** * @dev triggered when the owner is updated */ 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() private view { require(msg.sender == _owner, "ERR_ACCESS_DENIED"); } /** * @dev allows transferring the contract ownership * * Requirements: * * - the caller must be the owner of the contract * * note the new owner still needs to accept the transfer */ 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); } /** * @dev returns the address of the current owner */ function owner() public view override returns (address) { return _owner; } /** * @dev returns the address of the new owner candidate */ function newOwner() external view returns (address) { return _newOwner; } }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../converter/interfaces/IConverterAnchor.sol"; import "../../utility/interfaces/IOwned.sol"; /** * @dev DSToken interface */ interface IDSToken is IConverterAnchor, IERC20 { function issue(address recipient, uint256 amount) external; function destroy(address recipient, uint256 amount) external; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./interfaces/IReserveToken.sol"; import "./SafeERC20Ex.sol"; /** * @dev This library implements ERC20 and SafeERC20 utilities for reserve tokens, which can be either ERC20 tokens or ETH */ library ReserveToken { using SafeERC20 for IERC20; using SafeERC20Ex for IERC20; // the address that represents an ETH reserve IReserveToken public constant NATIVE_TOKEN_ADDRESS = IReserveToken(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); /** * @dev returns whether the provided token represents an ERC20 or ETH reserve */ function isNativeToken(IReserveToken reserveToken) internal pure returns (bool) { return reserveToken == NATIVE_TOKEN_ADDRESS; } /** * @dev returns the balance of the reserve token */ function balanceOf(IReserveToken reserveToken, address account) internal view returns (uint256) { if (isNativeToken(reserveToken)) { return account.balance; } return toIERC20(reserveToken).balanceOf(account); } /** * @dev transfers a specific amount of the reserve token */ function safeTransfer( IReserveToken reserveToken, address to, uint256 amount ) internal { if (amount == 0) { return; } if (isNativeToken(reserveToken)) { payable(to).transfer(amount); } else { toIERC20(reserveToken).safeTransfer(to, amount); } } /** * @dev transfers a specific amount of the reserve token from a specific holder using the allowance mechanism * * note that the function ignores a reserve token which represents an ETH reserve */ function safeTransferFrom( IReserveToken reserveToken, address from, address to, uint256 amount ) internal { if (amount == 0 || isNativeToken(reserveToken)) { return; } toIERC20(reserveToken).safeTransferFrom(from, to, amount); } /** * @dev ensures that the spender has sufficient allowance * * note that this function ignores a reserve token which represents an ETH reserve */ function ensureApprove( IReserveToken reserveToken, address spender, uint256 amount ) internal { if (isNativeToken(reserveToken)) { return; } toIERC20(reserveToken).ensureApprove(spender, amount); } /** * @dev utility function that converts an IReserveToken to an IERC20 */ function toIERC20(IReserveToken reserveToken) private pure returns (IERC20) { return IERC20(address(reserveToken)); } }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "../../utility/interfaces/IOwned.sol"; /** * @dev Converter Anchor interface */ interface IConverterAnchor is IOwned { }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IConverterAnchor.sol"; import "../../utility/interfaces/IOwned.sol"; import "../../token/interfaces/IReserveToken.sol"; /** * @dev 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( IReserveToken sourceToken, IReserveToken targetToken, uint256 sourceAmount ) external view returns (uint256, uint256); function convert( IReserveToken sourceToken, IReserveToken targetToken, uint256 sourceAmount, address trader, address payable beneficiary ) external payable returns (uint256); function conversionFee() external view returns (uint32); function maxConversionFee() external view returns (uint32); function reserveBalance(IReserveToken reserveToken) external view returns (uint256); receive() external payable; function transferAnchorOwnership(address newOwner) external; function acceptAnchorOwnership() external; function setConversionFee(uint32 fee) external; function addReserve(IReserveToken token, uint32 weight) external; function transferReservesOnUpgrade(address newConverter) external; function onUpgradeComplete() external; // deprecated, backward compatibility function token() external view returns (IConverterAnchor); function transferTokenOwnership(address newOwner) external; function acceptTokenOwnership() external; function reserveTokenCount() external view returns (uint16); function reserveTokens() external view returns (IReserveToken[] memory); function connectors(IReserveToken reserveToken) external view returns ( uint256, uint32, bool, bool, bool ); function getConnectorBalance(IReserveToken connectorToken) external view returns (uint256); function connectorTokens(uint256 index) external view returns (IReserveToken); function connectorTokenCount() external view returns (uint16); /** * @dev triggered when the converter is activated */ event Activation(uint16 indexed converterType, IConverterAnchor indexed anchor, bool indexed activated); /** * @dev triggered when a conversion between two tokens occurs */ event Conversion( IReserveToken indexed sourceToken, IReserveToken indexed targetToken, address indexed trader, uint256 sourceAmount, uint256 targetAmount, 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 */ event TokenRateUpdate(address indexed token1, address indexed token2, uint256 rateN, uint256 rateD); /** * @dev triggered when the conversion fee is updated */ event ConversionFeeUpdate(uint32 prevFee, uint32 newFee); }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "../../token/interfaces/IReserveToken.sol"; import "./IConverterAnchor.sol"; /** * @dev Converter Registry interface */ 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 (IReserveToken); function isConvertibleToken(address value) external view returns (bool); function getConvertibleTokenAnchorCount(IReserveToken convertibleToken) external view returns (uint256); function getConvertibleTokenAnchors(IReserveToken convertibleToken) external view returns (address[] memory); function getConvertibleTokenAnchor(IReserveToken convertibleToken, uint256 index) external view returns (IConverterAnchor); function isConvertibleTokenAnchor(IReserveToken convertibleToken, address value) external view returns (bool); function getLiquidityPoolByConfig( uint16 converterType, IReserveToken[] memory reserveTokens, uint32[] memory reserveWeights ) external view returns (IConverterAnchor); }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "./ILiquidityProtectionStore.sol"; import "./ILiquidityProtectionStats.sol"; import "./ILiquidityProtectionSettings.sol"; import "./ILiquidityProtectionSystemStore.sol"; import "./ITransferPositionCallback.sol"; import "../../utility/interfaces/ITokenHolder.sol"; import "../../token/interfaces/IReserveToken.sol"; import "../../converter/interfaces/IConverterAnchor.sol"; /** * @dev Liquidity Protection interface */ interface ILiquidityProtection { function store() external view returns (ILiquidityProtectionStore); function stats() external view returns (ILiquidityProtectionStats); function settings() external view returns (ILiquidityProtectionSettings); function addLiquidityFor( address owner, IConverterAnchor poolAnchor, IReserveToken reserveToken, uint256 amount ) external payable returns (uint256); function addLiquidity( IConverterAnchor poolAnchor, IReserveToken reserveToken, uint256 amount ) external payable returns (uint256); function removeLiquidity(uint256 id, uint32 portion) external; function transferPosition(uint256 id, address newProvider) external returns (uint256); function transferPositionAndNotify( uint256 id, address newProvider, ITransferPositionCallback callback, bytes calldata data ) external returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IClaimable.sol"; /// @title Mintable Token interface interface IMintableToken is IERC20, IClaimable { function issue(address to, uint256 amount) external; function destroy(address from, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT 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; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; /** * @dev Owned interface */ interface IOwned { function owner() external view returns (address); function transferOwnership(address newOwner) external; function acceptOwnership() external; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; /** * @dev This contract is used to represent reserve tokens, which are tokens that can either be regular ERC20 tokens or * native ETH (represented by the NATIVE_TOKEN_ADDRESS address) * * Please note that this interface is intentionally doesn't inherit from IERC20, so that it'd be possible to effectively * override its balanceOf() function in the ReserveToken library */ interface IReserveToken { }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; /** * @dev Extends the SafeERC20 library with additional operations */ library SafeERC20Ex { using SafeERC20 for IERC20; /** * @dev ensures that the spender has sufficient allowance */ function ensureApprove( IERC20 token, address spender, uint256 amount ) internal { if (amount == 0) { return; } uint256 allowance = token.allowance(address(this), spender); if (allowance >= amount) { return; } if (allowance > 0) { token.safeApprove(spender, 0); } token.safeApprove(spender, amount); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "../../converter/interfaces/IConverterAnchor.sol"; import "../../token/interfaces/IDSToken.sol"; import "../../token/interfaces/IReserveToken.sol"; import "../../utility/interfaces/IOwned.sol"; /** * @dev Liquidity Protection Store interface */ interface ILiquidityProtectionStore is IOwned { function withdrawTokens( IReserveToken token, address recipient, uint256 amount ) external; function protectedLiquidity(uint256 id) external view returns ( address, IDSToken, IReserveToken, uint256, uint256, uint256, uint256, uint256 ); function addProtectedLiquidity( address provider, IDSToken poolToken, IReserveToken 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(IReserveToken poolToken) external view returns (uint256); function incSystemBalance(IReserveToken poolToken, uint256 poolAmount) external; function decSystemBalance(IReserveToken poolToken, uint256 poolAmount) external; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "../../converter/interfaces/IConverterAnchor.sol"; import "../../token/interfaces/IDSToken.sol"; import "../../token/interfaces/IReserveToken.sol"; /** * @dev Liquidity Protection Stats interface */ interface ILiquidityProtectionStats { function increaseTotalAmounts( address provider, IDSToken poolToken, IReserveToken reserveToken, uint256 poolAmount, uint256 reserveAmount ) external; function decreaseTotalAmounts( address provider, IDSToken poolToken, IReserveToken reserveToken, uint256 poolAmount, uint256 reserveAmount ) external; function addProviderPool(address provider, IDSToken poolToken) external returns (bool); function removeProviderPool(address provider, IDSToken poolToken) external returns (bool); function totalPoolAmount(IDSToken poolToken) external view returns (uint256); function totalReserveAmount(IDSToken poolToken, IReserveToken reserveToken) external view returns (uint256); function totalProviderAmount( address provider, IDSToken poolToken, IReserveToken reserveToken ) external view returns (uint256); function providerPools(address provider) external view returns (IDSToken[] memory); }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "../../converter/interfaces/IConverterAnchor.sol"; import "../../token/interfaces/IReserveToken.sol"; import "./ILiquidityProvisionEventsSubscriber.sol"; /** * @dev Liquidity Protection Settings interface */ interface ILiquidityProtectionSettings { function isPoolWhitelisted(IConverterAnchor poolAnchor) external view returns (bool); function poolWhitelist() external view returns (address[] memory); function subscribers() external view returns (address[] memory); 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 addLiquidityDisabled(IConverterAnchor poolAnchor, IReserveToken reserveToken) external view returns (bool); function minProtectionDelay() external view returns (uint256); function maxProtectionDelay() external view returns (uint256); function minNetworkCompensation() external view returns (uint256); function lockDuration() external view returns (uint256); function averageRateMaxDeviation() external view returns (uint32); }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../converter/interfaces/IConverterAnchor.sol"; /** * @dev Liquidity Protection System Store interface */ interface ILiquidityProtectionSystemStore { function systemBalance(IERC20 poolToken) external view returns (uint256); function incSystemBalance(IERC20 poolToken, uint256 poolAmount) external; function decSystemBalance(IERC20 poolToken, uint256 poolAmount) external; function networkTokensMinted(IConverterAnchor poolAnchor) external view returns (uint256); function incNetworkTokensMinted(IConverterAnchor poolAnchor, uint256 amount) external; function decNetworkTokensMinted(IConverterAnchor poolAnchor, uint256 amount) external; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; /** * @dev Transfer position event callback interface */ interface ITransferPositionCallback { function onTransferPosition( uint256 newId, address provider, bytes calldata data ) external; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "../../token/interfaces/IReserveToken.sol"; import "./IOwned.sol"; /** * @dev Token Holder interface */ interface ITokenHolder is IOwned { receive() external payable; function withdrawTokens( IReserveToken reserveToken, address payable to, uint256 amount ) external; function withdrawTokensMultiple( IReserveToken[] calldata reserveTokens, address payable to, uint256[] calldata amounts ) external; }
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity 0.6.12; import "../../converter/interfaces/IConverterAnchor.sol"; import "../../token/interfaces/IReserveToken.sol"; /** * @dev Liquidity provision events subscriber interface */ interface ILiquidityProvisionEventsSubscriber { function onAddingLiquidity( address provider, IConverterAnchor poolAnchor, IReserveToken reserveToken, uint256 poolAmount, uint256 reserveAmount ) external; function onRemovingLiquidity( uint256 id, address provider, IConverterAnchor poolAnchor, IReserveToken reserveToken, uint256 poolAmount, uint256 reserveAmount ) external; }
{ "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IBancorNetworkV3","name":"networkV3","type":"address"},{"internalType":"address payable","name":"vaultV3","type":"address"},{"internalType":"contract ILiquidityProtectionSettings","name":"settings","type":"address"},{"internalType":"contract ILiquidityProtectionStore","name":"store","type":"address"},{"internalType":"contract ILiquidityProtectionStats","name":"stats","type":"address"},{"internalType":"contract ILiquidityProtectionSystemStore","name":"systemStore","type":"address"},{"internalType":"contract ITokenHolder","name":"wallet","type":"address"},{"internalType":"contract ITokenGovernance","name":"networkTokenGovernance","type":"address"},{"internalType":"contract ITokenGovernance","name":"govTokenGovernance","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":[],"name":"acceptWalletOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor","name":"poolAnchor","type":"address"},{"internalType":"contract IReserveToken","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 IReserveToken","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":[{"components":[{"internalType":"contract IDSToken","name":"poolToken","type":"address"},{"internalType":"contract IReserveToken","name":"reserveToken","type":"address"},{"internalType":"uint256[]","name":"positionIds","type":"uint256[]"}],"internalType":"struct LiquidityProtection.PositionList[]","name":"positionLists","type":"tuple[]"}],"name":"migratePositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor[]","name":"poolAnchors","type":"address[]"}],"name":"migrateSystemPoolTokens","outputs":[],"stateMutability":"nonpayable","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 IConverterAnchor","name":"poolAnchor","type":"address"}],"name":"poolAvailableSpace","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IDSToken","name":"poolToken","type":"address"},{"internalType":"contract IReserveToken","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":"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":"stats","outputs":[{"internalType":"contract ILiquidityProtectionStats","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":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"newProvider","type":"address"}],"name":"transferPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"newProvider","type":"address"},{"internalType":"contract ITransferPositionCallback","name":"callback","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transferPositionAndNotify","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferStoreOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferWalletOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101e06040523480156200001257600080fd5b50604051620060e9380380620060e9833981016040819052620000359162000254565b600080546001600160a01b03191633179055600160025562000057896200021f565b62000062886200021f565b6200006d876200021f565b62000078866200021f565b62000083856200021f565b6200008e846200021f565b62000099836200021f565b6001600160601b031960608a811b821660805289811b821660a05288811b821660c05287811b821660e05286811b82166101005285811b82166101205284811b82166101405283811b82166101805282901b166101c05260408051637e062a3560e11b815290516001600160a01b0384169163fc0c546a916004808301926020929190829003018186803b1580156200013157600080fd5b505afa15801562000146573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016c91906200032a565b6001600160a01b0316610160816001600160a01b031660601b81525050806001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015620001c357600080fd5b505afa158015620001d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001fe91906200032a565b60601b6001600160601b0319166101a052506200039d975050505050505050565b6001600160a01b038116620002515760405162461bcd60e51b8152600401620002489062000350565b60405180910390fd5b50565b60008060008060008060008060006101208a8c03121562000273578485fd5b8951620002808162000387565b60208b0151909950620002938162000387565b60408b0151909850620002a68162000387565b60608b0151909750620002b98162000387565b60808b0151909650620002cc8162000387565b60a08b0151909550620002df8162000387565b60c08b0151909450620002f28162000387565b60e08b0151909350620003058162000387565b6101008b0151909250620003198162000387565b809150509295985092959850929598565b6000602082840312156200033c578081fd5b8151620003498162000387565b9392505050565b60208082526013908201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604082015260600190565b6001600160a01b03811681146200025157600080fd5b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c6101805160601c6101a05160601c6101c05160601c615b6f6200057a6000398061228c528061401d52508061224652508061167952806125545280613aff5250806104fc52806105215280610aed528061196b5280611a855280611e0d528061242452806124ae52806125cd528061263a528061293f5280612a2d5280612ac05280612bef5280613ee35280613fd452806140985250806107555280610ac05280610ed752806112eb528061239952806125ef5280614311525080610441528061126d52806115fb52806119bb5280611ad75280611fab52806121ba52806128a65280613a815280613f4552806141a9528061434552508061111e5280613273528061336752806133eb5250806109165280610a045280610dcc5280610e365280610f605280611c845280613155528061320152806134955280613c27525080610fca528061114252806117ff52806118ba52806120dc5280612cd75280612f575280612ffd52806136ab5280613740528061394b5280613b7652806140d752508061065b528061069b52508061296c5280612a005280612b2a5280612b665250615b6f6000f3fe6080604052600436106101395760003560e01c8063975057e7116100ab578063caee4c8f1161006f578063caee4c8f14610350578063d4ee1d9014610363578063d80528ae14610378578063e06174e41461038d578063e4a76726146103a2578063f2fde38b146103b557610140565b8063975057e7146102bb578063b55bb6c0146102d0578063bf3b1101146102f0578063c2250a9914610310578063c83df6631461033057610140565b8063630d8c63116100fd578063630d8c63146102005780636d533e9b14610220578063782ed90c1461024f57806379ba50971461026f57806389d94b46146102845780638da5cb5b1461029957610140565b80631e83958b1461014557806324afe2d91461016757806328790b5a1461019e57806340083480146101b357806355bd513f146101e057610140565b3661014057005b600080fd5b34801561015157600080fd5b50610165610160366004614f07565b6103d5565b005b34801561017357600080fd5b50610187610182366004614e03565b610719565b604051610195929190615a8f565b60405180910390f35b3480156101aa57600080fd5b5061016561074b565b3480156101bf57600080fd5b506101d36101ce3660046150e3565b6107c8565b6040516101959190615423565b3480156101ec57600080fd5b506101d36101fb3660046150b4565b61088a565b34801561020c57600080fd5b5061016561021b36600461517d565b6108d4565b34801561022c57600080fd5b5061024061023b3660046151e5565b610b59565b60405161019593929190615a9d565b34801561025b57600080fd5b5061016561026a3660046151c1565b610cef565b34801561027b57600080fd5b50610165610d34565b34801561029057600080fd5b50610165610dc2565b3480156102a557600080fd5b506102ae610e25565b60405161019591906152b5565b3480156102c757600080fd5b506102ae610e34565b3480156102dc57600080fd5b506101656102eb366004614f07565b610e58565b3480156102fc57600080fd5b5061016561030b366004614e03565b610eb8565b34801561031c57600080fd5b5061016561032b366004614e03565b610f41565b34801561033c57600080fd5b506101d361034b36600461503b565b610f95565b6101d361035e366004614e3b565b611093565b34801561036f57600080fd5b506102ae61110d565b34801561038457600080fd5b506102ae61111c565b34801561039957600080fd5b506102ae611140565b6101d36103b0366004614ffb565b611164565b3480156103c157600080fd5b506101656103d0366004614e03565b6111d2565b6002805414156104005760405162461bcd60e51b81526004016103f79061590e565b60405180910390fd5b6002805561040c61122a565b8060005b8181101561070e57600084848381811061042657fe5b905060200201602081019061043b9190614e03565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635121220c836040518263ffffffff1660e01b815260040161048b91906152b5565b60206040518083038186803b1580156104a357600080fd5b505afa1580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db919061509c565b90506104e78282611256565b60006104f28361135c565b905060608061054a7f0000000000000000000000000000000000000000000000000000000000000000610545857f00000000000000000000000000000000000000000000000000000000000000006113d5565b6114fd565b915091506060836001600160a01b031663b127c0a58685856040518463ffffffff1660e01b815260040161058093929190615a64565b600060405180830381600087803b15801561059a57600080fd5b505af11580156105ae573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105d69190810190614f47565b90506106168a8a898181106105e757fe5b90506020020160208101906105fc9190614e03565b8260008151811061060957fe5b60200260200101516115e4565b61063c8360018151811061062657fe5b60200260200101516001600160a01b03166116b0565b15610696576106918160018151811061065157fe5b60200260200101517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166116d590919063ffffffff16565b6106fc565b6106fc7f0000000000000000000000000000000000000000000000000000000000000000826001815181106106c757fe5b6020026020010151856001815181106106dc57fe5b60200260200101516001600160a01b03166117769092919063ffffffff16565b50506001909401935061041092505050565b505060016002555050565b60008082610726816117e8565b61072f816118a3565b6107388461195b565b61074185611a80565b9250925050915091565b61075361122a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107ae57600080fd5b505af11580156107c2573d6000803e3d6000fd5b50505050565b60006002805414156107ec5760405162461bcd60e51b81526004016103f79061590e565b60028055846107fa81611b8c565b8461080481611b8c565b6000610811338a8a611bb2565b604051635c2ba84560e01b81529091506001600160a01b03881690635c2ba8459061084690849033908b908b90600401615a1d565b600060405180830381600087803b15801561086057600080fd5b505af1158015610874573d6000803e3d6000fd5b5050600160025550909998505050505050505050565b60006002805414156108ae5760405162461bcd60e51b81526004016103f79061590e565b60028055816108bc81611b8c565b6108c7338585611bb2565b6001600255949350505050565b6002805414156108f65760405162461bcd60e51b81526004016103f79061590e565b60028055604051637a1036f560e11b815260609081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f4206dea9061094f903390889088906004016152e2565b60006040518083038186803b15801561096757600080fd5b505afa15801561097b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109a39190810190614f7a565b9150915060008083519050825181146109b857fe5b805b8015610aa25760001981016109cd611bf9565b8582815181106109d957fe5b602002602001015111156109ed5750610a99565b6040516390e0661b60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906390e0661b90610a3d9033908c8601906004016152c9565b600060405180830381600087803b158015610a5757600080fd5b505af1158015610a6b573d6000803e3d6000fd5b50505050610a95868281518110610a7e57fe5b602002602001015185611bfd90919063ffffffff16565b9350505b600019016109ba565b508115610b4c57604051632f1a9acf60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635e35359e90610b19907f0000000000000000000000000000000000000000000000000000000000000000903390879060040161531d565b600060405180830381600087803b158015610b3357600080fd5b505af1158015610b47573d6000803e3d6000fd5b505050505b5050600160025550505050565b600080600084610b6881611c22565b610b70614c7f565b610b7988611c5d565b80519091506001600160a01b0316610ba35760405162461bcd60e51b81526004016103f79061599b565b8060e00151861015610bc75760405162461bcd60e51b81526004016103f7906159ee565b63ffffffff8716620f424014610bfb57610bf0816060015182608001518963ffffffff16611d44565b608083015260608201525b610c03614cdf565b610c1f826020015183604001518460a001518560c00151611d70565b90506000610c468360200151846040015185606001518660800151868860e001518e611dd4565b9050610c558360400151611e0b565b15610c6b57955085945060009350610ce5915050565b610c73614d14565b610c8584602001518560400151611e3d565b90506000610c9d838387602001518860600151611f79565b90506000610cc7828460000151610cc26002876020015161205490919063ffffffff16565b61208e565b90506000610cd685838861209e565b949a5090985092965050505050505b5093509350939050565b600280541415610d115760405162461bcd60e51b81526004016103f79061590e565b6002805580610d1f81611c22565b610d2a338484612183565b5050600160025550565b6001546001600160a01b03163314610d5e5760405162461bcd60e51b81526004016103f7906159c3565b600154600080546040516001600160a01b0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b610dca61122a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107ae57600080fd5b6000546001600160a01b031690565b7f000000000000000000000000000000000000000000000000000000000000000090565b600280541415610e7a5760405162461bcd60e51b81526004016103f79061590e565b600280558060005b8181101561070e57610eb0848483818110610e9957fe5b9050602002810190610eab9190615afa565b6126e2565b600101610e82565b610ec061122a565b60405163f2fde38b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f2fde38b90610f0c9084906004016152b5565b600060405180830381600087803b158015610f2657600080fd5b505af1158015610f3a573d6000803e3d6000fd5b5050505050565b610f4961122a565b60405163f2fde38b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f2fde38b90610f0c9084906004016152b5565b600080610fa387868861208e565b9050610fad614cdf565b610fb98a8a8787611d70565b905060006110748b8b858c866110677f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ce3f3adb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561102157600080fd5b505afa158015611035573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611059919061509c565b611061611bf9565b90612c98565b61106f611bf9565b611dd4565b905061108481620f42408b61208e565b9b9a5050505050505050505050565b60006002805414156110b75760405162461bcd60e51b81526004016103f79061590e565b60028055846110c581611b8c565b846110cf816117e8565b6110d8816118a3565b85856110e48282612cc0565b856110ee81612d7f565b6110fa8a8a8a8a612d9f565b60016002559a9950505050505050505050565b6001546001600160a01b031690565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006002805414156111885760405162461bcd60e51b81526004016103f79061590e565b6002805583611196816117e8565b61119f816118a3565b84846111ab8282612cc0565b846111b581612d7f565b6111c133898989612d9f565b600160025598975050505050505050565b6111da61122a565b6000546001600160a01b03828116911614156112085760405162461bcd60e51b81526004016103f790615496565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146112545760405162461bcd60e51b81526004016103f7906159c3565b565b604051630671a97960e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906319c6a5e4906112a490859085906004016152c9565b600060405180830381600087803b1580156112be57600080fd5b505af11580156112d2573d6000803e3d6000fd5b5050604051632f1a9acf60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250635e35359e91506113269085903090869060040161531d565b600060405180830381600087803b15801561134057600080fd5b505af1158015611354573d6000803e3d6000fd5b505050505050565b6000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561139757600080fd5b505afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf9190614e1f565b92915050565b600080836001600160a01b03166319b6401560006040518263ffffffff1660e01b81526004016114059190615423565b60206040518083038186803b15801561141d57600080fd5b505afa158015611431573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114559190614e1f565b9050826001600160a01b0316816001600160a01b031614156114f3576040516319b6401560e01b81526001600160a01b038516906319b640159061149e90600190600401615423565b60206040518083038186803b1580156114b657600080fd5b505afa1580156114ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ee9190614e1f565b6114f5565b805b949350505050565b60408051600280825260608281019093528291829181602001602082028036833750506040805160028082526060808301845294955090925090602083019080368337019050509050858260008151811061155457fe5b60200260200101906001600160a01b031690816001600160a01b031681525050848260018151811061158257fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001816000815181106115b157fe5b6020026020010181815250506001816001815181106115cc57fe5b602090810291909101015290925090505b9250929050565b604051634017d1dd60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063802fa3ba9061163290859085906004016152c9565b600060405180830381600087803b15801561164c57600080fd5b505af1158015611660573d6000803e3d6000fd5b5050604051630852cd8d60e31b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692506342966c689150611326908490600401615423565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14919050565b804710156116f55760405162461bcd60e51b81526004016103f7906155c0565b6000826001600160a01b03168260405161170e90612dfe565b60006040518083038185875af1925050503d806000811461174b576040519150601f19603f3d011682016040523d82523d6000602084013e611750565b606091505b50509050806117715760405162461bcd60e51b81526004016103f790615563565b505050565b8061178057611771565b611789836116b0565b156117ca576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156117c4573d6000803e3d6000fd5b50611771565b61177182826117d886612dfe565b6001600160a01b03169190612e01565b604051631a9ec62960e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d4f63148906118349084906004016152b5565b60206040518083038186803b15801561184c57600080fd5b505afa158015611860573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118849190614fdb565b6118a05760405162461bcd60e51b81526004016103f79061575e565b50565b60405163159354c160e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632b26a982906118ef9084906004016152b5565b60206040518083038186803b15801561190757600080fd5b505afa15801561191b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193f9190614fdb565b6118a05760405162461bcd60e51b81526004016103f7906154be565b6000806119678361135c565b90507f0000000000000000000000000000000000000000000000000000000000000000600061199683836113d5565b90506000806119a6858486612e57565b9150915060006119b588612f52565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663350ed8e78a6040518263ffffffff1660e01b8152600401611a0591906152b5565b60206040518083038186803b158015611a1d57600080fd5b505afa158015611a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a55919061509c565b9050600081611a648484613091565b039050611a7281868661208e565b9a9950505050505050505050565b6000817f0000000000000000000000000000000000000000000000000000000000000000611aac614d14565b611ab68383611e3d565b9050611b838160200151611b7d60016110618560000151611b7787600001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635121220c8c6040518263ffffffff1660e01b8152600401611b2191906152b5565b60206040518083038186803b158015611b3957600080fd5b505afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b71919061509c565b90612054565b90611bfd565b906130a8565b95945050505050565b6001600160a01b0381166118a05760405162461bcd60e51b81526004016103f7906157c5565b6000611bbc614c7f565b611bca8585620f42406130da565b9050611bee8382602001518360400151846060015185608001518660e00151613314565b9150505b9392505050565b4290565b6000828201838110156114f35760405162461bcd60e51b81526004016103f79061545f565b60008163ffffffff16118015611c415750620f424063ffffffff821611155b6118a05760405162461bcd60e51b81526004016103f7906158e1565b611c65614c7f565b611c6d614c7f565b604051635290ffbb60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635290ffbb90611cb9908690600401615423565b6101006040518083038186803b158015611cd257600080fd5b505afa158015611ce6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0a9190614e8b565b60e089015260c088015260a0870152608086015260608501526001600160a01b039081166040850152908116602084015216815292915050565b600080611d558584620f424061208e565b611d638585620f424061208e565b915091505b935093915050565b611d78614cdf565b611d80614d14565b611d88614d14565b611d928787613535565b915091506001600160801b0381602001518260000151846020015185600001511717171115611dbd57fe5b611dc985858484613626565b979650505050505050565b6000611dde614d14565b611de88989611e3d565b9050611df2614d14565b611dfc8585613691565b9050611a72828989898561383c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b611e45614d14565b6000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e8057600080fd5b505afa158015611e94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb8919061509c565b90506000611ec58561135c565b90506000816001600160a01b031663d8959512866040518263ffffffff1660e01b8152600401611ef591906152b5565b60206040518083038186803b158015611f0d57600080fd5b505afa158015611f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f45919061509c565b90506040518060400160405280611f6660028461205490919063ffffffff16565b8152602001939093525090949350505050565b600080611f9f86611f986002886020015161205490919063ffffffff16565b875161208e565b905061204a81612045857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635121220c896040518263ffffffff1660e01b8152600401611ff591906152b5565b60206040518083038186803b15801561200d57600080fd5b505afa158015612021573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b77919061509c565b613917565b9695505050505050565b600082612063575060006113cf565b8282028284828161207057fe5b04146114f35760405162461bcd60e51b81526004016103f79061571d565b60006114f582611b7d8686612054565b60008284116120af57506000611bf2565b60006120d884860384608001516001600160801b03168560a001516001600160801b031661208e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a80c76ff6040518163ffffffff1660e01b815260040160206040518083038186803b15801561213357600080fd5b505afa158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b919061509c565b8110612178579050611bf2565b506000949350505050565b61218b614c7f565b6121968484846130da565b60208101516060820151604051631990807d60e11b81529293506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263332100fa926121ef9290916004016152c9565b600060405180830381600087803b15801561220957600080fd5b505af115801561221d573d6000803e3d6000fd5b5050505061222e8160400151611e0b565b156122f3576080810151612270906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169086903090613926565b6080810151604051630852cd8d60e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916342966c68916122c09190600401615423565b600060405180830381600087803b1580156122da57600080fd5b505af11580156122ee573d6000803e3d6000fd5b505050505b6122fb614cdf565b612317826020015183604001518460a001518560c00151611d70565b905061235981604001516001600160801b031682606001516001600160801b031683608001516001600160801b03168460a001516001600160801b0316613947565b60006123808360200151846040015185606001518660800151868860e0015161106f611bf9565b905061238f8360400151611e0b565b156123d5576123c37f0000000000000000000000000000000000000000000000000000000000000000846020015183613a6a565b6123cd8682613b6f565b505050611771565b6123dd614d14565b6123ef84602001518560400151611e3d565b90506000612404838387602001516000611f79565b9050612414856020015182611256565b61244885602001518287604001517f0000000000000000000000000000000000000000000000000000000000000000613cb2565b6040850151600090612463906001600160a01b031630613d57565b604087015190915061247f906001600160a01b03168a83611776565b600061248c85838861209e565b90508015612620576040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a08231906124e39030906004016152b5565b60206040518083038186803b1580156124fb57600080fd5b505afa15801561250f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612533919061509c565b9050818110156125c0576040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f199061258d903090858703906004016152c9565b600060405180830381600087803b1580156125a757600080fd5b505af11580156125bb573d6000803e3d6000fd5b505050505b6126146001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000084612e01565b61261e8b83613b6f565b505b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319061266f9030906004016152b5565b60206040518083038186803b15801561268757600080fd5b505afa15801561269b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bf919061509c565b905080156126d5576126d58860200151826115e4565b5050505050505050505050565b60006126f16020830183614e03565b905060006127056040840160208501614e03565b905061270f614d14565b6127198383611e3d565b9050612723614d14565b61272b614d14565b6127358585613535565b915091506127558260000151836020015183600001518460200151613947565b600080808061276760408b018b615ab3565b9050905060005b8181101561288e5761277e614c7f565b6127a93361278f60408f018f615ab3565b8581811061279957fe5b90506020020135620f42406130da565b90508a6001600160a01b031681602001516001600160a01b03161480156127e55750896001600160a01b031681604001516001600160a01b0316145b6128015760405162461bcd60e51b81526004016103f79061578e565b6060810151612811908790611bfd565b955061282a816080015186611bfd90919063ffffffff16565b9450612834614cdf565b6128488260a001518360c001518b8b613626565b905061287f6128788b8460600151856080015185604051806040016040528060018152602001600181525061383c565b8690611bfd565b9450505080600101905061276e565b50604051631990807d60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063332100fa906128dd908c9088906004016152c9565b600060405180830381600087803b1580156128f757600080fd5b505af115801561290b573d6000803e3d6000fd5b5050505061291888611e0b565b15612a9d57612928308a84613a6a565b60405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390612996907f00000000000000000000000000000000000000000000000000000000000000009086906004016152c9565b602060405180830381600087803b1580156129b057600080fd5b505af11580156129c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e89190614fdb565b50604051633d1c24e760e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633d1c24e790612a5d907f0000000000000000000000000000000000000000000000000000000000000000903390879081908a906004016153f2565b600060405180830381600087803b158015612a7757600080fd5b505af1158015612a8b573d6000803e3d6000fd5b505050505050505050505050506118a0565b6000612aac83898c6000611f79565b9050612ab88a82611256565b612ae48a828b7f0000000000000000000000000000000000000000000000000000000000000000613cb2565b6000612af96001600160a01b038b1630613d57565b90506000612b0f8b6001600160a01b03166116b0565b15612b1b575080612b4f565b612b4f6001600160a01b038c167f000000000000000000000000000000000000000000000000000000000000000084613dfc565b604051633d1c24e760e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633d1c24e7908390612ba5908f9033908b9089908e906004016153f2565b6000604051808303818588803b158015612bbe57600080fd5b505af1158015612bd2573d6000803e3d6000fd5b50506040516370a0823160e01b8152600093506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692506370a082319150612c269030906004016152b5565b60206040518083038186803b158015612c3e57600080fd5b505afa158015612c52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c76919061509c565b90508015612c8857612c888d826115e4565b5050505050505050505050505050565b600082821115612cba5760405162461bcd60e51b81526004016103f79061552c565b50900390565b604051634f2b8d3560e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639e571a6a90612d0e9085908590600401615303565b60206040518083038186803b158015612d2657600080fd5b505afa158015612d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5e9190614fdb565b15612d7b5760405162461bcd60e51b81526004016103f7906154f5565b5050565b600081116118a05760405162461bcd60e51b81526004016103f7906156a4565b6000612daa83611e0b565b15612dcb57612db96000613ebf565b612dc4858584613ede565b90506114f5565b612df2612de0846001600160a01b03166116b0565b612deb576000612ded565b825b613ebf565b611b8385858585614093565b90565b6117718363a9059cbb60e01b8484604051602401612e209291906152c9565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526143e7565b600080846001600160a01b031663d8959512856040518263ffffffff1660e01b8152600401612e8691906152b5565b60206040518083038186803b158015612e9e57600080fd5b505afa158015612eb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed6919061509c565b604051636c4aca8960e11b81526001600160a01b0387169063d895951290612f029087906004016152b5565b60206040518083038186803b158015612f1a57600080fd5b505afa158015612f2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d63919061509c565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663943fd08a846040518263ffffffff1660e01b8152600401612fa191906152b5565b60206040518083038186803b158015612fb957600080fd5b505afa158015612fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff1919061509c565b9050600081116113cf577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b97b55ce6040518163ffffffff1660e01b815260040160206040518083038186803b15801561305457600080fd5b505afa158015613068573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308c919061509c565b611bf2565b6000818310156130a15781611bf2565b5090919050565b60008082116130c95760405162461bcd60e51b81526004016103f79061566d565b8183816130d257fe5b049392505050565b6130e2614c7f565b6130ea614c7f565b6130f48486614476565b905061310381602001516118a3565b61310b611bf9565b8160e001511061312d5760405162461bcd60e51b81526004016103f7906156cc565b63ffffffff8316620f424014156131c157604051636f366b7160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636f366b719061318a908790600401615423565b600060405180830381600087803b1580156131a457600080fd5b505af11580156131b8573d6000803e3d6000fd5b50505050613271565b606081015160808201516131dc828263ffffffff8816611d44565b608085018190526060850182905260405163161139bd60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263b089cde89261323c928b92880391870390600401615a9d565b600060405180830381600087803b15801561325657600080fd5b505af115801561326a573d6000803e3d6000fd5b5050505050505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166327396b6d826000015183602001518460400151856060015186608001516040518663ffffffff1660e01b81526004016132d9959493929190615341565b600060405180830381600087803b1580156132f357600080fd5b505af1158015613307573d6000803e3d6000fd5b5092979650505050505050565b600061331e614d14565b613326614d14565b6133308888613535565b915091506133508260000151836020015183600001518460200151613947565b604051630aa558ef60e41b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aa558ef0906133a4908c908c908c908c908c90600401615341565b600060405180830381600087803b1580156133be57600080fd5b505af11580156133d2573d6000803e3d6000fd5b5050604051637ea5e0f360e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063fd4bc1e69150613424908c908c90600401615303565b602060405180830381600087803b15801561343e57600080fd5b505af1158015613452573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134769190614fdb565b50815160208301516040516361d5f08760e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016926361d5f087926134d6928e928e928e928e928e9290918e90600401615375565b602060405180830381600087803b1580156134f057600080fd5b505af1158015613504573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613528919061509c565b9998505050505050505050565b61353d614d14565b613545614d14565b60006135508561135c565b9050600061355e82866113d5565b905060008061356e848489612e57565b91509150600080856001600160a01b0316631f0181bc8a6040518263ffffffff1660e01b81526004016135a191906152b5565b604080518083038186803b1580156135b857600080fd5b505afa1580156135cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f0919061519e565b60408051808201825296875260208088019690965280518082019091529182529381019390935250919890975095505050505050565b61362e614cdf565b6001600160801b03848617111561364157fe5b506040805160c0810182526001600160801b03958616815293851660208086019190915283518616918501919091529182015184166060840152805184166080840152015190911660a082015290565b613699614d14565b60006136a58385612c98565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632c560f896040518163ffffffff1660e01b815260040160206040518083038186803b15801561370257600080fd5b505afa158015613716573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373a919061509c565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ce3f3adb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561379757600080fd5b505afa1580156137ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137cf919061509c565b9050818310156137fa57604051806040016040528060008152602001600181525093505050506113cf565b80831061382257604051806040016040528060018152602001600181525093505050506113cf565b604080518082019091529283526020830152509392505050565b6000613846614d14565b604051806040016040528085600001516001600160801b0316815260200185602001516001600160801b0316815250905061387f614d14565b50604080518082018252908501516001600160801b03908116825260608601511660208201526138ad614d14565b604051806040016040528087608001516001600160801b031681526020018760a001516001600160801b0316815250905060006138ec898b86866144c6565b90506138f6614d14565b61390085846145cb565b9050611084896139108b85613091565b838a614699565b60008183106130a15781611bf2565b6107c2846323b872dd60e01b858585604051602401612e209392919061531d565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166324a088686040518163ffffffff1660e01b815260040160206040518083038186803b1580156139a257600080fd5b505afa1580156139b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139da919061520b565b620f42400363ffffffff1690506000613a0482611b7184611b71878b61205490919063ffffffff16565b90506000613a1b620f4240611b7185818a8a612054565b90506000613a32620f4240611b7181818c8a612054565b9050818311158015613a445750808211155b613a605760405162461bcd60e51b81526004016103f7906156f3565b5050505050505050565b604051636f566c2760e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063deacd84e90613ab890859085906004016152c9565b600060405180830381600087803b158015613ad257600080fd5b505af1158015613ae6573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692506340c10f199150613b3890869085906004016152c9565b600060405180830381600087803b158015613b5257600080fd5b505af1158015613b66573d6000803e3d6000fd5b50505050505050565b6000613c0d7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663045544436040518163ffffffff1660e01b815260040160206040518083038186803b158015613bcd57600080fd5b505afa158015613be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c05919061509c565b611b77611bf9565b60405163dbae3a5d60e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dbae3a5d90613c60908690869086906004016152e2565b602060405180830381600087803b158015613c7a57600080fd5b505af1158015613c8e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c2919061509c565b6000613cbd8561135c565b9050606080613ccc85856114fd565b60405163b127c0a560e01b815291935091506001600160a01b0384169063b127c0a590613d0190899086908690600401615a64565b600060405180830381600087803b158015613d1b57600080fd5b505af1158015613d2f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613a609190810190614f47565b6000613d62836116b0565b15613d7857506001600160a01b038116316113cf565b613d8183612dfe565b6001600160a01b03166370a08231836040518263ffffffff1660e01b8152600401613dac91906152b5565b60206040518083038186803b158015613dc457600080fd5b505afa158015613dd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf2919061509c565b801580613e845750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90613e329030908690600401615303565b60206040518083038186803b158015613e4a57600080fd5b505afa158015613e5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e82919061509c565b155b613ea05760405162461bcd60e51b81526004016103f790615945565b6117718363095ea7b360e01b8484604051602401612e209291906152c9565b8034146118a05760405162461bcd60e51b81526004016103f7906157f2565b6000827f0000000000000000000000000000000000000000000000000000000000000000613f0a614d14565b613f148383611e3d565b90506000613f2b868360200151846000015161208e565b604051630671a97960e21b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906319c6a5e490613f7c90879085906004016152c9565b600060405180830381600087803b158015613f9657600080fd5b505af1158015613faa573d6000803e3d6000fd5b505050506000613fc5898686858b613fc0611bf9565b613314565b9050613ffc6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308a613926565b61400688886115e4565b6040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990614054908c908b906004016152c9565b600060405180830381600087803b15801561406e57600080fd5b505af1158015614082573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000837f0000000000000000000000000000000000000000000000000000000000000000826140c18361135c565b90506000806140d1838986612e57565b915091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166312588d0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561412e57600080fd5b505afa158015614142573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614166919061509c565b8110156141855760405162461bcd60e51b81526004016103f790615829565b600061419288838561208e565b9050600061419f8b612f52565b905060006141f3837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663350ed8e78f6040518263ffffffff1660e01b8152600401611ff591906152b5565b9050818111156142155760405162461bcd60e51b81526004016103f79061563d565b614220308d85613a6a565b6142346001600160a01b038816878561471b565b6142468b6001600160a01b03166116b0565b6142735761425f6001600160a01b038c1633308d61474c565b6142736001600160a01b038c16878c61471b565b614281868c898d8734614787565b6040516370a0823160e01b81526000906001600160a01b038a16906370a08231906142b09030906004016152b5565b60206040518083038186803b1580156142c857600080fd5b505afa1580156142dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614300919061509c565b90506143366001600160a01b038a167f000000000000000000000000000000000000000000000000000000000000000083612e01565b604051631990807d60e11b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063332100fa90614389908c90600286048603906004016152c9565b600060405180830381600087803b1580156143a357600080fd5b505af11580156143b7573d6000803e3d6000fd5b505050506143d58e8a8e600285816143cb57fe5b048f613fc0611bf9565b9e9d5050505050505050505050505050565b606061443c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148c79092919063ffffffff16565b805190915015611771578080602001905181019061445a9190614fdb565b6117715760405162461bcd60e51b81526004016103f790615897565b61447e614c7f565b614486614c7f565b61448f84611c5d565b9050826001600160a01b031681600001516001600160a01b0316146114f35760405162461bcd60e51b81526004016103f7906159c3565b82518151602084015160009283926144eb92611b71916144e69190612054565b6148d6565b9050600061451a8660200151611b716145158760200151896000015161205490919063ffffffff16565b6148f6565b90508187028783828161452957fe5b0414156145445781818161453957fe5b0493505050506114f5565b600080898511614555578985614558565b848a5b915091506000806145758487856000198161456f57fe5b0461494c565b91509150600061458f8488878161458857fe5b0490612054565b905081156145bb576145ac8183868602816145a657fe5b04613091565b985050505050505050506114f5565b9c9b505050505050505050505050565b6145d3614d14565b602083015182516000916145e79190612054565b845160208501519192506000916145fd91612054565b905081810260008284838161460e57fe5b041461462c5761461d836148f6565b614626856148f6565b02614635565b614635826148f6565b905060006146438585611bfd565b905060028106614676576002810490506040518060400160405280838303815260200182815250955050505050506113cf565b604080518082019091526002909202810382526020820152935050505092915050565b805160009081906146aa9087612054565b602084015190915060006146c76146c18484613091565b88613091565b90506000806146e488600001518960200151856000198161456f57fe5b9092509050611a726147036146f98387612054565b611b7d8589612054565b611b7783611b7d6147148288612c98565b8e90612054565b614724836116b0565b1561472e57611771565b611771828261473c86612dfe565b6001600160a01b03169190614994565b80158061475d575061475d846116b0565b15614767576107c2565b6107c283838361477688612dfe565b6001600160a01b0316929190613926565b60408051600280825260608083018452926020830190803683375050604080516002808252606080830184529495509092509060208301908036833701905050905086826000815181106147d757fe5b60200260200101906001600160a01b031690816001600160a01b031681525050858260018151811061480557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050848160008151811061483357fe5b602002602001018181525050838160018151811061484d57fe5b6020908102919091010152604051637d8916bd60e01b81526001600160a01b03891690637d8916bd90859061488b90869086906001906004016153bc565b6000604051808303818588803b1580156148a457600080fd5b505af11580156148b8573d6000803e3d6000fd5b50505050505050505050505050565b60606114f58484600085614a5d565b6000806148e2836148f6565b905082818202146113cf5780600101611bf2565b6000806002830460010190506000600282858161490f57fe5b0483018161491957fe5b0490505b8082111561494557809150600282858161493357fe5b0483018161493d57fe5b04905061491d565b5092915050565b60008084848482118061495e57508481115b156149745761496e828287614b13565b90925090505b808214614985579092509050611d68565b50600196879650945050505050565b8061499e57611771565b604051636eb1769f60e11b81526000906001600160a01b0385169063dd62ed3e906149cf9030908790600401615303565b60206040518083038186803b1580156149e757600080fd5b505afa1580156149fb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a1f919061509c565b9050818110614a2e5750611771565b8015614a4957614a496001600160a01b038516846000613dfc565b6107c26001600160a01b0385168484613dfc565b606082471015614a7f5760405162461bcd60e51b81526004016103f7906155f7565b614a8885614b4c565b614aa45760405162461bcd60e51b81526004016103f790615860565b60006060866001600160a01b03168587604051614ac19190615299565b60006040518083038185875af1925050503d8060008114614afe576040519150601f19603f3d011682016040523d82523d6000602084013e614b03565b606091505b5091509150611dc9828286614b52565b600080838511614b3157614b28858585614b8b565b91509150611d68565b600080614b3f868887614b8b565b9890975095505050505050565b3b151590565b60608315614b61575081611bf2565b825115614b715782518084602001fd5b8160405162461bcd60e51b81526004016103f7919061542c565b60008060008360001981614b9b57fe5b04905080861115614bd4576000816001018781614bb457fe5b046001019050808781614bc357fe5b049650808681614bcf57fe5b049550505b848614614c3f578584026000614bea8888614c4f565b9050878110614c10576000614bff8383614c53565b955050508385039250611d68915050565b6002888803048703821015614c2e5760008694509450505050611d68565b600180870394509450505050611d68565b5050600290910493849350915050565b0190565b6000600282048203828481614c6457fe5b0681614c6c57fe5b04828481614c7657fe5b04019392505050565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604051806040016040528060008152602001600081525090565b60008083601f840112614d3f578182fd5b50813567ffffffffffffffff811115614d56578182fd5b60208301915083602080830285010111156115dd57600080fd5b600082601f830112614d80578081fd5b815167ffffffffffffffff80821115614d97578283fd5b602080830260405182828201018181108582111715614db4578687fd5b604052848152945081850192508582018187018301881015614dd557600080fd5b600091505b84821015614df8578051845292820192600191909101908201614dda565b505050505092915050565b600060208284031215614e14578081fd5b81356114f381615b3b565b600060208284031215614e30578081fd5b81516114f381615b3b565b60008060008060808587031215614e50578283fd5b8435614e5b81615b3b565b93506020850135614e6b81615b3b565b92506040850135614e7b81615b3b565b9396929550929360600135925050565b600080600080600080600080610100898b031215614ea7578384fd5b8851614eb281615b3b565b60208a0151909850614ec381615b3b565b60408a0151909750614ed481615b3b565b60608a015160808b015160a08c015160c08d015160e0909d01519b9e9a9d50929b919a9099929850909650945092505050565b60008060208385031215614f19578182fd5b823567ffffffffffffffff811115614f2f578283fd5b614f3b85828601614d2e565b90969095509350505050565b600060208284031215614f58578081fd5b815167ffffffffffffffff811115614f6e578182fd5b6114f584828501614d70565b60008060408385031215614f8c578182fd5b825167ffffffffffffffff80821115614fa3578384fd5b614faf86838701614d70565b93506020850151915080821115614fc4578283fd5b50614fd185828601614d70565b9150509250929050565b600060208284031215614fec578081fd5b815180151581146114f3578182fd5b60008060006060848603121561500f578081fd5b833561501a81615b3b565b9250602084013561502a81615b3b565b929592945050506040919091013590565b600080600080600080600060e0888a031215615055578081fd5b873561506081615b3b565b9650602088013561507081615b3b565b96999698505050506040850135946060810135946080820135945060a0820135935060c0909101359150565b6000602082840312156150ad578081fd5b5051919050565b600080604083850312156150c6578182fd5b8235915060208301356150d881615b3b565b809150509250929050565b6000806000806000608086880312156150fa578283fd5b85359450602086013561510c81615b3b565b9350604086013561511c81615b3b565b9250606086013567ffffffffffffffff80821115615138578283fd5b818801915088601f83011261514b578283fd5b813581811115615159578384fd5b89602082850101111561516a578384fd5b9699959850939650602001949392505050565b6000806040838503121561518f578182fd5b50508035926020909101359150565b600080604083850312156151b0578182fd5b505080516020909101519092909150565b600080604083850312156151d3578182fd5b8235915060208301356150d881615b50565b6000806000606084860312156151f9578081fd5b83359250602084013561502a81615b50565b60006020828403121561521c578081fd5b81516114f381615b50565b6000815180845260208085019450808401835b8381101561525f5781516001600160a01b03168752958201959082019060010161523a565b509495945050505050565b6000815180845260208085019450808401835b8381101561525f5781518752958201959082019060010161527d565b600082516152ab818460208701615b0f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b03988916815296881660208801529490961660408601526060850192909252608084015260a083015260c082019290925260e08101919091526101000190565b6000606082526153cf6060830186615227565b82810360208401526153e1818661526a565b915050826040830152949350505050565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b90815260200190565b600060208252825180602084015261544b816040850160208701615b0f565b601f01601f19169190910160400192915050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600e908201526d22a9292fa9a0a6a2afa7aba722a960911b604082015260600190565b60208082526018908201527f4552525f504f4f4c5f4e4f545f57484954454c49535445440000000000000000604082015260600190565b6020808252601a908201527f4552525f4144445f4c49515549444954595f44495341424c4544000000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252603a908201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260408201527f6563697069656e74206d61792068617665207265766572746564000000000000606082015260800190565b6020808252601d908201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b60208082526016908201527511549497d3505617d05353d5539517d4915050d2115160521b604082015260600190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252600e908201526d4552525f5a45524f5f56414c554560901b604082015260600190565b6020808252600d908201526c4552525f544f4f5f4541524c5960981b604082015260600190565b60208082526010908201526f4552525f494e56414c49445f5241544560801b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526016908201527511549497d413d3d317d393d517d4d5541413d495115160521b604082015260600190565b60208082526019908201527f4552525f494e56414c49445f504f534954494f4e5f4c49535400000000000000604082015260600190565b6020808252601390820152724552525f494e56414c49445f4144445245535360681b604082015260600190565b60208082526017908201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604082015260600190565b60208082526018908201527f4552525f4e4f545f454e4f5547485f4c49515549444954590000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526013908201527222a9292fa4a72b20a624a22fa827a92a24a7a760691b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b6020808252600e908201526d11549497d253959053125117d25160921b604082015260600190565b60208082526011908201527011549497d050d0d154d4d7d11153925151607a1b604082015260600190565b60208082526015908201527404552525f494e56414c49445f54494d455354414d5605c1b604082015260600190565b8481526001600160a01b03841660208201526060604082018190528101829052600082846080840137818301608090810191909152601f909201601f191601019392505050565b600084825260606020830152615a7d6060830185615227565b828103604084015261204a818561526a565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000808335601e19843603018112615ac9578283fd5b83018035915067ffffffffffffffff821115615ae3578283fd5b60209081019250810236038213156115dd57600080fd5b60008235605e198336030181126152ab578182fd5b60005b83811015615b2a578181015183820152602001615b12565b838111156107c25750506000910152565b6001600160a01b03811681146118a057600080fd5b63ffffffff811681146118a057600080fdfea164736f6c634300060c000a000000000000000000000000eef417e1d5cc832e619ae18d2f140de2999dd4fb000000000000000000000000649765821d9f64198c905ec0b2b037a4a52bc373000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf46000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb550000000000000000000000009712bb50dc6efb8a3d7d12cea500a50967d2d471000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b87131000000000000000000000000d1d846312b819743974786050848d9b3d06b9b55000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2440000000000000000000000000887ae1251e180d7d453aedebee26e1639f20113
Deployed Bytecode
0x6080604052600436106101395760003560e01c8063975057e7116100ab578063caee4c8f1161006f578063caee4c8f14610350578063d4ee1d9014610363578063d80528ae14610378578063e06174e41461038d578063e4a76726146103a2578063f2fde38b146103b557610140565b8063975057e7146102bb578063b55bb6c0146102d0578063bf3b1101146102f0578063c2250a9914610310578063c83df6631461033057610140565b8063630d8c63116100fd578063630d8c63146102005780636d533e9b14610220578063782ed90c1461024f57806379ba50971461026f57806389d94b46146102845780638da5cb5b1461029957610140565b80631e83958b1461014557806324afe2d91461016757806328790b5a1461019e57806340083480146101b357806355bd513f146101e057610140565b3661014057005b600080fd5b34801561015157600080fd5b50610165610160366004614f07565b6103d5565b005b34801561017357600080fd5b50610187610182366004614e03565b610719565b604051610195929190615a8f565b60405180910390f35b3480156101aa57600080fd5b5061016561074b565b3480156101bf57600080fd5b506101d36101ce3660046150e3565b6107c8565b6040516101959190615423565b3480156101ec57600080fd5b506101d36101fb3660046150b4565b61088a565b34801561020c57600080fd5b5061016561021b36600461517d565b6108d4565b34801561022c57600080fd5b5061024061023b3660046151e5565b610b59565b60405161019593929190615a9d565b34801561025b57600080fd5b5061016561026a3660046151c1565b610cef565b34801561027b57600080fd5b50610165610d34565b34801561029057600080fd5b50610165610dc2565b3480156102a557600080fd5b506102ae610e25565b60405161019591906152b5565b3480156102c757600080fd5b506102ae610e34565b3480156102dc57600080fd5b506101656102eb366004614f07565b610e58565b3480156102fc57600080fd5b5061016561030b366004614e03565b610eb8565b34801561031c57600080fd5b5061016561032b366004614e03565b610f41565b34801561033c57600080fd5b506101d361034b36600461503b565b610f95565b6101d361035e366004614e3b565b611093565b34801561036f57600080fd5b506102ae61110d565b34801561038457600080fd5b506102ae61111c565b34801561039957600080fd5b506102ae611140565b6101d36103b0366004614ffb565b611164565b3480156103c157600080fd5b506101656103d0366004614e03565b6111d2565b6002805414156104005760405162461bcd60e51b81526004016103f79061590e565b60405180910390fd5b6002805561040c61122a565b8060005b8181101561070e57600084848381811061042657fe5b905060200201602081019061043b9190614e03565b905060007f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b871316001600160a01b0316635121220c836040518263ffffffff1660e01b815260040161048b91906152b5565b60206040518083038186803b1580156104a357600080fd5b505afa1580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db919061509c565b90506104e78282611256565b60006104f28361135c565b905060608061054a7f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c610545857f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c6113d5565b6114fd565b915091506060836001600160a01b031663b127c0a58685856040518463ffffffff1660e01b815260040161058093929190615a64565b600060405180830381600087803b15801561059a57600080fd5b505af11580156105ae573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105d69190810190614f47565b90506106168a8a898181106105e757fe5b90506020020160208101906105fc9190614e03565b8260008151811061060957fe5b60200260200101516115e4565b61063c8360018151811061062657fe5b60200260200101516001600160a01b03166116b0565b15610696576106918160018151811061065157fe5b60200260200101517f000000000000000000000000649765821d9f64198c905ec0b2b037a4a52bc3736001600160a01b03166116d590919063ffffffff16565b6106fc565b6106fc7f000000000000000000000000649765821d9f64198c905ec0b2b037a4a52bc373826001815181106106c757fe5b6020026020010151856001815181106106dc57fe5b60200260200101516001600160a01b03166117769092919063ffffffff16565b50506001909401935061041092505050565b505060016002555050565b60008082610726816117e8565b61072f816118a3565b6107388461195b565b61074185611a80565b9250925050915091565b61075361122a565b7f000000000000000000000000d1d846312b819743974786050848d9b3d06b9b556001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107ae57600080fd5b505af11580156107c2573d6000803e3d6000fd5b50505050565b60006002805414156107ec5760405162461bcd60e51b81526004016103f79061590e565b60028055846107fa81611b8c565b8461080481611b8c565b6000610811338a8a611bb2565b604051635c2ba84560e01b81529091506001600160a01b03881690635c2ba8459061084690849033908b908b90600401615a1d565b600060405180830381600087803b15801561086057600080fd5b505af1158015610874573d6000803e3d6000fd5b5050600160025550909998505050505050505050565b60006002805414156108ae5760405162461bcd60e51b81526004016103f79061590e565b60028055816108bc81611b8c565b6108c7338585611bb2565b6001600255949350505050565b6002805414156108f65760405162461bcd60e51b81526004016103f79061590e565b60028055604051637a1036f560e11b815260609081906001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55169063f4206dea9061094f903390889088906004016152e2565b60006040518083038186803b15801561096757600080fd5b505afa15801561097b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109a39190810190614f7a565b9150915060008083519050825181146109b857fe5b805b8015610aa25760001981016109cd611bf9565b8582815181106109d957fe5b602002602001015111156109ed5750610a99565b6040516390e0661b60e01b81526001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb5516906390e0661b90610a3d9033908c8601906004016152c9565b600060405180830381600087803b158015610a5757600080fd5b505af1158015610a6b573d6000803e3d6000fd5b50505050610a95868281518110610a7e57fe5b602002602001015185611bfd90919063ffffffff16565b9350505b600019016109ba565b508115610b4c57604051632f1a9acf60e11b81526001600160a01b037f000000000000000000000000d1d846312b819743974786050848d9b3d06b9b551690635e35359e90610b19907f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c903390879060040161531d565b600060405180830381600087803b158015610b3357600080fd5b505af1158015610b47573d6000803e3d6000fd5b505050505b5050600160025550505050565b600080600084610b6881611c22565b610b70614c7f565b610b7988611c5d565b80519091506001600160a01b0316610ba35760405162461bcd60e51b81526004016103f79061599b565b8060e00151861015610bc75760405162461bcd60e51b81526004016103f7906159ee565b63ffffffff8716620f424014610bfb57610bf0816060015182608001518963ffffffff16611d44565b608083015260608201525b610c03614cdf565b610c1f826020015183604001518460a001518560c00151611d70565b90506000610c468360200151846040015185606001518660800151868860e001518e611dd4565b9050610c558360400151611e0b565b15610c6b57955085945060009350610ce5915050565b610c73614d14565b610c8584602001518560400151611e3d565b90506000610c9d838387602001518860600151611f79565b90506000610cc7828460000151610cc26002876020015161205490919063ffffffff16565b61208e565b90506000610cd685838861209e565b949a5090985092965050505050505b5093509350939050565b600280541415610d115760405162461bcd60e51b81526004016103f79061590e565b6002805580610d1f81611c22565b610d2a338484612183565b5050600160025550565b6001546001600160a01b03163314610d5e5760405162461bcd60e51b81526004016103f7906159c3565b600154600080546040516001600160a01b0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b610dca61122a565b7f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb556001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156107ae57600080fd5b6000546001600160a01b031690565b7f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb5590565b600280541415610e7a5760405162461bcd60e51b81526004016103f79061590e565b600280558060005b8181101561070e57610eb0848483818110610e9957fe5b9050602002810190610eab9190615afa565b6126e2565b600101610e82565b610ec061122a565b60405163f2fde38b60e01b81526001600160a01b037f000000000000000000000000d1d846312b819743974786050848d9b3d06b9b55169063f2fde38b90610f0c9084906004016152b5565b600060405180830381600087803b158015610f2657600080fd5b505af1158015610f3a573d6000803e3d6000fd5b5050505050565b610f4961122a565b60405163f2fde38b60e01b81526001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55169063f2fde38b90610f0c9084906004016152b5565b600080610fa387868861208e565b9050610fad614cdf565b610fb98a8a8787611d70565b905060006110748b8b858c866110677f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b031663ce3f3adb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561102157600080fd5b505afa158015611035573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611059919061509c565b611061611bf9565b90612c98565b61106f611bf9565b611dd4565b905061108481620f42408b61208e565b9b9a5050505050505050505050565b60006002805414156110b75760405162461bcd60e51b81526004016103f79061590e565b60028055846110c581611b8c565b846110cf816117e8565b6110d8816118a3565b85856110e48282612cc0565b856110ee81612d7f565b6110fa8a8a8a8a612d9f565b60016002559a9950505050505050505050565b6001546001600160a01b031690565b7f0000000000000000000000009712bb50dc6efb8a3d7d12cea500a50967d2d47190565b7f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf4690565b60006002805414156111885760405162461bcd60e51b81526004016103f79061590e565b6002805583611196816117e8565b61119f816118a3565b84846111ab8282612cc0565b846111b581612d7f565b6111c133898989612d9f565b600160025598975050505050505050565b6111da61122a565b6000546001600160a01b03828116911614156112085760405162461bcd60e51b81526004016103f790615496565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146112545760405162461bcd60e51b81526004016103f7906159c3565b565b604051630671a97960e21b81526001600160a01b037f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b8713116906319c6a5e4906112a490859085906004016152c9565b600060405180830381600087803b1580156112be57600080fd5b505af11580156112d2573d6000803e3d6000fd5b5050604051632f1a9acf60e11b81526001600160a01b037f000000000000000000000000d1d846312b819743974786050848d9b3d06b9b55169250635e35359e91506113269085903090869060040161531d565b600060405180830381600087803b15801561134057600080fd5b505af1158015611354573d6000803e3d6000fd5b505050505050565b6000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561139757600080fd5b505afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf9190614e1f565b92915050565b600080836001600160a01b03166319b6401560006040518263ffffffff1660e01b81526004016114059190615423565b60206040518083038186803b15801561141d57600080fd5b505afa158015611431573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114559190614e1f565b9050826001600160a01b0316816001600160a01b031614156114f3576040516319b6401560e01b81526001600160a01b038516906319b640159061149e90600190600401615423565b60206040518083038186803b1580156114b657600080fd5b505afa1580156114ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ee9190614e1f565b6114f5565b805b949350505050565b60408051600280825260608281019093528291829181602001602082028036833750506040805160028082526060808301845294955090925090602083019080368337019050509050858260008151811061155457fe5b60200260200101906001600160a01b031690816001600160a01b031681525050848260018151811061158257fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506001816000815181106115b157fe5b6020026020010181815250506001816001815181106115cc57fe5b602090810291909101015290925090505b9250929050565b604051634017d1dd60e11b81526001600160a01b037f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b87131169063802fa3ba9061163290859085906004016152c9565b600060405180830381600087803b15801561164c57600080fd5b505af1158015611660573d6000803e3d6000fd5b5050604051630852cd8d60e31b81526001600160a01b037f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2441692506342966c689150611326908490600401615423565b6001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14919050565b804710156116f55760405162461bcd60e51b81526004016103f7906155c0565b6000826001600160a01b03168260405161170e90612dfe565b60006040518083038185875af1925050503d806000811461174b576040519150601f19603f3d011682016040523d82523d6000602084013e611750565b606091505b50509050806117715760405162461bcd60e51b81526004016103f790615563565b505050565b8061178057611771565b611789836116b0565b156117ca576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156117c4573d6000803e3d6000fd5b50611771565b61177182826117d886612dfe565b6001600160a01b03169190612e01565b604051631a9ec62960e31b81526001600160a01b037f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf46169063d4f63148906118349084906004016152b5565b60206040518083038186803b15801561184c57600080fd5b505afa158015611860573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118849190614fdb565b6118a05760405162461bcd60e51b81526004016103f79061575e565b50565b60405163159354c160e11b81526001600160a01b037f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf461690632b26a982906118ef9084906004016152b5565b60206040518083038186803b15801561190757600080fd5b505afa15801561191b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193f9190614fdb565b6118a05760405162461bcd60e51b81526004016103f7906154be565b6000806119678361135c565b90507f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c600061199683836113d5565b90506000806119a6858486612e57565b9150915060006119b588612f52565b905060007f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b871316001600160a01b031663350ed8e78a6040518263ffffffff1660e01b8152600401611a0591906152b5565b60206040518083038186803b158015611a1d57600080fd5b505afa158015611a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a55919061509c565b9050600081611a648484613091565b039050611a7281868661208e565b9a9950505050505050505050565b6000817f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c611aac614d14565b611ab68383611e3d565b9050611b838160200151611b7d60016110618560000151611b7787600001517f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b871316001600160a01b0316635121220c8c6040518263ffffffff1660e01b8152600401611b2191906152b5565b60206040518083038186803b158015611b3957600080fd5b505afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b71919061509c565b90612054565b90611bfd565b906130a8565b95945050505050565b6001600160a01b0381166118a05760405162461bcd60e51b81526004016103f7906157c5565b6000611bbc614c7f565b611bca8585620f42406130da565b9050611bee8382602001518360400151846060015185608001518660e00151613314565b9150505b9392505050565b4290565b6000828201838110156114f35760405162461bcd60e51b81526004016103f79061545f565b60008163ffffffff16118015611c415750620f424063ffffffff821611155b6118a05760405162461bcd60e51b81526004016103f7906158e1565b611c65614c7f565b611c6d614c7f565b604051635290ffbb60e01b81526001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb551690635290ffbb90611cb9908690600401615423565b6101006040518083038186803b158015611cd257600080fd5b505afa158015611ce6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0a9190614e8b565b60e089015260c088015260a0870152608086015260608501526001600160a01b039081166040850152908116602084015216815292915050565b600080611d558584620f424061208e565b611d638585620f424061208e565b915091505b935093915050565b611d78614cdf565b611d80614d14565b611d88614d14565b611d928787613535565b915091506001600160801b0381602001518260000151846020015185600001511717171115611dbd57fe5b611dc985858484613626565b979650505050505050565b6000611dde614d14565b611de88989611e3d565b9050611df2614d14565b611dfc8585613691565b9050611a72828989898561383c565b7f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c6001600160a01b0390811691161490565b611e45614d14565b6000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e8057600080fd5b505afa158015611e94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb8919061509c565b90506000611ec58561135c565b90506000816001600160a01b031663d8959512866040518263ffffffff1660e01b8152600401611ef591906152b5565b60206040518083038186803b158015611f0d57600080fd5b505afa158015611f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f45919061509c565b90506040518060400160405280611f6660028461205490919063ffffffff16565b8152602001939093525090949350505050565b600080611f9f86611f986002886020015161205490919063ffffffff16565b875161208e565b905061204a81612045857f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b871316001600160a01b0316635121220c896040518263ffffffff1660e01b8152600401611ff591906152b5565b60206040518083038186803b15801561200d57600080fd5b505afa158015612021573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b77919061509c565b613917565b9695505050505050565b600082612063575060006113cf565b8282028284828161207057fe5b04146114f35760405162461bcd60e51b81526004016103f79061571d565b60006114f582611b7d8686612054565b60008284116120af57506000611bf2565b60006120d884860384608001516001600160801b03168560a001516001600160801b031661208e565b90507f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b031663a80c76ff6040518163ffffffff1660e01b815260040160206040518083038186803b15801561213357600080fd5b505afa158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b919061509c565b8110612178579050611bf2565b506000949350505050565b61218b614c7f565b6121968484846130da565b60208101516060820151604051631990807d60e11b81529293506001600160a01b037f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b87131169263332100fa926121ef9290916004016152c9565b600060405180830381600087803b15801561220957600080fd5b505af115801561221d573d6000803e3d6000fd5b5050505061222e8160400151611e0b565b156122f3576080810151612270906001600160a01b037f00000000000000000000000048fb253446873234f2febbf9bdeaa72d9d387f94169086903090613926565b6080810151604051630852cd8d60e31b81526001600160a01b037f0000000000000000000000000887ae1251e180d7d453aedebee26e1639f2011316916342966c68916122c09190600401615423565b600060405180830381600087803b1580156122da57600080fd5b505af11580156122ee573d6000803e3d6000fd5b505050505b6122fb614cdf565b612317826020015183604001518460a001518560c00151611d70565b905061235981604001516001600160801b031682606001516001600160801b031683608001516001600160801b03168460a001516001600160801b0316613947565b60006123808360200151846040015185606001518660800151868860e0015161106f611bf9565b905061238f8360400151611e0b565b156123d5576123c37f000000000000000000000000d1d846312b819743974786050848d9b3d06b9b55846020015183613a6a565b6123cd8682613b6f565b505050611771565b6123dd614d14565b6123ef84602001518560400151611e3d565b90506000612404838387602001516000611f79565b9050612414856020015182611256565b61244885602001518287604001517f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c613cb2565b6040850151600090612463906001600160a01b031630613d57565b604087015190915061247f906001600160a01b03168a83611776565b600061248c85838861209e565b90508015612620576040516370a0823160e01b81526000906001600160a01b037f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c16906370a08231906124e39030906004016152b5565b60206040518083038186803b1580156124fb57600080fd5b505afa15801561250f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612533919061509c565b9050818110156125c0576040516340c10f1960e01b81526001600160a01b037f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc24416906340c10f199061258d903090858703906004016152c9565b600060405180830381600087803b1580156125a757600080fd5b505af11580156125bb573d6000803e3d6000fd5b505050505b6126146001600160a01b037f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c167f000000000000000000000000d1d846312b819743974786050848d9b3d06b9b5584612e01565b61261e8b83613b6f565b505b6040516370a0823160e01b81526000906001600160a01b037f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c16906370a082319061266f9030906004016152b5565b60206040518083038186803b15801561268757600080fd5b505afa15801561269b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bf919061509c565b905080156126d5576126d58860200151826115e4565b5050505050505050505050565b60006126f16020830183614e03565b905060006127056040840160208501614e03565b905061270f614d14565b6127198383611e3d565b9050612723614d14565b61272b614d14565b6127358585613535565b915091506127558260000151836020015183600001518460200151613947565b600080808061276760408b018b615ab3565b9050905060005b8181101561288e5761277e614c7f565b6127a93361278f60408f018f615ab3565b8581811061279957fe5b90506020020135620f42406130da565b90508a6001600160a01b031681602001516001600160a01b03161480156127e55750896001600160a01b031681604001516001600160a01b0316145b6128015760405162461bcd60e51b81526004016103f79061578e565b6060810151612811908790611bfd565b955061282a816080015186611bfd90919063ffffffff16565b9450612834614cdf565b6128488260a001518360c001518b8b613626565b905061287f6128788b8460600151856080015185604051806040016040528060018152602001600181525061383c565b8690611bfd565b9450505080600101905061276e565b50604051631990807d60e11b81526001600160a01b037f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b87131169063332100fa906128dd908c9088906004016152c9565b600060405180830381600087803b1580156128f757600080fd5b505af115801561290b573d6000803e3d6000fd5b5050505061291888611e0b565b15612a9d57612928308a84613a6a565b60405163095ea7b360e01b81526001600160a01b037f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c169063095ea7b390612996907f000000000000000000000000eef417e1d5cc832e619ae18d2f140de2999dd4fb9086906004016152c9565b602060405180830381600087803b1580156129b057600080fd5b505af11580156129c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e89190614fdb565b50604051633d1c24e760e01b81526001600160a01b037f000000000000000000000000eef417e1d5cc832e619ae18d2f140de2999dd4fb1690633d1c24e790612a5d907f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c903390879081908a906004016153f2565b600060405180830381600087803b158015612a7757600080fd5b505af1158015612a8b573d6000803e3d6000fd5b505050505050505050505050506118a0565b6000612aac83898c6000611f79565b9050612ab88a82611256565b612ae48a828b7f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c613cb2565b6000612af96001600160a01b038b1630613d57565b90506000612b0f8b6001600160a01b03166116b0565b15612b1b575080612b4f565b612b4f6001600160a01b038c167f000000000000000000000000eef417e1d5cc832e619ae18d2f140de2999dd4fb84613dfc565b604051633d1c24e760e01b81526001600160a01b037f000000000000000000000000eef417e1d5cc832e619ae18d2f140de2999dd4fb1690633d1c24e7908390612ba5908f9033908b9089908e906004016153f2565b6000604051808303818588803b158015612bbe57600080fd5b505af1158015612bd2573d6000803e3d6000fd5b50506040516370a0823160e01b8152600093506001600160a01b037f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c1692506370a082319150612c269030906004016152b5565b60206040518083038186803b158015612c3e57600080fd5b505afa158015612c52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c76919061509c565b90508015612c8857612c888d826115e4565b5050505050505050505050505050565b600082821115612cba5760405162461bcd60e51b81526004016103f79061552c565b50900390565b604051634f2b8d3560e11b81526001600160a01b037f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf461690639e571a6a90612d0e9085908590600401615303565b60206040518083038186803b158015612d2657600080fd5b505afa158015612d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5e9190614fdb565b15612d7b5760405162461bcd60e51b81526004016103f7906154f5565b5050565b600081116118a05760405162461bcd60e51b81526004016103f7906156a4565b6000612daa83611e0b565b15612dcb57612db96000613ebf565b612dc4858584613ede565b90506114f5565b612df2612de0846001600160a01b03166116b0565b612deb576000612ded565b825b613ebf565b611b8385858585614093565b90565b6117718363a9059cbb60e01b8484604051602401612e209291906152c9565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526143e7565b600080846001600160a01b031663d8959512856040518263ffffffff1660e01b8152600401612e8691906152b5565b60206040518083038186803b158015612e9e57600080fd5b505afa158015612eb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed6919061509c565b604051636c4aca8960e11b81526001600160a01b0387169063d895951290612f029087906004016152b5565b60206040518083038186803b158015612f1a57600080fd5b505afa158015612f2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d63919061509c565b6000807f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b031663943fd08a846040518263ffffffff1660e01b8152600401612fa191906152b5565b60206040518083038186803b158015612fb957600080fd5b505afa158015612fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff1919061509c565b9050600081116113cf577f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b031663b97b55ce6040518163ffffffff1660e01b815260040160206040518083038186803b15801561305457600080fd5b505afa158015613068573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308c919061509c565b611bf2565b6000818310156130a15781611bf2565b5090919050565b60008082116130c95760405162461bcd60e51b81526004016103f79061566d565b8183816130d257fe5b049392505050565b6130e2614c7f565b6130ea614c7f565b6130f48486614476565b905061310381602001516118a3565b61310b611bf9565b8160e001511061312d5760405162461bcd60e51b81526004016103f7906156cc565b63ffffffff8316620f424014156131c157604051636f366b7160e01b81526001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb551690636f366b719061318a908790600401615423565b600060405180830381600087803b1580156131a457600080fd5b505af11580156131b8573d6000803e3d6000fd5b50505050613271565b606081015160808201516131dc828263ffffffff8816611d44565b608085018190526060850182905260405163161139bd60e31b81526001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55169263b089cde89261323c928b92880391870390600401615a9d565b600060405180830381600087803b15801561325657600080fd5b505af115801561326a573d6000803e3d6000fd5b5050505050505b7f0000000000000000000000009712bb50dc6efb8a3d7d12cea500a50967d2d4716001600160a01b03166327396b6d826000015183602001518460400151856060015186608001516040518663ffffffff1660e01b81526004016132d9959493929190615341565b600060405180830381600087803b1580156132f357600080fd5b505af1158015613307573d6000803e3d6000fd5b5092979650505050505050565b600061331e614d14565b613326614d14565b6133308888613535565b915091506133508260000151836020015183600001518460200151613947565b604051630aa558ef60e41b81526001600160a01b037f0000000000000000000000009712bb50dc6efb8a3d7d12cea500a50967d2d471169063aa558ef0906133a4908c908c908c908c908c90600401615341565b600060405180830381600087803b1580156133be57600080fd5b505af11580156133d2573d6000803e3d6000fd5b5050604051637ea5e0f360e11b81526001600160a01b037f0000000000000000000000009712bb50dc6efb8a3d7d12cea500a50967d2d47116925063fd4bc1e69150613424908c908c90600401615303565b602060405180830381600087803b15801561343e57600080fd5b505af1158015613452573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134769190614fdb565b50815160208301516040516361d5f08760e01b81526001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb5516926361d5f087926134d6928e928e928e928e928e9290918e90600401615375565b602060405180830381600087803b1580156134f057600080fd5b505af1158015613504573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613528919061509c565b9998505050505050505050565b61353d614d14565b613545614d14565b60006135508561135c565b9050600061355e82866113d5565b905060008061356e848489612e57565b91509150600080856001600160a01b0316631f0181bc8a6040518263ffffffff1660e01b81526004016135a191906152b5565b604080518083038186803b1580156135b857600080fd5b505afa1580156135cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f0919061519e565b60408051808201825296875260208088019690965280518082019091529182529381019390935250919890975095505050505050565b61362e614cdf565b6001600160801b03848617111561364157fe5b506040805160c0810182526001600160801b03958616815293851660208086019190915283518616918501919091529182015184166060840152805184166080840152015190911660a082015290565b613699614d14565b60006136a58385612c98565b905060007f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b0316632c560f896040518163ffffffff1660e01b815260040160206040518083038186803b15801561370257600080fd5b505afa158015613716573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373a919061509c565b905060007f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b031663ce3f3adb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561379757600080fd5b505afa1580156137ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137cf919061509c565b9050818310156137fa57604051806040016040528060008152602001600181525093505050506113cf565b80831061382257604051806040016040528060018152602001600181525093505050506113cf565b604080518082019091529283526020830152509392505050565b6000613846614d14565b604051806040016040528085600001516001600160801b0316815260200185602001516001600160801b0316815250905061387f614d14565b50604080518082018252908501516001600160801b03908116825260608601511660208201526138ad614d14565b604051806040016040528087608001516001600160801b031681526020018760a001516001600160801b0316815250905060006138ec898b86866144c6565b90506138f6614d14565b61390085846145cb565b9050611084896139108b85613091565b838a614699565b60008183106130a15781611bf2565b6107c2846323b872dd60e01b858585604051602401612e209392919061531d565b60007f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b03166324a088686040518163ffffffff1660e01b815260040160206040518083038186803b1580156139a257600080fd5b505afa1580156139b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139da919061520b565b620f42400363ffffffff1690506000613a0482611b7184611b71878b61205490919063ffffffff16565b90506000613a1b620f4240611b7185818a8a612054565b90506000613a32620f4240611b7181818c8a612054565b9050818311158015613a445750808211155b613a605760405162461bcd60e51b81526004016103f7906156f3565b5050505050505050565b604051636f566c2760e11b81526001600160a01b037f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b87131169063deacd84e90613ab890859085906004016152c9565b600060405180830381600087803b158015613ad257600080fd5b505af1158015613ae6573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b037f000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2441692506340c10f199150613b3890869085906004016152c9565b600060405180830381600087803b158015613b5257600080fd5b505af1158015613b66573d6000803e3d6000fd5b50505050505050565b6000613c0d7f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b031663045544436040518163ffffffff1660e01b815260040160206040518083038186803b158015613bcd57600080fd5b505afa158015613be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c05919061509c565b611b77611bf9565b60405163dbae3a5d60e01b81529091506001600160a01b037f000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55169063dbae3a5d90613c60908690869086906004016152e2565b602060405180830381600087803b158015613c7a57600080fd5b505af1158015613c8e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c2919061509c565b6000613cbd8561135c565b9050606080613ccc85856114fd565b60405163b127c0a560e01b815291935091506001600160a01b0384169063b127c0a590613d0190899086908690600401615a64565b600060405180830381600087803b158015613d1b57600080fd5b505af1158015613d2f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613a609190810190614f47565b6000613d62836116b0565b15613d7857506001600160a01b038116316113cf565b613d8183612dfe565b6001600160a01b03166370a08231836040518263ffffffff1660e01b8152600401613dac91906152b5565b60206040518083038186803b158015613dc457600080fd5b505afa158015613dd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf2919061509c565b801580613e845750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90613e329030908690600401615303565b60206040518083038186803b158015613e4a57600080fd5b505afa158015613e5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e82919061509c565b155b613ea05760405162461bcd60e51b81526004016103f790615945565b6117718363095ea7b360e01b8484604051602401612e209291906152c9565b8034146118a05760405162461bcd60e51b81526004016103f7906157f2565b6000827f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c613f0a614d14565b613f148383611e3d565b90506000613f2b868360200151846000015161208e565b604051630671a97960e21b81529091506001600160a01b037f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b8713116906319c6a5e490613f7c90879085906004016152c9565b600060405180830381600087803b158015613f9657600080fd5b505af1158015613faa573d6000803e3d6000fd5b505050506000613fc5898686858b613fc0611bf9565b613314565b9050613ffc6001600160a01b037f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c1633308a613926565b61400688886115e4565b6040516340c10f1960e01b81526001600160a01b037f0000000000000000000000000887ae1251e180d7d453aedebee26e1639f2011316906340c10f1990614054908c908b906004016152c9565b600060405180830381600087803b15801561406e57600080fd5b505af1158015614082573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000837f0000000000000000000000001f573d6fb3f13d689ff844b4ce37794d79a7ff1c826140c18361135c565b90506000806140d1838986612e57565b915091507f000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf466001600160a01b03166312588d0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561412e57600080fd5b505afa158015614142573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614166919061509c565b8110156141855760405162461bcd60e51b81526004016103f790615829565b600061419288838561208e565b9050600061419f8b612f52565b905060006141f3837f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b871316001600160a01b031663350ed8e78f6040518263ffffffff1660e01b8152600401611ff591906152b5565b9050818111156142155760405162461bcd60e51b81526004016103f79061563d565b614220308d85613a6a565b6142346001600160a01b038816878561471b565b6142468b6001600160a01b03166116b0565b6142735761425f6001600160a01b038c1633308d61474c565b6142736001600160a01b038c16878c61471b565b614281868c898d8734614787565b6040516370a0823160e01b81526000906001600160a01b038a16906370a08231906142b09030906004016152b5565b60206040518083038186803b1580156142c857600080fd5b505afa1580156142dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614300919061509c565b90506143366001600160a01b038a167f000000000000000000000000d1d846312b819743974786050848d9b3d06b9b5583612e01565b604051631990807d60e11b81527f000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b871316001600160a01b03169063332100fa90614389908c90600286048603906004016152c9565b600060405180830381600087803b1580156143a357600080fd5b505af11580156143b7573d6000803e3d6000fd5b505050506143d58e8a8e600285816143cb57fe5b048f613fc0611bf9565b9e9d5050505050505050505050505050565b606061443c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148c79092919063ffffffff16565b805190915015611771578080602001905181019061445a9190614fdb565b6117715760405162461bcd60e51b81526004016103f790615897565b61447e614c7f565b614486614c7f565b61448f84611c5d565b9050826001600160a01b031681600001516001600160a01b0316146114f35760405162461bcd60e51b81526004016103f7906159c3565b82518151602084015160009283926144eb92611b71916144e69190612054565b6148d6565b9050600061451a8660200151611b716145158760200151896000015161205490919063ffffffff16565b6148f6565b90508187028783828161452957fe5b0414156145445781818161453957fe5b0493505050506114f5565b600080898511614555578985614558565b848a5b915091506000806145758487856000198161456f57fe5b0461494c565b91509150600061458f8488878161458857fe5b0490612054565b905081156145bb576145ac8183868602816145a657fe5b04613091565b985050505050505050506114f5565b9c9b505050505050505050505050565b6145d3614d14565b602083015182516000916145e79190612054565b845160208501519192506000916145fd91612054565b905081810260008284838161460e57fe5b041461462c5761461d836148f6565b614626856148f6565b02614635565b614635826148f6565b905060006146438585611bfd565b905060028106614676576002810490506040518060400160405280838303815260200182815250955050505050506113cf565b604080518082019091526002909202810382526020820152935050505092915050565b805160009081906146aa9087612054565b602084015190915060006146c76146c18484613091565b88613091565b90506000806146e488600001518960200151856000198161456f57fe5b9092509050611a726147036146f98387612054565b611b7d8589612054565b611b7783611b7d6147148288612c98565b8e90612054565b614724836116b0565b1561472e57611771565b611771828261473c86612dfe565b6001600160a01b03169190614994565b80158061475d575061475d846116b0565b15614767576107c2565b6107c283838361477688612dfe565b6001600160a01b0316929190613926565b60408051600280825260608083018452926020830190803683375050604080516002808252606080830184529495509092509060208301908036833701905050905086826000815181106147d757fe5b60200260200101906001600160a01b031690816001600160a01b031681525050858260018151811061480557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050848160008151811061483357fe5b602002602001018181525050838160018151811061484d57fe5b6020908102919091010152604051637d8916bd60e01b81526001600160a01b03891690637d8916bd90859061488b90869086906001906004016153bc565b6000604051808303818588803b1580156148a457600080fd5b505af11580156148b8573d6000803e3d6000fd5b50505050505050505050505050565b60606114f58484600085614a5d565b6000806148e2836148f6565b905082818202146113cf5780600101611bf2565b6000806002830460010190506000600282858161490f57fe5b0483018161491957fe5b0490505b8082111561494557809150600282858161493357fe5b0483018161493d57fe5b04905061491d565b5092915050565b60008084848482118061495e57508481115b156149745761496e828287614b13565b90925090505b808214614985579092509050611d68565b50600196879650945050505050565b8061499e57611771565b604051636eb1769f60e11b81526000906001600160a01b0385169063dd62ed3e906149cf9030908790600401615303565b60206040518083038186803b1580156149e757600080fd5b505afa1580156149fb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a1f919061509c565b9050818110614a2e5750611771565b8015614a4957614a496001600160a01b038516846000613dfc565b6107c26001600160a01b0385168484613dfc565b606082471015614a7f5760405162461bcd60e51b81526004016103f7906155f7565b614a8885614b4c565b614aa45760405162461bcd60e51b81526004016103f790615860565b60006060866001600160a01b03168587604051614ac19190615299565b60006040518083038185875af1925050503d8060008114614afe576040519150601f19603f3d011682016040523d82523d6000602084013e614b03565b606091505b5091509150611dc9828286614b52565b600080838511614b3157614b28858585614b8b565b91509150611d68565b600080614b3f868887614b8b565b9890975095505050505050565b3b151590565b60608315614b61575081611bf2565b825115614b715782518084602001fd5b8160405162461bcd60e51b81526004016103f7919061542c565b60008060008360001981614b9b57fe5b04905080861115614bd4576000816001018781614bb457fe5b046001019050808781614bc357fe5b049650808681614bcf57fe5b049550505b848614614c3f578584026000614bea8888614c4f565b9050878110614c10576000614bff8383614c53565b955050508385039250611d68915050565b6002888803048703821015614c2e5760008694509450505050611d68565b600180870394509450505050611d68565b5050600290910493849350915050565b0190565b6000600282048203828481614c6457fe5b0681614c6c57fe5b04828481614c7657fe5b04019392505050565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b604051806040016040528060008152602001600081525090565b60008083601f840112614d3f578182fd5b50813567ffffffffffffffff811115614d56578182fd5b60208301915083602080830285010111156115dd57600080fd5b600082601f830112614d80578081fd5b815167ffffffffffffffff80821115614d97578283fd5b602080830260405182828201018181108582111715614db4578687fd5b604052848152945081850192508582018187018301881015614dd557600080fd5b600091505b84821015614df8578051845292820192600191909101908201614dda565b505050505092915050565b600060208284031215614e14578081fd5b81356114f381615b3b565b600060208284031215614e30578081fd5b81516114f381615b3b565b60008060008060808587031215614e50578283fd5b8435614e5b81615b3b565b93506020850135614e6b81615b3b565b92506040850135614e7b81615b3b565b9396929550929360600135925050565b600080600080600080600080610100898b031215614ea7578384fd5b8851614eb281615b3b565b60208a0151909850614ec381615b3b565b60408a0151909750614ed481615b3b565b60608a015160808b015160a08c015160c08d015160e0909d01519b9e9a9d50929b919a9099929850909650945092505050565b60008060208385031215614f19578182fd5b823567ffffffffffffffff811115614f2f578283fd5b614f3b85828601614d2e565b90969095509350505050565b600060208284031215614f58578081fd5b815167ffffffffffffffff811115614f6e578182fd5b6114f584828501614d70565b60008060408385031215614f8c578182fd5b825167ffffffffffffffff80821115614fa3578384fd5b614faf86838701614d70565b93506020850151915080821115614fc4578283fd5b50614fd185828601614d70565b9150509250929050565b600060208284031215614fec578081fd5b815180151581146114f3578182fd5b60008060006060848603121561500f578081fd5b833561501a81615b3b565b9250602084013561502a81615b3b565b929592945050506040919091013590565b600080600080600080600060e0888a031215615055578081fd5b873561506081615b3b565b9650602088013561507081615b3b565b96999698505050506040850135946060810135946080820135945060a0820135935060c0909101359150565b6000602082840312156150ad578081fd5b5051919050565b600080604083850312156150c6578182fd5b8235915060208301356150d881615b3b565b809150509250929050565b6000806000806000608086880312156150fa578283fd5b85359450602086013561510c81615b3b565b9350604086013561511c81615b3b565b9250606086013567ffffffffffffffff80821115615138578283fd5b818801915088601f83011261514b578283fd5b813581811115615159578384fd5b89602082850101111561516a578384fd5b9699959850939650602001949392505050565b6000806040838503121561518f578182fd5b50508035926020909101359150565b600080604083850312156151b0578182fd5b505080516020909101519092909150565b600080604083850312156151d3578182fd5b8235915060208301356150d881615b50565b6000806000606084860312156151f9578081fd5b83359250602084013561502a81615b50565b60006020828403121561521c578081fd5b81516114f381615b50565b6000815180845260208085019450808401835b8381101561525f5781516001600160a01b03168752958201959082019060010161523a565b509495945050505050565b6000815180845260208085019450808401835b8381101561525f5781518752958201959082019060010161527d565b600082516152ab818460208701615b0f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b03988916815296881660208801529490961660408601526060850192909252608084015260a083015260c082019290925260e08101919091526101000190565b6000606082526153cf6060830186615227565b82810360208401526153e1818661526a565b915050826040830152949350505050565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b90815260200190565b600060208252825180602084015261544b816040850160208701615b0f565b601f01601f19169190910160400192915050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600e908201526d22a9292fa9a0a6a2afa7aba722a960911b604082015260600190565b60208082526018908201527f4552525f504f4f4c5f4e4f545f57484954454c49535445440000000000000000604082015260600190565b6020808252601a908201527f4552525f4144445f4c49515549444954595f44495341424c4544000000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252603a908201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260408201527f6563697069656e74206d61792068617665207265766572746564000000000000606082015260800190565b6020808252601d908201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b60208082526016908201527511549497d3505617d05353d5539517d4915050d2115160521b604082015260600190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252600e908201526d4552525f5a45524f5f56414c554560901b604082015260600190565b6020808252600d908201526c4552525f544f4f5f4541524c5960981b604082015260600190565b60208082526010908201526f4552525f494e56414c49445f5241544560801b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526016908201527511549497d413d3d317d393d517d4d5541413d495115160521b604082015260600190565b60208082526019908201527f4552525f494e56414c49445f504f534954494f4e5f4c49535400000000000000604082015260600190565b6020808252601390820152724552525f494e56414c49445f4144445245535360681b604082015260600190565b60208082526017908201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604082015260600190565b60208082526018908201527f4552525f4e4f545f454e4f5547485f4c49515549444954590000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526013908201527222a9292fa4a72b20a624a22fa827a92a24a7a760691b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b6020808252600e908201526d11549497d253959053125117d25160921b604082015260600190565b60208082526011908201527011549497d050d0d154d4d7d11153925151607a1b604082015260600190565b60208082526015908201527404552525f494e56414c49445f54494d455354414d5605c1b604082015260600190565b8481526001600160a01b03841660208201526060604082018190528101829052600082846080840137818301608090810191909152601f909201601f191601019392505050565b600084825260606020830152615a7d6060830185615227565b828103604084015261204a818561526a565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000808335601e19843603018112615ac9578283fd5b83018035915067ffffffffffffffff821115615ae3578283fd5b60209081019250810236038213156115dd57600080fd5b60008235605e198336030181126152ab578182fd5b60005b83811015615b2a578181015183820152602001615b12565b838111156107c25750506000910152565b6001600160a01b03811681146118a057600080fd5b63ffffffff811681146118a057600080fdfea164736f6c634300060c000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000eef417e1d5cc832e619ae18d2f140de2999dd4fb000000000000000000000000649765821d9f64198c905ec0b2b037a4a52bc373000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf46000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb550000000000000000000000009712bb50dc6efb8a3d7d12cea500a50967d2d471000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b87131000000000000000000000000d1d846312b819743974786050848d9b3d06b9b55000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc2440000000000000000000000000887ae1251e180d7d453aedebee26e1639f20113
-----Decoded View---------------
Arg [0] : networkV3 (address): 0xeEF417e1D5CC832e619ae18D2F140De2999dD4fB
Arg [1] : vaultV3 (address): 0x649765821D9f64198c905eC0B2B037a4a52Bc373
Arg [2] : settings (address): 0xF7D28FaA1FE9Ea53279fE6e3Cde75175859bdF46
Arg [3] : store (address): 0xf5FAB5DBD2f3bf675dE4cB76517d4767013cfB55
Arg [4] : stats (address): 0x9712Bb50DC6Efb8a3d7D12cEA500a50967d2d471
Arg [5] : systemStore (address): 0xc4C5634De585d43DaEC8fA2a6Fb6286cd9B87131
Arg [6] : wallet (address): 0xD1D846312B819743974786050848D9B3d06b9b55
Arg [7] : networkTokenGovernance (address): 0xa489C2b5b36835A327851Ab917A80562B5AFC244
Arg [8] : govTokenGovernance (address): 0x0887ae1251E180d7D453aeDEBee26e1639f20113
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000eef417e1d5cc832e619ae18d2f140de2999dd4fb
Arg [1] : 000000000000000000000000649765821d9f64198c905ec0b2b037a4a52bc373
Arg [2] : 000000000000000000000000f7d28faa1fe9ea53279fe6e3cde75175859bdf46
Arg [3] : 000000000000000000000000f5fab5dbd2f3bf675de4cb76517d4767013cfb55
Arg [4] : 0000000000000000000000009712bb50dc6efb8a3d7d12cea500a50967d2d471
Arg [5] : 000000000000000000000000c4c5634de585d43daec8fa2a6fb6286cd9b87131
Arg [6] : 000000000000000000000000d1d846312b819743974786050848d9b3d06b9b55
Arg [7] : 000000000000000000000000a489c2b5b36835a327851ab917a80562b5afc244
Arg [8] : 0000000000000000000000000887ae1251e180d7d453aedebee26e1639f20113
Loading...
Loading
Loading...
Loading

Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
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.