Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 70 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Unstake And With... | 20383794 | 33 days ago | IN | 0 ETH | 0.0422344 | ||||
Unstake And With... | 20181722 | 61 days ago | IN | 0 ETH | 0.01354043 | ||||
Unstake And With... | 20062159 | 78 days ago | IN | 0 ETH | 0.09609026 | ||||
Unstake And With... | 20041882 | 80 days ago | IN | 0 ETH | 0.11044955 | ||||
Unstake And With... | 19990445 | 88 days ago | IN | 0 ETH | 0.11078715 | ||||
Unstake And With... | 19667483 | 133 days ago | IN | 0 ETH | 0.06782982 | ||||
Deposit For | 19663312 | 133 days ago | IN | 0 ETH | 0.04583348 | ||||
Unstake And With... | 19623309 | 139 days ago | IN | 0 ETH | 0.04568555 | ||||
Unstake And With... | 19597824 | 143 days ago | IN | 0 ETH | 0.05711302 | ||||
Unstake And With... | 19593169 | 143 days ago | IN | 0 ETH | 0.03673921 | ||||
Deposit For | 19588485 | 144 days ago | IN | 0 ETH | 0.12231979 | ||||
Unstake And With... | 19588156 | 144 days ago | IN | 0 ETH | 0.0384842 | ||||
Unstake And With... | 19497628 | 157 days ago | IN | 0 ETH | 0.05444408 | ||||
Unstake And With... | 19456339 | 162 days ago | IN | 0 ETH | 0.07693271 | ||||
Deposit For | 19451351 | 163 days ago | IN | 0 ETH | 0.05708688 | ||||
Deposit For | 19432112 | 166 days ago | IN | 0 ETH | 0.17398889 | ||||
Deposit For | 19396289 | 171 days ago | IN | 0 ETH | 0.17348584 | ||||
Unstake And With... | 19382194 | 173 days ago | IN | 0 ETH | 0.1814896 | ||||
Unstake And With... | 19373696 | 174 days ago | IN | 0 ETH | 0.08776832 | ||||
Withdraw | 19353966 | 177 days ago | IN | 0 ETH | 0.06796831 | ||||
Deposit For | 19351879 | 177 days ago | IN | 0 ETH | 0.06102781 | ||||
Unstake And With... | 19287244 | 186 days ago | IN | 0 ETH | 0.06735164 | ||||
Unstake And With... | 19279389 | 187 days ago | IN | 0 ETH | 0.11237094 | ||||
Deposit For | 19260403 | 190 days ago | IN | 0 ETH | 0.05371513 | ||||
Unstake And With... | 19251260 | 191 days ago | IN | 0 ETH | 0.03820809 |
Latest 2 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
19079209 | 215 days ago | Contract Creation | 0 ETH | |||
19079209 | 215 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ConicPool
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "BaseConicPool.sol"; contract ConicPool is BaseConicPool { using EnumerableSet for EnumerableSet.AddressSet; using ScaledMath for uint256; uint256 internal constant _DEPEG_UNDERLYING_MULTIPLIER = 2; constructor( address _underlying, IRewardManager _rewardManager, address _controller, string memory _lpTokenName, string memory _symbol, address _cvx, address _crv ) BaseConicPool(_underlying, _rewardManager, _controller, _lpTokenName, _symbol, _cvx, _crv) {} function _updatePriceCache() internal override { address[] memory underlyings = getAllUnderlyingCoins(); IOracle priceOracle_ = controller.priceOracle(); for (uint256 i; i < underlyings.length; i++) { address coin = underlyings[i]; _cachedPrices[coin] = priceOracle_.getUSDPrice(coin); } } function _isAssetDepegged(address asset_) internal view override returns (bool) { uint256 depegThreshold_ = depegThreshold; if (asset_ == address(underlying)) depegThreshold_ *= _DEPEG_UNDERLYING_MULTIPLIER; // Threshold is higher for underlying uint256 cachedPrice_ = _cachedPrices[asset_]; uint256 currentPrice_ = controller.priceOracle().getUSDPrice(asset_); uint256 priceDiff_ = cachedPrice_.absSub(currentPrice_); uint256 priceDiffPercent_ = priceDiff_.divDown(cachedPrice_); return priceDiffPercent_ > depegThreshold_; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "Ownable.sol"; import "ERC20.sol"; import "Address.sol"; import "EnumerableSet.sol"; import "EnumerableMap.sol"; import "IERC20.sol"; import "SafeERC20.sol"; import "IERC20Metadata.sol"; import "ERC165Checker.sol"; import "IConicPool.sol"; import "IRewardManager.sol"; import "IWithdrawalProcessor.sol"; import "ICurveRegistryCache.sol"; import "IInflationManager.sol"; import "ILpTokenStaker.sol"; import "IOracle.sol"; import "IBaseRewardPool.sol"; import "LpToken.sol"; import "Pausable.sol"; import "ConicPoolWeightManager.sol"; import "ScaledMath.sol"; import "ArrayExtensions.sol"; abstract contract BaseConicPool is IConicPool, Pausable { using ArrayExtensions for uint256[]; using ArrayExtensions for address[]; using EnumerableSet for EnumerableSet.AddressSet; using EnumerableMap for EnumerableMap.AddressToUintMap; using SafeERC20 for IERC20; using SafeERC20 for IERC20Metadata; using SafeERC20 for ILpToken; using ScaledMath for uint256; using Address for address; using ERC165Checker for address; // Avoid stack depth errors struct DepositVars { uint256 exchangeRate; uint256 underlyingBalanceIncrease; uint256 mintableUnderlyingAmount; uint256 lpReceived; uint256 underlyingBalanceBefore; uint256 allocatedBalanceBefore; uint256[] allocatedPerPoolBefore; uint256 underlyingBalanceAfter; uint256 allocatedBalanceAfter; uint256[] allocatedPerPoolAfter; } uint256 internal constant _IDLE_RATIO_UPPER_BOUND = 0.2e18; uint256 internal constant _MIN_DEPEG_THRESHOLD = 0.01e18; uint256 internal constant _MAX_DEPEG_THRESHOLD = 0.1e18; uint256 internal constant _MAX_DEVIATION_UPPER_BOUND = 0.2e18; uint256 internal constant _TOTAL_UNDERLYING_CACHE_EXPIRY = 3 days; uint256 internal constant _MAX_USD_VALUE_FOR_REMOVING_POOL = 100e18; uint256 internal constant _MIN_EMERGENCY_REBALANCING_REWARD_FACTOR = 1e18; uint256 internal constant _MAX_EMERGENCY_REBALANCING_REWARD_FACTOR = 100e18; IERC20 internal immutable CVX; IERC20 internal immutable CRV; IERC20 internal constant CNC = IERC20(0x9aE380F0272E2162340a5bB646c354271c0F5cFC); address internal constant _WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; IERC20Metadata public immutable override underlying; ILpToken public immutable override lpToken; IRewardManager public immutable rewardManager; IConicPoolWeightManager public immutable weightManager; /// @dev once the deviation gets under this threshold, the reward distribution will be paused /// until the next rebalancing. This is expressed as a ratio, scaled with 18 decimals uint256 public maxDeviation = 0.02e18; // 2% uint256 public maxIdleCurveLpRatio = 0.05e18; // triggers Convex staking when exceeded bool public isShutdown; uint256 public depegThreshold = 0.03e18; // 3% uint256 internal _cacheUpdatedTimestamp; uint256 internal _cachedTotalUnderlying; /// @dev `true` if the rebalancing rewards are enabled, i.e. can become active /// A pool starts rebalancing rewards disabled, and these need to be enabled through governance bool public rebalancingRewardsEnabled; /// @dev `true` while the reward distribution is active bool public rebalancingRewardActive; /// @notice the time at which rebalancing rewards have been activated uint64 public rebalancingRewardsActivatedAt; /// @notice The factor by which the rebalancing reward is multiplied when a pool is depegged uint256 public emergencyRebalancingRewardsFactor = 10e18; /// @notice The factor by which the rebalancing reward is multiplied /// this is 1 (scaled to 18 decimals) for normal rebalancing situations but is set /// to `emergencyRebalancingRewardsFactor` when a pool is depegged uint256 public rebalancingRewardsFactor; /// @dev the absolute value in terms of USD of the total deviation after /// the weights have been updated uint256 public totalDeviationAfterWeightUpdate; mapping(address => uint256) _cachedPrices; modifier onlyController() { require(msg.sender == address(controller), "not authorized"); _; } constructor( address _underlying, IRewardManager _rewardManager, address _controller, string memory _lpTokenName, string memory _symbol, address _cvx, address _crv ) Pausable(IController(_controller)) { require( _underlying != _cvx && _underlying != _crv && _underlying != address(CNC), "invalid underlying" ); underlying = IERC20Metadata(_underlying); uint8 decimals = IERC20Metadata(_underlying).decimals(); lpToken = new LpToken(_controller, address(this), decimals, _lpTokenName, _symbol); rewardManager = _rewardManager; weightManager = new ConicPoolWeightManager( IController(_controller), IERC20Metadata(_underlying) ); CVX = IERC20(_cvx); CRV = IERC20(_crv); CVX.safeApprove(address(_rewardManager), type(uint256).max); CRV.safeApprove(address(_rewardManager), type(uint256).max); CNC.safeApprove(address(_rewardManager), type(uint256).max); } /// @dev We always delegate-call to the Curve handler, which means /// that we need to be able to receive the ETH to unwrap it and /// send it to the Curve pool, as well as to receive it back from /// the Curve pool when withdrawing receive() external payable { require(address(underlying) == _WETH_ADDRESS, "not WETH pool"); } /// @notice Deposit underlying on behalf of someone /// @param underlyingAmount Amount of underlying to deposit /// @param minLpReceived The minimum amount of LP to accept from the deposit /// @return lpReceived The amount of LP received function depositFor( address account, uint256 underlyingAmount, uint256 minLpReceived, bool stake ) public override notPaused returns (uint256) { runSanityChecks(); DepositVars memory vars; // Preparing deposit require(!isShutdown, "pool is shut down"); require(underlyingAmount > 0, "deposit amount cannot be zero"); _updateAdapterCachedPrices(); uint256 underlyingPrice_ = controller.priceOracle().getUSDPrice(address(underlying)); // We use the cached price of LP tokens, which is effectively the latest price // because we just updated the cache ( vars.underlyingBalanceBefore, vars.allocatedBalanceBefore, vars.allocatedPerPoolBefore ) = _getTotalAndPerPoolUnderlying(underlyingPrice_, IPoolAdapter.PriceMode.Cached); vars.exchangeRate = _exchangeRate(vars.underlyingBalanceBefore); // Executing deposit underlying.safeTransferFrom(msg.sender, address(this), underlyingAmount); _depositToCurve( vars.allocatedBalanceBefore, vars.allocatedPerPoolBefore, underlying.balanceOf(address(this)) ); // Minting LP Tokens // We use the minimum between the price of the LP tokens before and after deposit ( vars.underlyingBalanceAfter, vars.allocatedBalanceAfter, vars.allocatedPerPoolAfter ) = _getTotalAndPerPoolUnderlying(underlyingPrice_, IPoolAdapter.PriceMode.Minimum); vars.underlyingBalanceIncrease = vars.underlyingBalanceAfter - vars.underlyingBalanceBefore; vars.mintableUnderlyingAmount = _min(underlyingAmount, vars.underlyingBalanceIncrease); vars.lpReceived = vars.mintableUnderlyingAmount.divDown(vars.exchangeRate); require(vars.lpReceived >= minLpReceived, "too much slippage"); _cachedTotalUnderlying = vars.underlyingBalanceAfter; _cacheUpdatedTimestamp = block.timestamp; if (stake) { lpToken.mint(address(this), vars.lpReceived, account); ILpTokenStaker lpTokenStaker = controller.lpTokenStaker(); lpToken.forceApprove(address(lpTokenStaker), vars.lpReceived); lpTokenStaker.stakeFor(vars.lpReceived, address(this), account); } else { lpToken.mint(account, vars.lpReceived, account); } _handleRebalancingRewards( account, vars.allocatedBalanceBefore, vars.allocatedPerPoolBefore, vars.allocatedBalanceAfter, vars.allocatedPerPoolAfter ); emit Deposit(msg.sender, account, underlyingAmount, vars.lpReceived); return vars.lpReceived; } /// @notice Deposit underlying /// @param underlyingAmount Amount of underlying to deposit /// @param minLpReceived The minimum amoun of LP to accept from the deposit /// @return lpReceived The amount of LP received function deposit( uint256 underlyingAmount, uint256 minLpReceived ) external override returns (uint256) { return depositFor(msg.sender, underlyingAmount, minLpReceived, true); } /// @notice Deposit underlying /// @param underlyingAmount Amount of underlying to deposit /// @param minLpReceived The minimum amoun of LP to accept from the deposit /// @param stake Whether or not to stake in the LpTokenStaker /// @return lpReceived The amount of LP received function deposit( uint256 underlyingAmount, uint256 minLpReceived, bool stake ) external override returns (uint256) { return depositFor(msg.sender, underlyingAmount, minLpReceived, stake); } function _depositToCurve( uint256 totalUnderlying_, uint256[] memory allocatedPerPool, uint256 underlyingAmount_ ) internal { uint256 depositsRemaining_ = underlyingAmount_; uint256 totalAfterDeposit_ = totalUnderlying_ + underlyingAmount_; // NOTE: avoid modifying `allocatedPerPool` uint256[] memory allocatedPerPoolCopy = allocatedPerPool.copy(); while (depositsRemaining_ > 0) { (uint256 poolIndex_, uint256 maxDeposit_) = weightManager.getDepositPool( totalAfterDeposit_, allocatedPerPoolCopy, _getMaxDeviation() ); // account for rounding errors if (depositsRemaining_ < maxDeposit_ + 1e2) { maxDeposit_ = depositsRemaining_; } address pool_ = weightManager.getPoolAtIndex(poolIndex_); // Depositing into least balanced pool uint256 toDeposit_ = _min(depositsRemaining_, maxDeposit_); address poolAdapter = address(controller.poolAdapterFor(pool_)); poolAdapter.functionDelegateCall( abi.encodeWithSignature( "deposit(address,address,uint256)", pool_, address(underlying), toDeposit_ ) ); depositsRemaining_ -= toDeposit_; allocatedPerPoolCopy[poolIndex_] += toDeposit_; } } /// @notice Get current underlying balance of pool function totalUnderlying() public view virtual returns (uint256) { (uint256 totalUnderlying_, , ) = getTotalAndPerPoolUnderlying(); return totalUnderlying_; } function updateRewardSpendingApproval(address token, bool approved) external { require(msg.sender == address(rewardManager), "not authorized"); uint256 amount = approved ? type(uint256).max : 0; IERC20(token).safeApprove(address(rewardManager), amount); } function _exchangeRate(uint256 totalUnderlying_) internal view returns (uint256) { uint256 lpSupply = lpToken.totalSupply(); if (lpSupply == 0 || totalUnderlying_ == 0) return ScaledMath.ONE; return totalUnderlying_.divDown(lpSupply); } /// @notice Get current exchange rate for the pool's LP token to the underlying function exchangeRate() public view virtual override returns (uint256) { return _exchangeRate(totalUnderlying()); } /// @notice Get current exchange rate for the pool's LP token to USD /// @dev This is using the cached total underlying value, so is not precisely accurate. function usdExchangeRate() external view virtual override returns (uint256) { uint256 underlyingPrice = controller.priceOracle().getUSDPrice(address(underlying)); return _exchangeRate(cachedTotalUnderlying()).mulDown(underlyingPrice); } /// @notice Unstake LP Tokens and withdraw underlying /// @param conicLpAmount Amount of LP tokens to burn /// @param minUnderlyingReceived Minimum amount of underlying to redeem /// This should always be set to a reasonable value (e.g. 2%), otherwise /// the user withdrawing could be forced into paying a withdrawal penalty fee /// by another user /// @return uint256 Total underlying withdrawn function unstakeAndWithdraw( uint256 conicLpAmount, uint256 minUnderlyingReceived, address to ) public override returns (uint256) { controller.lpTokenStaker().unstakeFrom(conicLpAmount, msg.sender); return withdraw(conicLpAmount, minUnderlyingReceived, to); } function unstakeAndWithdraw( uint256 conicLpAmount, uint256 minUnderlyingReceived ) external returns (uint256) { return unstakeAndWithdraw(conicLpAmount, minUnderlyingReceived, msg.sender); } function withdraw( uint256 conicLpAmount, uint256 minUnderlyingReceived ) public override returns (uint256) { return withdraw(conicLpAmount, minUnderlyingReceived, msg.sender); } /// @notice Withdraw underlying /// @param conicLpAmount Amount of LP tokens to burn /// @param minUnderlyingReceived Minimum amount of underlying to redeem /// This should always be set to a reasonable value (e.g. 2%), otherwise /// the user withdrawing could be forced into paying a withdrawal penalty fee /// by another user /// @return uint256 Total underlying withdrawn function withdraw( uint256 conicLpAmount, uint256 minUnderlyingReceived, address to ) public override returns (uint256) { runSanityChecks(); // Preparing Withdrawals require(lpToken.balanceOf(msg.sender) >= conicLpAmount, "insufficient balance"); uint256 underlyingBalanceBefore_ = underlying.balanceOf(address(this)); // Processing Withdrawals ( uint256 totalUnderlying_, uint256 allocatedUnderlying_, uint256[] memory allocatedPerPool ) = getTotalAndPerPoolUnderlying(); uint256 underlyingToReceive_ = conicLpAmount.mulDown(_exchangeRate(totalUnderlying_)); { if (underlyingBalanceBefore_ < underlyingToReceive_) { uint256 underlyingToWithdraw_ = underlyingToReceive_ - underlyingBalanceBefore_; _withdrawFromCurve(allocatedUnderlying_, allocatedPerPool, underlyingToWithdraw_); } } // Sending Underlying and burning LP Tokens uint256 underlyingWithdrawn_ = _min( underlying.balanceOf(address(this)), underlyingToReceive_ ); require(underlyingWithdrawn_ >= minUnderlyingReceived, "too much slippage"); lpToken.burn(msg.sender, conicLpAmount, msg.sender); underlying.safeTransfer(to, underlyingWithdrawn_); _cachedTotalUnderlying = totalUnderlying_ - underlyingWithdrawn_; _cacheUpdatedTimestamp = block.timestamp; // state has already been updated, so no need to worry about re-entrancy if (to.supportsInterface(type(IWithdrawalProcessor).interfaceId)) { IWithdrawalProcessor(to).processWithdrawal(msg.sender, underlyingWithdrawn_); } emit Withdraw(msg.sender, underlyingWithdrawn_); return underlyingWithdrawn_; } function _withdrawFromCurve( uint256 totalUnderlying_, uint256[] memory allocatedPerPool, uint256 amount_ ) internal { uint256 withdrawalsRemaining_ = amount_; uint256 totalAfterWithdrawal_ = totalUnderlying_ - amount_; // NOTE: avoid modifying `allocatedPerPool` uint256[] memory allocatedPerPoolCopy = allocatedPerPool.copy(); while (withdrawalsRemaining_ > 0) { (uint256 poolIndex_, uint256 maxWithdrawal_) = weightManager.getWithdrawPool( totalAfterWithdrawal_, allocatedPerPoolCopy, _getMaxDeviation() ); address pool_ = weightManager.getPoolAtIndex(poolIndex_); // Withdrawing from least balanced pool uint256 toWithdraw_ = _min(withdrawalsRemaining_, maxWithdrawal_); address poolAdapter = address(controller.poolAdapterFor(pool_)); poolAdapter.functionDelegateCall( abi.encodeWithSignature( "withdraw(address,address,uint256)", pool_, underlying, toWithdraw_ ) ); withdrawalsRemaining_ -= toWithdraw_; allocatedPerPoolCopy[poolIndex_] -= toWithdraw_; } } function allPools() external view override returns (address[] memory) { return weightManager.allPools(); } function poolsCount() external view override returns (uint256) { return weightManager.poolsCount(); } function getPoolAtIndex(uint256 _index) external view override returns (address) { return weightManager.getPoolAtIndex(_index); } function isRegisteredPool(address _pool) external view returns (bool) { return weightManager.isRegisteredPool(_pool); } // Controller and Admin functions function addPool(address _pool) external override onlyOwner { weightManager.addPool(_pool); address booster = controller.convexBooster(); address lpToken_ = controller.poolAdapterFor(_pool).lpToken(_pool); IERC20(lpToken_).safeApprove(booster, type(uint256).max); } function removePool(address _pool) external override onlyOwner { weightManager.removePool(_pool); address booster = controller.convexBooster(); address lpToken_ = controller.poolAdapterFor(_pool).lpToken(_pool); IERC20(lpToken_).safeApprove(booster, 0); } function updateWeights(PoolWeight[] memory poolWeights) external onlyController { runSanityChecks(); weightManager.updateWeights(poolWeights); ( uint256 totalUnderlying_, uint256 totalAllocated, uint256[] memory allocatedPerPool ) = getTotalAndPerPoolUnderlying(); uint256 totalDeviation = weightManager.computeTotalDeviation( totalUnderlying_, allocatedPerPool ); totalDeviationAfterWeightUpdate = totalDeviation; rebalancingRewardActive = rebalancingRewardsEnabled && !_isBalanced(allocatedPerPool, totalAllocated); rebalancingRewardsFactor = ScaledMath.ONE; rebalancingRewardsActivatedAt = uint64(block.timestamp); // Updating price cache for all pools // Used for seeing if a pool has depegged _updatePriceCache(); } function shutdownPool() external override onlyController { require(!isShutdown, "pool already shut down"); isShutdown = true; emit Shutdown(); } function updateDepegThreshold(uint256 newDepegThreshold_) external onlyOwner { require(newDepegThreshold_ >= _MIN_DEPEG_THRESHOLD, "invalid depeg threshold"); require(newDepegThreshold_ <= _MAX_DEPEG_THRESHOLD, "invalid depeg threshold"); require(newDepegThreshold_ != depegThreshold, "same as current"); depegThreshold = newDepegThreshold_; emit DepegThresholdUpdated(newDepegThreshold_); } /// @notice Called when an underlying of a Curve Pool has depegged and we want to exit the pool. /// Will check if a coin has depegged, and will revert if not. /// Sets the weight of the Curve Pool to 0, and re-enables CNC rewards for deposits. /// @dev Cannot be called if the underlying of this pool itself has depegged. /// @param curvePool_ The Curve Pool to handle. function handleDepeggedCurvePool(address curvePool_) external override { runSanityChecks(); require(!_isAssetDepegged(address(underlying)), "underlying is depegged"); require(_isPoolDepegged(curvePool_), "pool is not depegged"); weightManager.handleDepeggedCurvePool(curvePool_); // Updating total deviation ( uint256 totalUnderlying_, , uint256[] memory allocatedPerPool ) = getTotalAndPerPoolUnderlying(); uint256 totalDeviation = weightManager.computeTotalDeviation( totalUnderlying_, allocatedPerPool ); totalDeviationAfterWeightUpdate = totalDeviation; if (rebalancingRewardsEnabled) { IPoolAdapter poolAdapter = controller.poolAdapterFor(curvePool_); uint256 usdValue = poolAdapter.computePoolValueInUSD(address(this), curvePool_); if (usdValue > _MAX_USD_VALUE_FOR_REMOVING_POOL) { // if the rebalancing rewards were already active // we reset the activated at because the rewards factor is now increased rebalancingRewardsActivatedAt = uint64(block.timestamp); rebalancingRewardsFactor = emergencyRebalancingRewardsFactor; rebalancingRewardActive = true; } } emit HandledDepeggedCurvePool(curvePool_); } /** * @notice Allows anyone to set the weight of a Curve pool to 0 if the Convex pool for the * associated PID has been shut down. This is a very unlikely outcome and the method does * not reenable rebalancing rewards. * @param curvePool_ Curve pool for which the Convex PID is invalid (has been shut down) */ function handleInvalidConvexPid(address curvePool_) external override returns (uint256) { runSanityChecks(); uint256 pid = weightManager.handleInvalidConvexPid(curvePool_); emit HandledInvalidConvexPid(curvePool_, pid); return pid; } function setMaxIdleCurveLpRatio(uint256 maxIdleCurveLpRatio_) external onlyOwner { require(maxIdleCurveLpRatio != maxIdleCurveLpRatio_, "same as current"); require(maxIdleCurveLpRatio_ <= _IDLE_RATIO_UPPER_BOUND, "ratio exceeds upper bound"); maxIdleCurveLpRatio = maxIdleCurveLpRatio_; emit NewMaxIdleCurveLpRatio(maxIdleCurveLpRatio_); } function setMaxDeviation(uint256 maxDeviation_) external override onlyOwner { require(maxDeviation != maxDeviation_, "same as current"); require(maxDeviation_ <= _MAX_DEVIATION_UPPER_BOUND, "deviation exceeds upper bound"); maxDeviation = maxDeviation_; emit MaxDeviationUpdated(maxDeviation_); } function getWeight(address curvePool) external view override returns (uint256) { return weightManager.getWeight(curvePool); } function getWeights() external view override returns (PoolWeight[] memory) { return weightManager.getWeights(); } function getAllocatedUnderlying() external view override returns (PoolWithAmount[] memory) { address[] memory pools = weightManager.allPools(); PoolWithAmount[] memory perPoolAllocated = new PoolWithAmount[](pools.length); (, , uint256[] memory allocated) = getTotalAndPerPoolUnderlying(); for (uint256 i; i < perPoolAllocated.length; i++) { perPoolAllocated[i] = PoolWithAmount(pools[i], allocated[i]); } return perPoolAllocated; } function computeTotalDeviation() external view override returns (uint256) { ( , uint256 allocatedUnderlying_, uint256[] memory perPoolUnderlying ) = getTotalAndPerPoolUnderlying(); return weightManager.computeTotalDeviation(allocatedUnderlying_, perPoolUnderlying); } function cachedTotalUnderlying() public view virtual override returns (uint256) { if (block.timestamp > _cacheUpdatedTimestamp + _TOTAL_UNDERLYING_CACHE_EXPIRY) { return totalUnderlying(); } return _cachedTotalUnderlying; } function getTotalAndPerPoolUnderlying() public view returns ( uint256 totalUnderlying_, uint256 totalAllocated_, uint256[] memory perPoolUnderlying_ ) { uint256 underlyingPrice_ = controller.priceOracle().getUSDPrice(address(underlying)); return _getTotalAndPerPoolUnderlying(underlyingPrice_, IPoolAdapter.PriceMode.Latest); } function isBalanced() external view override returns (bool) { ( , uint256 allocatedUnderlying_, uint256[] memory allocatedPerPool_ ) = getTotalAndPerPoolUnderlying(); return _isBalanced(allocatedPerPool_, allocatedUnderlying_); } function setRebalancingRewardsEnabled(bool enabled) external override onlyOwner { require(rebalancingRewardsEnabled != enabled, "same as current"); rebalancingRewardsEnabled = enabled; emit RebalancingRewardsEnabledSet(enabled); } function setEmergencyRebalancingRewardFactor(uint256 factor_) external onlyOwner { require(factor_ >= _MIN_EMERGENCY_REBALANCING_REWARD_FACTOR, "factor below minimum"); require(factor_ <= _MAX_EMERGENCY_REBALANCING_REWARD_FACTOR, "factor above maximum"); require(factor_ != emergencyRebalancingRewardsFactor, "same as current"); emergencyRebalancingRewardsFactor = factor_; emit EmergencyRebalancingRewardFactorUpdated(factor_); } function _updateAdapterCachedPrices() internal { address[] memory pools = weightManager.allPools(); uint256 poolsLength_ = pools.length; for (uint256 i; i < poolsLength_; i++) { address pool_ = pools[i]; IPoolAdapter poolAdapter = controller.poolAdapterFor(pool_); poolAdapter.updatePriceCache(pool_); } } /** * @notice Returns several values related to the Omnipools's underlying assets. * @param underlyingPrice_ Price of the underlying asset in USD * @return totalUnderlying_ Total underlying value of the Omnipool * @return totalAllocated_ Total underlying value of the Omnipool that is allocated to Curve pools * @return perPoolUnderlying_ Array of underlying values of the Omnipool that is allocated to each Curve pool */ function _getTotalAndPerPoolUnderlying( uint256 underlyingPrice_, IPoolAdapter.PriceMode priceMode ) internal view returns ( uint256 totalUnderlying_, uint256 totalAllocated_, uint256[] memory perPoolUnderlying_ ) { address[] memory pools = weightManager.allPools(); uint256 poolsLength_ = pools.length; perPoolUnderlying_ = new uint256[](poolsLength_); for (uint256 i; i < poolsLength_; i++) { address pool_ = pools[i]; uint256 poolUnderlying_ = controller.poolAdapterFor(pool_).computePoolValueInUnderlying( address(this), pool_, address(underlying), underlyingPrice_, priceMode ); perPoolUnderlying_[i] = poolUnderlying_; totalAllocated_ += poolUnderlying_; } totalUnderlying_ = totalAllocated_ + underlying.balanceOf(address(this)); } function _handleRebalancingRewards( address account, uint256 allocatedBalanceBefore_, uint256[] memory allocatedPerPoolBefore, uint256 allocatedBalanceAfter_, uint256[] memory allocatedPerPoolAfter ) internal { if (!rebalancingRewardActive) return; uint256 deviationBefore = weightManager.computeTotalDeviation( allocatedBalanceBefore_, allocatedPerPoolBefore ); uint256 deviationAfter = weightManager.computeTotalDeviation( allocatedBalanceAfter_, allocatedPerPoolAfter ); controller.inflationManager().handleRebalancingRewards( account, deviationBefore, deviationAfter ); if (_isBalanced(allocatedPerPoolAfter, allocatedBalanceAfter_)) { rebalancingRewardActive = false; } } function _min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } function _isBalanced( uint256[] memory allocatedPerPool_, uint256 totalAllocated_ ) internal view returns (bool) { return weightManager.isBalanced(allocatedPerPool_, totalAllocated_, maxDeviation); } function getAllUnderlyingCoins() public view returns (address[] memory) { address[] memory pools = weightManager.allPools(); uint256 poolsLength_ = pools.length; address[] memory underlyings_ = new address[](0); for (uint256 i; i < poolsLength_; i++) { address pool_ = pools[i]; address[] memory coins = controller.poolAdapterFor(pool_).getAllUnderlyingCoins(pool_); underlyings_ = underlyings_.concat(coins); } return underlyings_.removeDuplicates(); } function _isPoolDepegged(address pool_) internal view returns (bool) { address[] memory coins = controller.poolAdapterFor(pool_).getAllUnderlyingCoins(pool_); for (uint256 i; i < coins.length; i++) { address coin = coins[i]; if (_isAssetDepegged(coin)) return true; } return false; } function runSanityChecks() public virtual {} function _getMaxDeviation() internal view returns (uint256) { return rebalancingRewardActive ? 0 : maxDeviation; } function _updatePriceCache() internal virtual; function _isAssetDepegged(address asset_) internal view virtual returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "IERC20.sol"; import "IERC20Metadata.sol"; import "Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 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://consensys.net/diligence/blog/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.8.0/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"); (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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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 /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableMap.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. pragma solidity ^0.8.0; import "EnumerableSet.sol"; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * The following map types are supported: * * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableMap. * ==== */ library EnumerableMap { using EnumerableSet for EnumerableSet.Bytes32Set; // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Map type with // bytes32 keys and values. // The Map implementation uses private functions, and user-facing // implementations (such as Uint256ToAddressMap) are just wrappers around // the underlying Map. // This means that we can only create new EnumerableMaps for types that fit // in bytes32. struct Bytes32ToBytes32Map { // Storage of keys EnumerableSet.Bytes32Set _keys; mapping(bytes32 => bytes32) _values; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { map._values[key] = value; return map._keys.add(key); } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { delete map._values[key]; return map._keys.remove(key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { return map._keys.contains(key); } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { return map._keys.length(); } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { bytes32 key = map._keys.at(index); return (key, map._values[key]); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { bytes32 value = map._values[key]; if (value == bytes32(0)) { return (contains(map, key), bytes32(0)); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { bytes32 value = map._values[key]; require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); return value; } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( Bytes32ToBytes32Map storage map, bytes32 key, string memory errorMessage ) internal view returns (bytes32) { bytes32 value = map._values[key]; require(value != 0 || contains(map, key), errorMessage); return value; } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { return map._keys.values(); } // UintToUintMap struct UintToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(key))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) { return uint256(get(map._inner, bytes32(key), errorMessage)); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintToAddressMap struct UintToAddressMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key))))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( UintToAddressMap storage map, uint256 key, string memory errorMessage ) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage)))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressToUintMap struct AddressToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(AddressToUintMap storage map, address key) internal returns (bool) { return remove(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(AddressToUintMap storage map, address key) internal view returns (bool) { return contains(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. O(1). */ function length(AddressToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (address(uint160(uint256(key))), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(AddressToUintMap storage map, address key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( AddressToUintMap storage map, address key, string memory errorMessage ) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage)); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(AddressToUintMap storage map) internal view returns (address[] memory) { bytes32[] memory store = keys(map._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // Bytes32ToUintMap struct Bytes32ToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { return set(map._inner, key, bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { return remove(map._inner, key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { return contains(map._inner, key); } /** * @dev Returns the number of elements in the map. O(1). */ function length(Bytes32ToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (key, uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, key); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { return uint256(get(map._inner, key)); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( Bytes32ToUintMap storage map, bytes32 key, string memory errorMessage ) internal view returns (uint256) { return uint256(get(map._inner, key, errorMessage)); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { bytes32[] memory store = keys(map._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "IERC20.sol"; import "IERC20Permit.sol"; import "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 Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ 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' 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)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @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). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // 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 cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; import "IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface. */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. * * _Available since v3.4._ */ function getSupportedInterfaces( address account, bytes4[] memory interfaceIds ) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * * Some precompiled contracts will falsely indicate support for a given interface, so caution * should be exercised when using this function. * * Interface identification is specified in ERC-165. */ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { // prepare call bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); // perform static call bool success; uint256 returnSize; uint256 returnValue; assembly { success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) returnSize := returndatasize() returnValue := mload(0x00) } return success && returnSize >= 0x20 && returnValue > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "ILpToken.sol"; import "IRewardManager.sol"; import "IOracle.sol"; import "IController.sol"; import "IPausable.sol"; import "IConicPoolWeightManagement.sol"; interface IConicPool is IConicPoolWeightManagement, IPausable { event Deposit( address indexed sender, address indexed receiver, uint256 depositedAmount, uint256 lpReceived ); event Withdraw(address indexed account, uint256 amount); event NewWeight(address indexed curvePool, uint256 newWeight); event NewMaxIdleCurveLpRatio(uint256 newRatio); event ClaimedRewards(uint256 claimedCrv, uint256 claimedCvx); event HandledDepeggedCurvePool(address curvePool_); event HandledInvalidConvexPid(address curvePool_, uint256 pid_); event CurvePoolAdded(address curvePool_); event CurvePoolRemoved(address curvePool_); event Shutdown(); event DepegThresholdUpdated(uint256 newThreshold); event MaxDeviationUpdated(uint256 newMaxDeviation); event RebalancingRewardsEnabledSet(bool enabled); event EmergencyRebalancingRewardFactorUpdated(uint256 factor); struct PoolWithAmount { address poolAddress; uint256 amount; } function underlying() external view returns (IERC20Metadata); function lpToken() external view returns (ILpToken); function rewardManager() external view returns (IRewardManager); function depegThreshold() external view returns (uint256); function maxIdleCurveLpRatio() external view returns (uint256); function setMaxIdleCurveLpRatio(uint256 value) external; function setMaxDeviation(uint256 maxDeviation_) external; function updateDepegThreshold(uint256 value) external; function depositFor( address _account, uint256 _amount, uint256 _minLpReceived, bool stake ) external returns (uint256); function deposit(uint256 _amount, uint256 _minLpReceived) external returns (uint256); function deposit( uint256 _amount, uint256 _minLpReceived, bool stake ) external returns (uint256); function exchangeRate() external view returns (uint256); function usdExchangeRate() external view returns (uint256); function unstakeAndWithdraw(uint256 _amount, uint256 _minAmount) external returns (uint256); function unstakeAndWithdraw( uint256 _amount, uint256 _minAmount, address _to ) external returns (uint256); function withdraw(uint256 _amount, uint256 _minAmount) external returns (uint256); function withdraw(uint256 _amount, uint256 _minAmount, address _to) external returns (uint256); function getAllocatedUnderlying() external view returns (PoolWithAmount[] memory); function rebalancingRewardActive() external view returns (bool); function totalDeviationAfterWeightUpdate() external view returns (uint256); function computeTotalDeviation() external view returns (uint256); /// @notice returns the total amount of funds held by this pool in terms of underlying function totalUnderlying() external view returns (uint256); function getTotalAndPerPoolUnderlying() external view returns ( uint256 totalUnderlying_, uint256 totalAllocated_, uint256[] memory perPoolUnderlying_ ); /// @notice same as `totalUnderlying` but returns a cached version /// that might be slightly outdated if oracle prices have changed /// @dev this is useful in cases where we want to reduce gas usage and do /// not need a precise value function cachedTotalUnderlying() external view returns (uint256); function updateRewardSpendingApproval(address token, bool approved) external; function shutdownPool() external; function isShutdown() external view returns (bool); function isBalanced() external view returns (bool); function rebalancingRewardsEnabled() external view returns (bool); function setRebalancingRewardsEnabled(bool enabled) external; function getAllUnderlyingCoins() external view returns (address[] memory result); function rebalancingRewardsFactor() external view returns (uint256); function rebalancingRewardsActivatedAt() external view returns (uint64); function getWeights() external view returns (PoolWeight[] memory); function runSanityChecks() external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "IERC20Metadata.sol"; interface ILpToken is IERC20Metadata { function minter() external view returns (address); function mint(address account, uint256 amount, address ubo) external returns (uint256); function burn(address _owner, uint256 _amount, address ubo) external returns (uint256); function taint(address from, address to, uint256 amount) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IRewardManager { event ClaimedRewards(uint256 claimedCrv, uint256 claimedCvx); event SoldRewardTokens(uint256 targetTokenReceived); event ExtraRewardAdded(address reward); event ExtraRewardRemoved(address reward); event ExtraRewardsCurvePoolSet(address extraReward, address curvePool); event FeesSet(uint256 feePercentage); event FeesEnabled(uint256 feePercentage); event EarningsClaimed( address indexed claimedBy, uint256 cncEarned, uint256 crvEarned, uint256 cvxEarned ); function accountCheckpoint(address account) external; function poolCheckpoint() external returns (bool); function addExtraReward(address reward) external returns (bool); function addBatchExtraRewards(address[] memory rewards) external; function conicPool() external view returns (address); function setFeePercentage(uint256 _feePercentage) external; function claimableRewards( address account ) external view returns (uint256 cncRewards, uint256 crvRewards, uint256 cvxRewards); function claimEarnings() external returns (uint256, uint256, uint256); function claimPoolEarningsAndSellRewardTokens() external; function feePercentage() external view returns (uint256); function feesEnabled() external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IOracle { event TokenUpdated(address indexed token, address feed, uint256 maxDelay, bool isEthPrice); /// @notice returns the price in USD of symbol. function getUSDPrice(address token) external view returns (uint256); /// @notice returns if the given token is supported for pricing. function isTokenSupported(address token) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "IConicPoolWeightManagement.sol"; import "IConicPool.sol"; import "IGenericOracle.sol"; import "IInflationManager.sol"; import "ILpTokenStaker.sol"; import "IBonding.sol"; import "IPoolAdapter.sol"; import "IFeeRecipient.sol"; import "ICurveRegistryCache.sol"; interface IController { event PoolAdded(address indexed pool); event PoolRemoved(address indexed pool); event PoolShutdown(address indexed pool); event ConvexBoosterSet(address convexBooster); event CurveHandlerSet(address curveHandler); event ConvexHandlerSet(address convexHandler); event CurveRegistryCacheSet(address curveRegistryCache); event InflationManagerSet(address inflationManager); event BondingSet(address bonding); event FeeRecipientSet(address feeRecipient); event PriceOracleSet(address priceOracle); event WeightUpdateMinDelaySet(uint256 weightUpdateMinDelay); event PauseManagerSet(address indexed manager, bool isManager); event MultiDepositsWithdrawsWhitelistSet(address pool, bool allowed); event MinimumTaintedTransferAmountSet(address indexed token, uint256 amount); event DefaultPoolAdapterSet(address poolAdapter); event CustomPoolAdapterSet(address indexed pool, address poolAdapter); struct WeightUpdate { address conicPoolAddress; IConicPoolWeightManagement.PoolWeight[] weights; } function initialize(address _lpTokenStaker) external; // inflation manager function inflationManager() external view returns (IInflationManager); function setInflationManager(address manager) external; // views function curveRegistryCache() external view returns (ICurveRegistryCache); // pool adapter function poolAdapterFor(address pool) external view returns (IPoolAdapter); function defaultPoolAdapter() external view returns (IPoolAdapter); function setDefaultPoolAdapter(address poolAdapter) external; function setCustomPoolAdapter(address pool, address poolAdapter) external; /// lp token staker function switchLpTokenStaker(address _lpTokenStaker) external; function lpTokenStaker() external view returns (ILpTokenStaker); // bonding function bonding() external view returns (IBonding); function setBonding(address _bonding) external; // fees function feeRecipient() external view returns (IFeeRecipient); function setFeeRecipient(address _feeRecipient) external; // oracle function priceOracle() external view returns (IGenericOracle); function setPriceOracle(address oracle) external; // pool functions function listPools() external view returns (address[] memory); function listActivePools() external view returns (address[] memory); function isPool(address poolAddress) external view returns (bool); function isActivePool(address poolAddress) external view returns (bool); function addPool(address poolAddress) external; function shutdownPool(address poolAddress) external; function removePool(address poolAddress) external; function cncToken() external view returns (address); function lastWeightUpdate(address poolAddress) external view returns (uint256); function updateWeights(WeightUpdate memory update) external; function updateAllWeights(WeightUpdate[] memory weights) external; // handler functions function convexBooster() external view returns (address); function curveHandler() external view returns (address); function convexHandler() external view returns (address); function setConvexBooster(address _convexBooster) external; function setCurveHandler(address _curveHandler) external; function setConvexHandler(address _convexHandler) external; function setCurveRegistryCache(address curveRegistryCache_) external; function setWeightUpdateMinDelay(uint256 delay) external; function isPauseManager(address account) external view returns (bool); function listPauseManagers() external view returns (address[] memory); function setPauseManager(address account, bool isManager) external; // deposit/withdrawal whitelist function isAllowedMultipleDepositsWithdraws(address poolAddress) external view returns (bool); function setAllowedMultipleDepositsWithdraws(address account, bool allowed) external; function getMultipleDepositsWithdrawsWhitelist() external view returns (address[] memory); // tainted transfer amount function setMinimumTaintedTransferAmount(address token, uint256 amount) external; function getMinimumTaintedTransferAmount(address token) external view returns (uint256); // constants function MAX_WEIGHT_UPDATE_MIN_DELAY() external view returns (uint256); function MIN_WEIGHT_UPDATE_MIN_DELAY() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IConicPoolWeightManagement { struct PoolWeight { address poolAddress; uint256 weight; } function addPool(address pool) external; function removePool(address pool) external; function updateWeights(PoolWeight[] memory poolWeights) external; function handleDepeggedCurvePool(address curvePool_) external; function handleInvalidConvexPid(address pool) external returns (uint256); function allPools() external view returns (address[] memory); function poolsCount() external view returns (uint256); function getPoolAtIndex(uint256 _index) external view returns (address); function getWeight(address curvePool) external view returns (uint256); function getWeights() external view returns (PoolWeight[] memory); function isRegisteredPool(address _pool) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "IOracle.sol"; interface IGenericOracle is IOracle { /// @notice returns the oracle to be used to price `token` function getOracle(address token) external view returns (IOracle); /// @notice converts the price of an LP token to the given underlying function curveLpToUnderlying( address curveLpToken, address underlying, uint256 curveLpAmount ) external view returns (uint256); /// @notice same as above but avoids fetching the underlying price again function curveLpToUnderlying( address curveLpToken, address underlying, uint256 curveLpAmount, uint256 underlyingPrice ) external view returns (uint256); /// @notice converts the price an underlying asset to a given Curve LP token function underlyingToCurveLp( address underlying, address curveLpToken, uint256 underlyingAmount ) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IInflationManager { event TokensClaimed(address indexed pool, uint256 cncAmount); event RebalancingRewardHandlerAdded(address indexed pool, address indexed handler); event RebalancingRewardHandlerRemoved(address indexed pool, address indexed handler); event PoolWeightsUpdated(); function executeInflationRateUpdate() external; function updatePoolWeights() external; /// @notice returns the weights of the Conic pools to know how much inflation /// each of them will receive, as well as the total amount of USD value in all the pools function computePoolWeights() external view returns (address[] memory _pools, uint256[] memory poolWeights, uint256 totalUSDValue); function computePoolWeight( address pool ) external view returns (uint256 poolWeight, uint256 totalUSDValue); function currentInflationRate() external view returns (uint256); function getCurrentPoolInflationRate(address pool) external view returns (uint256); function handleRebalancingRewards( address account, uint256 deviationBefore, uint256 deviationAfter ) external; function addPoolRebalancingRewardHandler( address poolAddress, address rebalancingRewardHandler ) external; function removePoolRebalancingRewardHandler( address poolAddress, address rebalancingRewardHandler ) external; function rebalancingRewardHandlers( address poolAddress ) external view returns (address[] memory); function hasPoolRebalancingRewardHandler( address poolAddress, address handler ) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface ILpTokenStaker { event LpTokenStaked(address indexed account, uint256 amount); event LpTokenUnstaked(address indexed account, uint256 amount); event TokensClaimed(address indexed pool, uint256 cncAmount); event Shutdown(); function stake(uint256 amount, address conicPool) external; function unstake(uint256 amount, address conicPool) external; function stakeFor(uint256 amount, address conicPool, address account) external; function unstakeFor(uint256 amount, address conicPool, address account) external; function unstakeFrom(uint256 amount, address account) external; function getUserBalanceForPool( address conicPool, address account ) external view returns (uint256); function getBalanceForPool(address conicPool) external view returns (uint256); function updateBoost(address user) external; function claimCNCRewardsForPool(address pool) external; function claimableCnc(address pool) external view returns (uint256); function checkpoint(address pool) external returns (uint256); function shutdown() external; function getBoost(address user) external view returns (uint256); function isShutdown() external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IBonding { event CncStartPriceSet(uint256 startPrice); event PriceIncreaseFactorSet(uint256 factor); event MinBondingAmountSet(uint256 amount); event Bonded( address indexed account, address indexed recipient, uint256 lpTokenAmount, uint256 cncReceived, uint256 lockTime ); event DebtPoolSet(address indexed pool); event DebtPoolFeesClaimed(uint256 crvAmount, uint256 cvxAmount, uint256 cncAmount); event StreamClaimed(address indexed account, uint256 amount); event BondingStarted(uint256 amount, uint256 epochs); event RemainingCNCRecovered(uint256 amount); function startBonding() external; function setCncStartPrice(uint256 _cncStartPrice) external; function setCncPriceIncreaseFactor(uint256 _priceIncreaseFactor) external; function setMinBondingAmount(uint256 _minBondingAmount) external; function setDebtPool(address _debtPool) external; function bondCncCrvUsd( uint256 lpTokenAmount, uint256 minCncReceived, uint64 cncLockTime ) external returns (uint256); function recoverRemainingCNC() external; function claimStream() external; function claimFeesForDebtPool() external; function streamCheckpoint() external; function accountCheckpoint(address account) external; function computeCurrentCncBondPrice() external view returns (uint256); function cncAvailable() external view returns (uint256); function cncBondPrice() external view returns (uint256); function bondCncCrvUsdFor( uint256 lpTokenAmount, uint256 minCncReceived, uint64 cncLockTime, address recipient ) external returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IPoolAdapter { /// @notice This is to set which LP token price the value computation should use /// `Latest` uses a freshly computed price /// `Cached` uses the price in cache /// `Minimum` uses the minimum of these two enum PriceMode { Latest, Cached, Minimum } /// @notice Deposit `underlyingAmount` of `underlying` into `pool` /// @dev This function should be written with the assumption that it will be delegate-called into function deposit(address pool, address underlying, uint256 underlyingAmount) external; /// @notice Withdraw `underlyingAmount` of `underlying` from `pool` /// @dev This function should be written with the assumption that it will be delegate-called into function withdraw(address pool, address underlying, uint256 underlyingAmount) external; /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of USD function computePoolValueInUSD( address conicPool, address pool ) external view returns (uint256 usdAmount); /// @notice Updates the price caches of the given pools function updatePriceCache(address pool) external; /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of USD /// using the given price mode function computePoolValueInUSD( address conicPool, address pool, PriceMode priceMode ) external view returns (uint256 usdAmount); /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of underlying function computePoolValueInUnderlying( address conicPool, address pool, address underlying, uint256 underlyingPrice ) external view returns (uint256 underlyingAmount); /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of underlying /// using the given price mode function computePoolValueInUnderlying( address conicPool, address pool, address underlying, uint256 underlyingPrice, PriceMode priceMode ) external view returns (uint256 underlyingAmount); /// @notice Claim earnings of `conicPool` from `pool` function claimEarnings(address conicPool, address pool) external; /// @notice Returns the LP token of a given `pool` function lpToken(address pool) external view returns (address); /// @notice Returns true if `pool` supports `asset` function supportsAsset(address pool, address asset) external view returns (bool); /// @notice Returns the amount of CRV earned by `pool` on Convex function getCRVEarnedOnConvex( address account, address curvePool ) external view returns (uint256); /// @notice Executes a sanity check, e.g. checking for reentrancy function executeSanityCheck(address pool) external; /// @notice returns all the underlying coins of the pool function getAllUnderlyingCoins(address pool) external view returns (address[] memory); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IFeeRecipient { event FeesReceived(address indexed sender, uint256 crvAmount, uint256 cvxAmount); function receiveFees(uint256 amountCrv, uint256 amountCvx) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "IBooster.sol"; import "CurvePoolUtils.sol"; interface ICurveRegistryCache { event PoolInitialized(address indexed pool, uint256 indexed pid); function BOOSTER() external view returns (IBooster); function initPool(address pool_) external; function initPool(address pool_, uint256 pid_) external; function lpToken(address pool_) external view returns (address); function assetType(address pool_) external view returns (CurvePoolUtils.AssetType); function isRegistered(address pool_) external view returns (bool); function hasCoinDirectly(address pool_, address coin_) external view returns (bool); function hasCoinAnywhere(address pool_, address coin_) external view returns (bool); function basePool(address pool_) external view returns (address); function coinIndex(address pool_, address coin_) external view returns (int128); function nCoins(address pool_) external view returns (uint256); function coinIndices( address pool_, address from_, address to_ ) external view returns (int128, int128, bool); function decimals(address pool_) external view returns (uint256[] memory); function interfaceVersion(address pool_) external view returns (uint256); function poolFromLpToken(address lpToken_) external view returns (address); function coins(address pool_) external view returns (address[] memory); function getPid(address _pool) external view returns (uint256); function getRewardPool(address _pool) external view returns (address); function isShutdownPid(uint256 pid_) external view returns (bool); /// @notice this returns the underlying coins of a pool, including the underlying of the base pool /// if the given pool is a meta pool /// This does not return the LP token of the base pool as an underlying /// e.g. if the pool is 3CrvFrax, this will return FRAX, DAI, USDC, USDT function getAllUnderlyingCoins(address pool) external view returns (address[] memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; interface IBooster { function poolInfo( uint256 pid ) external view returns ( address lpToken, address token, address gauge, address crvRewards, address stash, bool shutdown ); function poolLength() external view returns (uint256); function deposit(uint256 _pid, uint256 _amount, bool _stake) external returns (bool); function withdraw(uint256 _pid, uint256 _amount) external returns (bool); function withdrawAll(uint256 _pid) external returns (bool); function depositAll(uint256 _pid, bool _stake) external returns (bool); function earmarkRewards(uint256 _pid) external returns (bool); function isShutdown() external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "ICurvePoolV2.sol"; import "ICurvePoolV1.sol"; import "ScaledMath.sol"; library CurvePoolUtils { using ScaledMath for uint256; error NotWithinThreshold(address pool, uint256 assetA, uint256 assetB); /// @dev by default, allow for 30 bps deviation regardless of pool fees uint256 internal constant _DEFAULT_IMBALANCE_BUFFER = 30e14; /// @dev Curve scales the `fee` by 1e10 uint8 internal constant _CURVE_POOL_FEE_DECIMALS = 10; /// @dev allow imbalance to be buffer + 3x the fee, e.g. if fee is 3.6 bps and buffer is 30 bps, allow 40.8 bps uint256 internal constant _FEE_IMBALANCE_MULTIPLIER = 3; enum AssetType { USD, ETH, BTC, OTHER, CRYPTO } struct PoolMeta { address pool; uint256 numberOfCoins; AssetType assetType; uint256[] decimals; uint256[] prices; uint256[] imbalanceBuffers; } function ensurePoolBalanced(PoolMeta memory poolMeta) internal view { uint256 poolFee = ICurvePoolV1(poolMeta.pool).fee().convertScale( _CURVE_POOL_FEE_DECIMALS, 18 ); for (uint256 i = 0; i < poolMeta.numberOfCoins - 1; i++) { uint256 fromDecimals = poolMeta.decimals[i]; uint256 fromBalance = 10 ** fromDecimals; uint256 fromPrice = poolMeta.prices[i]; for (uint256 j = i + 1; j < poolMeta.numberOfCoins; j++) { uint256 toDecimals = poolMeta.decimals[j]; uint256 toPrice = poolMeta.prices[j]; uint256 toExpectedUnscaled = (fromBalance * fromPrice) / toPrice; uint256 toExpected = toExpectedUnscaled.convertScale( uint8(fromDecimals), uint8(toDecimals) ); uint256 toActual; if (poolMeta.assetType == AssetType.CRYPTO) { // Handling crypto pools toActual = ICurvePoolV2(poolMeta.pool).get_dy(i, j, fromBalance); } else { // Handling other pools toActual = ICurvePoolV1(poolMeta.pool).get_dy( int128(uint128(i)), int128(uint128(j)), fromBalance ); } uint256 _maxImbalanceBuffer = poolMeta.imbalanceBuffers[i].max( poolMeta.imbalanceBuffers[j] ); if (!_isWithinThreshold(toExpected, toActual, poolFee, _maxImbalanceBuffer)) revert NotWithinThreshold(poolMeta.pool, i, j); } } } function _isWithinThreshold( uint256 a, uint256 b, uint256 poolFee, uint256 imbalanceBuffer ) internal pure returns (bool) { if (imbalanceBuffer == 0) imbalanceBuffer = _DEFAULT_IMBALANCE_BUFFER; uint256 imbalanceTreshold = imbalanceBuffer + poolFee * _FEE_IMBALANCE_MULTIPLIER; if (a > b) return (a - b).divDown(a) <= imbalanceTreshold; return (b - a).divDown(b) <= imbalanceTreshold; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; interface ICurvePoolV2 { function token() external view returns (address); function coins(uint256 i) external view returns (address); function factory() external view returns (address); function exchange( uint256 i, uint256 j, uint256 dx, uint256 min_dy, bool use_eth, address receiver ) external returns (uint256); function exchange_underlying( uint256 i, uint256 j, uint256 dx, uint256 min_dy, address receiver ) external returns (uint256); function add_liquidity( uint256[2] memory amounts, uint256 min_mint_amount, bool use_eth, address receiver ) external returns (uint256); function add_liquidity( uint256[2] memory amounts, uint256 min_mint_amount ) external returns (uint256); function add_liquidity( uint256[3] memory amounts, uint256 min_mint_amount, bool use_eth, address receiver ) external returns (uint256); function add_liquidity( uint256[3] memory amounts, uint256 min_mint_amount ) external returns (uint256); function remove_liquidity( uint256 _amount, uint256[2] memory min_amounts, bool use_eth, address receiver ) external; function remove_liquidity(uint256 _amount, uint256[2] memory min_amounts) external; function remove_liquidity( uint256 _amount, uint256[3] memory min_amounts, bool use_eth, address receiver ) external; function remove_liquidity(uint256 _amount, uint256[3] memory min_amounts) external; function remove_liquidity_one_coin( uint256 token_amount, uint256 i, uint256 min_amount, bool use_eth, address receiver ) external returns (uint256); function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256); function calc_token_amount(uint256[] memory amounts) external view returns (uint256); function calc_withdraw_one_coin( uint256 token_amount, uint256 i ) external view returns (uint256); function get_virtual_price() external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; interface ICurvePoolV1 { function get_virtual_price() external view returns (uint256); function add_liquidity(uint256[8] calldata amounts, uint256 min_mint_amount) external; function add_liquidity(uint256[7] calldata amounts, uint256 min_mint_amount) external; function add_liquidity(uint256[6] calldata amounts, uint256 min_mint_amount) external; function add_liquidity(uint256[5] calldata amounts, uint256 min_mint_amount) external; function add_liquidity(uint256[4] calldata amounts, uint256 min_mint_amount) external; function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount) external; function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount) external; function remove_liquidity_imbalance( uint256[4] calldata amounts, uint256 max_burn_amount ) external; function remove_liquidity_imbalance( uint256[3] calldata amounts, uint256 max_burn_amount ) external; function remove_liquidity_imbalance( uint256[2] calldata amounts, uint256 max_burn_amount ) external; function lp_token() external view returns (address); function A_PRECISION() external view returns (uint256); function A_precise() external view returns (uint256); function remove_liquidity(uint256 _amount, uint256[3] calldata min_amounts) external; function exchange( int128 from, int128 to, uint256 _from_amount, uint256 _min_to_amount ) external; function coins(uint256 i) external view returns (address); function balances(uint256 i) external view returns (uint256); function get_dy(int128 i, int128 j, uint256 _dx) external view returns (uint256); function calc_token_amount( uint256[4] calldata amounts, bool deposit ) external view returns (uint256); function calc_token_amount( uint256[3] calldata amounts, bool deposit ) external view returns (uint256); function calc_token_amount( uint256[2] calldata amounts, bool deposit ) external view returns (uint256); function calc_withdraw_one_coin( uint256 _token_amount, int128 i ) external view returns (uint256); function remove_liquidity_one_coin( uint256 _token_amount, int128 i, uint256 min_amount ) external; function fee() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; library ScaledMath { uint256 internal constant DECIMALS = 18; uint256 internal constant ONE = 10 ** DECIMALS; function mulDown(uint256 a, uint256 b) internal pure returns (uint256) { return (a * b) / ONE; } function mulDown(uint256 a, uint256 b, uint256 decimals) internal pure returns (uint256) { return (a * b) / (10 ** decimals); } function divDown(uint256 a, uint256 b) internal pure returns (uint256) { return (a * ONE) / b; } function divDown(uint256 a, uint256 b, uint256 decimals) internal pure returns (uint256) { return (a * 10 ** decimals) / b; } function divUp(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } return ((a * ONE) - 1) / b + 1; } function mulDown(int256 a, int256 b) internal pure returns (int256) { return (a * b) / int256(ONE); } function mulDownUint128(uint128 a, uint128 b) internal pure returns (uint128) { return (a * b) / uint128(ONE); } function mulDown(int256 a, int256 b, uint256 decimals) internal pure returns (int256) { return (a * b) / int256(10 ** decimals); } function divDown(int256 a, int256 b) internal pure returns (int256) { return (a * int256(ONE)) / b; } function divDownUint128(uint128 a, uint128 b) internal pure returns (uint128) { return (a * uint128(ONE)) / b; } function divDown(int256 a, int256 b, uint256 decimals) internal pure returns (int256) { return (a * int256(10 ** decimals)) / b; } function convertScale( uint256 a, uint8 fromDecimals, uint8 toDecimals ) internal pure returns (uint256) { if (fromDecimals == toDecimals) return a; if (fromDecimals > toDecimals) return downscale(a, fromDecimals, toDecimals); return upscale(a, fromDecimals, toDecimals); } function convertScale( int256 a, uint8 fromDecimals, uint8 toDecimals ) internal pure returns (int256) { if (fromDecimals == toDecimals) return a; if (fromDecimals > toDecimals) return downscale(a, fromDecimals, toDecimals); return upscale(a, fromDecimals, toDecimals); } function upscale( uint256 a, uint8 fromDecimals, uint8 toDecimals ) internal pure returns (uint256) { return a * (10 ** (toDecimals - fromDecimals)); } function downscale( uint256 a, uint8 fromDecimals, uint8 toDecimals ) internal pure returns (uint256) { return a / (10 ** (fromDecimals - toDecimals)); } function upscale( int256 a, uint8 fromDecimals, uint8 toDecimals ) internal pure returns (int256) { return a * int256(10 ** (toDecimals - fromDecimals)); } function downscale( int256 a, uint8 fromDecimals, uint8 toDecimals ) internal pure returns (int256) { return a / int256(10 ** (fromDecimals - toDecimals)); } function intPow(uint256 a, uint256 n) internal pure returns (uint256) { uint256 result = ONE; for (uint256 i; i < n; ) { result = mulDown(result, a); unchecked { ++i; } } return result; } function absSub(uint256 a, uint256 b) internal pure returns (uint256) { unchecked { return a >= b ? a - b : b - a; } } function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a <= b ? a : b; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "Ownable.sol"; import "IController.sol"; interface IPausable { event Paused(uint256 pausedUntil); event PauseDurationSet(uint256 pauseDuration); function controller() external view returns (IController); function pausedUntil() external view returns (uint256); function pauseDuration() external view returns (uint256); function isPaused() external view returns (bool); function setPauseDuration(uint256 _pauseDuration) external; function pause() external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; interface IWithdrawalProcessor { function processWithdrawal(address account, uint256 underlyingAmount) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; interface IBaseRewardPool { function stakeFor(address, uint256) external; function stake(uint256) external; function stakeAll() external returns (bool); function withdraw(uint256 amount, bool claim) external returns (bool); function withdrawAndUnwrap(uint256 amount, bool claim) external returns (bool); function earned(address account) external view returns (uint256); function getReward() external; function getReward(address _account, bool _claimExtras) external; function extraRewardsLength() external view returns (uint256); function extraRewards(uint256 _pid) external view returns (address); function rewardToken() external view returns (address); function balanceOf(address account) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "ERC20.sol"; import "SafeERC20.sol"; import "IController.sol"; import "ILpToken.sol"; contract LpToken is ILpToken, ERC20 { IController public immutable controller; address public immutable override minter; modifier onlyMinter() { require(msg.sender == minter, "not authorized"); _; } mapping(address => uint256) internal _lastEvent; uint8 private __decimals; constructor( address _controller, address _minter, uint8 _decimals, string memory name_, string memory symbol_ ) ERC20(name_, symbol_) { controller = IController(_controller); minter = _minter; __decimals = _decimals; } function decimals() public view virtual override(ERC20, IERC20Metadata) returns (uint8) { return __decimals; } function mint( address _account, uint256 _amount, address ubo ) external override onlyMinter returns (uint256) { _ensureSingleEvent(ubo, _amount); _mint(_account, _amount); return _amount; } function burn( address _owner, uint256 _amount, address ubo ) external override onlyMinter returns (uint256) { _ensureSingleEvent(ubo, _amount); _burn(_owner, _amount); return _amount; } function taint(address from, address to, uint256 amount) external { require(msg.sender == address(controller.lpTokenStaker()), "not authorized"); _taint(from, to, amount); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal override { // mint/burn are handled in their respective functions if (from == address(0) || to == address(0)) return; // lpTokenStaker calls `taint` as needed address lpTokenStaker = address(controller.lpTokenStaker()); if (from == lpTokenStaker || to == lpTokenStaker) return; // taint any other type of transfer _taint(from, to, amount); } function _ensureSingleEvent(address ubo, uint256 amount) internal { if ( !controller.isAllowedMultipleDepositsWithdraws(ubo) && amount > controller.getMinimumTaintedTransferAmount(address(this)) ) { require(_lastEvent[ubo] != block.number, "cannot mint/burn twice in a block"); _lastEvent[ubo] = block.number; } } function _taint(address from, address to, uint256 amount) internal { if ( from != to && _lastEvent[from] == block.number && amount > controller.getMinimumTaintedTransferAmount(address(this)) ) { _lastEvent[to] = block.number; } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "Ownable.sol"; import "IController.sol"; import "IPausable.sol"; abstract contract Pausable is Ownable, IPausable { uint256 internal constant _MIN_PAUSE_DURATION = 1 hours; uint256 internal constant _MAX_PAUSE_DURATION = 3 days; uint256 internal constant _INITIAL_PAUSE_DURATION = 8 hours; uint256 public pausedUntil; uint256 public pauseDuration; IController public immutable controller; modifier notPaused() { require(!isPaused(), "paused"); _; } constructor(IController _controller) { controller = _controller; pauseDuration = _INITIAL_PAUSE_DURATION; } function setPauseDuration(uint256 _pauseDuration) external onlyOwner { require(_pauseDuration >= _MIN_PAUSE_DURATION, "pause duration too short"); require(_pauseDuration <= _MAX_PAUSE_DURATION, "pause duration too long"); pauseDuration = _pauseDuration; emit PauseDurationSet(pauseDuration); } function pause() external { require(controller.isPauseManager(msg.sender), "not pause manager"); pausedUntil = block.timestamp + pauseDuration; emit Paused(pausedUntil); } function isPaused() public view override returns (bool) { return pausedUntil >= block.timestamp; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "EnumerableSet.sol"; import "EnumerableMap.sol"; import "SafeERC20.sol"; import "IConicPool.sol"; import "IConicPoolWeightManager.sol"; import "ScaledMath.sol"; contract ConicPoolWeightManager is IConicPoolWeightManager { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableMap for EnumerableMap.AddressToUintMap; using ScaledMath for uint256; using SafeERC20 for IERC20; event CurvePoolAdded(address curvePool_); event CurvePoolRemoved(address curvePool_); event NewWeight(address indexed curvePool, uint256 newWeight); uint256 internal constant _MAX_USD_VALUE_FOR_REMOVING_POOL = 100e18; uint256 internal constant _MAX_CURVE_POOLS = 10; IConicPool public immutable conicPool; IController public immutable controller; IERC20Metadata public immutable underlying; EnumerableSet.AddressSet internal _pools; EnumerableMap.AddressToUintMap internal weights; // liquidity allocation weights modifier onlyController() { require(msg.sender == address(controller), "not authorized"); _; } modifier onlyConicPool() { require(msg.sender == address(conicPool), "not authorized"); _; } constructor(IController _controller, IERC20Metadata _underlying) { conicPool = IConicPool(msg.sender); controller = _controller; underlying = _underlying; } function addPool(address _pool) external onlyConicPool { require(_pools.length() < _MAX_CURVE_POOLS, "max pools reached"); require(!_pools.contains(_pool), "pool already added"); IPoolAdapter poolAdapter = controller.poolAdapterFor(_pool); bool supported_ = poolAdapter.supportsAsset(_pool, address(underlying)); require(supported_, "coin not in pool"); address lpToken_ = poolAdapter.lpToken(_pool); require(controller.priceOracle().isTokenSupported(lpToken_), "cannot price LP Token"); if (!weights.contains(_pool)) weights.set(_pool, 0); require(_pools.add(_pool), "failed to add pool"); emit CurvePoolAdded(_pool); } // This requires that the weight of the pool is first set to 0 function removePool(address _pool) external onlyConicPool { require(_pools.contains(_pool), "pool not added"); require(_pools.length() > 1, "cannot remove last pool"); IPoolAdapter poolAdapter = controller.poolAdapterFor(_pool); uint256 usdValue = poolAdapter.computePoolValueInUSD(address(conicPool), _pool); require(usdValue < _MAX_USD_VALUE_FOR_REMOVING_POOL, "pool has allocated funds"); uint256 weight = weights.get(_pool); require(weight == 0, "pool has weight set"); require(_pools.remove(_pool), "pool not removed"); require(weights.remove(_pool), "weight not removed"); emit CurvePoolRemoved(_pool); } function updateWeights(PoolWeight[] memory poolWeights) external onlyConicPool { require(poolWeights.length == _pools.length(), "invalid pool weights"); uint256 total; address previousPool; for (uint256 i; i < poolWeights.length; i++) { address pool_ = poolWeights[i].poolAddress; require(pool_ > previousPool, "pools not sorted"); require(isRegisteredPool(pool_), "pool is not registered"); uint256 newWeight = poolWeights[i].weight; weights.set(pool_, newWeight); emit NewWeight(pool_, newWeight); total += newWeight; previousPool = pool_; } require(total == ScaledMath.ONE, "weights do not sum to 1"); } function handleDepeggedCurvePool(address curvePool_) external onlyConicPool { // Validation require(isRegisteredPool(curvePool_), "pool is not registered"); require(weights.get(curvePool_) != 0, "pool weight already 0"); // Set target curve pool weight to 0 // Scale up other weights to compensate _setWeightToZero(curvePool_); } function handleInvalidConvexPid(address curvePool_) external onlyConicPool returns (uint256) { require(isRegisteredPool(curvePool_), "curve pool not registered"); ICurveRegistryCache registryCache_ = controller.curveRegistryCache(); uint256 pid = registryCache_.getPid(curvePool_); require(registryCache_.isShutdownPid(pid), "convex pool pid is not shut down"); _setWeightToZero(curvePool_); return pid; } function getDepositPool( uint256 totalUnderlying_, uint256[] memory allocatedPerPool, uint256 maxDeviation ) external view returns (uint256 poolIndex, uint256 maxDepositAmount) { uint256 poolsCount_ = allocatedPerPool.length; int256 iPoolIndex = -1; for (uint256 i; i < poolsCount_; i++) { address pool_ = _pools.at(i); uint256 allocatedUnderlying_ = allocatedPerPool[i]; uint256 weight_ = weights.get(pool_); uint256 targetAllocation_ = totalUnderlying_.mulDown(weight_); if (allocatedUnderlying_ >= targetAllocation_) continue; // Compute max balance with deviation uint256 weightWithDeviation_ = weight_.mulDown(ScaledMath.ONE + maxDeviation); weightWithDeviation_ = weightWithDeviation_ > ScaledMath.ONE ? ScaledMath.ONE : weightWithDeviation_; uint256 maxBalance_ = totalUnderlying_.mulDown(weightWithDeviation_); uint256 maxDepositAmount_ = maxBalance_ - allocatedUnderlying_; if (maxDepositAmount_ <= maxDepositAmount) continue; maxDepositAmount = maxDepositAmount_; iPoolIndex = int256(i); } require(iPoolIndex > -1, "error retrieving deposit pool"); poolIndex = uint256(iPoolIndex); } function getWithdrawPool( uint256 totalUnderlying_, uint256[] memory allocatedPerPool, uint256 maxDeviation ) external view returns (uint256 withdrawPoolIndex, uint256 maxWithdrawalAmount) { uint256 poolsCount_ = allocatedPerPool.length; int256 iWithdrawPoolIndex = -1; for (uint256 i; i < poolsCount_; i++) { address curvePool_ = _pools.at(i); uint256 weight_ = weights.get(curvePool_); uint256 allocatedUnderlying_ = allocatedPerPool[i]; // If a pool has a weight of 0, // withdraw from it if it has more than the max lp value if (weight_ == 0) { uint256 price_ = controller.priceOracle().getUSDPrice(address(underlying)); uint256 allocatedUsd = (price_ * allocatedUnderlying_) / 10 ** underlying.decimals(); if (allocatedUsd >= _MAX_USD_VALUE_FOR_REMOVING_POOL / 2) { return (uint256(i), allocatedUnderlying_); } } uint256 targetAllocation_ = totalUnderlying_.mulDown(weight_); if (allocatedUnderlying_ <= targetAllocation_) continue; uint256 minBalance_ = targetAllocation_ - targetAllocation_.mulDown(maxDeviation); uint256 maxWithdrawalAmount_ = allocatedUnderlying_ - minBalance_; if (maxWithdrawalAmount_ <= maxWithdrawalAmount) continue; maxWithdrawalAmount = maxWithdrawalAmount_; iWithdrawPoolIndex = int256(i); } require(iWithdrawPoolIndex > -1, "error retrieving withdraw pool"); withdrawPoolIndex = uint256(iWithdrawPoolIndex); } function allPools() external view returns (address[] memory) { return _pools.values(); } function poolsCount() external view returns (uint256) { return _pools.length(); } function getPoolAtIndex(uint256 _index) external view returns (address) { return _pools.at(_index); } function isRegisteredPool(address _pool) public view returns (bool) { return _pools.contains(_pool); } function getWeight(address pool) external view returns (uint256) { return weights.get(pool); } function getWeights() external view returns (IConicPool.PoolWeight[] memory) { uint256 length_ = _pools.length(); IConicPool.PoolWeight[] memory weights_ = new IConicPool.PoolWeight[](length_); for (uint256 i; i < length_; i++) { (address pool_, uint256 weight_) = weights.at(i); weights_[i] = PoolWeight(pool_, weight_); } return weights_; } function computeTotalDeviation( uint256 allocatedUnderlying_, uint256[] memory perPoolAllocations_ ) external view returns (uint256) { uint256 totalDeviation; for (uint256 i; i < perPoolAllocations_.length; i++) { uint256 weight = weights.get(_pools.at(i)); uint256 targetAmount = allocatedUnderlying_.mulDown(weight); totalDeviation += targetAmount.absSub(perPoolAllocations_[i]); } return totalDeviation; } function isBalanced( uint256[] memory allocatedPerPool_, uint256 totalAllocated_, uint256 maxDeviation ) external view returns (bool) { if (totalAllocated_ == 0) return true; for (uint256 i; i < allocatedPerPool_.length; i++) { uint256 weight_ = weights.get(_pools.at(i)); uint256 currentAllocated_ = allocatedPerPool_[i]; // If a curve pool has a weight of 0, if (weight_ == 0) { uint256 price_ = controller.priceOracle().getUSDPrice(address(underlying)); uint256 allocatedUsd_ = (price_ * currentAllocated_) / 10 ** underlying.decimals(); if (allocatedUsd_ >= _MAX_USD_VALUE_FOR_REMOVING_POOL / 2) { return false; } continue; } uint256 targetAmount = totalAllocated_.mulDown(weight_); uint256 deviation = targetAmount.absSub(currentAllocated_); uint256 deviationRatio = deviation.divDown(targetAmount); if (deviationRatio > maxDeviation) return false; } return true; } function _setWeightToZero(address zeroedPool) internal { uint256 weight_ = weights.get(zeroedPool); if (weight_ == 0) return; require(weight_ != ScaledMath.ONE, "can't remove last pool"); uint256 scaleUp_ = ScaledMath.ONE.divDown(ScaledMath.ONE - weights.get(zeroedPool)); uint256 curvePoolLength_ = _pools.length(); weights.set(zeroedPool, 0); emit NewWeight(zeroedPool, 0); address[] memory nonZeroPools = new address[](curvePoolLength_ - 1); uint256[] memory nonZeroWeights = new uint256[](curvePoolLength_ - 1); uint256 nonZeroPoolsCount; for (uint256 i; i < curvePoolLength_; i++) { address pool_ = _pools.at(i); uint256 currentWeight = weights.get(pool_); if (currentWeight == 0) continue; nonZeroPools[nonZeroPoolsCount] = pool_; nonZeroWeights[nonZeroPoolsCount] = currentWeight; nonZeroPoolsCount++; } uint256 totalWeight; for (uint256 i; i < nonZeroPoolsCount; i++) { address pool_ = nonZeroPools[i]; uint256 newWeight_ = nonZeroWeights[i].mulDown(scaleUp_); // ensure that the sum of the weights is 1 despite potential rounding errors if (i == nonZeroPoolsCount - 1) { newWeight_ = ScaledMath.ONE - totalWeight; } totalWeight += newWeight_; weights.set(pool_, newWeight_); emit NewWeight(pool_, newWeight_); } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; import "IConicPoolWeightManagement.sol"; interface IConicPoolWeightManager is IConicPoolWeightManagement { function getDepositPool( uint256 totalUnderlying_, uint256[] memory allocatedPerPool, uint256 maxDeviation ) external view returns (uint256 poolIndex, uint256 maxDepositAmount); function getWithdrawPool( uint256 totalUnderlying_, uint256[] memory allocatedPerPool, uint256 maxDeviation ) external view returns (uint256 withdrawPoolIndex, uint256 maxWithdrawalAmount); function computeTotalDeviation( uint256 allocatedUnderlying_, uint256[] memory perPoolAllocations_ ) external view returns (uint256); function isBalanced( uint256[] memory allocatedPerPool_, uint256 totalAllocated_, uint256 maxDeviation ) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.17; library ArrayExtensions { function copy(uint256[] memory array) internal pure returns (uint256[] memory) { uint256[] memory copy_ = new uint256[](array.length); for (uint256 i = 0; i < array.length; i++) { copy_[i] = array[i]; } return copy_; } function concat( address[] memory a, address[] memory b ) internal pure returns (address[] memory result) { result = new address[](a.length + b.length); for (uint256 i; i < a.length; i++) result[i] = a[i]; for (uint256 i; i < b.length; i++) result[i + a.length] = b[i]; } function includes(address[] memory array, address element) internal pure returns (bool) { return _includes(array, element, array.length); } function _includes( address[] memory array, address element, uint256 until ) internal pure returns (bool) { for (uint256 i; i < until; i++) { if (array[i] == element) return true; } return false; } function removeDuplicates(address[] memory array) internal pure returns (address[] memory) { address[] memory unique = new address[](array.length); uint256 j; for (uint256 i; i < array.length; i++) { if (!_includes(unique, array[i], j)) { unique[j++] = array[i]; } } return trim(unique, j); } function trim( address[] memory array, uint256 length ) internal pure returns (address[] memory trimmed) { trimmed = new address[](length); for (uint256 i; i < length; i++) trimmed[i] = array[i]; } }
{ "evmVersion": "london", "optimizer": { "enabled": true, "runs": 200 }, "libraries": { "ConicPool.sol": {} }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"contract IRewardManager","name":"_rewardManager","type":"address"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"string","name":"_lpTokenName","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_cvx","type":"address"},{"internalType":"address","name":"_crv","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"claimedCrv","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimedCvx","type":"uint256"}],"name":"ClaimedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"curvePool_","type":"address"}],"name":"CurvePoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"curvePool_","type":"address"}],"name":"CurvePoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newThreshold","type":"uint256"}],"name":"DepegThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpReceived","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"factor","type":"uint256"}],"name":"EmergencyRebalancingRewardFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"curvePool_","type":"address"}],"name":"HandledDepeggedCurvePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"curvePool_","type":"address"},{"indexed":false,"internalType":"uint256","name":"pid_","type":"uint256"}],"name":"HandledInvalidConvexPid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxDeviation","type":"uint256"}],"name":"MaxDeviationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"NewMaxIdleCurveLpRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"curvePool","type":"address"},{"indexed":false,"internalType":"uint256","name":"newWeight","type":"uint256"}],"name":"NewWeight","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pauseDuration","type":"uint256"}],"name":"PauseDurationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pausedUntil","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"RebalancingRewardsEnabledSet","type":"event"},{"anonymous":false,"inputs":[],"name":"Shutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allPools","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cachedTotalUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"computeTotalDeviation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depegThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"internalType":"uint256","name":"minLpReceived","type":"uint256"},{"internalType":"bool","name":"stake","type":"bool"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"internalType":"uint256","name":"minLpReceived","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"internalType":"uint256","name":"minLpReceived","type":"uint256"},{"internalType":"bool","name":"stake","type":"bool"}],"name":"depositFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyRebalancingRewardsFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllUnderlyingCoins","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllocatedUnderlying","outputs":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IConicPool.PoolWithAmount[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getPoolAtIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalAndPerPoolUnderlying","outputs":[{"internalType":"uint256","name":"totalUnderlying_","type":"uint256"},{"internalType":"uint256","name":"totalAllocated_","type":"uint256"},{"internalType":"uint256[]","name":"perPoolUnderlying_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"curvePool","type":"address"}],"name":"getWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWeights","outputs":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"weight","type":"uint256"}],"internalType":"struct IConicPoolWeightManagement.PoolWeight[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"curvePool_","type":"address"}],"name":"handleDepeggedCurvePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"curvePool_","type":"address"}],"name":"handleInvalidConvexPid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBalanced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"name":"isRegisteredPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken","outputs":[{"internalType":"contract ILpToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDeviation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxIdleCurveLpRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pausedUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalancingRewardActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalancingRewardsActivatedAt","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalancingRewardsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalancingRewardsFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"name":"removePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardManager","outputs":[{"internalType":"contract IRewardManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"runSanityChecks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"factor_","type":"uint256"}],"name":"setEmergencyRebalancingRewardFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxDeviation_","type":"uint256"}],"name":"setMaxDeviation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxIdleCurveLpRatio_","type":"uint256"}],"name":"setMaxIdleCurveLpRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pauseDuration","type":"uint256"}],"name":"setPauseDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setRebalancingRewardsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shutdownPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalDeviationAfterWeightUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"conicLpAmount","type":"uint256"},{"internalType":"uint256","name":"minUnderlyingReceived","type":"uint256"}],"name":"unstakeAndWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"conicLpAmount","type":"uint256"},{"internalType":"uint256","name":"minUnderlyingReceived","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"unstakeAndWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newDepegThreshold_","type":"uint256"}],"name":"updateDepegThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"updateRewardSpendingApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"weight","type":"uint256"}],"internalType":"struct IConicPoolWeightManagement.PoolWeight[]","name":"poolWeights","type":"tuple[]"}],"name":"updateWeights","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weightManager","outputs":[{"internalType":"contract IConicPoolWeightManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"conicLpAmount","type":"uint256"},{"internalType":"uint256","name":"minUnderlyingReceived","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"conicLpAmount","type":"uint256"},{"internalType":"uint256","name":"minUnderlyingReceived","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
61016060405266470de4df82000060035566b1a2bc2ec50000600455666a94d74f430000600655678ac7230489e80000600a553480156200003f57600080fd5b506040516200a4be3803806200a4be83398101604081905262000062916200080c565b86868686868686846200007533620002e6565b6001600160a01b0390811660805261708060025587811690831614801590620000b05750806001600160a01b0316876001600160a01b031614155b8015620000da57506001600160a01b038716739ae380f0272e2162340a5bb646c354271c0f5cfc14155b620001215760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420756e6465726c79696e6760701b60448201526064015b60405180910390fd5b866001600160a01b031660e0816001600160a01b0316815250506000876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200017c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001a29190620008e3565b90508530828787604051620001b7906200070a565b620001c79594939291906200093d565b604051809103906000f080158015620001e4573d6000803e3d6000fd5b506001600160a01b0390811661010052871661012052604051869089906200020c9062000718565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801562000240573d6000803e3d6000fd5b506001600160a01b039081166101405283811660a081905290831660c05262000279908860001962000336602090811b620033d917901c565b620002a28760001960c0516001600160a01b03166200033660201b620033d9179092919060201c565b620002d1739ae380f0272e2162340a5bb646c354271c0f5cfc8860001962000336602090811b620033d917901c565b50505050505050505050505050505062000a05565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b801580620003b45750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156200038c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003b2919062000994565b155b620004285760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606482015260840162000118565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620004809185916200048516565b505050565b6000620004e1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200056660201b62003521179092919060201c565b905080516000148062000505575080806020019051810190620005059190620009ae565b620004805760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000118565b60606200057784846000856200057f565b949350505050565b606082471015620005e25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000118565b600080866001600160a01b03168587604051620006009190620009d2565b60006040518083038185875af1925050503d80600081146200063f576040519150601f19603f3d011682016040523d82523d6000602084013e62000644565b606091505b509092509050620006588783838762000663565b979650505050505050565b60608315620006d7578251600003620006cf576001600160a01b0385163b620006cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000118565b508162000577565b620005778383815115620006ee5781518083602001fd5b8060405162461bcd60e51b8152600401620001189190620009f0565b611517806200671d83390190565b61288a8062007c3483390190565b6001600160a01b03811681146200073c57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200077257818101518382015260200162000758565b50506000910152565b600082601f8301126200078d57600080fd5b81516001600160401b0380821115620007aa57620007aa6200073f565b604051601f8301601f19908116603f01168101908282118183101715620007d557620007d56200073f565b81604052838152866020858801011115620007ef57600080fd5b6200080284602083016020890162000755565b9695505050505050565b600080600080600080600060e0888a0312156200082857600080fd5b8751620008358162000726565b6020890151909750620008488162000726565b60408901519096506200085b8162000726565b60608901519095506001600160401b03808211156200087957600080fd5b620008878b838c016200077b565b955060808a01519150808211156200089e57600080fd5b50620008ad8a828b016200077b565b93505060a0880151620008c08162000726565b60c0890151909250620008d38162000726565b8091505092959891949750929550565b600060208284031215620008f657600080fd5b815160ff811681146200090857600080fd5b9392505050565b600081518084526200092981602086016020860162000755565b601f01601f19169290920160200192915050565b6001600160a01b0386811682528516602082015260ff8416604082015260a06060820181905260009062000974908301856200090f565b82810360808401526200098881856200090f565b98975050505050505050565b600060208284031215620009a757600080fd5b5051919050565b600060208284031215620009c157600080fd5b815180151581146200090857600080fd5b60008251620009e681846020870162000755565b9190910192915050565b6020815260006200090860208301846200090f565b60805160a05160c05160e051610100516101205161014051615ad962000c44600039600081816106f701528181610f5301528181611163015281816112e2015281816117a10152818161181101528181611aff01528181612449015281816125de0152818161276e0152818161284d015281816128cb015281816129f601528181612ad001528181612c6a01528181612d10015281816130a701528181613627015281816136e201528181613b9e015281816141720152818161438f01528181614457015281816147010152818161477f015261498c01526000818161048f01528181611a4e0152611aae01526000818161072b01528181610b3e01528181610dce015281816121420152818161224101528181612322015261353501526000818161038c015281816107bd01528181610c0e01528181610cf401528181610e5101528181611639015281816116cc01528181611ef301528181611f9e01528181611ff301528181612f220152818161380001528181613d3701528181613e1001528181613ea8015261457d0152600050506000505060008181610b030152818161103c015281816111e9015281816115a2015281816118d301528181611b5f01528181611c0401528181611e5c015281816121b4015281816124de015281816127f901528181612e8b01528181612fbf01528181613107015281816131ac0152818161378001528181613cba01528181613f0e015281816140330152818161424a015281816144fd015281816148100152614a140152615ad96000f3fe6080604052600436106103855760003560e01c80638456cb59116101d1578063c5c63e6511610102578063d6038dc6116100a0578063e2bbb1581161006f578063e2bbb15814610a9b578063f0ea87f614610abb578063f2fde38b14610ad1578063f77c479114610af157600080fd5b8063d6038dc614610a30578063d914cd4b14610a45578063da748b1014610a65578063dddbc04914610a7b57600080fd5b8063c9387332116100dc578063c9387332146109d0578063cb03a464146109f0578063ce75040e14610a05578063d1e6c1e514610a1a57600080fd5b8063c5c63e6514610986578063c699e6331461099b578063c70920bc146109bb57600080fd5b80639e4865621161016f578063b0a4396811610149578063b0a4396814610914578063b187bd2614610934578063b7b3b8c01461094c578063bf86d6901461096c57600080fd5b80639e486562146108bf578063a58f1d8e146108de578063ac6c5251146108f457600080fd5b80638da5cb5b116101ab5780638da5cb5b146108555780638dbfb25b14610873578063904c9bf0146108935780639765ca151461089f57600080fd5b80638456cb591461080957806386fe9a661461081e5780638c788de01461084057600080fd5b806336797aec116102b6578063441a3e70116102545780636e4f3338116102235780636e4f33381461076d5780636f307dc3146107ab578063715018a6146107df57806383645abf146107f457600080fd5b8063441a3e70146106c55780634af1cd69146106e55780635fcbd2851461071957806365f203551461074d57600080fd5b80633b7d0946116102905780633b7d09461461065a5780633ba0b9a91461067a5780633d4912c31461068f57806343a0d066146106a557600080fd5b806336797aec14610604578063377f7eaa146106245780633a172ddc1461063a57600080fd5b806322acb867116103235780632c3da47d116102fd5780632c3da47d146105765780632cf818011461059657806332f44c42146105c0578063331666fa146105e057600080fd5b806322acb8671461052957806324a71a661461054b5780632a1bab731461056057600080fd5b80630f4ef8a61161035f5780630f4ef8a61461047d5780631010b58c146104c957806310aec8f9146104e95780631280a5b61461050957600080fd5b80630526679c146104125780630ad58d2f1461043b5780630c3457891461045b57600080fd5b3661040d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21461040b5760405162461bcd60e51b815260206004820152600d60248201526c1b9bdd0815d15512081c1bdbdb609a1b60448201526064015b60405180910390fd5b005b600080fd5b34801561041e57600080fd5b5061042860025481565b6040519081526020015b60405180910390f35b34801561044757600080fd5b506104286104563660046151a0565b610b25565b34801561046757600080fd5b50610470610f4d565b60405161043291906151d9565b34801561048957600080fd5b506104b17f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610432565b3480156104d557600080fd5b506104b16104e4366004615226565b61114a565b3480156104f557600080fd5b5061042861050436600461523f565b6111dc565b34801561051557600080fd5b506104286105243660046151a0565b6111e5565b34801561053557600080fd5b5061053e6112de565b6040516104329190615261565b34801561055757600080fd5b5061042861136b565b34801561056c57600080fd5b5061042860035481565b34801561058257600080fd5b5061040b610591366004615226565b611394565b3480156105a257600080fd5b506009546105b09060ff1681565b6040519015158152602001610432565b3480156105cc57600080fd5b5061040b6105db366004615226565b611498565b3480156105ec57600080fd5b506105f5611599565b604051610432939291906152fc565b34801561061057600080fd5b5061040b61061f36600461531b565b6116c7565b34801561063057600080fd5b50610428600a5481565b34801561064657600080fd5b5061040b610655366004615346565b611a43565b34801561066657600080fd5b5061040b61067536600461531b565b611ad8565b34801561068657600080fd5b50610428611cf2565b34801561069b57600080fd5b5061042860065481565b3480156106b157600080fd5b506104286106c036600461537f565b611d04565b3480156106d157600080fd5b506104286106e036600461523f565b611d12565b3480156106f157600080fd5b506104b17f000000000000000000000000000000000000000000000000000000000000000081565b34801561072557600080fd5b506104b17f000000000000000000000000000000000000000000000000000000000000000081565b34801561075957600080fd5b506104286107683660046153ad565b611d1f565b34801561077957600080fd5b50600954610793906201000090046001600160401b031681565b6040516001600160401b039091168152602001610432565b3480156107b757600080fd5b506104b17f000000000000000000000000000000000000000000000000000000000000000081565b3480156107eb57600080fd5b5061040b61240c565b34801561080057600080fd5b50610428612420565b34801561081557600080fd5b5061040b6124c9565b34801561082a57600080fd5b506108336125d8565b60405161043291906153f7565b34801561084c57600080fd5b5061042861276a565b34801561086157600080fd5b506000546001600160a01b03166104b1565b34801561087f57600080fd5b5061040b61088e3660046154db565b6127ee565b34801561040b57600080fd5b3480156108ab57600080fd5b506104286108ba36600461531b565b6129d2565b3480156108cb57600080fd5b506009546105b090610100900460ff1681565b3480156108ea57600080fd5b5061042860045481565b34801561090057600080fd5b5061042861090f36600461531b565b612aae565b34801561092057600080fd5b5061040b61092f366004615226565b612b3d565b34801561094057600080fd5b506001544211156105b0565b34801561095857600080fd5b5061040b610967366004615593565b612bf3565b34801561097857600080fd5b506005546105b09060ff1681565b34801561099257600080fd5b50610470612c66565b3480156109a757600080fd5b506105b06109b636600461531b565b612cee565b3480156109c757600080fd5b50610428612d7d565b3480156109dc57600080fd5b5061040b6109eb366004615226565b612d88565b3480156109fc57600080fd5b506105b0612e6a565b348015610a1157600080fd5b50610428612e86565b348015610a2657600080fd5b50610428600c5481565b348015610a3c57600080fd5b5061040b612fb4565b348015610a5157600080fd5b5061040b610a6036600461531b565b613080565b348015610a7157600080fd5b5061042860015481565b348015610a8757600080fd5b5061040b610a96366004615226565b61329b565b348015610aa757600080fd5b50610428610ab636600461523f565b613351565b348015610ac757600080fd5b50610428600b5481565b348015610add57600080fd5b5061040b610aec36600461531b565b613360565b348015610afd57600080fd5b506104b17f000000000000000000000000000000000000000000000000000000000000000081565b60006040516370a0823160e01b815233600482015284907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610b8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb191906155b0565b1015610bf65760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610402565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8191906155b0565b90506000806000610c90611599565b9250925092506000610cab610ca485613530565b8a906135dd565b905080851015610cd0576000610cc186836155df565b9050610cce8484836135ff565b505b6040516370a0823160e01b8152306004820152600090610d65906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f91906155b0565b836138ba565b905088811015610dab5760405162461bcd60e51b8152602060048201526011602482015270746f6f206d75636820736c69707061676560781b6044820152606401610402565b60405163b8ce670d60e01b81523360048201819052602482018c905260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b8ce670d906064016020604051808303816000875af1158015610e1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4391906155b0565b50610e786001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001689836138d0565b610e8281866155df565b60085542600755610ea36001600160a01b038916632098244360e21b613900565b15610f0957604051632098244360e21b8152336004820152602481018290526001600160a01b03891690638260910c90604401600060405180830381600087803b158015610ef057600080fd5b505af1158015610f04573d6000803e3d6000fd5b505050505b60405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a2955050505050505b9392505050565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa158015610faf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fd791908101906155f2565b8051604080516000808252602082019092529293509091905b8281101561113857600084828151811061100c5761100c615680565b60209081029190910101516040516355eb6b3560e01b81526001600160a01b0380831660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a79190615696565b604051622708db60e01b81526001600160a01b0384811660048301529190911690622708db90602401600060405180830381865afa1580156110ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261111591908101906155f2565b9050611121848261391c565b935050508080611130906156b3565b915050610ff0565b5061114281613a47565b935050505090565b6040516304042d6360e21b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631010b58c90602401602060405180830381865afa1580156111b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d69190615696565b92915050565b6000610f468383335b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166348439e7e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611245573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112699190615696565b604051630325d16160e01b8152600481018690523360248201526001600160a01b039190911690630325d16190604401600060405180830381600087803b1580156112b357600080fd5b505af11580156112c7573d6000803e3d6000fd5b505050506112d6848484610b25565b949350505050565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166322acb8676040518163ffffffff1660e01b8152600401600060405180830381865afa15801561133e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261136691908101906156cc565b905090565b60006203f48060075461137e919061577f565b42111561138d57611366612d7d565b5060085490565b61139c613b3b565b670de0b6b3a76400008110156113eb5760405162461bcd60e51b8152602060048201526014602482015273666163746f722062656c6f77206d696e696d756d60601b6044820152606401610402565b68056bc75e2d6310000081111561143b5760405162461bcd60e51b8152602060048201526014602482015273666163746f722061626f7665206d6178696d756d60601b6044820152606401610402565b600a54810361145c5760405162461bcd60e51b815260040161040290615792565b600a8190556040518181527f43b89d4b5fdc149d21160712a4e8a2c76927dccd7aae23fd717f753758044a6f906020015b60405180910390a150565b6114a0613b3b565b662386f26fc100008110156114f15760405162461bcd60e51b81526020600482015260176024820152761a5b9d985b1a590819195c1959c81d1a1c995cda1bdb19604a1b6044820152606401610402565b67016345785d8a00008111156115435760405162461bcd60e51b81526020600482015260176024820152761a5b9d985b1a590819195c1959c81d1a1c995cda1bdb19604a1b6044820152606401610402565b60065481036115645760405162461bcd60e51b815260040161040290615792565b60068190556040518181527f20da4a1840e5e1bb25784e941f370e4db630545ed9434c8c0bad8e421480595b9060200161148d565b600080606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116229190615696565b604051638b2f0f4f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529190911690638b2f0f4f90602401602060405180830381865afa15801561168a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ae91906155b0565b90506116bb816000613b95565b93509350935050909192565b6116f07f0000000000000000000000000000000000000000000000000000000000000000613e98565b156117365760405162461bcd60e51b81526020600482015260166024820152751d5b99195c9b1e5a5b99c81a5cc819195c1959d9d95960521b6044820152606401610402565b61173f8161400f565b6117825760405162461bcd60e51b81526020600482015260146024820152731c1bdbdb081a5cc81b9bdd0819195c1959d9d95960621b6044820152606401610402565b604051630d9e5ebb60e21b81526001600160a01b0382811660048301527f000000000000000000000000000000000000000000000000000000000000000016906336797aec90602401600060405180830381600087803b1580156117e557600080fd5b505af11580156117f9573d6000803e3d6000fd5b50505050600080611808611599565b925050915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637e412a7a84846040518363ffffffff1660e01b815260040161185d9291906157bb565b602060405180830381865afa15801561187a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189e91906155b0565b600c81905560095490915060ff1615611a01576040516355eb6b3560e01b81526001600160a01b0385811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906355eb6b3590602401602060405180830381865afa15801561191c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119409190615696565b604051633dfa59d160e01b81523060048201526001600160a01b038781166024830152919250600091831690633dfa59d190604401602060405180830381865afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b691906155b0565b905068056bc75e2d631000008111156119fe5760098054600a54600b5561ff00196001600160401b03421662010000021669ffffffffffffffffff0019909116176101001790555b50505b6040516001600160a01b03851681527f7d90518f39c7f92fd9046bbb246d9c650dd159f73cca88aa7d919c89c040fa799060200160405180910390a150505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611a8b5760405162461bcd60e51b8152600401610402906157d4565b600081611a99576000611a9d565b6000195b9050611ad36001600160a01b0384167f0000000000000000000000000000000000000000000000000000000000000000836133d9565b505050565b611ae0613b3b565b604051631dbe84a360e11b81526001600160a01b0382811660048301527f00000000000000000000000000000000000000000000000000000000000000001690633b7d094690602401600060405180830381600087803b158015611b4357600080fd5b505af1158015611b57573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632cdacb506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bdf9190615696565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa158015611c4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6f9190615696565b604051631da958a960e21b81526001600160a01b03858116600483015291909116906376a562a490602401602060405180830381865afa158015611cb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdb9190615696565b9050611ad36001600160a01b0382168360006133d9565b6000611366611cff612d7d565b613530565b60006112d633858585611d1f565b6000610f46838333610b25565b6000611d2d60015442111590565b15611d635760405162461bcd60e51b81526020600482015260066024820152651c185d5cd95960d21b6044820152606401610402565b611db9604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016000815260200160008152602001606081525090565b60055460ff1615611e005760405162461bcd60e51b81526020600482015260116024820152703837b7b61034b99039b43aba103237bbb760791b6044820152606401610402565b60008511611e505760405162461bcd60e51b815260206004820152601d60248201527f6465706f73697420616d6f756e742063616e6e6f74206265207a65726f0000006044820152606401610402565b611e5861416e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc9190615696565b604051638b2f0f4f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529190911690638b2f0f4f90602401602060405180830381865afa158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6891906155b0565b9050611f75816001613b95565b60c085015260a084015260808301819052611f8f90613530565b8252611fc66001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333089614329565b60a082015160c08301516040516370a0823160e01b81523060048201526120639291906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561203a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205e91906155b0565b614367565b61206e816002613b95565b61012085015261010084015260e08301819052608083015161208f916155df565b602083018190526120a19087906138ba565b6040830181905282516120b4919061462f565b606083018190528511156120fe5760405162461bcd60e51b8152602060048201526011602482015270746f6f206d75636820736c69707061676560781b6044820152606401610402565b60e08201516008554260075583156122ec576060820151604051630d4d151360e01b815230600482015260248101919091526001600160a01b0388811660448301527f00000000000000000000000000000000000000000000000000000000000000001690630d4d1513906064016020604051808303816000875af115801561218b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121af91906155b0565b5060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166348439e7e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612210573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122349190615696565b90506122788184606001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166146489092919063ffffffff16565b60608301516040516333f1c33760e01b815260048101919091523060248201526001600160a01b0389811660448301528216906333f1c33790606401600060405180830381600087803b1580156122ce57600080fd5b505af11580156122e2573d6000803e3d6000fd5b5050505050612393565b6060820151604051630d4d151360e01b81526001600160a01b0389811660048301819052602483019390935260448201929092527f000000000000000000000000000000000000000000000000000000000000000090911690630d4d1513906064016020604051808303816000875af115801561236d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239191906155b0565b505b6123b2878360a001518460c001518561010001518661012001516146d7565b60608201516040805188815260208101929092526001600160a01b0389169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3506060015195945050505050565b612414613b3b565b61241e600061491f565b565b600080600061242d611599565b604051633f20953d60e11b815291945092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169150637e412a7a9061248190859085906004016157bb565b602060405180830381865afa15801561249e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c291906155b0565b9250505090565b604051634eb3ffc360e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690634eb3ffc390602401602060405180830381865afa15801561252d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255191906157fc565b6125915760405162461bcd60e51b81526020600482015260116024820152703737ba103830bab9b29036b0b730b3b2b960791b6044820152606401610402565b60025461259e904261577f565b60018190556040519081527f32fb7c9891bc4f963c7de9f1186d2a7755c7d6e9f4604dabe1d8bb3027c2f49e9060200160405180910390a1565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa15801561263a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261266291908101906155f2565b9050600081516001600160401b0381111561267f5761267f61544a565b6040519080825280602002602001820160405280156126c457816020015b604080518082019091526000808252602082015281526020019060019003908161269d5790505b50905060006126d1611599565b9250505060005b82518110156127615760405180604001604052808583815181106126fe576126fe615680565b60200260200101516001600160a01b0316815260200183838151811061272657612726615680565b602002602001015181525083828151811061274357612743615680565b60200260200101819052508080612759906156b3565b9150506126d8565b50909392505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638c788de06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127ca573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136691906155b0565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146128365760405162461bcd60e51b8152600401610402906157d4565b604051638dbfb25b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638dbfb25b90612882908490600401615261565b600060405180830381600087803b15801561289c57600080fd5b505af11580156128b0573d6000803e3d6000fd5b5050505060008060006128c1611599565b92509250925060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637e412a7a85846040518363ffffffff1660e01b81526004016129179291906157bb565b602060405180830381865afa158015612934573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061295891906155b0565b600c81905560095490915060ff1680156129795750612977828461496f565b155b600980549115156101000261ff001990921691909117905561299d6012600a6158fd565b600b556009805469ffffffffffffffff0000191662010000426001600160401b0316021790556129cb614a04565b5050505050565b604051639765ca1560e01b81526001600160a01b03828116600483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690639765ca15906024016020604051808303816000875af1158015612a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6391906155b0565b604080516001600160a01b0386168152602081018390529192507fb6e3324444a482d3e4041851d767063381c41cd9abc8a3191a0b61e3896f9443910160405180910390a192915050565b60405163ac6c525160e01b81526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063ac6c525190602401602060405180830381865afa158015612b19573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d691906155b0565b612b45613b3b565b8060045403612b665760405162461bcd60e51b815260040161040290615792565b6702c68af0bb140000811115612bbe5760405162461bcd60e51b815260206004820152601960248201527f726174696f206578636565647320757070657220626f756e64000000000000006044820152606401610402565b60048190556040518181527fcf75d305993755a06325155bdff6a203ff5eb28a3561e219588aeb6aba8b3b549060200161148d565b612bfb613b3b565b60095481151560ff909116151503612c255760405162461bcd60e51b815260040161040290615792565b6009805460ff19168215159081179091556040519081527f279cee3d8f87ec526dc3da1f7f9000d2bedd53531863d9e85e52ea363c3d13059060200161148d565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa158015612cc6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261136691908101906155f2565b60405163c699e63360e01b81526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063c699e63390602401602060405180830381865afa158015612d59573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d691906157fc565b600080612761611599565b612d90613b3b565b610e10811015612de25760405162461bcd60e51b815260206004820152601860248201527f7061757365206475726174696f6e20746f6f2073686f727400000000000000006044820152606401610402565b6203f480811115612e355760405162461bcd60e51b815260206004820152601760248201527f7061757365206475726174696f6e20746f6f206c6f6e670000000000000000006044820152606401610402565b60028190556040518181527fa959cb2cc91580147f93f66fb85db8f308cfdaef3989ab5265408ff80ef6fa669060200161148d565b6000806000612e77611599565b92509250506124c2818361496f565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ee7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0b9190615696565b604051638b2f0f4f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529190911690638b2f0f4f90602401602060405180830381865afa158015612f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9791906155b0565b9050612fae81612fa8611cff61136b565b906135dd565b91505090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ffc5760405162461bcd60e51b8152600401610402906157d4565b60055460ff16156130485760405162461bcd60e51b81526020600482015260166024820152753837b7b61030b63932b0b23c9039b43aba103237bbb760511b6044820152606401610402565b6005805460ff191660011790556040517f4426aa1fb73e391071491fcfe21a88b5c38a0a0333a1f6e77161470439704cf890600090a1565b613088613b3b565b60405163d914cd4b60e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063d914cd4b90602401600060405180830381600087803b1580156130eb57600080fd5b505af11580156130ff573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632cdacb506040518163ffffffff1660e01b8152600401602060405180830381865afa158015613163573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131879190615696565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa1580156131f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132179190615696565b604051631da958a960e21b81526001600160a01b03858116600483015291909116906376a562a490602401602060405180830381865afa15801561325f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132839190615696565b9050611ad36001600160a01b038216836000196133d9565b6132a3613b3b565b80600354036132c45760405162461bcd60e51b815260040161040290615792565b6702c68af0bb14000081111561331c5760405162461bcd60e51b815260206004820152601d60248201527f646576696174696f6e206578636565647320757070657220626f756e640000006044820152606401610402565b60038190556040518181527f3f9ef5ed5d378ef819698e4b3c710d362f981f90087b428b7a1ee1e716d689d59060200161148d565b6000610f463384846001611d1f565b613368613b3b565b6001600160a01b0381166133cd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610402565b6133d68161491f565b50565b8015806134535750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561342d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345191906155b0565b155b6134be5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610402565b6040516001600160a01b038316602482015260448101829052611ad390849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614b5b565b60606112d68484600085614c30565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b591906155b0565b90508015806135c2575082155b156135d357610f466012600a6158fd565b610f46838261462f565b60006135eb6012600a6158fd565b6135f58385615909565b610f469190615920565b80600061360c82866155df565b9050600061361985614d0b565b90505b82156138b2576000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166339d82513858561365e614da9565b6040518463ffffffff1660e01b815260040161367c93929190615942565b6040805180830381865afa158015613698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136bc919061596b565b6040516304042d6360e21b81526004810183905291935091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631010b58c90602401602060405180830381865afa158015613729573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374d9190615696565b9050600061375b87846138ba565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa1580156137c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137eb9190615696565b6040516001600160a01b0380861660248301527f0000000000000000000000000000000000000000000000000000000000000000166044820152606481018490529091506138709060840160408051601f198184030181529190526020810180516001600160e01b0316636ce5768960e11b1790526001600160a01b03831690614dc8565b5061387b82896155df565b97508186868151811061389057613890615680565b602002602001018181516138a491906155df565b90525061361c945050505050565b505050505050565b60008183106138c95781610f46565b5090919050565b6040516001600160a01b038316602482015260448101829052611ad390849063a9059cbb60e01b906064016134ea565b600061390b83614ded565b8015610f465750610f468383614e20565b60608151835161392c919061577f565b6001600160401b038111156139435761394361544a565b60405190808252806020026020018201604052801561396c578160200160208202803683370190505b50905060005b83518110156139d15783818151811061398d5761398d615680565b60200260200101518282815181106139a7576139a7615680565b6001600160a01b0390921660209283029190910190910152806139c9816156b3565b915050613972565b5060005b8251811015613a40578281815181106139f0576139f0615680565b602002602001015182855183613a06919061577f565b81518110613a1657613a16615680565b6001600160a01b039092166020928302919091019091015280613a38816156b3565b9150506139d5565b5092915050565b6060600082516001600160401b03811115613a6457613a6461544a565b604051908082528060200260200182016040528015613a8d578160200160208202803683370190505b5090506000805b8451811015613b3057613ac183868381518110613ab357613ab3615680565b602002602001015184614ea5565b613b1e57848181518110613ad757613ad7615680565b6020026020010151838380613aeb906156b3565b945081518110613afd57613afd615680565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80613b28816156b3565b915050613a94565b506112d68282614f0a565b6000546001600160a01b0316331461241e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610402565b600080606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa158015613bfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c2291908101906155f2565b8051909150806001600160401b03811115613c3f57613c3f61544a565b604051908082528060200260200182016040528015613c68578160200160208202803683370190505b50925060005b81811015613dfa576000838281518110613c8a57613c8a615680565b60209081029190910101516040516355eb6b3560e01b81526001600160a01b0380831660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa158015613d01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d259190615696565b6001600160a01b0316630fee68b330847f00000000000000000000000000000000000000000000000000000000000000008e8e6040518663ffffffff1660e01b8152600401613d7895949392919061598f565b602060405180830381865afa158015613d95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db991906155b0565b905080868481518110613dce57613dce615680565b6020908102919091010152613de3818861577f565b965050508080613df2906156b3565b915050613c6e565b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8391906155b0565b613e8d908561577f565b945050509250925092565b6006546000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811690841603613edf57613edc600282615909565b90505b6001600160a01b038084166000908152600d60209081526040808320548151632630c12f60e01b8152915190947f00000000000000000000000000000000000000000000000000000000000000001692632630c12f92600480820193918290030181865afa158015613f55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f799190615696565b604051638b2f0f4f60e01b81526001600160a01b0387811660048301529190911690638b2f0f4f90602401602060405180830381865afa158015613fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe591906155b0565b90506000613ff38383614fb1565b90506000614001828561462f565b949094119695505050505050565b6040516355eb6b3560e01b81526001600160a01b03828116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa15801561407a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061409e9190615696565b604051622708db60e01b81526001600160a01b0385811660048301529190911690622708db90602401600060405180830381865afa1580156140e4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261410c91908101906155f2565b905060005b815181101561416457600082828151811061412e5761412e615680565b6020026020010151905061414181613e98565b1561415157506001949350505050565b508061415c816156b3565b915050614111565b5060009392505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa1580156141ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526141f691908101906155f2565b805190915060005b81811015611ad357600083828151811061421a5761421a615680565b60209081029190910101516040516355eb6b3560e01b81526001600160a01b0380831660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa158015614291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142b59190615696565b60405163415ec73b60e01b81526001600160a01b0384811660048301529192509082169063415ec73b90602401600060405180830381600087803b1580156142fc57600080fd5b505af1158015614310573d6000803e3d6000fd5b5050505050508080614321906156b3565b9150506141fe565b6040516001600160a01b03808516602483015283166044820152606481018290526143619085906323b872dd60e01b906084016134ea565b50505050565b806000614374828661577f565b9050600061438185614d0b565b90505b82156138b2576000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166312968a2985856143c6614da9565b6040518463ffffffff1660e01b81526004016143e493929190615942565b6040805180830381865afa158015614400573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614424919061596b565b909250905061443481606461577f565b85101561443e5750835b6040516304042d6360e21b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631010b58c90602401602060405180830381865afa1580156144a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144ca9190615696565b905060006144d887846138ba565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906355eb6b3590602401602060405180830381865afa158015614544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145689190615696565b6040516001600160a01b0380861660248301527f0000000000000000000000000000000000000000000000000000000000000000166044820152606481018490529091506145ed9060840160408051601f198184030181529190526020810180516001600160e01b0316638340f54960e01b1790526001600160a01b03831690614dc8565b506145f882896155df565b97508186868151811061460d5761460d615680565b60200260200101818151614621919061577f565b905250614384945050505050565b60008161463e6012600a6158fd565b6135f59085615909565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526146998482614fc9565b614361576040516001600160a01b0384166024820152600060448201526146cd90859063095ea7b360e01b906064016134ea565b6143618482614b5b565b600954610100900460ff16156129cb57604051633f20953d60e11b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637e412a7a9061473890889088906004016157bb565b602060405180830381865afa158015614755573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061477991906155b0565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637e412a7a85856040518363ffffffff1660e01b81526004016147cb9291906157bb565b602060405180830381865afa1580156147e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480c91906155b0565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dbcd89fa6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561486c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148909190615696565b604051630a48af5f60e11b81526001600160a01b038981166004830152602482018590526044820184905291909116906314915ebe90606401600060405180830381600087803b1580156148e357600080fd5b505af11580156148f7573d6000803e3d6000fd5b50505050614905838561496f565b15614916576009805461ff00191690555b50505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6003546040516328cb81ef60e11b81526000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163519703de916149c391879187916004016159e4565b602060405180830381865afa1580156149e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4691906157fc565b6000614a0e610f4d565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a949190615696565b905060005b8251811015611ad3576000838281518110614ab657614ab6615680565b6020908102919091010151604051638b2f0f4f60e01b81526001600160a01b03808316600483015291925090841690638b2f0f4f90602401602060405180830381865afa158015614b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b2f91906155b0565b6001600160a01b039091166000908152600d602052604090205580614b53816156b3565b915050614a99565b6000614bb0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135219092919063ffffffff16565b9050805160001480614bd1575080806020019051810190614bd191906157fc565b611ad35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610402565b606082471015614c915760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610402565b600080866001600160a01b03168587604051614cad9190615a2d565b60006040518083038185875af1925050503d8060008114614cea576040519150601f19603f3d011682016040523d82523d6000602084013e614cef565b606091505b5091509150614d0087838387615070565b979650505050505050565b6060600082516001600160401b03811115614d2857614d2861544a565b604051908082528060200260200182016040528015614d51578160200160208202803683370190505b50905060005b8351811015613a4057838181518110614d7257614d72615680565b6020026020010151828281518110614d8c57614d8c615680565b602090810291909101015280614da1816156b3565b915050614d57565b600954600090610100900460ff16614dc2575060035490565b50600090565b6060610f468383604051806060016040528060278152602001615a7d602791396150e9565b6000614e00826301ffc9a760e01b614e20565b80156111d65750614e19826001600160e01b0319614e20565b1592915050565b604080516001600160e01b03198316602480830191909152825180830390910181526044909101909152602080820180516001600160e01b03166301ffc9a760e01b178152825160009392849283928392918391908a617530fa92503d91506000519050828015614e92575060208210155b8015614d00575015159695505050505050565b6000805b82811015614eff57836001600160a01b0316858281518110614ecd57614ecd615680565b60200260200101516001600160a01b031603614eed576001915050610f46565b80614ef7816156b3565b915050614ea9565b506000949350505050565b6060816001600160401b03811115614f2457614f2461544a565b604051908082528060200260200182016040528015614f4d578160200160208202803683370190505b50905060005b82811015613a4057838181518110614f6d57614f6d615680565b6020026020010151828281518110614f8757614f87615680565b6001600160a01b039092166020928302919091019091015280614fa9816156b3565b915050614f53565b600081831015614fc357828203610f46565b50900390565b6000806000846001600160a01b031684604051614fe69190615a2d565b6000604051808303816000865af19150503d8060008114615023576040519150601f19603f3d011682016040523d82523d6000602084013e615028565b606091505b509150915081801561505257508051158061505257508080602001905181019061505291906157fc565b801561506757506001600160a01b0385163b15155b95945050505050565b606083156150df5782516000036150d8576001600160a01b0385163b6150d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610402565b50816112d6565b6112d68383615161565b6060600080856001600160a01b0316856040516151069190615a2d565b600060405180830381855af49150503d8060008114615141576040519150601f19603f3d011682016040523d82523d6000602084013e615146565b606091505b509150915061515786838387615070565b9695505050505050565b8151156151715781518083602001fd5b8060405162461bcd60e51b81526004016104029190615a49565b6001600160a01b03811681146133d657600080fd5b6000806000606084860312156151b557600080fd5b833592506020840135915060408401356151ce8161518b565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b8181101561521a5783516001600160a01b0316835292840192918401916001016151f5565b50909695505050505050565b60006020828403121561523857600080fd5b5035919050565b6000806040838503121561525257600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156152b4576152a484835180516001600160a01b03168252602090810151910152565b928401929085019060010161527e565b5091979650505050505050565b600081518084526020808501945080840160005b838110156152f1578151875295820195908201906001016152d5565b509495945050505050565b83815282602082015260606040820152600061506760608301846152c1565b60006020828403121561532d57600080fd5b8135610f468161518b565b80151581146133d657600080fd5b6000806040838503121561535957600080fd5b82356153648161518b565b9150602083013561537481615338565b809150509250929050565b60008060006060848603121561539457600080fd5b833592506020840135915060408401356151ce81615338565b600080600080608085870312156153c357600080fd5b84356153ce8161518b565b9350602085013592506040850135915060608501356153ec81615338565b939692955090935050565b602080825282518282018190526000919060409081850190868401855b828110156152b45761543a84835180516001600160a01b03168252602090810151910152565b9284019290850190600101615414565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156154825761548261544a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156154b0576154b061544a565b604052919050565b60006001600160401b038211156154d1576154d161544a565b5060051b60200190565b600060208083850312156154ee57600080fd5b82356001600160401b0381111561550457600080fd5b8301601f8101851361551557600080fd5b8035615528615523826154b8565b615488565b81815260069190911b8201830190838101908783111561554757600080fd5b928401925b82841015614d0057604084890312156155655760008081fd5b61556d615460565b84356155788161518b565b8152848601358682015282526040909301929084019061554c565b6000602082840312156155a557600080fd5b8135610f4681615338565b6000602082840312156155c257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156111d6576111d66155c9565b6000602080838503121561560557600080fd5b82516001600160401b0381111561561b57600080fd5b8301601f8101851361562c57600080fd5b805161563a615523826154b8565b81815260059190911b8201830190838101908783111561565957600080fd5b928401925b82841015614d005783516156718161518b565b8252928401929084019061565e565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156156a857600080fd5b8151610f468161518b565b6000600182016156c5576156c56155c9565b5060010190565b600060208083850312156156df57600080fd5b82516001600160401b038111156156f557600080fd5b8301601f8101851361570657600080fd5b8051615714615523826154b8565b81815260069190911b8201830190838101908783111561573357600080fd5b928401925b82841015614d0057604084890312156157515760008081fd5b615759615460565b84516157648161518b565b81528486015186820152825260409093019290840190615738565b808201808211156111d6576111d66155c9565b6020808252600f908201526e1cd85b5948185cc818dd5c9c995b9d608a1b604082015260600190565b8281526040602082015260006112d660408301846152c1565b6020808252600e908201526d1b9bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60006020828403121561580e57600080fd5b8151610f4681615338565b600181815b8085111561585457816000190482111561583a5761583a6155c9565b8085161561584757918102915b93841c939080029061581e565b509250929050565b60008261586b575060016111d6565b81615878575060006111d6565b816001811461588e5760028114615898576158b4565b60019150506111d6565b60ff8411156158a9576158a96155c9565b50506001821b6111d6565b5060208310610133831016604e8410600b84101617156158d7575081810a6111d6565b6158e18383615819565b80600019048211156158f5576158f56155c9565b029392505050565b6000610f46838361585c565b80820281158282048414176111d6576111d66155c9565b60008261593d57634e487b7160e01b600052601260045260246000fd5b500490565b83815260606020820152600061595b60608301856152c1565b9050826040830152949350505050565b6000806040838503121561597e57600080fd5b505080516020909101519092909150565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a08101600383106159d457634e487b7160e01b600052602160045260246000fd5b8260808301529695505050505050565b6060815260006159f760608301866152c1565b60208301949094525060400152919050565b60005b83811015615a24578181015183820152602001615a0c565b50506000910152565b60008251615a3f818460208701615a09565b9190910192915050565b6020815260008251806020840152615a68816040850160208701615a09565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e036bcfeb1a7d33ecc69abc563e339a4f1f63b3230b1dc5a2a85bc92779392cf64736f6c6343000811003360c06040523480156200001157600080fd5b506040516200151738038062001517833981016040819052620000349162000166565b818160036200004483826200029f565b5060046200005382826200029f565b505050506001600160a01b0393841660805250911660a0526006805460ff191660ff9092169190911790556200036b565b80516001600160a01b03811681146200009c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620000c957600080fd5b81516001600160401b0380821115620000e657620000e6620000a1565b604051601f8301601f19908116603f01168101908282118183101715620001115762000111620000a1565b816040528381526020925086838588010111156200012e57600080fd5b600091505b8382101562000152578582018301518183018401529082019062000133565b600093810190920192909252949350505050565b600080600080600060a086880312156200017f57600080fd5b6200018a8662000084565b94506200019a6020870162000084565b9350604086015160ff81168114620001b157600080fd5b60608701519093506001600160401b0380821115620001cf57600080fd5b620001dd89838a01620000b7565b93506080880151915080821115620001f457600080fd5b506200020388828901620000b7565b9150509295509295909350565b600181811c908216806200022557607f821691505b6020821081036200024657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200029a57600081815260208120601f850160051c81016020861015620002755750805b601f850160051c820191505b81811015620002965782815560010162000281565b5050505b505050565b81516001600160401b03811115620002bb57620002bb620000a1565b620002d381620002cc845462000210565b846200024c565b602080601f8311600181146200030b5760008415620002f25750858301515b600019600386901b1c1916600185901b17855562000296565b600085815260208120601f198616915b828110156200033c578886015182559484019460019091019084016200031b565b50858210156200035b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a051611155620003c2600039600081816101280152818161035b01526104a8015260008181610280015281816104fb01528181610729015281816107b101528181610d450152610e0901526111556000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c806370a0823111610097578063b8ce670d11610066578063b8ce670d14610240578063c5c94cee14610253578063dd62ed3e14610268578063f77c47911461027b57600080fd5b806370a08231146101e957806395d89b4114610212578063a457c2d71461021a578063a9059cbb1461022d57600080fd5b806318160ddd116100d357806318160ddd146101a657806323b872dd146101ae578063313ce567146101c157806339509351146101d657600080fd5b806306fdde03146101055780630754617214610123578063095ea7b3146101625780630d4d151314610185575b600080fd5b61010d6102a2565b60405161011a9190610ed2565b60405180910390f35b61014a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161011a565b610175610170366004610f38565b610334565b604051901515815260200161011a565b610198610193366004610f64565b61034e565b60405190815260200161011a565b600254610198565b6101756101bc366004610fa6565b6103bd565b60065460405160ff909116815260200161011a565b6101756101e4366004610f38565b6103e1565b6101986101f7366004610fe7565b6001600160a01b031660009081526020819052604090205490565b61010d610403565b610175610228366004610f38565b610412565b61017561023b366004610f38565b61048d565b61019861024e366004610f64565b61049b565b610266610261366004610fa6565b6104f9565b005b61019861027636600461100b565b6105bb565b61014a7f000000000000000000000000000000000000000000000000000000000000000081565b6060600380546102b190611044565b80601f01602080910402602001604051908101604052809291908181526020018280546102dd90611044565b801561032a5780601f106102ff5761010080835404028352916020019161032a565b820191906000526020600020905b81548152906001019060200180831161030d57829003601f168201915b5050505050905090565b6000336103428185856105e6565b60019150505b92915050565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103a15760405162461bcd60e51b81526004016103989061107e565b60405180910390fd5b6103ab828461070a565b6103b584846108be565b509092915050565b6000336103cb858285610989565b6103d6858585610a03565b506001949350505050565b6000336103428185856103f483836105bb565b6103fe91906110a6565b6105e6565b6060600480546102b190611044565b6000338161042082866105bb565b9050838110156104805760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610398565b6103d682868684036105e6565b600033610342818585610a03565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104e55760405162461bcd60e51b81526004016103989061107e565b6104ef828461070a565b6103b58484610bb2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166348439e7e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057b91906110c7565b6001600160a01b0316336001600160a01b0316146105ab5760405162461bcd60e51b81526004016103989061107e565b6105b6838383610cf0565b505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166106485760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610398565b6001600160a01b0382166106a95760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610398565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b604051636b6ba9bf60e11b81526001600160a01b0383811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063d6d7537e90602401602060405180830381865afa158015610770573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079491906110e4565b158015610827575060405163038d8da360e51b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906371b1b46090602401602060405180830381865afa158015610800573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108249190611106565b81115b156108ba576001600160a01b03821660009081526005602052604090205443900361089e5760405162461bcd60e51b815260206004820152602160248201527f63616e6e6f74206d696e742f6275726e20747769636520696e206120626c6f636044820152606b60f81b6064820152608401610398565b6001600160a01b03821660009081526005602052604090204390555b5050565b6001600160a01b0382166109145760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610398565b61092060008383610dde565b806002600082825461093291906110a6565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600061099584846105bb565b905060001981146109fd57818110156109f05760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610398565b6109fd84848484036105e6565b50505050565b6001600160a01b038316610a675760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610398565b6001600160a01b038216610ac95760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610398565b610ad4838383610dde565b6001600160a01b03831660009081526020819052604090205481811015610b4c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610398565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36109fd565b6001600160a01b038216610c125760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610398565b610c1e82600083610dde565b6001600160a01b03821660009081526020819052604090205481811015610c925760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610398565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b816001600160a01b0316836001600160a01b031614158015610d2957506001600160a01b03831660009081526005602052604090205443145b8015610dbb575060405163038d8da360e51b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906371b1b46090602401602060405180830381865afa158015610d94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db89190611106565b81115b156105b657506001600160a01b0316600090815260056020526040902043905550565b6001600160a01b0383161580610dfb57506001600160a01b038216155b15610e0557505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166348439e7e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8991906110c7565b9050806001600160a01b0316846001600160a01b03161480610ebc5750806001600160a01b0316836001600160a01b0316145b15610ec75750505050565b6109fd848484610cf0565b600060208083528351808285015260005b81811015610eff57858101830151858201604001528201610ee3565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b0381168114610f3557600080fd5b50565b60008060408385031215610f4b57600080fd5b8235610f5681610f20565b946020939093013593505050565b600080600060608486031215610f7957600080fd5b8335610f8481610f20565b9250602084013591506040840135610f9b81610f20565b809150509250925092565b600080600060608486031215610fbb57600080fd5b8335610fc681610f20565b92506020840135610fd681610f20565b929592945050506040919091013590565b600060208284031215610ff957600080fd5b813561100481610f20565b9392505050565b6000806040838503121561101e57600080fd5b823561102981610f20565b9150602083013561103981610f20565b809150509250929050565b600181811c9082168061105857607f821691505b60208210810361107857634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600e908201526d1b9bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b8082018082111561034857634e487b7160e01b600052601160045260246000fd5b6000602082840312156110d957600080fd5b815161100481610f20565b6000602082840312156110f657600080fd5b8151801515811461100457600080fd5b60006020828403121561111857600080fd5b505191905056fea2646970667358221220160f75bd8dd6eee3c41e6e92401893b9d88332b6b4536dec6eb583525622a08364736f6c6343000811003360e06040523480156200001157600080fd5b506040516200288a3803806200288a833981016040819052620000349162000069565b336080526001600160a01b0391821660a0521660c052620000a8565b6001600160a01b03811681146200006657600080fd5b50565b600080604083850312156200007d57600080fd5b82516200008a8162000050565b60208401519092506200009d8162000050565b809150509250929050565b60805160a05160c05161273b6200014f600039600081816101eb0152818161074a015281816107c501528181610df101528181610e6c01526116ab0152600081816102d6015281816106b301528181610a6e01528181610d5a015281816113450152818161161f01526117d80152600081816102120152818161056f0152818161096e01528181610af201528181611043015281816112af0152611526015261273b6000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c80637e412a7a116100a2578063ac6c525111610071578063ac6c525114610283578063c5c63e6514610296578063c699e633146102ab578063d914cd4b146102be578063f77c4791146102d157600080fd5b80637e412a7a146102345780638c788de0146102555780638dbfb25b1461025d5780639765ca151461027057600080fd5b806339d82513116100e957806339d825131461019d5780633b7d0946146101b0578063519703de146101c35780636f307dc3146101e65780637d59ce011461020d57600080fd5b80631010b58c1461011b57806312968a291461014b57806322acb8671461017357806336797aec14610188575b600080fd5b61012e610129366004612116565b6102f8565b6040516001600160a01b0390911681526020015b60405180910390f35b61015e61015936600461222e565b61030a565b60408051928352602083019190915201610142565b61017b61047d565b604051610142919061227e565b61019b6101963660046122eb565b610564565b005b61015e6101ab36600461222e565b610658565b61019b6101be3660046122eb565b610963565b6101d66101d1366004612308565b610cf9565b6040519015158152602001610142565b61012e7f000000000000000000000000000000000000000000000000000000000000000081565b61012e7f000000000000000000000000000000000000000000000000000000000000000081565b610247610242366004612356565b610fa4565b604051908152602001610142565b610247611027565b61019b61026b36600461239d565b611038565b61024761027e3660046122eb565b6112a2565b6102476102913660046122eb565b6114f6565b61029e611503565b604051610142919061245c565b6101d66102b93660046122eb565b61150f565b61019b6102cc3660046122eb565b61151b565b61012e7f000000000000000000000000000000000000000000000000000000000000000081565b600061030481836119ab565b92915050565b81516000908190600019825b8281101561041a57600061032a81836119ab565b90506000888381518110610340576103406124a9565b6020026020010151905060006103608360026119b790919063ffffffff16565b9050600061036e8c836119cc565b90508083106103805750505050610408565b60006103a38b6103926012600a6125b9565b61039c91906125c5565b84906119cc565b90506103b16012600a6125b9565b81116103bd57806103c9565b6103c96012600a6125b9565b905060006103d78e836119cc565b905060006103e586836125d8565b90508a81116103fa5750505050505050610408565b809a50879850505050505050505b80610412816125eb565b915050610316565b5060001981136104715760405162461bcd60e51b815260206004820152601d60248201527f6572726f722072657472696576696e67206465706f73697420706f6f6c00000060448201526064015b60405180910390fd5b96919550909350505050565b6060600061048b60006119ee565b905060008167ffffffffffffffff8111156104a8576104a861212f565b6040519080825280602002602001820160405280156104ed57816020015b60408051808201909152600080825260208201528152602001906001900390816104c65790505b50905060005b8281101561055d576000806105096002846119f8565b915091506040518060400160405280836001600160a01b031681526020018281525084848151811061053d5761053d6124a9565b602002602001018190525050508080610555906125eb565b9150506104f3565b5092915050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105ac5760405162461bcd60e51b815260040161046890612604565b6105b58161150f565b6105fa5760405162461bcd60e51b81526020600482015260166024820152751c1bdbdb081a5cc81b9bdd081c9959da5cdd195c995960521b6044820152606401610468565b6106056002826119b7565b60000361064c5760405162461bcd60e51b81526020600482015260156024820152740706f6f6c2077656967687420616c7265616479203605c1b6044820152606401610468565b61065581611a14565b50565b81516000908190600019825b8281101561090957600061067881836119ab565b905060006106876002836119b7565b9050600089848151811061069d5761069d6124a9565b60200260200101519050816000036108945760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561070f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610733919061262c565b604051638b2f0f4f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529190911690638b2f0f4f90602401602060405180830381865afa15801561079b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bf9190612649565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610821573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108459190612662565b61085090600a612685565b61085a8484612694565b61086491906126ab565b905061087a600268056bc75e2d631000006126ab565b81106108915750939750955061095b945050505050565b50505b60006108a08c846119cc565b90508082116108b257505050506108f7565b60006108be828c6119cc565b6108c890836125d8565b905060006108d682856125d8565b90508981116108ea575050505050506108f7565b8099508697505050505050505b80610901816125eb565b915050610664565b5060001981136104715760405162461bcd60e51b815260206004820152601e60248201527f6572726f722072657472696576696e6720776974686472617720706f6f6c00006044820152606401610468565b935093915050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109ab5760405162461bcd60e51b815260040161046890612604565b6109b6600082611d6b565b6109f35760405162461bcd60e51b815260206004820152600e60248201526d1c1bdbdb081b9bdd08185919195960921b6044820152606401610468565b60016109ff60006119ee565b11610a4c5760405162461bcd60e51b815260206004820152601760248201527f63616e6e6f742072656d6f7665206c61737420706f6f6c0000000000000000006044820152606401610468565b6040516355eb6b3560e01b81526001600160a01b0382811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906355eb6b3590602401602060405180830381865afa158015610ab7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610adb919061262c565b604051633dfa59d160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528481166024830152919250600091831690633dfa59d190604401602060405180830381865afa158015610b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b739190612649565b905068056bc75e2d631000008110610bcd5760405162461bcd60e51b815260206004820152601860248201527f706f6f6c2068617320616c6c6f63617465642066756e647300000000000000006044820152606401610468565b6000610bda6002856119b7565b90508015610c205760405162461bcd60e51b81526020600482015260136024820152721c1bdbdb081a185cc81dd95a59da1d081cd95d606a1b6044820152606401610468565b610c2b600085611d8d565b610c6a5760405162461bcd60e51b815260206004820152601060248201526f1c1bdbdb081b9bdd081c995b5bdd995960821b6044820152606401610468565b610c75600285611da2565b610cb65760405162461bcd60e51b81526020600482015260126024820152711dd95a59da1d081b9bdd081c995b5bdd995960721b6044820152606401610468565b6040516001600160a01b03851681527fca2456580e344539a90d4d0369fc77866a3135141e2e51621b88d2f010c6bbe2906020015b60405180910390a150505050565b600082600003610d0b57506001610f9d565b60005b8451811015610f97576000610d2e610d2682846119ab565b6002906119b7565b90506000868381518110610d4457610d446124a9565b6020026020010151905081600003610f3e5760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dda919061262c565b604051638b2f0f4f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529190911690638b2f0f4f90602401602060405180830381865afa158015610e42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e669190612649565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ec8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eec9190612662565b610ef790600a612685565b610f018484612694565b610f0b91906126ab565b9050610f21600268056bc75e2d631000006126ab565b8110610f3557600095505050505050610f9d565b50505050610f85565b6000610f4a87846119cc565b90506000610f588284611db7565b90506000610f668284611dcf565b905087811115610f7f5760009650505050505050610f9d565b50505050505b80610f8f816125eb565b915050610d0e565b50600190505b9392505050565b60008060005b835181101561101f576000610fc2610d2682846119ab565b90506000610fd087836119cc565b9050610ffe868481518110610fe757610fe76124a9565b602002602001015182611db790919063ffffffff16565b61100890856125c5565b935050508080611017906125eb565b915050610faa565b509392505050565b600061103360006119ee565b905090565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110805760405162461bcd60e51b815260040161046890612604565b61108a60006119ee565b8151146110d05760405162461bcd60e51b8152602060048201526014602482015273696e76616c696420706f6f6c207765696768747360601b6044820152606401610468565b60008060005b83518110156112425760008482815181106110f3576110f36124a9565b6020026020010151600001519050826001600160a01b0316816001600160a01b0316116111555760405162461bcd60e51b815260206004820152601060248201526f1c1bdbdb1cc81b9bdd081cdbdc9d195960821b6044820152606401610468565b61115e8161150f565b6111a35760405162461bcd60e51b81526020600482015260166024820152751c1bdbdb081a5cc81b9bdd081c9959da5cdd195c995960521b6044820152606401610468565b60008583815181106111b7576111b76124a9565b60200260200101516020015190506111db82826002611de89092919063ffffffff16565b50816001600160a01b03167f49175c3467edeba7662e939bf84305eaf5084072855b0560f6ac3e145cd172ae8260405161121791815260200190565b60405180910390a261122981866125c5565b945090925081905061123a816125eb565b9150506110d6565b5061124f6012600a6125b9565b821461129d5760405162461bcd60e51b815260206004820152601760248201527f7765696768747320646f206e6f742073756d20746f20310000000000000000006044820152606401610468565b505050565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112ec5760405162461bcd60e51b815260040161046890612604565b6112f58261150f565b6113415760405162461bcd60e51b815260206004820152601960248201527f637572766520706f6f6c206e6f742072656769737465726564000000000000006044820152606401610468565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639f82b2176040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c5919061262c565b6040516343b55f3560e01b81526001600160a01b0385811660048301529192506000918316906343b55f3590602401602060405180830381865afa158015611411573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114359190612649565b604051631cec69e560e11b8152600481018290529091506001600160a01b038316906339d8d3ca90602401602060405180830381865afa15801561147d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a191906126cd565b6114ed5760405162461bcd60e51b815260206004820181905260248201527f636f6e76657820706f6f6c20706964206973206e6f74207368757420646f776e6044820152606401610468565b610f9d84611a14565b60006103046002836119b7565b60606110336000611e06565b60006103048183611d6b565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115635760405162461bcd60e51b815260040161046890612604565b600a61156f60006119ee565b106115b05760405162461bcd60e51b81526020600482015260116024820152701b585e081c1bdbdb1cc81c995858da1959607a1b6044820152606401610468565b6115bb600082611d6b565b156115fd5760405162461bcd60e51b81526020600482015260126024820152711c1bdbdb08185b1c9958591e48185919195960721b6044820152606401610468565b6040516355eb6b3560e01b81526001600160a01b0382811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906355eb6b3590602401602060405180830381865afa158015611668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168c919061262c565b604051632aa2d3f760e21b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000008116602483015291925060009183169063aa8b4fdc90604401602060405180830381865afa158015611700573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172491906126cd565b9050806117665760405162461bcd60e51b815260206004820152601060248201526f18dbda5b881b9bdd081a5b881c1bdbdb60821b6044820152606401610468565b604051631da958a960e21b81526001600160a01b038481166004830152600091908416906376a562a490602401602060405180830381865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d4919061262c565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611834573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611858919061262c565b6040516375151b6360e01b81526001600160a01b03838116600483015291909116906375151b6390602401602060405180830381865afa1580156118a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c491906126cd565b6119085760405162461bcd60e51b815260206004820152601560248201527431b0b73737ba10383934b1b2902628102a37b5b2b760591b6044820152606401610468565b611913600285611e13565b611926576119246002856000611de8565b505b611931600085611e28565b6119725760405162461bcd60e51b815260206004820152601260248201527119985a5b1959081d1bc8185919081c1bdbdb60721b6044820152606401610468565b6040516001600160a01b03851681527fbadad752e47b51d72487f7881b9baa7c0ed207b8d84f37c0e23eb0a6d67e5b1590602001610ceb565b6000610f9d8383611e3d565b6000610f9d836001600160a01b038416611e67565b60006119da6012600a6125b9565b6119e48385612694565b610f9d91906126ab565b6000610304825490565b6000808080611a078686611ed7565b9097909650945050505050565b6000611a216002836119b7565b905080600003611a2f575050565b611a3b6012600a6125b9565b8103611a825760405162461bcd60e51b815260206004820152601660248201527518d85b89dd081c995b5bdd99481b185cdd081c1bdbdb60521b6044820152606401610468565b6000611aba611a926002856119b7565b611a9e6012600a6125b9565b611aa891906125d8565b611ab46012600a6125b9565b90611dcf565b90506000611ac860006119ee565b9050611ad76002856000611de8565b50836001600160a01b03167f49175c3467edeba7662e939bf84305eaf5084072855b0560f6ac3e145cd172ae6000604051611b1491815260200190565b60405180910390a26000611b296001836125d8565b67ffffffffffffffff811115611b4157611b4161212f565b604051908082528060200260200182016040528015611b6a578160200160208202803683370190505b5090506000611b7a6001846125d8565b67ffffffffffffffff811115611b9257611b9261212f565b604051908082528060200260200182016040528015611bbb578160200160208202803683370190505b5090506000805b84811015611c69576000611bd681836119ab565b90506000611be56002836119b7565b905080600003611bf6575050611c57565b81868581518110611c0957611c096124a9565b60200260200101906001600160a01b031690816001600160a01b03168152505080858581518110611c3c57611c3c6124a9565b602090810291909101015283611c51816125eb565b94505050505b80611c61816125eb565b915050611bc2565b506000805b82811015611d60576000858281518110611c8a57611c8a6124a9565b602002602001015190506000611cc289878581518110611cac57611cac6124a9565b60200260200101516119cc90919063ffffffff16565b9050611ccf6001866125d8565b8303611cef5783611ce26012600a6125b9565b611cec91906125d8565b90505b611cf981856125c5565b9350611d0760028383611de8565b50816001600160a01b03167f49175c3467edeba7662e939bf84305eaf5084072855b0560f6ac3e145cd172ae82604051611d4391815260200190565b60405180910390a250508080611d58906125eb565b915050611c6e565b505050505050505050565b6001600160a01b03811660009081526001830160205260408120541515610f9d565b6000610f9d836001600160a01b038416611f02565b6000610f9d836001600160a01b038416611ff5565b600081831015611dc957828203610f9d565b50900390565b600081611dde6012600a6125b9565b6119e49085612694565b6000611dfe846001600160a01b03851684612012565b949350505050565b60606000610f9d8361202f565b6000610f9d836001600160a01b03841661208b565b6000610f9d836001600160a01b038416612097565b6000826000018281548110611e5457611e546124a9565b9060005260206000200154905092915050565b600081815260028301602052604081205480151580611e8b5750611e8b848461208b565b610f9d5760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610468565b60008080611ee585856119ab565b600081815260029690960160205260409095205494959350505050565b60008181526001830160205260408120548015611feb576000611f266001836125d8565b8554909150600090611f3a906001906125d8565b9050818114611f9f576000866000018281548110611f5a57611f5a6124a9565b9060005260206000200154905080876000018481548110611f7d57611f7d6124a9565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611fb057611fb06126ef565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610304565b6000915050610304565b60008181526002830160205260408120819055610f9d83836120e6565b60008281526002840160205260408120829055611dfe84846120f2565b60608160000180548060200260200160405190810160405280929190818152602001828054801561207f57602002820191906000526020600020905b81548152602001906001019080831161206b575b50505050509050919050565b6000610f9d83836120fe565b60008181526001830160205260408120546120de57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610304565b506000610304565b6000610f9d8383611f02565b6000610f9d8383612097565b60008181526001830160205260408120541515610f9d565b60006020828403121561212857600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156121685761216861212f565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156121975761219761212f565b604052919050565b600067ffffffffffffffff8211156121b9576121b961212f565b5060051b60200190565b600082601f8301126121d457600080fd5b813560206121e96121e48361219f565b61216e565b82815260059290921b8401810191818101908684111561220857600080fd5b8286015b84811015612223578035835291830191830161220c565b509695505050505050565b60008060006060848603121561224357600080fd5b83359250602084013567ffffffffffffffff81111561226157600080fd5b61226d868287016121c3565b925050604084013590509250925092565b602080825282518282018190526000919060409081850190868401855b828110156122c957815180516001600160a01b0316855286015186850152928401929085019060010161229b565b5091979650505050505050565b6001600160a01b038116811461065557600080fd5b6000602082840312156122fd57600080fd5b8135610f9d816122d6565b60008060006060848603121561231d57600080fd5b833567ffffffffffffffff81111561233457600080fd5b612340868287016121c3565b9660208601359650604090950135949350505050565b6000806040838503121561236957600080fd5b82359150602083013567ffffffffffffffff81111561238757600080fd5b612393858286016121c3565b9150509250929050565b600060208083850312156123b057600080fd5b823567ffffffffffffffff8111156123c757600080fd5b8301601f810185136123d857600080fd5b80356123e66121e48261219f565b81815260069190911b8201830190838101908783111561240557600080fd5b928401925b8284101561245157604084890312156124235760008081fd5b61242b612145565b8435612436816122d6565b8152848601358682015282526040909301929084019061240a565b979650505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561249d5783516001600160a01b031683529284019291840191600101612478565b50909695505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600181815b808511156125105781600019048211156124f6576124f66124bf565b8085161561250357918102915b93841c93908002906124da565b509250929050565b60008261252757506001610304565b8161253457506000610304565b816001811461254a576002811461255457612570565b6001915050610304565b60ff841115612565576125656124bf565b50506001821b610304565b5060208310610133831016604e8410600b8410161715612593575081810a610304565b61259d83836124d5565b80600019048211156125b1576125b16124bf565b029392505050565b6000610f9d8383612518565b80820180821115610304576103046124bf565b81810381811115610304576103046124bf565b6000600182016125fd576125fd6124bf565b5060010190565b6020808252600e908201526d1b9bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60006020828403121561263e57600080fd5b8151610f9d816122d6565b60006020828403121561265b57600080fd5b5051919050565b60006020828403121561267457600080fd5b815160ff81168114610f9d57600080fd5b6000610f9d60ff841683612518565b8082028115828204841417610304576103046124bf565b6000826126c857634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156126df57600080fd5b81518015158114610f9d57600080fd5b634e487b7160e01b600052603160045260246000fdfea2646970667358221220bbfff24b88d8efa029fa1f79e284862232aa7e6ecab53f8f11c1f365bb31197d64736f6c63430008110033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000015c606c60afcfaa8e57777d947c40e92041195320000000000000000000000002790ec478f150a98f5d96755601a26403df57eae00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52000000000000000000000000000000000000000000000000000000000000000a436f6e69632055534443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007636e635553444300000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106103855760003560e01c80638456cb59116101d1578063c5c63e6511610102578063d6038dc6116100a0578063e2bbb1581161006f578063e2bbb15814610a9b578063f0ea87f614610abb578063f2fde38b14610ad1578063f77c479114610af157600080fd5b8063d6038dc614610a30578063d914cd4b14610a45578063da748b1014610a65578063dddbc04914610a7b57600080fd5b8063c9387332116100dc578063c9387332146109d0578063cb03a464146109f0578063ce75040e14610a05578063d1e6c1e514610a1a57600080fd5b8063c5c63e6514610986578063c699e6331461099b578063c70920bc146109bb57600080fd5b80639e4865621161016f578063b0a4396811610149578063b0a4396814610914578063b187bd2614610934578063b7b3b8c01461094c578063bf86d6901461096c57600080fd5b80639e486562146108bf578063a58f1d8e146108de578063ac6c5251146108f457600080fd5b80638da5cb5b116101ab5780638da5cb5b146108555780638dbfb25b14610873578063904c9bf0146108935780639765ca151461089f57600080fd5b80638456cb591461080957806386fe9a661461081e5780638c788de01461084057600080fd5b806336797aec116102b6578063441a3e70116102545780636e4f3338116102235780636e4f33381461076d5780636f307dc3146107ab578063715018a6146107df57806383645abf146107f457600080fd5b8063441a3e70146106c55780634af1cd69146106e55780635fcbd2851461071957806365f203551461074d57600080fd5b80633b7d0946116102905780633b7d09461461065a5780633ba0b9a91461067a5780633d4912c31461068f57806343a0d066146106a557600080fd5b806336797aec14610604578063377f7eaa146106245780633a172ddc1461063a57600080fd5b806322acb867116103235780632c3da47d116102fd5780632c3da47d146105765780632cf818011461059657806332f44c42146105c0578063331666fa146105e057600080fd5b806322acb8671461052957806324a71a661461054b5780632a1bab731461056057600080fd5b80630f4ef8a61161035f5780630f4ef8a61461047d5780631010b58c146104c957806310aec8f9146104e95780631280a5b61461050957600080fd5b80630526679c146104125780630ad58d2f1461043b5780630c3457891461045b57600080fd5b3661040d577f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21461040b5760405162461bcd60e51b815260206004820152600d60248201526c1b9bdd0815d15512081c1bdbdb609a1b60448201526064015b60405180910390fd5b005b600080fd5b34801561041e57600080fd5b5061042860025481565b6040519081526020015b60405180910390f35b34801561044757600080fd5b506104286104563660046151a0565b610b25565b34801561046757600080fd5b50610470610f4d565b60405161043291906151d9565b34801561048957600080fd5b506104b17f00000000000000000000000015c606c60afcfaa8e57777d947c40e920411953281565b6040516001600160a01b039091168152602001610432565b3480156104d557600080fd5b506104b16104e4366004615226565b61114a565b3480156104f557600080fd5b5061042861050436600461523f565b6111dc565b34801561051557600080fd5b506104286105243660046151a0565b6111e5565b34801561053557600080fd5b5061053e6112de565b6040516104329190615261565b34801561055757600080fd5b5061042861136b565b34801561056c57600080fd5b5061042860035481565b34801561058257600080fd5b5061040b610591366004615226565b611394565b3480156105a257600080fd5b506009546105b09060ff1681565b6040519015158152602001610432565b3480156105cc57600080fd5b5061040b6105db366004615226565b611498565b3480156105ec57600080fd5b506105f5611599565b604051610432939291906152fc565b34801561061057600080fd5b5061040b61061f36600461531b565b6116c7565b34801561063057600080fd5b50610428600a5481565b34801561064657600080fd5b5061040b610655366004615346565b611a43565b34801561066657600080fd5b5061040b61067536600461531b565b611ad8565b34801561068657600080fd5b50610428611cf2565b34801561069b57600080fd5b5061042860065481565b3480156106b157600080fd5b506104286106c036600461537f565b611d04565b3480156106d157600080fd5b506104286106e036600461523f565b611d12565b3480156106f157600080fd5b506104b17f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c481565b34801561072557600080fd5b506104b17f000000000000000000000000d02bcdbe1d7790bdc4e1c365bff8269d8f5e035e81565b34801561075957600080fd5b506104286107683660046153ad565b611d1f565b34801561077957600080fd5b50600954610793906201000090046001600160401b031681565b6040516001600160401b039091168152602001610432565b3480156107b757600080fd5b506104b17f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b3480156107eb57600080fd5b5061040b61240c565b34801561080057600080fd5b50610428612420565b34801561081557600080fd5b5061040b6124c9565b34801561082a57600080fd5b506108336125d8565b60405161043291906153f7565b34801561084c57600080fd5b5061042861276a565b34801561086157600080fd5b506000546001600160a01b03166104b1565b34801561087f57600080fd5b5061040b61088e3660046154db565b6127ee565b34801561040b57600080fd5b3480156108ab57600080fd5b506104286108ba36600461531b565b6129d2565b3480156108cb57600080fd5b506009546105b090610100900460ff1681565b3480156108ea57600080fd5b5061042860045481565b34801561090057600080fd5b5061042861090f36600461531b565b612aae565b34801561092057600080fd5b5061040b61092f366004615226565b612b3d565b34801561094057600080fd5b506001544211156105b0565b34801561095857600080fd5b5061040b610967366004615593565b612bf3565b34801561097857600080fd5b506005546105b09060ff1681565b34801561099257600080fd5b50610470612c66565b3480156109a757600080fd5b506105b06109b636600461531b565b612cee565b3480156109c757600080fd5b50610428612d7d565b3480156109dc57600080fd5b5061040b6109eb366004615226565b612d88565b3480156109fc57600080fd5b506105b0612e6a565b348015610a1157600080fd5b50610428612e86565b348015610a2657600080fd5b50610428600c5481565b348015610a3c57600080fd5b5061040b612fb4565b348015610a5157600080fd5b5061040b610a6036600461531b565b613080565b348015610a7157600080fd5b5061042860015481565b348015610a8757600080fd5b5061040b610a96366004615226565b61329b565b348015610aa757600080fd5b50610428610ab636600461523f565b613351565b348015610ac757600080fd5b50610428600b5481565b348015610add57600080fd5b5061040b610aec36600461531b565b613360565b348015610afd57600080fd5b506104b17f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae81565b60006040516370a0823160e01b815233600482015284907f000000000000000000000000d02bcdbe1d7790bdc4e1c365bff8269d8f5e035e6001600160a01b0316906370a0823190602401602060405180830381865afa158015610b8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb191906155b0565b1015610bf65760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610402565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015610c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8191906155b0565b90506000806000610c90611599565b9250925092506000610cab610ca485613530565b8a906135dd565b905080851015610cd0576000610cc186836155df565b9050610cce8484836135ff565b505b6040516370a0823160e01b8152306004820152600090610d65906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a0823190602401602060405180830381865afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f91906155b0565b836138ba565b905088811015610dab5760405162461bcd60e51b8152602060048201526011602482015270746f6f206d75636820736c69707061676560781b6044820152606401610402565b60405163b8ce670d60e01b81523360048201819052602482018c905260448201527f000000000000000000000000d02bcdbe1d7790bdc4e1c365bff8269d8f5e035e6001600160a01b03169063b8ce670d906064016020604051808303816000875af1158015610e1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4391906155b0565b50610e786001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481689836138d0565b610e8281866155df565b60085542600755610ea36001600160a01b038916632098244360e21b613900565b15610f0957604051632098244360e21b8152336004820152602481018290526001600160a01b03891690638260910c90604401600060405180830381600087803b158015610ef057600080fd5b505af1158015610f04573d6000803e3d6000fd5b505050505b60405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a2955050505050505b9392505050565b606060007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa158015610faf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fd791908101906155f2565b8051604080516000808252602082019092529293509091905b8281101561113857600084828151811061100c5761100c615680565b60209081029190910101516040516355eb6b3560e01b81526001600160a01b0380831660048301529192506000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a79190615696565b604051622708db60e01b81526001600160a01b0384811660048301529190911690622708db90602401600060405180830381865afa1580156110ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261111591908101906155f2565b9050611121848261391c565b935050508080611130906156b3565b915050610ff0565b5061114281613a47565b935050505090565b6040516304042d6360e21b8152600481018290526000907f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b031690631010b58c90602401602060405180830381865afa1580156111b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d69190615696565b92915050565b6000610f468383335b60007f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b03166348439e7e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611245573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112699190615696565b604051630325d16160e01b8152600481018690523360248201526001600160a01b039190911690630325d16190604401600060405180830381600087803b1580156112b357600080fd5b505af11580156112c7573d6000803e3d6000fd5b505050506112d6848484610b25565b949350505050565b60607f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b03166322acb8676040518163ffffffff1660e01b8152600401600060405180830381865afa15801561133e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261136691908101906156cc565b905090565b60006203f48060075461137e919061577f565b42111561138d57611366612d7d565b5060085490565b61139c613b3b565b670de0b6b3a76400008110156113eb5760405162461bcd60e51b8152602060048201526014602482015273666163746f722062656c6f77206d696e696d756d60601b6044820152606401610402565b68056bc75e2d6310000081111561143b5760405162461bcd60e51b8152602060048201526014602482015273666163746f722061626f7665206d6178696d756d60601b6044820152606401610402565b600a54810361145c5760405162461bcd60e51b815260040161040290615792565b600a8190556040518181527f43b89d4b5fdc149d21160712a4e8a2c76927dccd7aae23fd717f753758044a6f906020015b60405180910390a150565b6114a0613b3b565b662386f26fc100008110156114f15760405162461bcd60e51b81526020600482015260176024820152761a5b9d985b1a590819195c1959c81d1a1c995cda1bdb19604a1b6044820152606401610402565b67016345785d8a00008111156115435760405162461bcd60e51b81526020600482015260176024820152761a5b9d985b1a590819195c1959c81d1a1c995cda1bdb19604a1b6044820152606401610402565b60065481036115645760405162461bcd60e51b815260040161040290615792565b60068190556040518181527f20da4a1840e5e1bb25784e941f370e4db630545ed9434c8c0bad8e421480595b9060200161148d565b600080606060007f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116229190615696565b604051638b2f0f4f60e01b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301529190911690638b2f0f4f90602401602060405180830381865afa15801561168a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ae91906155b0565b90506116bb816000613b95565b93509350935050909192565b6116f07f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48613e98565b156117365760405162461bcd60e51b81526020600482015260166024820152751d5b99195c9b1e5a5b99c81a5cc819195c1959d9d95960521b6044820152606401610402565b61173f8161400f565b6117825760405162461bcd60e51b81526020600482015260146024820152731c1bdbdb081a5cc81b9bdd0819195c1959d9d95960621b6044820152606401610402565b604051630d9e5ebb60e21b81526001600160a01b0382811660048301527f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c416906336797aec90602401600060405180830381600087803b1580156117e557600080fd5b505af11580156117f9573d6000803e3d6000fd5b50505050600080611808611599565b925050915060007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b0316637e412a7a84846040518363ffffffff1660e01b815260040161185d9291906157bb565b602060405180830381865afa15801561187a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189e91906155b0565b600c81905560095490915060ff1615611a01576040516355eb6b3560e01b81526001600160a01b0385811660048301526000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae909116906355eb6b3590602401602060405180830381865afa15801561191c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119409190615696565b604051633dfa59d160e01b81523060048201526001600160a01b038781166024830152919250600091831690633dfa59d190604401602060405180830381865afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b691906155b0565b905068056bc75e2d631000008111156119fe5760098054600a54600b5561ff00196001600160401b03421662010000021669ffffffffffffffffff0019909116176101001790555b50505b6040516001600160a01b03851681527f7d90518f39c7f92fd9046bbb246d9c650dd159f73cca88aa7d919c89c040fa799060200160405180910390a150505050565b336001600160a01b037f00000000000000000000000015c606c60afcfaa8e57777d947c40e92041195321614611a8b5760405162461bcd60e51b8152600401610402906157d4565b600081611a99576000611a9d565b6000195b9050611ad36001600160a01b0384167f00000000000000000000000015c606c60afcfaa8e57777d947c40e9204119532836133d9565b505050565b611ae0613b3b565b604051631dbe84a360e11b81526001600160a01b0382811660048301527f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c41690633b7d094690602401600060405180830381600087803b158015611b4357600080fd5b505af1158015611b57573d6000803e3d6000fd5b5050505060007f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b0316632cdacb506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bdf9190615696565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa158015611c4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6f9190615696565b604051631da958a960e21b81526001600160a01b03858116600483015291909116906376a562a490602401602060405180830381865afa158015611cb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cdb9190615696565b9050611ad36001600160a01b0382168360006133d9565b6000611366611cff612d7d565b613530565b60006112d633858585611d1f565b6000610f46838333610b25565b6000611d2d60015442111590565b15611d635760405162461bcd60e51b81526020600482015260066024820152651c185d5cd95960d21b6044820152606401610402565b611db9604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016000815260200160008152602001606081525090565b60055460ff1615611e005760405162461bcd60e51b81526020600482015260116024820152703837b7b61034b99039b43aba103237bbb760791b6044820152606401610402565b60008511611e505760405162461bcd60e51b815260206004820152601d60248201527f6465706f73697420616d6f756e742063616e6e6f74206265207a65726f0000006044820152606401610402565b611e5861416e565b60007f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edc9190615696565b604051638b2f0f4f60e01b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301529190911690638b2f0f4f90602401602060405180830381865afa158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6891906155b0565b9050611f75816001613b95565b60c085015260a084015260808301819052611f8f90613530565b8252611fc66001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333089614329565b60a082015160c08301516040516370a0823160e01b81523060048201526120639291906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a0823190602401602060405180830381865afa15801561203a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205e91906155b0565b614367565b61206e816002613b95565b61012085015261010084015260e08301819052608083015161208f916155df565b602083018190526120a19087906138ba565b6040830181905282516120b4919061462f565b606083018190528511156120fe5760405162461bcd60e51b8152602060048201526011602482015270746f6f206d75636820736c69707061676560781b6044820152606401610402565b60e08201516008554260075583156122ec576060820151604051630d4d151360e01b815230600482015260248101919091526001600160a01b0388811660448301527f000000000000000000000000d02bcdbe1d7790bdc4e1c365bff8269d8f5e035e1690630d4d1513906064016020604051808303816000875af115801561218b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121af91906155b0565b5060007f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b03166348439e7e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612210573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122349190615696565b90506122788184606001517f000000000000000000000000d02bcdbe1d7790bdc4e1c365bff8269d8f5e035e6001600160a01b03166146489092919063ffffffff16565b60608301516040516333f1c33760e01b815260048101919091523060248201526001600160a01b0389811660448301528216906333f1c33790606401600060405180830381600087803b1580156122ce57600080fd5b505af11580156122e2573d6000803e3d6000fd5b5050505050612393565b6060820151604051630d4d151360e01b81526001600160a01b0389811660048301819052602483019390935260448201929092527f000000000000000000000000d02bcdbe1d7790bdc4e1c365bff8269d8f5e035e90911690630d4d1513906064016020604051808303816000875af115801561236d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239191906155b0565b505b6123b2878360a001518460c001518561010001518661012001516146d7565b60608201516040805188815260208101929092526001600160a01b0389169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3506060015195945050505050565b612414613b3b565b61241e600061491f565b565b600080600061242d611599565b604051633f20953d60e11b815291945092506001600160a01b037f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c4169150637e412a7a9061248190859085906004016157bb565b602060405180830381865afa15801561249e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c291906155b0565b9250505090565b604051634eb3ffc360e01b81523360048201527f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b031690634eb3ffc390602401602060405180830381865afa15801561252d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255191906157fc565b6125915760405162461bcd60e51b81526020600482015260116024820152703737ba103830bab9b29036b0b730b3b2b960791b6044820152606401610402565b60025461259e904261577f565b60018190556040519081527f32fb7c9891bc4f963c7de9f1186d2a7755c7d6e9f4604dabe1d8bb3027c2f49e9060200160405180910390a1565b606060007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa15801561263a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261266291908101906155f2565b9050600081516001600160401b0381111561267f5761267f61544a565b6040519080825280602002602001820160405280156126c457816020015b604080518082019091526000808252602082015281526020019060019003908161269d5790505b50905060006126d1611599565b9250505060005b82518110156127615760405180604001604052808583815181106126fe576126fe615680565b60200260200101516001600160a01b0316815260200183838151811061272657612726615680565b602002602001015181525083828151811061274357612743615680565b60200260200101819052508080612759906156b3565b9150506126d8565b50909392505050565b60007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b0316638c788de06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127ca573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136691906155b0565b336001600160a01b037f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16146128365760405162461bcd60e51b8152600401610402906157d4565b604051638dbfb25b60e01b81526001600160a01b037f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c41690638dbfb25b90612882908490600401615261565b600060405180830381600087803b15801561289c57600080fd5b505af11580156128b0573d6000803e3d6000fd5b5050505060008060006128c1611599565b92509250925060007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b0316637e412a7a85846040518363ffffffff1660e01b81526004016129179291906157bb565b602060405180830381865afa158015612934573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061295891906155b0565b600c81905560095490915060ff1680156129795750612977828461496f565b155b600980549115156101000261ff001990921691909117905561299d6012600a6158fd565b600b556009805469ffffffffffffffff0000191662010000426001600160401b0316021790556129cb614a04565b5050505050565b604051639765ca1560e01b81526001600160a01b03828116600483015260009182917f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c41690639765ca15906024016020604051808303816000875af1158015612a3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6391906155b0565b604080516001600160a01b0386168152602081018390529192507fb6e3324444a482d3e4041851d767063381c41cd9abc8a3191a0b61e3896f9443910160405180910390a192915050565b60405163ac6c525160e01b81526001600160a01b0382811660048301526000917f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c49091169063ac6c525190602401602060405180830381865afa158015612b19573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d691906155b0565b612b45613b3b565b8060045403612b665760405162461bcd60e51b815260040161040290615792565b6702c68af0bb140000811115612bbe5760405162461bcd60e51b815260206004820152601960248201527f726174696f206578636565647320757070657220626f756e64000000000000006044820152606401610402565b60048190556040518181527fcf75d305993755a06325155bdff6a203ff5eb28a3561e219588aeb6aba8b3b549060200161148d565b612bfb613b3b565b60095481151560ff909116151503612c255760405162461bcd60e51b815260040161040290615792565b6009805460ff19168215159081179091556040519081527f279cee3d8f87ec526dc3da1f7f9000d2bedd53531863d9e85e52ea363c3d13059060200161148d565b60607f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa158015612cc6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261136691908101906155f2565b60405163c699e63360e01b81526001600160a01b0382811660048301526000917f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c49091169063c699e63390602401602060405180830381865afa158015612d59573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d691906157fc565b600080612761611599565b612d90613b3b565b610e10811015612de25760405162461bcd60e51b815260206004820152601860248201527f7061757365206475726174696f6e20746f6f2073686f727400000000000000006044820152606401610402565b6203f480811115612e355760405162461bcd60e51b815260206004820152601760248201527f7061757365206475726174696f6e20746f6f206c6f6e670000000000000000006044820152606401610402565b60028190556040518181527fa959cb2cc91580147f93f66fb85db8f308cfdaef3989ab5265408ff80ef6fa669060200161148d565b6000806000612e77611599565b92509250506124c2818361496f565b6000807f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ee7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0b9190615696565b604051638b2f0f4f60e01b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301529190911690638b2f0f4f90602401602060405180830381865afa158015612f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9791906155b0565b9050612fae81612fa8611cff61136b565b906135dd565b91505090565b336001600160a01b037f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae1614612ffc5760405162461bcd60e51b8152600401610402906157d4565b60055460ff16156130485760405162461bcd60e51b81526020600482015260166024820152753837b7b61030b63932b0b23c9039b43aba103237bbb760511b6044820152606401610402565b6005805460ff191660011790556040517f4426aa1fb73e391071491fcfe21a88b5c38a0a0333a1f6e77161470439704cf890600090a1565b613088613b3b565b60405163d914cd4b60e01b81526001600160a01b0382811660048301527f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c4169063d914cd4b90602401600060405180830381600087803b1580156130eb57600080fd5b505af11580156130ff573d6000803e3d6000fd5b5050505060007f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b0316632cdacb506040518163ffffffff1660e01b8152600401602060405180830381865afa158015613163573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131879190615696565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa1580156131f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132179190615696565b604051631da958a960e21b81526001600160a01b03858116600483015291909116906376a562a490602401602060405180830381865afa15801561325f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132839190615696565b9050611ad36001600160a01b038216836000196133d9565b6132a3613b3b565b80600354036132c45760405162461bcd60e51b815260040161040290615792565b6702c68af0bb14000081111561331c5760405162461bcd60e51b815260206004820152601d60248201527f646576696174696f6e206578636565647320757070657220626f756e640000006044820152606401610402565b60038190556040518181527f3f9ef5ed5d378ef819698e4b3c710d362f981f90087b428b7a1ee1e716d689d59060200161148d565b6000610f463384846001611d1f565b613368613b3b565b6001600160a01b0381166133cd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610402565b6133d68161491f565b50565b8015806134535750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561342d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345191906155b0565b155b6134be5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610402565b6040516001600160a01b038316602482015260448101829052611ad390849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614b5b565b60606112d68484600085614c30565b6000807f000000000000000000000000d02bcdbe1d7790bdc4e1c365bff8269d8f5e035e6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b591906155b0565b90508015806135c2575082155b156135d357610f466012600a6158fd565b610f46838261462f565b60006135eb6012600a6158fd565b6135f58385615909565b610f469190615920565b80600061360c82866155df565b9050600061361985614d0b565b90505b82156138b2576000807f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b03166339d82513858561365e614da9565b6040518463ffffffff1660e01b815260040161367c93929190615942565b6040805180830381865afa158015613698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136bc919061596b565b6040516304042d6360e21b81526004810183905291935091506000906001600160a01b037f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c41690631010b58c90602401602060405180830381865afa158015613729573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374d9190615696565b9050600061375b87846138ba565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa1580156137c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137eb9190615696565b6040516001600160a01b0380861660248301527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48166044820152606481018490529091506138709060840160408051601f198184030181529190526020810180516001600160e01b0316636ce5768960e11b1790526001600160a01b03831690614dc8565b5061387b82896155df565b97508186868151811061389057613890615680565b602002602001018181516138a491906155df565b90525061361c945050505050565b505050505050565b60008183106138c95781610f46565b5090919050565b6040516001600160a01b038316602482015260448101829052611ad390849063a9059cbb60e01b906064016134ea565b600061390b83614ded565b8015610f465750610f468383614e20565b60608151835161392c919061577f565b6001600160401b038111156139435761394361544a565b60405190808252806020026020018201604052801561396c578160200160208202803683370190505b50905060005b83518110156139d15783818151811061398d5761398d615680565b60200260200101518282815181106139a7576139a7615680565b6001600160a01b0390921660209283029190910190910152806139c9816156b3565b915050613972565b5060005b8251811015613a40578281815181106139f0576139f0615680565b602002602001015182855183613a06919061577f565b81518110613a1657613a16615680565b6001600160a01b039092166020928302919091019091015280613a38816156b3565b9150506139d5565b5092915050565b6060600082516001600160401b03811115613a6457613a6461544a565b604051908082528060200260200182016040528015613a8d578160200160208202803683370190505b5090506000805b8451811015613b3057613ac183868381518110613ab357613ab3615680565b602002602001015184614ea5565b613b1e57848181518110613ad757613ad7615680565b6020026020010151838380613aeb906156b3565b945081518110613afd57613afd615680565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80613b28816156b3565b915050613a94565b506112d68282614f0a565b6000546001600160a01b0316331461241e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610402565b600080606060007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa158015613bfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c2291908101906155f2565b8051909150806001600160401b03811115613c3f57613c3f61544a565b604051908082528060200260200182016040528015613c68578160200160208202803683370190505b50925060005b81811015613dfa576000838281518110613c8a57613c8a615680565b60209081029190910101516040516355eb6b3560e01b81526001600160a01b0380831660048301529192506000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa158015613d01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d259190615696565b6001600160a01b0316630fee68b330847f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488e8e6040518663ffffffff1660e01b8152600401613d7895949392919061598f565b602060405180830381865afa158015613d95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db991906155b0565b905080868481518110613dce57613dce615680565b6020908102919091010152613de3818861577f565b965050508080613df2906156b3565b915050613c6e565b506040516370a0823160e01b81523060048201527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015613e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8391906155b0565b613e8d908561577f565b945050509250925092565b6006546000906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811690841603613edf57613edc600282615909565b90505b6001600160a01b038084166000908152600d60209081526040808320548151632630c12f60e01b8152915190947f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae1692632630c12f92600480820193918290030181865afa158015613f55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f799190615696565b604051638b2f0f4f60e01b81526001600160a01b0387811660048301529190911690638b2f0f4f90602401602060405180830381865afa158015613fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe591906155b0565b90506000613ff38383614fb1565b90506000614001828561462f565b949094119695505050505050565b6040516355eb6b3560e01b81526001600160a01b03828116600483015260009182917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa15801561407a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061409e9190615696565b604051622708db60e01b81526001600160a01b0385811660048301529190911690622708db90602401600060405180830381865afa1580156140e4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261410c91908101906155f2565b905060005b815181101561416457600082828151811061412e5761412e615680565b6020026020010151905061414181613e98565b1561415157506001949350505050565b508061415c816156b3565b915050614111565b5060009392505050565b60007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b031663c5c63e656040518163ffffffff1660e01b8152600401600060405180830381865afa1580156141ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526141f691908101906155f2565b805190915060005b81811015611ad357600083828151811061421a5761421a615680565b60209081029190910101516040516355eb6b3560e01b81526001600160a01b0380831660048301529192506000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa158015614291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142b59190615696565b60405163415ec73b60e01b81526001600160a01b0384811660048301529192509082169063415ec73b90602401600060405180830381600087803b1580156142fc57600080fd5b505af1158015614310573d6000803e3d6000fd5b5050505050508080614321906156b3565b9150506141fe565b6040516001600160a01b03808516602483015283166044820152606481018290526143619085906323b872dd60e01b906084016134ea565b50505050565b806000614374828661577f565b9050600061438185614d0b565b90505b82156138b2576000807f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b03166312968a2985856143c6614da9565b6040518463ffffffff1660e01b81526004016143e493929190615942565b6040805180830381865afa158015614400573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614424919061596b565b909250905061443481606461577f565b85101561443e5750835b6040516304042d6360e21b8152600481018390526000907f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b031690631010b58c90602401602060405180830381865afa1580156144a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144ca9190615696565b905060006144d887846138ba565b6040516355eb6b3560e01b81526001600160a01b0384811660048301529192506000917f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae16906355eb6b3590602401602060405180830381865afa158015614544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145689190615696565b6040516001600160a01b0380861660248301527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48166044820152606481018490529091506145ed9060840160408051601f198184030181529190526020810180516001600160e01b0316638340f54960e01b1790526001600160a01b03831690614dc8565b506145f882896155df565b97508186868151811061460d5761460d615680565b60200260200101818151614621919061577f565b905250614384945050505050565b60008161463e6012600a6158fd565b6135f59085615909565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526146998482614fc9565b614361576040516001600160a01b0384166024820152600060448201526146cd90859063095ea7b360e01b906064016134ea565b6143618482614b5b565b600954610100900460ff16156129cb57604051633f20953d60e11b81526000906001600160a01b037f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c41690637e412a7a9061473890889088906004016157bb565b602060405180830381865afa158015614755573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061477991906155b0565b905060007f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c46001600160a01b0316637e412a7a85856040518363ffffffff1660e01b81526004016147cb9291906157bb565b602060405180830381865afa1580156147e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480c91906155b0565b90507f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b031663dbcd89fa6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561486c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148909190615696565b604051630a48af5f60e11b81526001600160a01b038981166004830152602482018590526044820184905291909116906314915ebe90606401600060405180830381600087803b1580156148e357600080fd5b505af11580156148f7573d6000803e3d6000fd5b50505050614905838561496f565b15614916576009805461ff00191690555b50505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6003546040516328cb81ef60e11b81526000916001600160a01b037f0000000000000000000000009c323a3b948098b411f44b55779288f01116f7c4169163519703de916149c391879187916004016159e4565b602060405180830381865afa1580156149e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4691906157fc565b6000614a0e610f4d565b905060007f0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a949190615696565b905060005b8251811015611ad3576000838281518110614ab657614ab6615680565b6020908102919091010151604051638b2f0f4f60e01b81526001600160a01b03808316600483015291925090841690638b2f0f4f90602401602060405180830381865afa158015614b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b2f91906155b0565b6001600160a01b039091166000908152600d602052604090205580614b53816156b3565b915050614a99565b6000614bb0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135219092919063ffffffff16565b9050805160001480614bd1575080806020019051810190614bd191906157fc565b611ad35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610402565b606082471015614c915760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610402565b600080866001600160a01b03168587604051614cad9190615a2d565b60006040518083038185875af1925050503d8060008114614cea576040519150601f19603f3d011682016040523d82523d6000602084013e614cef565b606091505b5091509150614d0087838387615070565b979650505050505050565b6060600082516001600160401b03811115614d2857614d2861544a565b604051908082528060200260200182016040528015614d51578160200160208202803683370190505b50905060005b8351811015613a4057838181518110614d7257614d72615680565b6020026020010151828281518110614d8c57614d8c615680565b602090810291909101015280614da1816156b3565b915050614d57565b600954600090610100900460ff16614dc2575060035490565b50600090565b6060610f468383604051806060016040528060278152602001615a7d602791396150e9565b6000614e00826301ffc9a760e01b614e20565b80156111d65750614e19826001600160e01b0319614e20565b1592915050565b604080516001600160e01b03198316602480830191909152825180830390910181526044909101909152602080820180516001600160e01b03166301ffc9a760e01b178152825160009392849283928392918391908a617530fa92503d91506000519050828015614e92575060208210155b8015614d00575015159695505050505050565b6000805b82811015614eff57836001600160a01b0316858281518110614ecd57614ecd615680565b60200260200101516001600160a01b031603614eed576001915050610f46565b80614ef7816156b3565b915050614ea9565b506000949350505050565b6060816001600160401b03811115614f2457614f2461544a565b604051908082528060200260200182016040528015614f4d578160200160208202803683370190505b50905060005b82811015613a4057838181518110614f6d57614f6d615680565b6020026020010151828281518110614f8757614f87615680565b6001600160a01b039092166020928302919091019091015280614fa9816156b3565b915050614f53565b600081831015614fc357828203610f46565b50900390565b6000806000846001600160a01b031684604051614fe69190615a2d565b6000604051808303816000865af19150503d8060008114615023576040519150601f19603f3d011682016040523d82523d6000602084013e615028565b606091505b509150915081801561505257508051158061505257508080602001905181019061505291906157fc565b801561506757506001600160a01b0385163b15155b95945050505050565b606083156150df5782516000036150d8576001600160a01b0385163b6150d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610402565b50816112d6565b6112d68383615161565b6060600080856001600160a01b0316856040516151069190615a2d565b600060405180830381855af49150503d8060008114615141576040519150601f19603f3d011682016040523d82523d6000602084013e615146565b606091505b509150915061515786838387615070565b9695505050505050565b8151156151715781518083602001fd5b8060405162461bcd60e51b81526004016104029190615a49565b6001600160a01b03811681146133d657600080fd5b6000806000606084860312156151b557600080fd5b833592506020840135915060408401356151ce8161518b565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b8181101561521a5783516001600160a01b0316835292840192918401916001016151f5565b50909695505050505050565b60006020828403121561523857600080fd5b5035919050565b6000806040838503121561525257600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156152b4576152a484835180516001600160a01b03168252602090810151910152565b928401929085019060010161527e565b5091979650505050505050565b600081518084526020808501945080840160005b838110156152f1578151875295820195908201906001016152d5565b509495945050505050565b83815282602082015260606040820152600061506760608301846152c1565b60006020828403121561532d57600080fd5b8135610f468161518b565b80151581146133d657600080fd5b6000806040838503121561535957600080fd5b82356153648161518b565b9150602083013561537481615338565b809150509250929050565b60008060006060848603121561539457600080fd5b833592506020840135915060408401356151ce81615338565b600080600080608085870312156153c357600080fd5b84356153ce8161518b565b9350602085013592506040850135915060608501356153ec81615338565b939692955090935050565b602080825282518282018190526000919060409081850190868401855b828110156152b45761543a84835180516001600160a01b03168252602090810151910152565b9284019290850190600101615414565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156154825761548261544a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156154b0576154b061544a565b604052919050565b60006001600160401b038211156154d1576154d161544a565b5060051b60200190565b600060208083850312156154ee57600080fd5b82356001600160401b0381111561550457600080fd5b8301601f8101851361551557600080fd5b8035615528615523826154b8565b615488565b81815260069190911b8201830190838101908783111561554757600080fd5b928401925b82841015614d0057604084890312156155655760008081fd5b61556d615460565b84356155788161518b565b8152848601358682015282526040909301929084019061554c565b6000602082840312156155a557600080fd5b8135610f4681615338565b6000602082840312156155c257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156111d6576111d66155c9565b6000602080838503121561560557600080fd5b82516001600160401b0381111561561b57600080fd5b8301601f8101851361562c57600080fd5b805161563a615523826154b8565b81815260059190911b8201830190838101908783111561565957600080fd5b928401925b82841015614d005783516156718161518b565b8252928401929084019061565e565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156156a857600080fd5b8151610f468161518b565b6000600182016156c5576156c56155c9565b5060010190565b600060208083850312156156df57600080fd5b82516001600160401b038111156156f557600080fd5b8301601f8101851361570657600080fd5b8051615714615523826154b8565b81815260069190911b8201830190838101908783111561573357600080fd5b928401925b82841015614d0057604084890312156157515760008081fd5b615759615460565b84516157648161518b565b81528486015186820152825260409093019290840190615738565b808201808211156111d6576111d66155c9565b6020808252600f908201526e1cd85b5948185cc818dd5c9c995b9d608a1b604082015260600190565b8281526040602082015260006112d660408301846152c1565b6020808252600e908201526d1b9bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60006020828403121561580e57600080fd5b8151610f4681615338565b600181815b8085111561585457816000190482111561583a5761583a6155c9565b8085161561584757918102915b93841c939080029061581e565b509250929050565b60008261586b575060016111d6565b81615878575060006111d6565b816001811461588e5760028114615898576158b4565b60019150506111d6565b60ff8411156158a9576158a96155c9565b50506001821b6111d6565b5060208310610133831016604e8410600b84101617156158d7575081810a6111d6565b6158e18383615819565b80600019048211156158f5576158f56155c9565b029392505050565b6000610f46838361585c565b80820281158282048414176111d6576111d66155c9565b60008261593d57634e487b7160e01b600052601260045260246000fd5b500490565b83815260606020820152600061595b60608301856152c1565b9050826040830152949350505050565b6000806040838503121561597e57600080fd5b505080516020909101519092909150565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a08101600383106159d457634e487b7160e01b600052602160045260246000fd5b8260808301529695505050505050565b6060815260006159f760608301866152c1565b60208301949094525060400152919050565b60005b83811015615a24578181015183820152602001615a0c565b50506000910152565b60008251615a3f818460208701615a09565b9190910192915050565b6020815260008251806020840152615a68816040850160208701615a09565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e036bcfeb1a7d33ecc69abc563e339a4f1f63b3230b1dc5a2a85bc92779392cf64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000015c606c60afcfaa8e57777d947c40e92041195320000000000000000000000002790ec478f150a98f5d96755601a26403df57eae00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52000000000000000000000000000000000000000000000000000000000000000a436f6e69632055534443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007636e635553444300000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _underlying (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _rewardManager (address): 0x15C606C60AfcfaA8e57777d947C40E9204119532
Arg [2] : _controller (address): 0x2790EC478f150a98F5D96755601a26403DF57EaE
Arg [3] : _lpTokenName (string): Conic USDC
Arg [4] : _symbol (string): cncUSDC
Arg [5] : _cvx (address): 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B
Arg [6] : _crv (address): 0xD533a949740bb3306d119CC777fa900bA034cd52
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 00000000000000000000000015c606c60afcfaa8e57777d947c40e9204119532
Arg [2] : 0000000000000000000000002790ec478f150a98f5d96755601a26403df57eae
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [5] : 0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b
Arg [6] : 000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52
Arg [7] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [8] : 436f6e6963205553444300000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [10] : 636e635553444300000000000000000000000000000000000000000000000000
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.