More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 11 from a total of 11 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 19174909 | 379 days ago | IN | 0 ETH | 0.00387139 | ||||
Withdraw | 14980253 | 979 days ago | IN | 0 ETH | 0.0044133 | ||||
Withdraw | 14973064 | 980 days ago | IN | 0 ETH | 0.00369702 | ||||
Withdraw | 14972922 | 980 days ago | IN | 0 ETH | 0.00357251 | ||||
Approve | 14970527 | 981 days ago | IN | 0 ETH | 0.00136402 | ||||
Approve | 14928556 | 988 days ago | IN | 0 ETH | 0.00368116 | ||||
Approve | 14920856 | 989 days ago | IN | 0 ETH | 0.00146496 | ||||
Withdraw | 14920745 | 989 days ago | IN | 0 ETH | 0.00592909 | ||||
Withdraw | 14920377 | 989 days ago | IN | 0 ETH | 0.00347475 | ||||
Approve | 14916438 | 990 days ago | IN | 0 ETH | 0.00112515 | ||||
Approve | 14916435 | 990 days ago | IN | 0 ETH | 0.00176749 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
AaveV2StablecoinCellar
Compiler Version
v0.8.11+commit.d7f03943
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; import { SafeTransferLib } from "@rari-capital/solmate/src/utils/SafeTransferLib.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IAaveIncentivesController } from "./interfaces/IAaveIncentivesController.sol"; import { IStakedTokenV2 } from "./interfaces/IStakedTokenV2.sol"; import { ICurveSwaps } from "./interfaces/ICurveSwaps.sol"; import { ISushiSwapRouter } from "./interfaces/ISushiSwapRouter.sol"; import { IGravity } from "./interfaces/IGravity.sol"; import { ILendingPool } from "./interfaces/ILendingPool.sol"; import { MathUtils } from "./utils/MathUtils.sol"; import "./Errors.sol"; import { IAaveV2StablecoinCellar } from "./interfaces/IAaveV2StablecoinCellar.sol"; /** * @title Sommelier Aave V2 Stablecoin Cellar * @notice Dynamic ERC4626 that changes positions to always get the best yield for stablecoins on Aave. * @author Brian Le */ contract AaveV2StablecoinCellar is IAaveV2StablecoinCellar, ERC20, Ownable { using SafeTransferLib for ERC20; using MathUtils for uint256; /** * @notice The asset that makes up the cellar's holding pool. Will change whenever the cellar * rebalances into a new position. * @dev The cellar denotes its inactive assets in this token. While it waits in the holding pool * to be entered into a position, it is used as exit liquidity from those redeeming their * shares for capital efficiency. */ ERC20 public asset; /** * @notice An interest-bearing derivative of the current asset returned by Aave for lending * the current asset. Represents cellar's portion of active assets earning yield in a * lending position. */ ERC20 public assetAToken; /** * @notice The decimals of precision used by the current asset. * @dev Since stablecoins don't use the standard 18 decimals of precision (eg. USDC and USDT), * we cache this to use for decimal conversions when performing calculations and storing data. */ uint8 public assetDecimals; /** * @notice Mapping from a user's address to all their deposits and balances. * @dev Used to determining which of a user's shares are active (ie. entered into a position earning * yield vs inactive (ie. waiting in the holding pool to be entered into a position and not * earning yield). */ mapping(address => UserDeposit[]) public userDeposits; /** * @notice Mapping from a user's address to the index of their first non-zero deposit in `userDeposits`. * @dev Saves gas when looping through all of a user's deposits. */ mapping(address => uint256) public currentDepositIndex; /** * @notice Whether an asset position is trusted or not. Prevents cellar from rebalancing into an * asset that has not been trusted by the users. Trusting / distrusting of an asset is done * through governance. */ mapping(address => bool) public isTrusted; /** * @notice Last time all inactive assets were entered into a strategy and made active. Used to * determining which of a user's shares are active. */ uint256 public lastTimeEnteredPosition; /** * @notice The value fees are divided by to get a percentage. Represents the maximum percent (100%). */ uint256 public constant DENOMINATOR = 100_00; /** * @notice The percentage of platform fees taken off of active assets over a year. */ uint256 public constant PLATFORM_FEE = 1_00; // 1% /** * @notice The percentage of performance fees taken off of cellar gains. */ uint256 public constant PERFORMANCE_FEE = 10_00; // 10% /** * @notice Stores fee-related data. */ IAaveV2StablecoinCellar.Fees public fees; /** * @notice Cosmos address of the fee distributor as a hex value. * @dev The Gravity contract expects a 32-byte value formatted in a specific way. */ bytes32 public feesDistributor = hex"000000000000000000000000b813554b423266bbd4c16c32fa383394868c1f55"; /** * @notice Maximum amount of assets that can be managed by the cellar. Denominated in the same decimals * as the current asset. * @dev Set to `type(uint256).max` to have no limit. */ uint256 public liquidityLimit; /** * @notice Maximum amount of assets per wallet. Denominated in the same decimals as the current asset. * @dev Set to `type(uint256).max` to have no limit. */ uint256 public depositLimit; /** * @notice Whether or not the contract is shutdown in case of an emergency. */ bool public isShutdown; // ======================================== INITIALIZATION ======================================== /** * @notice Curve Registry Exchange contract. Used for rebalancing positions. */ ICurveSwaps public immutable curveRegistryExchange; // 0x81C46fECa27B31F3ADC2b91eE4be9717d1cd3DD7 /** * @notice SushiSwap Router V2 contract. Used for reinvesting rewards back into the current position. */ ISushiSwapRouter public immutable sushiswapRouter; // 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F /** * @notice Aave Lending Pool V2 contract. Used to deposit and withdraw from the current position. */ ILendingPool public immutable lendingPool; // 0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9 /** * @notice Aave Incentives Controller V2 contract. Used to claim and unstake rewards to reinvest. */ IAaveIncentivesController public immutable incentivesController; // 0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5 /** * @notice Cosmos Gravity Bridge contract. Used to transfer fees to `feeDistributor` on the Sommelier chain. */ IGravity public immutable gravityBridge; // 0x69592e6f9d21989a043646fE8225da2600e5A0f7 /** * @notice stkAAVE address. Used to swap rewards to the current asset to reinvest. */ IStakedTokenV2 public immutable stkAAVE; // 0x4da27a545c0c5B758a6BA100e3a049001de870f5 /** * @notice AAVE address. Used to swap rewards to the current asset to reinvest. */ ERC20 public immutable AAVE; // 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9 /** * @notice WETH address. Used to swap rewards to the current asset to reinvest. */ ERC20 public immutable WETH; // 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 /** * @dev Owner will be set to the Gravity Bridge, which relays instructions from the Steward * module to the cellars. * https://github.com/PeggyJV/steward * https://github.com/cosmos/gravity-bridge/blob/main/solidity/contracts/Gravity.sol * @param _asset current asset managed by the cellar * @param _approvedPositions list of approved positions to start with * @param _curveRegistryExchange Curve registry exchange * @param _sushiswapRouter Sushiswap V2 router address * @param _lendingPool Aave V2 lending pool address * @param _incentivesController _incentivesController * @param _gravityBridge Cosmos Gravity Bridge address * @param _stkAAVE stkAAVE address * @param _AAVE AAVE address * @param _WETH WETH address */ constructor( ERC20 _asset, address[] memory _approvedPositions, ICurveSwaps _curveRegistryExchange, ISushiSwapRouter _sushiswapRouter, ILendingPool _lendingPool, IAaveIncentivesController _incentivesController, IGravity _gravityBridge, IStakedTokenV2 _stkAAVE, ERC20 _AAVE, ERC20 _WETH ) ERC20("Sommelier Aave V2 Stablecoin Cellar LP Token", "aave2-CLR-S", 18) { // Initialize immutables. curveRegistryExchange = _curveRegistryExchange; sushiswapRouter = _sushiswapRouter; lendingPool = _lendingPool; incentivesController = _incentivesController; gravityBridge = _gravityBridge; stkAAVE = _stkAAVE; AAVE = _AAVE; WETH = _WETH; // Initialize asset. isTrusted[address(_asset)] = true; _updatePosition(address(_asset)); // Initialize limits. uint256 powOfAssetDecimals = 10**assetDecimals; liquidityLimit = 5_000_000 * powOfAssetDecimals; depositLimit = 50_000 * powOfAssetDecimals; // Initialize approved positions. for (uint256 i; i < _approvedPositions.length; i++) isTrusted[_approvedPositions[i]] = true; // Transfer ownership to the Gravity Bridge. transferOwnership(address(_gravityBridge)); } // =============================== DEPOSIT/WITHDRAWAL OPERATIONS =============================== /** * @notice Deposits assets and mints the shares to receiver. * @param assets amount of assets to deposit * @param receiver address receiving the shares * @return shares amount of shares minted */ function deposit(uint256 assets, address receiver) external returns (uint256 shares) { // Depositing above balance will only deposit balance. uint256 depositableAssets = asset.balanceOf(msg.sender); if (assets > depositableAssets) assets = depositableAssets; (, shares) = _deposit(assets, 0, receiver); } /** * @notice Mints shares to receiver by depositing assets. * @param shares amount of shares to mint * @param receiver address receiving the shares * @return assets amount of assets deposited */ function mint(uint256 shares, address receiver) external returns (uint256 assets) { // Depositing above balance will only deposit balance. uint256 mintableShares = previewDeposit(asset.balanceOf(msg.sender)); if (shares > mintableShares) shares = mintableShares; (assets, ) = _deposit(0, shares, receiver); } function _deposit(uint256 assets, uint256 shares, address receiver) internal returns (uint256, uint256) { if (isShutdown) revert STATE_ContractShutdown(); // Must calculate before assets are transferred in. shares > 0 ? assets = previewMint(shares) : shares = previewDeposit(assets); // Prevent event spamming and user deposit spamming. if (shares == 0) revert USR_ZeroShares(); // Enforce global liquidity restrictions and deposit restrictions per wallet. if (assets > maxDeposit(receiver)) revert USR_DepositRestricted(assets, maxDeposit(receiver)); // Transfers assets into the cellar. asset.safeTransferFrom(msg.sender, address(this), assets); // Mint user tokens that represents their share of the cellar's assets. _mint(receiver, shares); // Store the user's deposit data. This will be used later on when the user wants to withdraw // their assets or transfer their shares. UserDeposit[] storage deposits = userDeposits[receiver]; deposits.push(UserDeposit({ // Always store asset amounts with 18 decimals of precision regardless of the asset's // decimals. This is so we can still use this data even after rebalancing to different // asset. assets: uint112(assets.changeDecimals(assetDecimals, decimals)), shares: uint112(shares), timeDeposited: uint32(block.timestamp) })); emit Deposit( msg.sender, receiver, address(asset), assets, shares ); return (assets, shares); } /** * @notice Withdraws assets to receiver by redeeming shares from owner. * @param assets amount of assets being withdrawn * @param receiver address of account receiving the assets * @param owner address of the owner of the shares being redeemed * @return shares amount of shares redeemed */ function withdraw( uint256 assets, address receiver, address owner ) external returns (uint256 shares) { // Ensures proceeding calculations are done with a standard 18 decimals of precision. Will // change back to the using the asset's usual decimals of precision when transferring assets // after all calculations are done. assets = assets.changeDecimals(assetDecimals, decimals); // Withdrawing above balance will only withdraw balance. (, shares) = _withdraw(assets, receiver, owner); } /** * @notice Redeems shares from owner to withdraw assets to receiver. * @param shares amount of shares redeemed * @param receiver address of account receiving the assets * @param owner address of the owner of the shares being redeemed * @return assets amount of assets sent to receiver */ function redeem( uint256 shares, address receiver, address owner ) external returns (uint256 assets) { // Withdrawing above balance will only withdraw balance. (assets, ) = _withdraw(_convertToAssets(shares), receiver, owner); } /** * @dev `assets` must be passed in with 18 decimals of precision. Must extend/truncate decimals of * the amount passed in if necessary to ensure this is true. */ function _withdraw( uint256 assets, address receiver, address owner ) internal returns (uint256, uint256) { if (balanceOf[owner] == 0) revert USR_ZeroShares(); if (assets == 0) revert USR_ZeroAssets(); // Tracks amount of shares to redeem. uint256 shares; // Retrieve the user's deposits to begin looping through them, generally from oldest to // newest deposits. This may not be the case if shares have been transferred to the owner, // which will be added to the end of the owner's deposits regardless of time deposited. UserDeposit[] storage deposits = userDeposits[owner]; // Tracks the amount of assets left to withdraw. Updated at the end of each loop. uint256 leftToWithdraw = assets; // Saves gas by avoiding calling `_convertToAssets` on active shares during each loop. uint256 exchangeRate = _convertToAssets(1e18); for (uint256 i = currentDepositIndex[owner]; i < deposits.length; i++) { UserDeposit storage d = deposits[i]; // Whether or not deposited shares are active or inactive. bool isActive = d.timeDeposited < lastTimeEnteredPosition; // If shares are active, convert them to the amount of assets they're worth to get the // maximum amount of assets withdrawable from this deposit. uint256 dAssets = isActive ? uint256(d.shares).mulWadDown(exchangeRate) : d.assets; // Determine the amount of assets and shares to withdraw from this deposit. uint256 withdrawnAssets = MathUtils.min(leftToWithdraw, dAssets); uint256 withdrawnShares = uint256(d.shares).mulDivUp(withdrawnAssets, dAssets); // For active shares, deletes the deposit data we don't need anymore for a gas refund. if (isActive) { delete d.assets; delete d.timeDeposited; } else { // Substract the amount of assets taken for this withdraw. d.assets -= uint112(withdrawnAssets); } // Subtract shares withdrawn and add to total. d.shares -= uint112(withdrawnShares); shares += withdrawnShares; // Update the counter of assets left to withdraw. leftToWithdraw -= withdrawnAssets; // Break if this is the last deposit or there is nothing left to withdraw. if (i == deposits.length - 1 || leftToWithdraw == 0) { // Store the user's next non-zero deposit to save gas on future looping. currentDepositIndex[owner] = d.shares != 0 ? i : i+1; break; } } // Check to see if the caller is approved to spend shares. if (msg.sender != owner) { uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; } // Redeem shares. _burn(owner, shares); // Determine the total amount of assets withdrawn. assets -= leftToWithdraw; // Convert assets decimals back for transfers. assets = assets.changeDecimals(decimals, assetDecimals); // Only withdraw from position if holding pool does not contain enough funds. _allocateAssets(assets); // Transfer assets to receiver from the cellar's holding pool. asset.safeTransfer(receiver, assets); emit Withdraw(receiver, owner, address(asset), assets, shares); // The amount of assets actually withdrawn may be less than assets attempted to withdraw // if attempted withdraw amount was less than the withdrawable balance. return (assets, shares); } // ================================== ACCOUNTING OPERATIONS ================================== /** * @dev The internal functions always use 18 decimals of precision while the public functions use * as many decimals as the current asset (aka they don't change the decimals). This is * because we want the user deposit data the cellar stores to be usable across different * assets regardless of the decimals used. This means the cellar will always perform * calculations and store data with a standard of 18 decimals of precision but will change * the decimals back when transferring assets outside the contract or returning data * through public view functions. */ /** * @notice Total amount of active asset entered into the current position. * @dev The aTokens' value is pegged to the value of the corresponding asset at a 1:1 ratio. We * can find the amount of assets active in a position simply by taking balance of aTokens * cellar holds. */ function activeAssets() public view returns (uint256) { return assetAToken.balanceOf(address(this)); } /** * @dev Same as `activeAssets` but forcibly denoted with 18 decimals of precision. */ function _activeAssets() internal view returns (uint256) { uint256 assets = assetAToken.balanceOf(address(this)); return assets.changeDecimals(assetDecimals, decimals); } /** * @notice Total amount of inactive asset in holding. */ function inactiveAssets() public view returns (uint256) { return asset.balanceOf(address(this)); } /** * @dev Same as `inactiveAssets` but forcibly denoted with 18 decimals of precision. */ function _inactiveAssets() internal view returns (uint256) { uint256 assets = asset.balanceOf(address(this)); return assets.changeDecimals(assetDecimals, decimals); } /** * @notice Total amount of the asset managed by the cellar. */ function totalAssets() public view returns (uint256) { return activeAssets() + inactiveAssets(); } /** * @dev Same as `totalAssets` but forcibly denoted with 18 decimals of precision. */ function _totalAssets() internal view returns (uint256) { return _activeAssets() + _inactiveAssets(); } /** * @notice The amount of shares that the cellar would exchange for the amount of assets provided * ASSUMING they are active. * @param assets amount of assets to convert * @return shares the assets can be exchanged for */ function convertToShares(uint256 assets) public view returns (uint256) { assets = assets.changeDecimals(assetDecimals, decimals); return _convertToShares(assets); } /** * @dev Same as `convertToShares` but forcibly denoted with 18 decimals of precision. */ function _convertToShares(uint256 assets) internal view returns (uint256) { uint256 currentTotalAssets = _totalAssets(); uint256 currentTotalSupply = totalSupply; return currentTotalAssets == 0 || currentTotalSupply == 0 ? assets : assets.mulDivDown(currentTotalSupply, currentTotalAssets); } /** * @notice The amount of assets that the cellar would exchange for the amount of shares provided * ASSUMING they are active. * @param shares amount of shares to convert * @return assets the shares can be exchanged for */ function convertToAssets(uint256 shares) public view returns (uint256) { uint256 assets = _convertToAssets(shares); return assets.changeDecimals(decimals, assetDecimals); } /** * @dev Same as `convertToAssets` but forcibly denoted with 18 decimals of precision. */ function _convertToAssets(uint256 shares) internal view returns (uint256) { return totalSupply == 0 ? shares : shares.mulDivDown(_totalAssets(), totalSupply); } /** * @notice Simulate the effects of depositing assets at the current block, given current on-chain * conditions. * @param assets amount of assets to deposit * @return shares that will be minted */ function previewDeposit(uint256 assets) public view returns (uint256) { return convertToShares(assets); } /** * @notice Simulate the effects of minting shares at the current block, given current on-chain * conditions. * @param shares amount of shares to mint * @return assets that will be deposited */ function previewMint(uint256 shares) public view returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. uint256 assets = supply == 0 ? shares : shares.mulDivUp(_totalAssets(), supply); return assets.changeDecimals(decimals, assetDecimals); } /** * @notice Simulate the effects of withdrawing assets at the current block, given current * on-chain conditions ASSUMING the shares being redeemed are all active. * @param assets amount of assets to withdraw * @return shares that will be redeemed */ function previewWithdraw(uint256 assets) public view returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); } /** * @notice Simulate the effects of redeeming shares at the current block, given current on-chain * conditions ASSUMING the shares being redeemed are all active. * @param shares amount of sharers to redeem * @return assets that can be withdrawn */ function previewRedeem(uint256 shares) public view returns (uint256) { return convertToAssets(shares); } // ======================================= STATE INFORMATION ===================================== /** * @notice Retrieve information on a user's deposit balances. * @param user address of the user * @return userActiveShares amount of active shares the user has * @return userInactiveShares amount of inactive shares the user has * @return userActiveAssets amount of active assets the user has * @return userInactiveAssets amount of inactive assets the user has */ function getUserBalances(address user) external view returns ( uint256 userActiveShares, uint256 userInactiveShares, uint256 userActiveAssets, uint256 userInactiveAssets ) { // Retrieve the user's deposits to begin looping through them, generally from oldest to // newest deposits. This may not be the case though if shares have been transferred to the // user, which will be added to the end of the user's deposits regardless of time // deposited. UserDeposit[] storage deposits = userDeposits[user]; // Saves gas by avoiding calling `_convertToAssets` on active shares during each loop. uint256 exchangeRate = _convertToAssets(1e18); for (uint256 i = currentDepositIndex[user]; i < deposits.length; i++) { UserDeposit storage d = deposits[i]; // Determine whether or not deposit is active or inactive. if (d.timeDeposited < lastTimeEnteredPosition) { // Saves an extra SLOAD if active and cast type to uint256. uint256 dShares = d.shares; userActiveShares += dShares; userActiveAssets += dShares.mulWadDown(exchangeRate); // Convert active shares to assets. } else { userInactiveShares += d.shares; userInactiveAssets += d.assets; } } // Return assets in their original units. userActiveAssets = userActiveAssets.changeDecimals(decimals, assetDecimals); userInactiveAssets = userInactiveAssets.changeDecimals(decimals, assetDecimals); } /** * @notice Retrieve a list of all of a user's deposits. * @dev This is provided because Solidity converts public arrays into index getters, * but we need a way to allow external contracts and users to access the whole array. * @param user address of the user * @return array of all the users deposits */ function getUserDeposits(address user) external view returns (UserDeposit[] memory) { return userDeposits[user]; } // =========================== DEPOSIT/WITHDRAWAL LIMIT OPERATIONS =========================== /** * @notice Total number of assets that can be deposited by owner into the cellar. * @param owner address of account that would receive the shares * @return maximum amount of assets that can be deposited */ function maxDeposit(address owner) public view returns (uint256) { if (isShutdown) return 0; if (depositLimit == type(uint256).max && liquidityLimit == type(uint256).max) // Conversion to fixed point will overflow if the number being converted has more integer // digits that fit in the bits reserved for them in the fixed point representation. This // is the maximum assets that can be deposited without overflowing. return uint256(type(uint112).max) / 10**(decimals - assetDecimals); uint256 leftUntilDepositLimit = depositLimit.subMin0(maxWithdraw(owner)); uint256 leftUntilLiquidityLimit = liquidityLimit.subMin0(totalAssets()); // Only return the more relevant of the two. return MathUtils.min(leftUntilDepositLimit, leftUntilLiquidityLimit); } /** * @notice Total number of shares that can be minted for owner from the cellar. * @param owner address of account that would receive the shares * @return maximum amount of shares that can be minted */ function maxMint(address owner) public view returns (uint256) { return convertToShares(maxDeposit(owner)); } /** * @notice Total number of assets that can be withdrawn from the cellar. * @param owner address of account that would holds the shares * @return maximum amount of assets that can be withdrawn */ function maxWithdraw(address owner) public view returns (uint256) { UserDeposit[] storage deposits = userDeposits[owner]; // Track max assets that can be withdrawn. uint256 assets; // Saves gas by avoiding calling `_convertToAssets` on active shares during each loop. uint256 exchangeRate = _convertToAssets(1e18); for (uint256 i = currentDepositIndex[owner]; i < deposits.length; i++) { UserDeposit storage d = deposits[i]; // Determine the amount of assets that can be withdrawn. Only redeem active shares for // assets, otherwise just withdrawn the original amount of assets that were deposited. assets += d.timeDeposited < lastTimeEnteredPosition ? uint256(d.shares).mulWadDown(exchangeRate) : d.assets; } // Converts back to decimals used by that asset. return assets.changeDecimals(decimals, assetDecimals); } /** * @notice Total number of shares that can be redeemed from the cellar. * @param owner address of account that would holds the shares * @return maximum amount of shares that can be redeemed */ function maxRedeem(address owner) public view returns (uint256) { return balanceOf[owner]; } // ====================================== FEE OPERATIONS ====================================== /** * @notice Take platform fees and performance fees off of cellar's active assets. */ function accrueFees() external updateYield { // Platform fees taken each accrual = activeAssets * (elapsedTime * (feePercentage / SECS_PER_YEAR)). uint256 elapsedTime = block.timestamp - fees.lastTimeAccruedPlatformFees; uint256 platformFeeInAssets = (_activeAssets() * elapsedTime * PLATFORM_FEE) / DENOMINATOR / 365 days; uint256 platformFees = _convertToShares(platformFeeInAssets); // Update tracking of last time platform fees were accrued. fees.lastTimeAccruedPlatformFees = uint32(block.timestamp); // Mint the cellar accrued platform fees as shares. _mint(address(this), platformFees); // Performance fees taken each accrual = yield * feePercentage uint256 yield = fees.yield; uint256 performanceFeeInAssets = yield.mulDivDown(PERFORMANCE_FEE, DENOMINATOR); uint256 performanceFees = _convertToShares(performanceFeeInAssets); // Reset tracking of yield since last accrual. fees.yield = 0; // Mint the cellar accrued performance fees as shares. _mint(address(this), performanceFees); // Update fees that have been accrued. fees.accruedPlatformFees += uint112(platformFees); fees.accruedPerformanceFees += uint112(performanceFees); emit AccruedPlatformFees(platformFees); emit AccruedPerformanceFees(performanceFees); } /** * @notice Tracks yield the cellar has gained since the last time fees were accrued. * @dev Must be called every time a function is called that updates `activeAssets`. */ modifier updateYield() { uint256 currentActiveAssets = _activeAssets(); uint256 lastActiveAssets = fees.lastActiveAssets; if (currentActiveAssets > lastActiveAssets) { fees.yield += uint112(currentActiveAssets - lastActiveAssets); } _; // Update this for next performance fee accrual. fees.lastActiveAssets = uint112(_activeAssets()); } /** * @notice Transfer accrued fees to the Sommelier Chain to distribute. */ function transferFees() external onlyOwner { // Cellar fees are accrued in shares and redeemed upon transfer. uint256 totalFees = ERC20(this).balanceOf(address(this)); uint256 feeInAssets = previewRedeem(totalFees); // Redeem our fee shares for assets to transfer to Cosmos. _burn(address(this), totalFees); // Only withdraw assets from position if the holding pool does not contain enough funds. // Otherwise, all assets will come from the holding pool. _allocateAssets(feeInAssets); // Transfer assets to a fee distributor on the Sommelier Chain. asset.safeApprove(address(gravityBridge), feeInAssets); gravityBridge.sendToCosmos(address(asset), feesDistributor, feeInAssets); emit TransferFees(fees.accruedPlatformFees, fees.accruedPerformanceFees); // Reset the tracker for fees accrued that are still waiting to be transferred. fees.accruedPlatformFees = 0; fees.accruedPerformanceFees = 0; } // =================================== GOVERNANCE OPERATIONS =================================== /** * @notice Trust or distrust an asset position on Aave (eg. FRAX, UST, FEI). */ function setTrust(address position, bool trust) external onlyOwner { isTrusted[position] = trust; // In the case that governance no longer trust the current position, pull all assets back into // the cellar. if (trust == false && position == address(asset)) _withdrawFromAave(address(asset), type(uint256).max); } /** * @notice Stop or start the contract. Used in an emergency or if the cellar has been retired. */ function setShutdown(bool shutdown, bool exitPosition) external onlyOwner { isShutdown = shutdown; // Withdraw everything from the current position on Aave if specified when shutting down. if (shutdown && exitPosition) _withdrawFromAave(address(asset), type(uint256).max); emit Shutdown(shutdown, exitPosition); } /** * @notice Update the address of the fee distributor on the Sommelier Chain. IMPORTANT: Ensure * that the address is formatted in the specific way that the Gravity contract expects * it to be. */ function setFeesDistributor(bytes32 newFeesDistributor) external onlyOwner { // Store for emitted event. bytes32 oldFeesDistributor = feesDistributor; // Change the fees distributor address. feesDistributor = newFeesDistributor; emit FeesDistributorChanged(oldFeesDistributor, newFeesDistributor); } // ===================================== ADMIN OPERATIONS ===================================== /** * @notice Enters into the current Aave stablecoin position. */ function enterPosition() external onlyOwner { if (isShutdown) revert STATE_ContractShutdown(); uint256 currentInactiveAssets = inactiveAssets(); // Deposits all inactive assets into the current position. _depositToAave(address(asset), currentInactiveAssets); // Update the last time cellar entered position. lastTimeEnteredPosition = block.timestamp; emit EnterPosition(address(asset), currentInactiveAssets); } /** * @notice Rebalances current assets into a new asset position. * @param route array of [initial token, pool, token, pool, token, ...] that specifies the swap route * @param swapParams multidimensional array of [i, j, swap type] where i and j are the correct values for the n'th pool in `_route` and swap type should be 1 for a stableswap `exchange`, 2 for stableswap `exchange_underlying`, 3 for a cryptoswap `exchange`, 4 for a cryptoswap `exchange_underlying` and 5 for Polygon factory metapools `exchange_underlying` * @param minAssetsOut minimum amount of assets received from swap */ function rebalance( address[9] memory route, uint256[3][4] memory swapParams, uint256 minAssetsOut ) external onlyOwner { if (isShutdown) revert STATE_ContractShutdown(); // Retrieve the last token in the route and store it as the new asset. address newAsset; for (uint256 i; ; i += 2) { if (i == 8 || route[i+1] == address(0)) { newAsset = route[i]; break; } } // Doesn't make sense to rebalance into the same asset. if (newAsset == address(asset)) revert USR_SameAsset(newAsset); // Pull all active assets entered into Aave back into the cellar so we can swap everything // into the new asset. _withdrawFromAave(address(asset), type(uint256).max); uint256 currentInactiveAssets = inactiveAssets(); // Perform stablecoin swap using Curve. asset.safeApprove(address(curveRegistryExchange), currentInactiveAssets); uint256 amountOut = curveRegistryExchange.exchange_multiple( route, swapParams, currentInactiveAssets, minAssetsOut ); // Store this later for the event we will emit. address oldAsset = address(asset); // Updates state for our new position and check to make sure Aave supports it before // rebalancing. _updatePosition(newAsset); // Deposit all newly swapped assets into Aave. _depositToAave(address(asset), amountOut); // Update the last time all inactive assets were entered into a position. lastTimeEnteredPosition = block.timestamp; emit Rebalance(oldAsset, newAsset, amountOut); } /** * @notice Reinvest rewards back into cellar's current position. * @dev Must be called within 2 day unstake period 10 days after `claimAndUnstake` was run. * @param minAssetsOut minimum amount of assets received after swapping AAVE to the current asset */ function reinvest(uint256 minAssetsOut) external onlyOwner { // Redeems the cellar's stkAAVE rewards for AAVE. stkAAVE.redeem(address(this), type(uint256).max); uint256 amountIn = AAVE.balanceOf(address(this)); // Specify the swap path from AAVE -> WETH -> current asset. address[] memory path = new address[](3); path[0] = address(AAVE); path[1] = address(WETH); path[2] = address(asset); // Perform a multihop swap using Sushiswap. AAVE.safeApprove(address(sushiswapRouter), amountIn); uint256[] memory amounts = sushiswapRouter.swapExactTokensForTokens( amountIn, minAssetsOut, path, address(this), block.timestamp + 60 ); uint256 amountOut = amounts[amounts.length - 1]; // Count reinvested rewards as yield. fees.yield += uint112(amountOut.changeDecimals(assetDecimals, decimals)); // In the case of a shutdown, we just may want to redeem any leftover rewards for users to // claim but without entering them back into a position in case the position has been exited. if (!isShutdown) _depositToAave(address(asset), amountOut); emit Reinvest(address(asset), amountIn, amountOut); } /** * @notice Claim rewards from Aave and begin cooldown period to unstake them. * @return claimed amount of rewards claimed from Aave */ function claimAndUnstake() external onlyOwner returns (uint256 claimed) { // Necessary to do as `claimRewards` accepts a dynamic array as first param. address[] memory aToken = new address[](1); aToken[0] = address(assetAToken); // Claim all stkAAVE rewards. claimed = incentivesController.claimRewards(aToken, type(uint256).max, address(this)); // Begin the cooldown period for unstaking stkAAVE to later redeem for AAVE. stkAAVE.cooldown(); emit ClaimAndUnstake(claimed); } /** * @notice Sweep tokens sent here that are not managed by the cellar. * @dev This may be used in case the wrong tokens are accidentally sent to this contract. * @param token address of token to transfer out of this cellar * @param to address to transfer sweeped tokens to */ function sweep(address token, address to) external onlyOwner { // Prevent sweeping of assets managed by the cellar and shares minted to the cellar as fees. if (token == address(asset) || token == address(assetAToken) || token == address(this)) revert USR_ProtectedAsset(token); // Transfer out tokens in this cellar that shouldn't be here. uint256 amount = ERC20(token).balanceOf(address(this)); ERC20(token).safeTransfer(to, amount); emit Sweep(token, to, amount); } /** * @notice Sets the maximum liquidity that cellar can manage. Careful to use the same decimals as the * current asset. */ function setLiquidityLimit(uint256 limit) external onlyOwner { // Store for emitted event. uint256 oldLimit = liquidityLimit; // Change the liquidity limit. liquidityLimit = limit; emit LiquidityLimitChanged(oldLimit, limit); } /** * @notice Sets the per-wallet deposit limit. Careful to use the same decimals as the current asset. */ function setDepositLimit(uint256 limit) external onlyOwner { // Store for emitted event. uint256 oldLimit = depositLimit; // Change the deposit limit. depositLimit = limit; emit DepositLimitChanged(oldLimit, limit); } // ========================================== HELPERS ========================================== /** * @notice Update state variables related to the current position. * @dev Be aware that when updating to an asset that uses less decimals than the previous * asset (eg. DAI -> USDC), `depositLimit` and `liquidityLimit` will lose some precision * due to truncation. * @param newAsset address of the new asset being managed by the cellar */ function _updatePosition(address newAsset) internal { // Retrieve the aToken that will represent the cellar's new position on Aave. (, , , , , , , address aTokenAddress, , , , ) = lendingPool.getReserveData(newAsset); // If the address is not null, it is supported by Aave. if (aTokenAddress == address(0)) revert USR_UnsupportedPosition(newAsset); // Update the decimals used by limits if necessary. uint8 oldAssetDecimals = assetDecimals; uint8 newAssetDecimals = ERC20(newAsset).decimals(); // Ensure the decimals of precision the new position uses will not break the cellar. if (newAssetDecimals > decimals) revert USR_TooManyDecimals(newAssetDecimals, decimals); // Ignore if decimals are the same or if it is the first time initializing a position. if (oldAssetDecimals != 0 && oldAssetDecimals != newAssetDecimals) { if (depositLimit != type(uint256).max) { depositLimit = depositLimit.changeDecimals(oldAssetDecimals, newAssetDecimals); } if (liquidityLimit != type(uint256).max) { liquidityLimit = liquidityLimit.changeDecimals(oldAssetDecimals, newAssetDecimals); } } // Update state related to the current position. asset = ERC20(newAsset); assetDecimals = newAssetDecimals; assetAToken = ERC20(aTokenAddress); } /** * @notice Ensures there is enough assets in the contract available for a transfer. * @dev Only withdraws from the current position if necessary. * @param assets The amount of assets to allocate */ function _allocateAssets(uint256 assets) internal { uint256 currentInactiveAssets = inactiveAssets(); // Only withdraw if not enough assets in the holding pool. if (assets > currentInactiveAssets) _withdrawFromAave(address(asset), assets - currentInactiveAssets); } /** * @notice Deposits cellar holdings into an Aave lending pool. * @param position the address of the asset position * @param assets the amount of assets to deposit */ function _depositToAave(address position, uint256 assets) internal updateYield { // Ensure the position has been trusted by governance. if (!isTrusted[position]) revert USR_UntrustedPosition(position); // Initialize starting point for first platform fee accrual to time when cellar first deposits // assets into a position on Aave. if (fees.lastTimeAccruedPlatformFees == 0) fees.lastTimeAccruedPlatformFees = uint32(block.timestamp); // Deposit assets into Aave position. ERC20(position).safeApprove(address(lendingPool), assets); lendingPool.deposit(position, assets, address(this), 0); emit DepositToAave(position, assets); } /** * @notice Withdraws assets from Aave. * @param position the address of the asset position * @param assets the amount of assets to withdraw */ function _withdrawFromAave(address position, uint256 assets) internal updateYield { // Skip withdrawal instead of reverting if there are no active assets to withdraw. Reverting // could potentially prevent important function calls from executing, such as `shutdown`, in // the case where there were no active assets because Aave would throw an error. if (activeAssets() > 0) { // Withdraw assets from Aave position. uint256 withdrawnAmount = lendingPool.withdraw(position, assets, address(this)); // `withdrawnAmount` may be less than `assets` if cellar tried withdrawing more than // it's balance on Aave. emit WithdrawFromAave(position, withdrawnAmount); } } // ================================= SHARE TRANSFER OPERATIONS ================================= /** * @dev Modified versions of Solmate's ERC20 transfer and transferFrom functions to work with the * cellar's active vs inactive shares model. */ /** * @notice Transfers shares from one account to another. * @param from address that is sending shares * @param to address that is receiving shares * @param amount amount of shares to transfer * @param onlyActive whether to only transfer active shares */ function transferFrom( address from, address to, uint256 amount, bool onlyActive ) public returns (bool) { // If the sender is not the owner of the shares, check to see if the owner has approved them // to spend their shares. if (from != msg.sender) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; } // Will revert here if sender is trying to transfer more shares then they have, so no need // for an explicit check. balanceOf[from] -= amount; // Cannot overflow because the sum of all user balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } // Retrieve the deposits from sender then begin looping through deposits, generally from // oldest to newest deposits. This may not be the case though if shares have been // transferred to the sender, as they will be added to the end of the sender's deposits // regardless of time deposited. UserDeposit[] storage depositsFrom = userDeposits[from]; // Tracks the amount of shares left to transfer; updated at the end of each loop. uint256 leftToTransfer = amount; for (uint256 i = currentDepositIndex[from]; i < depositsFrom.length; i++) { UserDeposit storage dFrom = depositsFrom[i]; // If we only want to transfer active shares, skips this deposit if it is inactive. bool isActive = dFrom.timeDeposited < lastTimeEnteredPosition; if (onlyActive && !isActive) continue; // Saves an extra SLOAD if active and cast type to uint256. uint256 dFromShares = dFrom.shares; // Determine the amount of assets and shares to transfer from this deposit. uint256 transferredShares = MathUtils.min(leftToTransfer, dFromShares); uint256 transferredAssets = uint256(dFrom.assets).mulDivUp(transferredShares, dFromShares); // For active shares, deletes the deposit data we don't need anymore for a gas refund. if (isActive) { delete dFrom.assets; delete dFrom.timeDeposited; } else { dFrom.assets -= uint112(transferredAssets); } // Taken shares from this deposit to transfer. dFrom.shares -= uint112(transferredShares); // Transfer new deposit to the end of receiver's list of deposits. userDeposits[to].push(UserDeposit({ assets: isActive ? 0 : uint112(transferredAssets), shares: uint112(transferredShares), timeDeposited: isActive ? 0 : dFrom.timeDeposited })); // Update the counter of assets left to transfer. leftToTransfer -= transferredShares; // Break if not shares left to transfer. if (leftToTransfer == 0) { // Only store the index for the next non-zero deposit to save gas on looping if // inactive deposits weren't skipped. if (!onlyActive) currentDepositIndex[from] = dFrom.shares != 0 ? i : i+1; break; } } // Will only happen if exhausted through all deposits and did not enough active shares to // transfer. if (leftToTransfer != 0) revert USR_NotEnoughActiveShares(leftToTransfer, amount); emit Transfer(from, to, amount); return true; } /** * @dev For compatibility with ERC20 standard. */ function transferFrom(address from, address to, uint256 amount) public override returns (bool) { // Defaults to allowing both active and inactive shares to be transferred. return transferFrom(from, to, amount, false); } function transfer(address to, uint256 amount) public override returns (bool) { // Defaults to allowing both active and inactive shares to be transferred. return transferFrom(msg.sender, to, amount, false); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*/////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*/////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*/////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*/////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*/////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*/////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*/////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*/////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. library SafeTransferLib { /*/////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool callStatus; assembly { // Transfer the ETH and store if it succeeded or not. callStatus := call(gas(), to, amount, 0, 0, 0, 0) } require(callStatus, "ETH_TRANSFER_FAILED"); } /*/////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 100 because the calldata length is 4 + 32 * 3. callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 68 because the calldata length is 4 + 32 * 2. callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 68 because the calldata length is 4 + 32 * 2. callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED"); } /*/////////////////////////////////////////////////////////////// INTERNAL HELPER LOGIC //////////////////////////////////////////////////////////////*/ function didLastOptionalReturnCallSucceed(bool callStatus) private pure returns (bool success) { assembly { // Get how many bytes the call returned. let returnDataSize := returndatasize() // If the call reverted: if iszero(callStatus) { // Copy the revert message into memory. returndatacopy(0, 0, returnDataSize) // Revert with the same message. revert(0, returnDataSize) } switch returnDataSize case 32 { // Copy the return data into memory. returndatacopy(0, 0, returnDataSize) // Set success to whether it returned true. success := iszero(iszero(mload(0))) } case 0 { // There was no return data. success := 1 } default { // It returned some malformed input. success := 0 } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _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: Apache-2.0 pragma solidity 0.8.11; interface IAaveIncentivesController { event RewardsAccrued(address indexed user, uint256 amount); event RewardsClaimed(address indexed user, address indexed to, address indexed claimer, uint256 amount); event ClaimerSet(address indexed user, address indexed claimer); /* * @dev Returns the configuration of the distribution for a certain asset * @param asset The address of the reference asset of the distribution * @return The asset index, the emission per second and the last updated timestamp **/ function getAssetData(address asset) external view returns ( uint256, uint256, uint256 ); /* * LEGACY ************************** * @dev Returns the configuration of the distribution for a certain asset * @param asset The address of the reference asset of the distribution * @return The asset index, the emission per second and the last updated timestamp **/ function assets(address asset) external view returns ( uint128, uint128, uint256 ); /** * @dev Whitelists an address to claim the rewards on behalf of another address * @param user The address of the user * @param claimer The address of the claimer */ function setClaimer(address user, address claimer) external; /** * @dev Returns the whitelisted claimer for a certain address (0x0 if not set) * @param user The address of the user * @return The claimer address */ function getClaimer(address user) external view returns (address); /** * @dev Configure assets for a certain rewards emission * @param assets The assets to incentivize * @param emissionsPerSecond The emission for each asset */ function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond) external; /** * @dev Called by the corresponding asset on any update that affects the rewards distribution * @param asset The address of the user * @param userBalance The balance of the user of the asset in the lending pool * @param totalSupply The total supply of the asset in the lending pool **/ function handleAction( address asset, uint256 userBalance, uint256 totalSupply ) external; /** * @dev Returns the total of rewards of an user, already accrued + not yet accrued * @param user The address of the user * @return The rewards **/ function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256); /** * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards * @param amount Amount of rewards to claim * @param to Address that will be receiving the rewards * @return Rewards claimed **/ function claimRewards( address[] calldata assets, uint256 amount, address to ) external returns (uint256); /** * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. The caller must * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager * @param amount Amount of rewards to claim * @param user Address to check and claim rewards * @param to Address that will be receiving the rewards * @return Rewards claimed **/ function claimRewardsOnBehalf( address[] calldata assets, uint256 amount, address user, address to ) external returns (uint256); /** * @dev returns the unclaimed rewards of the user * @param user the address of the user * @return the unclaimed user rewards */ function getUserUnclaimedRewards(address user) external view returns (uint256); /** * @dev returns the unclaimed rewards of the user * @param user the address of the user * @param asset The asset to incentivize * @return the user index for the asset */ function getUserAssetData(address user, address asset) external view returns (uint256); /** * @dev for backward compatibility with previous implementation of the Incentives controller */ function REWARD_TOKEN() external view returns (address); /** * @dev for backward compatibility with previous implementation of the Incentives controller */ function PRECISION() external view returns (uint8); /** * @dev Gets the distribution end timestamp of the emissions */ function DISTRIBUTION_END() external view returns (uint256); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.11; interface IStakedTokenV2 { function stake(address to, uint256 amount) external; function redeem(address to, uint256 amount) external; function cooldown() external; function claimRewards(address to, uint256 amount) external; function balanceOf(address account) external view returns (uint256); function stakersCooldowns(address account) external view returns (uint256); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; /** * @notice Partial interface for a Curve Registry Exchanges contract * @dev The registry exchange contract is used to find pools and query exchange rates for token swaps. * It also provides a unified exchange API that can be useful for on-chain integrators. **/ interface ICurveSwaps { /** * @notice Perform up to four swaps in a single transaction * @dev Routing and swap params must be determined off-chain. This * functionality is designed for gas efficiency over ease-of-use. * @param _route Array of [initial token, pool, token, pool, token, ...] * The array is iterated until a pool address of 0x00, then the last * given token is transferred to `_receiver` (address to transfer the final output token to) * @param _swap_params Multidimensional array of [i, j, swap type] where i and j are the correct * values for the n'th pool in `_route`. The swap type should be 1 for * a stableswap `exchange`, 2 for stableswap `exchange_underlying`, 3 * for a cryptoswap `exchange`, 4 for a cryptoswap `exchange_underlying` * and 5 for Polygon factory metapools `exchange_underlying` * @param _expected The minimum amount received after the final swap. * @return Received amount of final output token **/ function exchange_multiple( address[9] memory _route, uint256[3][4] memory _swap_params, uint256 _amount, uint256 _expected ) external returns (uint256); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; /** * @notice Partial interface for a SushiSwap Router contract **/ interface ISushiSwapRouter { /** * @notice Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the `path` * @dev The first element of `path` is the input token, the last is the output token, * and any intermediate elements represent intermediate pairs to trade through (if, for example, a direct pair does not exist). * `msg.sender` should have already given the router an allowance of at least `amountIn` on the input token * @param amountIn The amount of input tokens to send * @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert * @param path An array of token addresses. `path.length` must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity * @param to Recipient of the output tokens * @param deadline Unix timestamp after which the transaction will revert * @return amounts The input token amount and all subsequent output token amounts **/ function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; interface IGravity { function sendToCosmos( address _tokenContract, bytes32 _destination, uint256 _amount ) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; /** * @dev Partial interface for a Aave LendingPool contract, * which is the main point of interaction with an Aave protocol's market **/ interface ILendingPool { /** * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. * - E.g. User deposits 100 USDC and gets in return 100 aUSDC * @param asset The address of the underlying asset to deposit * @param amount The amount to be deposited * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function deposit( address asset, uint256 amount, address onBehalfOf, uint16 referralCode ) external; /** * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC * @param asset The address of the underlying asset to withdraw * @param amount The underlying amount to be withdrawn * - Send the value type(uint256).max in order to withdraw the whole aToken balance * @param to Address that will receive the underlying, same as msg.sender if the user * wants to receive it on his own wallet, or a different address if the beneficiary is a * different wallet * @return The final amount withdrawn **/ function withdraw( address asset, uint256 amount, address to ) external returns (uint256); /** * @dev Returns the normalized income normalized income of the reserve * @param asset The address of the underlying asset of the reserve * @return The reserve's normalized income */ function getReserveNormalizedIncome(address asset) external view returns (uint256); /** * @dev Returns the normalized income normalized income of the reserve * @param asset The address of the underlying asset of the reserve **/ function getReserveData(address asset) external view returns ( //stores the reserve configuration //bit 0-15: LTV //bit 16-31: Liq. threshold //bit 32-47: Liq. bonus //bit 48-55: Decimals //bit 56: Reserve is active //bit 57: reserve is frozen //bit 58: borrowing is enabled //bit 59: stable rate borrowing enabled //bit 60-63: reserved //bit 64-79: reserve factor uint256 configuration, //the liquidity index. Expressed in ray uint128 liquidityIndex, //variable borrow index. Expressed in ray uint128 variableBorrowIndex, //the current supply rate. Expressed in ray uint128 currentLiquidityRate, //the current variable borrow rate. Expressed in ray uint128 currentVariableBorrowRate, //the current stable borrow rate. Expressed in ray uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, //tokens addresses address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, //address of the interest rate strategy address interestRateStrategyAddress, //the id of the reserve. Represents the position in the list of the active reserves uint8 id ); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; library MathUtils { /** * @notice Substract and return 0 instead if results are negative. */ function subMin0(uint256 x, uint256 y) internal pure returns (uint256) { return x > y ? x - y : 0; } /** * @notice Used to change the decimals of precision used for an amount. */ function changeDecimals( uint256 amount, uint8 fromDecimals, uint8 toDecimals ) internal pure returns (uint256) { if (fromDecimals == toDecimals) { return amount; } else if (fromDecimals < toDecimals) { return amount * 10**(toDecimals - fromDecimals); } else { return ceilDiv(amount, 10**(fromDecimals - toDecimals)); } } // ===================================== OPENZEPPELIN'S MATH ===================================== function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } // ================================= SOLMATE's FIXEDPOINTMATHLIB ================================= uint256 public constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; // ========================================== USER ERRORS =========================================== /** * @dev These errors represent invalid user input to functions. Where appropriate, the invalid value * is specified along with constraints. These errors can be resolved by callers updating their * arguments. */ /** * @notice Attempted an action with zero assets. */ error USR_ZeroAssets(); /** * @notice Attempted an action with zero shares. */ error USR_ZeroShares(); /** * @notice Attempted deposit more than the max deposit. * @param assets the assets user attempted to deposit * @param maxDeposit the max assets that can be deposited */ error USR_DepositRestricted(uint256 assets, uint256 maxDeposit); /** * @notice Attempted to transfer more active shares than the user has. * @param activeShares amount of shares user has * @param attemptedActiveShares amount of shares user tried to transfer */ error USR_NotEnoughActiveShares(uint256 activeShares, uint256 attemptedActiveShares); /** * @notice Attempted swap into an asset that is not the current asset of the cellar. * @param assetOut address of the asset attempted to swap to * @param currentAsset address of the current asset of cellar */ error USR_InvalidSwap(address assetOut, address currentAsset); /** * @notice Attempted to sweep an asset that is managed by the cellar. * @param token address of the token that can't be sweeped */ error USR_ProtectedAsset(address token); /** * @notice Attempted rebalance into the same asset. * @param asset address of the asset */ error USR_SameAsset(address asset); /** * @notice Attempted to update the position to one that is not supported by the platform. * @param unsupportedPosition address of the unsupported position */ error USR_UnsupportedPosition(address unsupportedPosition); /** * @notice Attempted rebalance into an untrusted position. * @param asset address of the asset */ error USR_UntrustedPosition(address asset); /** * @notice Attempted to update a position to an asset that uses an incompatible amount of decimals. * @param newDecimals decimals of precision that the new position uses * @param maxDecimals maximum decimals of precision for a position to be compatible with the cellar */ error USR_TooManyDecimals(uint8 newDecimals, uint8 maxDecimals); /** * @notice User attempted to stake zero amout. */ error USR_ZeroDeposit(); /** * @notice User attempted to stake an amount smaller than the minimum deposit. * * @param amount Amount user attmpted to stake. * @param minimumDeposit The minimum deopsit amount accepted. */ error USR_MinimumDeposit(uint256 amount, uint256 minimumDeposit); /** * @notice The specified deposit ID does not exist for the caller. * * @param depositId The deposit ID provided for lookup. */ error USR_NoDeposit(uint256 depositId); /** * @notice The user is attempting to cancel unbonding for a deposit which is not unbonding. * * @param depositId The deposit ID the user attempted to cancel. */ error USR_NotUnbonding(uint256 depositId); /** * @notice The user is attempting to unbond a deposit which has already been unbonded. * * @param depositId The deposit ID the user attempted to unbond. */ error USR_AlreadyUnbonding(uint256 depositId); /** * @notice The user is attempting to unstake a deposit which is still timelocked. * * @param depositId The deposit ID the user attempted to unstake. */ error USR_StakeLocked(uint256 depositId); /** * @notice The contract owner attempted to update rewards but the new reward rate would cause overflow. */ error USR_RewardTooLarge(); /** * @notice The reward distributor attempted to update rewards but 0 rewards per epoch. * This can also happen if there is less than 1 wei of rewards per second of the * epoch - due to integer division this will also lead to 0 rewards. */ error USR_ZeroRewardsPerEpoch(); /** * @notice The caller attempted to stake with a lock value that did not * correspond to a valid staking time. * * @param lock The provided lock value. */ error USR_InvalidLockValue(uint256 lock); // ========================================== STATE ERRORS =========================================== /** * @dev These errors represent actions that are being prevented due to current contract state. * These errors do not relate to user input, and may or may not be resolved by other actions * or the progression of time. */ /** * @notice Attempted action was prevented due to contract being shutdown. */ error STATE_ContractShutdown(); /** * @notice Attempted to shutdown the contract when it was already shutdown. */ error STATE_AlreadyShutdown(); /** * @notice The caller attempted to start a reward period, but the contract did not have enough tokens * for the specified amount of rewards. * * @param rewardBalance The amount of distributionToken held by the contract. * @param reward The amount of rewards the caller attempted to distribute. */ error STATE_RewardsNotFunded(uint256 rewardBalance, uint256 reward); /** * @notice The caller attempted to change the epoch length, but current reward epochs were active. */ error STATE_RewardsOngoing(); /** * @notice The caller attempted to deposit stake, but there are no remaining rewards to pay out. */ error STATE_NoRewardsLeft(); /** * @notice The caller attempted to perform an an emergency unstake, but the contract * is not in emergency mode. */ error STATE_NoEmergencyUnstake(); /** * @notice The caller attempted to perform an an emergency unstake, but the contract * is not in emergency mode, or the emergency mode does not allow claiming rewards. */ error STATE_NoEmergencyClaim(); /** * @notice The caller attempted to perform a state-mutating action (e.g. staking or unstaking) * while the contract was paused. */ error STATE_ContractPaused(); /** * @notice The caller attempted to perform a state-mutating action (e.g. staking or unstaking) * while the contract was killed (placed in emergency mode). * @dev Emergency mode is irreversible. */ error STATE_ContractKilled();
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.11; /// @title interface for AaveV2StablecoinCellar interface IAaveV2StablecoinCellar { // ======================================= EVENTS ======================================= /** * @notice Emitted when assets are deposited into cellar. * @param caller the address of the caller * @param token the address of token the cellar receives * @param owner the address of the owner of shares * @param assets the amount of assets being deposited * @param shares the amount of shares minted to owner */ event Deposit(address indexed caller, address indexed owner, address indexed token, uint256 assets, uint256 shares); /** * @notice Emitted when assets are withdrawn from cellar. * @param receiver the address of the receiver of the withdrawn assets * @param owner the address of the owner of the shares * @param token the address of the token withdrawn * @param assets the amount of assets being withdrawn * @param shares the amount of shares burned from owner */ event Withdraw( address indexed receiver, address indexed owner, address indexed token, uint256 assets, uint256 shares ); /** * @notice Emitted on deposit to Aave. * @param position the address of the position * @param assets the amount of assets to deposit */ event DepositToAave(address indexed position, uint256 assets); /** * @notice Emitted on withdraw from Aave. * @param position the address of the position * @param assets the amount of assets to withdraw */ event WithdrawFromAave(address indexed position, uint256 assets); /** * @notice Emitted upon entering cellar's inactive assets into the current position on Aave. * @param position the address of the asset being entered into the current position * @param assets amount of assets being entered */ event EnterPosition(address indexed position, uint256 assets); /** * @notice Emitted upon claiming rewards and beginning cooldown period to unstake them. * @param rewardsClaimed amount of rewards that were claimed */ event ClaimAndUnstake(uint256 rewardsClaimed); /** * @notice Emitted upon reinvesting rewards into the current position. * @param token the address of the asset rewards were swapped to * @param rewards amount of rewards swapped to be reinvested * @param assets amount of assets received from swapping rewards */ event Reinvest(address indexed token, uint256 rewards, uint256 assets); /** * @notice Emitted on rebalance of Aave poisition. * @param oldAsset the address of the asset for the old position * @param newAsset the address of the asset for the new position * @param assets the amount of the new assets cellar has after rebalancing */ event Rebalance(address indexed oldAsset, address indexed newAsset, uint256 assets); /** * @notice Emitted when platform fees accrued. * @param feesInShares amount of fees accrued in shares */ event AccruedPlatformFees(uint256 feesInShares); /** * @notice Emitted when performance fees accrued. * @param feesInShares amount of fees accrued in shares */ event AccruedPerformanceFees(uint256 feesInShares); /** * @notice Emitted when platform fees are transferred to Cosmos. * @param platformFees amount of platform fees transferred * @param performanceFees amount of performance fees transferred */ event TransferFees(uint112 platformFees, uint112 performanceFees); /** * @notice Emitted when the liquidity limit is changed. * @param oldLimit amount the limit was changed from * @param newLimit amount the limit was changed to */ event LiquidityLimitChanged(uint256 oldLimit, uint256 newLimit); /** * @notice Emitted when the deposit limit is changed. * @param oldLimit amount the limit was changed from * @param newLimit amount the limit was changed to */ event DepositLimitChanged(uint256 oldLimit, uint256 newLimit); /** * @notice Emitted when fees distributor is changed. * @param oldFeesDistributor address of fee distributor was changed from * @param newFeesDistributor address of fee distributor was changed to */ event FeesDistributorChanged(bytes32 oldFeesDistributor, bytes32 newFeesDistributor); /** * @notice Emitted when tokens accidentally sent to cellar are recovered. * @param token the address of the token * @param to the address sweeped tokens were transferred to * @param amount amount transferred out */ event Sweep(address indexed token, address indexed to, uint256 amount); /** * @notice Emitted when cellar is shutdown. * @param isShutdown whether the contract is shutdown * @param exitPosition whether to exit the current position */ event Shutdown(bool isShutdown, bool exitPosition); // ======================================= STRUCTS ======================================= /** * @notice Stores user deposit data. * @param assets amount of assets deposited * @param shares amount of shares that were minted for their deposit * @param timeDeposited timestamp of when the user deposited */ struct UserDeposit { uint112 assets; uint112 shares; uint32 timeDeposited; } /** * @notice Stores fee-related data. */ struct Fees { /** * @notice Amount of yield earned since last time performance fees were accrued. */ uint112 yield; /** * @notice Amount of active assets in cellar since yield was last calculated. */ uint112 lastActiveAssets; /** * @notice Timestamp of last time platform fees were accrued. */ uint32 lastTimeAccruedPlatformFees; /** * @notice Amount of platform fees that have been accrued awaiting transfer. * @dev Fees are taken in shares and redeemed for assets at the time they are transferred from * the cellar to Cosmos to be distributed. */ uint112 accruedPlatformFees; /** * @notice Amount of performance fees that have been accrued awaiting transfer. * @dev Fees are taken in shares and redeemed for assets at the time they are transferred from * the cellar to Cosmos to be distributed. */ uint112 accruedPerformanceFees; } // ================================= DEPOSIT/WITHDRAWAL OPERATIONS ================================= function deposit(uint256 assets, address receiver) external returns (uint256); function mint(uint256 shares, address receiver) external returns (uint256); function withdraw( uint256 assets, address receiver, address owner ) external returns (uint256 shares); function redeem( uint256 shares, address receiver, address owner ) external returns (uint256 assets); // ==================================== ACCOUNTING OPERATIONS ==================================== function activeAssets() external view returns (uint256); function inactiveAssets() external view returns (uint256); function totalAssets() external view returns (uint256); function convertToShares(uint256 assets) external view returns (uint256); function convertToAssets(uint256 shares) external view returns (uint256); function previewDeposit(uint256 assets) external view returns (uint256); function previewMint(uint256 shares) external view returns (uint256); function previewWithdraw(uint256 assets) external view returns (uint256); function previewRedeem(uint256 shares) external view returns (uint256); // ======================================= STATE INFORMATION ===================================== function getUserBalances(address user) external view returns ( uint256 userActiveShares, uint256 userInactiveShares, uint256 userActiveAssets, uint256 userInactiveAssets ); function getUserDeposits(address user) external view returns (UserDeposit[] memory); // ============================ DEPOSIT/WITHDRAWAL LIMIT OPERATIONS ============================ function maxDeposit(address owner) external view returns (uint256); function maxMint(address owner) external view returns (uint256); function maxWithdraw(address owner) external view returns (uint256); function maxRedeem(address owner) external view returns (uint256); // ======================================= FEE OPERATIONS ======================================= function accrueFees() external; function transferFees() external; // ======================================= ADMIN OPERATIONS ======================================= function enterPosition() external; function rebalance( address[9] memory route, uint256[3][4] memory swapParams, uint256 minAmountOut ) external; function reinvest(uint256 minAmountOut) external; function claimAndUnstake() external returns (uint256 claimed); function sweep(address token, address to) external; function setLiquidityLimit(uint256 limit) external; function setDepositLimit(uint256 limit) external; function setShutdown(bool shutdown, bool exitPosition) external; // ================================== SHARE TRANSFER OPERATIONS ================================== function transferFrom( address from, address to, uint256 amount, bool onlyActive ) external returns (bool); }
// 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; } }
{ "metadata": { "bytecodeHash": "none" }, "optimizer": { "enabled": true, "runs": 100, "details": { "yul": true, "yulDetails": { "stackAllocation": true } } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ERC20","name":"_asset","type":"address"},{"internalType":"address[]","name":"_approvedPositions","type":"address[]"},{"internalType":"contract ICurveSwaps","name":"_curveRegistryExchange","type":"address"},{"internalType":"contract ISushiSwapRouter","name":"_sushiswapRouter","type":"address"},{"internalType":"contract ILendingPool","name":"_lendingPool","type":"address"},{"internalType":"contract IAaveIncentivesController","name":"_incentivesController","type":"address"},{"internalType":"contract IGravity","name":"_gravityBridge","type":"address"},{"internalType":"contract IStakedTokenV2","name":"_stkAAVE","type":"address"},{"internalType":"contract ERC20","name":"_AAVE","type":"address"},{"internalType":"contract ERC20","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"STATE_ContractShutdown","type":"error"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"maxDeposit","type":"uint256"}],"name":"USR_DepositRestricted","type":"error"},{"inputs":[{"internalType":"uint256","name":"activeShares","type":"uint256"},{"internalType":"uint256","name":"attemptedActiveShares","type":"uint256"}],"name":"USR_NotEnoughActiveShares","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"USR_ProtectedAsset","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"USR_SameAsset","type":"error"},{"inputs":[{"internalType":"uint8","name":"newDecimals","type":"uint8"},{"internalType":"uint8","name":"maxDecimals","type":"uint8"}],"name":"USR_TooManyDecimals","type":"error"},{"inputs":[{"internalType":"address","name":"unsupportedPosition","type":"address"}],"name":"USR_UnsupportedPosition","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"USR_UntrustedPosition","type":"error"},{"inputs":[],"name":"USR_ZeroAssets","type":"error"},{"inputs":[],"name":"USR_ZeroShares","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feesInShares","type":"uint256"}],"name":"AccruedPerformanceFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feesInShares","type":"uint256"}],"name":"AccruedPlatformFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rewardsClaimed","type":"uint256"}],"name":"ClaimAndUnstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"DepositLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"DepositToAave","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"EnterPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"oldFeesDistributor","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newFeesDistributor","type":"bytes32"}],"name":"FeesDistributorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"LiquidityLimitChanged","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":true,"internalType":"address","name":"oldAsset","type":"address"},{"indexed":true,"internalType":"address","name":"newAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"Rebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"Reinvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isShutdown","type":"bool"},{"indexed":false,"internalType":"bool","name":"exitPosition","type":"bool"}],"name":"Shutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Sweep","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"platformFees","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"performanceFees","type":"uint112"}],"name":"TransferFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"WithdrawFromAave","type":"event"},{"inputs":[],"name":"AAVE","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERFORMANCE_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PLATFORM_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activeAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetAToken","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimAndUnstake","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"currentDepositIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curveRegistryExchange","outputs":[{"internalType":"contract ICurveSwaps","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enterPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fees","outputs":[{"internalType":"uint112","name":"yield","type":"uint112"},{"internalType":"uint112","name":"lastActiveAssets","type":"uint112"},{"internalType":"uint32","name":"lastTimeAccruedPlatformFees","type":"uint32"},{"internalType":"uint112","name":"accruedPlatformFees","type":"uint112"},{"internalType":"uint112","name":"accruedPerformanceFees","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feesDistributor","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBalances","outputs":[{"internalType":"uint256","name":"userActiveShares","type":"uint256"},{"internalType":"uint256","name":"userInactiveShares","type":"uint256"},{"internalType":"uint256","name":"userActiveAssets","type":"uint256"},{"internalType":"uint256","name":"userInactiveAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserDeposits","outputs":[{"components":[{"internalType":"uint112","name":"assets","type":"uint112"},{"internalType":"uint112","name":"shares","type":"uint112"},{"internalType":"uint32","name":"timeDeposited","type":"uint32"}],"internalType":"struct IAaveV2StablecoinCellar.UserDeposit[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gravityBridge","outputs":[{"internalType":"contract IGravity","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"inactiveAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incentivesController","outputs":[{"internalType":"contract IAaveIncentivesController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTrusted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimeEnteredPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lendingPool","outputs":[{"internalType":"contract ILendingPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[9]","name":"route","type":"address[9]"},{"internalType":"uint256[3][4]","name":"swapParams","type":"uint256[3][4]"},{"internalType":"uint256","name":"minAssetsOut","type":"uint256"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minAssetsOut","type":"uint256"}],"name":"reinvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setDepositLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newFeesDistributor","type":"bytes32"}],"name":"setFeesDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setLiquidityLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"shutdown","type":"bool"},{"internalType":"bool","name":"exitPosition","type":"bool"}],"name":"setShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"position","type":"address"},{"internalType":"bool","name":"trust","type":"bool"}],"name":"setTrust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stkAAVE","outputs":[{"internalType":"contract IStakedTokenV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sushiswapRouter","outputs":[{"internalType":"contract ISushiSwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"onlyActive","type":"bool"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userDeposits","outputs":[{"internalType":"uint112","name":"assets","type":"uint112"},{"internalType":"uint112","name":"shares","type":"uint112"},{"internalType":"uint32","name":"timeDeposited","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101e060405273b813554b423266bbd4c16c32fa383394868c1f55600f553480156200002a57600080fd5b506040516200590d3803806200590d8339810160408190526200004d91620007c4565b6040518060600160405280602c8152602001620058e1602c91396040518060400160405280600b81526020016a61617665322d434c522d5360a81b81525060128260009080519060200190620000a5929190620006e0565b508151620000bb906001906020850190620006e0565b5060ff81166080524660a052620000d162000217565b60c05250620000e49150339050620002b3565b6001600160a01b0380891660e05287811661010052868116610120528581166101405284811661016052838116610180528281166101a0528181166101c0528a166000908152600b60205260409020805460ff19166001179055620001498a62000305565b6008546000906200016690600160a01b900460ff16600a62000a5f565b90506200017781624c4b4062000a70565b601055620001888161c35062000a70565b60115560005b8a51811015620001fa576001600b60008d8481518110620001b357620001b362000a92565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620001f18162000aa8565b9150506200018e565b5062000206856200054c565b505050505050505050505062000d6b565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516200024b919062000b03565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b610120516040516335ea6a7560e01b81526001600160a01b03838116600483015260009216906335ea6a759060240161018060405180830381865afa15801562000353573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000379919062000bd1565b5050505097505050505050505060006001600160a01b0316816001600160a01b03161415620003cb57604051630a5c5e7d60e11b81526001600160a01b03831660048201526024015b60405180910390fd5b6000600860149054906101000a900460ff1690506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000420573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000446919062000cc8565b905060805160ff168160ff1611156200048457608051604051630651982f60e11b815260ff80841660048301529091166024820152604401620003c2565b60ff8216158015906200049d57508060ff168260ff1614155b15620004ff5760001960115414620004d157620004cd82826011546200061d60201b62002c58179092919060201c565b6011555b60001960105414620004ff57620004fb82826010546200061d60201b62002c58179092919060201c565b6010555b600780546001600160a01b039586166001600160a01b031991821617909155600880549490951660ff909216600160a01b02166001600160a81b0319909316929092179190911790915550565b6006546001600160a01b03163314620005a85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620003c2565b6001600160a01b0381166200060f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620003c2565b6200061a81620002b3565b50565b60008160ff168360ff1614156200063657508262000696565b8160ff168360ff161015620006725762000651838362000ce6565b6200065e90600a62000a5f565b6200066a908562000a70565b905062000696565b6200066a8462000683848662000ce6565b6200069090600a62000a5f565b6200069d565b9392505050565b6000620006ab828462000d22565b15620006b9576001620006bc565b60005b60ff16620006cb838562000d39565b620006d7919062000d50565b90505b92915050565b828054620006ee9062000ac6565b90600052602060002090601f0160209004810192826200071257600085556200075d565b82601f106200072d57805160ff19168380011785556200075d565b828001600101855582156200075d579182015b828111156200075d57825182559160200191906001019062000740565b506200076b9291506200076f565b5090565b5b808211156200076b576000815560010162000770565b6001600160a01b03811681146200061a57600080fd5b8051620007a98162000786565b919050565b634e487b7160e01b600052604160045260246000fd5b6000806000806000806000806000806101408b8d031215620007e557600080fd5b8a51620007f28162000786565b60208c0151909a506001600160401b03808211156200081057600080fd5b818d0191508d601f8301126200082557600080fd5b8151818111156200083a576200083a620007ae565b604051601f19603f8360051b011681018181108482111715620008615762000861620007ae565b6040528181526020808201935060059290921b8401909101908f8211156200088857600080fd5b6020840193505b81841015620008b557620008a3846200079c565b8352602093840193909201916200088f565b9b50620008c99250505060408c016200079c565b9750620008d960608c016200079c565b9650620008e960808c016200079c565b9550620008f960a08c016200079c565b94506200090960c08c016200079c565b93506200091960e08c016200079c565b92506200092a6101008c016200079c565b91506200093b6101208c016200079c565b90509295989b9194979a5092959850565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620009a35781600019048211156200098757620009876200094c565b808516156200099557918102915b93841c939080029062000967565b509250929050565b600082620009bc57506001620006da565b81620009cb57506000620006da565b8160018114620009e45760028114620009ef5762000a0f565b6001915050620006da565b60ff84111562000a035762000a036200094c565b50506001821b620006da565b5060208310610133831016604e8410600b841016171562000a34575081810a620006da565b62000a40838362000962565b806000190482111562000a575762000a576200094c565b029392505050565b6000620006d760ff841683620009ab565b600081600019048311821515161562000a8d5762000a8d6200094c565b500290565b634e487b7160e01b600052603260045260246000fd5b600060001982141562000abf5762000abf6200094c565b5060010190565b600181811c9082168062000adb57607f821691505b6020821081141562000afd57634e487b7160e01b600052602260045260246000fd5b50919050565b600080835481600182811c91508083168062000b2057607f831692505b602080841082141562000b4157634e487b7160e01b86526022600452602486fd5b81801562000b58576001811462000b6a5762000b99565b60ff1986168952848901965062000b99565b60008a81526020902060005b8681101562000b915781548b82015290850190830162000b76565b505084890196505b509498975050505050505050565b80516001600160801b0381168114620007a957600080fd5b805160ff81168114620007a957600080fd5b6000806000806000806000806000806000806101808d8f03121562000bf557600080fd5b8c519b5062000c0760208e0162000ba7565b9a5062000c1760408e0162000ba7565b995062000c2760608e0162000ba7565b985062000c3760808e0162000ba7565b975062000c4760a08e0162000ba7565b965060c08d015164ffffffffff8116811462000c6257600080fd5b955062000c7260e08e016200079c565b945062000c836101008e016200079c565b935062000c946101208e016200079c565b925062000ca56101408e016200079c565b915062000cb66101608e0162000bbf565b90509295989b509295989b509295989b565b60006020828403121562000cdb57600080fd5b620006d78262000bbf565b600060ff821660ff84168082101562000d035762000d036200094c565b90039392505050565b634e487b7160e01b600052601260045260246000fd5b60008262000d345762000d3462000d0c565b500690565b60008262000d4b5762000d4b62000d0c565b500490565b6000821982111562000d665762000d666200094c565b500190565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c051614a1662000ecb600039600081816108270152611b400152600081816105ba01528181611a4c01528181611aec0152611bbf01526000818161048d015281816119cf0152612145015260008181610764015281816125f0015261264901526000818161084e01526120c101526000818161078b01528181612dcb01528181612f520152818161328c01526132e40152600081816109e901528181611be10152611c120152600081816107f801528181610ddb0152610e1a0152600061102f01526000610fff01526000818161051b01528181610b15015281816113d401528181611cef01528181611fb201528181611fef015281816122280152818161226f01528181612731015281816128d201528181613088015281816130cd015281816134b3015281816136c10152613b440152614a166000f3fe608060405234801561001057600080fd5b506004361061039d5760003560e01c806394bf804d116101eb578063bf86d69011610110578063d905777e116100a8578063d905777e1461097d578063dd62ed3e146109a6578063df05a52a146109d1578063e9240c2d146109e4578063e93f566514610a0b578063ecf7085814610a14578063ef8b30f714610a1d578063f2fde38b14610a30578063f82d4d9b14610a4357600080fd5b8063bf86d690146108e2578063c17f6740146108ef578063c2d4160114610902578063c2fbe7bc14610916578063c63d75b61461091e578063c6e6f59214610931578063cab5923814610944578063ce96cb7714610957578063d505accf1461096a57600080fd5b8063ad004e2011610183578063ad004e201461081a578063ad5c464814610822578063af1df25514610849578063b3d7f6b914610870578063b460af9414610883578063b8dc491b14610896578063ba087652146108a9578063bb27280b146108bc578063bdc8144b146108cf57600080fd5b806394bf804d146106a657806395d89b41146106b957806396d64879146106c15780639af1d35a146106e4578063a4da2d021461075f578063a59a997314610786578063a9059cbb146107ad578063abd3f612146107c0578063ac353510146107f357600080fd5b806337a4e834116102d15780636f2293ab116102695780636f2293ab1461061557806370a0823114610628578063715018a61461064857806372163715146106505780637ecebe001461065957806383b4918b146106795780638da5cb5b1461068c5780638e0bae7f14610694578063918f86741461069d57600080fd5b806337a4e8341461055f57806338d52e0f146105675780633982aabd1461057a5780633dc6eabf1461059a578063402d267d146105a257806348ccda3c146105b55780634cdad506146105dc5780636e553f65146105ef5780636e85f1831461060257600080fd5b806318160ddd1161034457806318160ddd146104775780631c17b946146104805780631fc29c011461048857806323b872dd146104bc5780632a5bf6d2146104cf57806330adf81f146104ef578063313ce5671461051657806334fbc9a11461054f5780633644e5151461055757600080fd5b806301e1d114146103a257806306fdde03146103bd57806307a2d13a146103d257806308f43333146103e5578063095ea7b3146104245780630a28a47714610447578063148349381461045a57806315f4c61114610462575b600080fd5b6103aa610a4c565b6040519081526020015b60405180910390f35b6103c5610a6d565b6040516103b49190613e44565b6103aa6103e0366004613e99565b610afb565b6103f86103f3366004613ec7565b610b4b565b604080516001600160701b03948516815293909216602084015263ffffffff16908201526060016103b4565b610437610432366004613ec7565b610b9a565b60405190151581526020016103b4565b6103aa610455366004613e99565b610c07565b6103aa610c33565b610475610470366004613faa565b610ca5565b005b6103aa60025481565b6103aa610f17565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6040516103b491906140b4565b6104376104ca3660046140c8565b610f48565b6104e26104dd366004614109565b610f5f565b6040516103b49190614126565b6103aa7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b61053d7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016103b4565b6103aa606481565b6103aa610ffb565b610475611051565b6007546104af906001600160a01b031681565b6103aa610588366004614109565b600a6020526000908152604090205481565b6104756112d1565b6103aa6105b0366004614109565b611390565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6103aa6105ea366004613e99565b61144f565b6103aa6105fd366004614191565b61145a565b610475610610366004613e99565b6114f3565b6104376106233660046141d6565b611568565b6103aa610636366004614109565b60036020526000908152604090205481565b610475611948565b6103aa60105481565b6103aa610667366004614109565b60056020526000908152604090205481565b610475610687366004613e99565b611983565b6104af611dcb565b6103aa600f5481565b6103aa61271081565b6103aa6106b4366004614191565b611dda565b6103c5611e75565b6104376106cf366004614109565b600b6020526000908152604090205460ff1681565b600d54600e5461071f916001600160701b0380821692600160701b808404831693600160e01b900463ffffffff169280831692919091041685565b604080516001600160701b039687168152948616602086015263ffffffff909316928401929092528316606083015291909116608082015260a0016103b4565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6104376107bb366004613ec7565b611e82565b6107d36107ce366004614109565b611e91565b6040805194855260208501939093529183015260608201526080016103b4565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6103aa612029565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6103aa61087e366004613e99565b6121f3565b6103aa610891366004614227565b612257565b6104756108a4366004614269565b6122a0565b6103aa6108b7366004614227565b612403565b6104756108ca366004614297565b612418565b6104756108dd366004613e99565b6124b9565b6012546104379060ff1681565b6008546104af906001600160a01b031681565b60085461053d90600160a01b900460ff1681565b610475612526565b6103aa61092c366004614109565b61270b565b6103aa61093f366004613e99565b612719565b6104756109523660046142ca565b612760565b6103aa610965366004614109565b6127ef565b6104756109783660046142f7565b612901565b6103aa61098b366004614109565b6001600160a01b031660009081526003602052604090205490565b6103aa6109b4366004614269565b600460209081526000928352604080842090915290825290205481565b6104756109df366004613e99565b612b40565b6104af7f000000000000000000000000000000000000000000000000000000000000000081565b6103aa6103e881565b6103aa60115481565b6103aa610a2b366004613e99565b612bad565b610475610a3e366004614109565b612bb8565b6103aa600c5481565b6000610a56610c33565b610a5e610f17565b610a68919061437e565b905090565b60008054610a7a90614396565b80601f0160208091040260200160405190810160405280929190818152602001828054610aa690614396565b8015610af35780601f10610ac857610100808354040283529160200191610af3565b820191906000526020600020905b815481529060010190602001808311610ad657829003601f168201915b505050505081565b600080610b0783612cc1565b600854909150610b449082907f000000000000000000000000000000000000000000000000000000000000000090600160a01b900460ff16612c58565b9392505050565b60096020528160005260406000208181548110610b6757600080fd5b6000918252602090912001546001600160701b038082169350600160701b8204169150600160e01b900463ffffffff1683565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610bf59086815260200190565b60405180910390a35060015b92915050565b6002546000908015610c2c57610c2781610c1f610a4c565b859190612cec565b610b44565b5090919050565b6007546040516370a0823160e01b81526000916001600160a01b0316906370a0823190610c649030906004016140b4565b602060405180830381865afa158015610c81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6891906143d1565b33610cae611dcb565b6001600160a01b031614610cdd5760405162461bcd60e51b8152600401610cd4906143ea565b60405180910390fd5b60125460ff1615610d0157604051632f22819760e11b815260040160405180910390fd5b6000805b8060081480610d3d5750600085610d1d83600161437e565b60098110610d2d57610d2d61441f565b60200201516001600160a01b0316145b15610d6057848160098110610d5457610d5461441f565b60200201519150610d72565b610d6b60028261437e565b9050610d05565b506007546001600160a01b0382811691161415610da4578060405163a337612b60e01b8152600401610cd491906140b4565b600754610dbc906001600160a01b0316600019612d1a565b6000610dc6610c33565b600754909150610e00906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000083612eba565b604051630d4f290960e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063353ca42490610e55908990899087908a90600401614435565b6020604051808303816000875af1158015610e74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9891906143d1565b6007549091506001600160a01b0316610eb084612f38565b600754610ec6906001600160a01b03168361319e565b42600c556040518281526001600160a01b0380861691908316907fb0850b8e0f9e8315dde3c9f9f31138283e6bbe16cd29e8552eb1dcdf9fac9e3b906020015b60405180910390a350505050505050565b6008546040516370a0823160e01b81526000916001600160a01b0316906370a0823190610c649030906004016140b4565b6000610f578484846000611568565b949350505050565b6001600160a01b0381166000908152600960209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610ff057600084815260209081902060408051606081018252918501546001600160701b038082168452600160701b82041683850152600160e01b900463ffffffff1690820152825260019092019101610f97565b505050509050919050565b60007f0000000000000000000000000000000000000000000000000000000000000000461461102c57610a6861338b565b507f000000000000000000000000000000000000000000000000000000000000000090565b600061105b613425565b600d54909150600160701b90046001600160701b0316808211156110c35761108381836144d1565b600d805460009061109e9084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b600d546000906110e090600160e01b900463ffffffff16426144d1565b905060006301e133806127106064846110f7613425565b6111019190614513565b61110b9190614513565b6111159190614548565b61111f9190614548565b9050600061112c826134dd565b600d80546001600160e01b0316600160e01b4263ffffffff160217905590506111553082613515565b600d546001600160701b03166000611172826103e861271061356f565b9050600061117f826134dd565b600d80546001600160701b0319169055905061119b3082613515565b600e80548591906000906111b99084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b0316021790555080600d600101600e8282829054906101000a90046001600160701b031661120491906144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055507fbb0dab1b2fba411c08a912a26b307680de2fcebcfa94469607a1a2ca6a5d8bf48460405161125991815260200190565b60405180910390a16040518181527f87ddcf7d00014b95f4de1ab15232c30192eabc2849f9cb6c677a5a79bf74e9ab9060200160405180910390a15050505050506112a2613425565b600d80546001600160701b0392909216600160701b02600160701b600160e01b03199092169190911790555050565b336112da611dcb565b6001600160a01b0316146113005760405162461bcd60e51b8152600401610cd4906143ea565b60125460ff161561132457604051632f22819760e11b815260040160405180910390fd5b600061132e610c33565b600754909150611347906001600160a01b03168261319e565b42600c556007546040518281526001600160a01b03909116907fb6f4b9255ee989b1844a8e6b7da8906b81200c38f7b3f4f1ac31e9a241c757509060200160405180910390a250565b60125460009060ff16156113a657506000919050565b6000196011541480156113bc5750600019601054145b15611414576008546113f890600160a01b900460ff167f000000000000000000000000000000000000000000000000000000000000000061455c565b61140390600a614663565b610c01906001600160701b03614548565b600061142b611422846127ef565b6011549061358e565b9050600061144361143a610a4c565b6010549061358e565b9050610f5782826135a8565b6000610c0182610afb565b6007546040516370a0823160e01b815260009182916001600160a01b03909116906370a082319061148f9033906004016140b4565b602060405180830381865afa1580156114ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d091906143d1565b9050808411156114de578093505b6114ea846000856135b7565b95945050505050565b336114fc611dcb565b6001600160a01b0316146115225760405162461bcd60e51b8152600401610cd4906143ea565b600f80549082905560408051828152602081018490527f513ac19cbbaaad4e450c732ed37635178b7d83bf8e84a940ffe7e052c9c7caa291015b60405180910390a15050565b60006001600160a01b03851633146115d8576001600160a01b038516600090815260046020908152604080832033845290915290205460001981146115d6576115b184826144d1565b6001600160a01b03871660009081526004602090815260408083203384529091529020555b505b6001600160a01b038516600090815260036020526040812080548592906116009084906144d1565b90915550506001600160a01b038085166000908152600360209081526040808320805488019055928816825260098152828220600a9091529190205484905b82548110156118d657600083828154811061165c5761165c61441f565b60009182526020909120600c5491018054909250600160e01b900463ffffffff1610868015611689575080155b156116955750506118c4565b8154600160701b90046001600160701b031660006116b386836135a8565b84549091506000906116cf906001600160701b03168385612cec565b905083156116ec578454600160701b600160e01b0316855561172e565b8454819086906000906117099084906001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b845482908690600e90611752908490600160701b90046001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550600960008d6001600160a01b03166001600160a01b031681526020019081526020016000206040518060600160405280866117b157836117b4565b60005b6001600160701b03168152602001846001600160701b03168152602001866117ea578754600160e01b900463ffffffff166117ed565b60005b63ffffffff9081169091528254600181018455600093845260209384902083519101805494840151604090940151909216600160e01b026001600160e01b036001600160701b03948516600160701b026001600160e01b03199096169490921693909317939093179290921617905561186682886144d1565b9650866118be57896118b4578454600160701b90046001600160701b03166118985761189386600161437e565b61189a565b855b6001600160a01b038e166000908152600a60205260409020555b50505050506118d6565b50505050505b806118ce8161469a565b91505061163f565b5080156119005760405163a09b101160e01b81526004810182905260248101869052604401610cd4565b856001600160a01b0316876001600160a01b03166000805160206149ea8339815191528760405161193391815260200190565b60405180910390a35060019695505050505050565b33611951611dcb565b6001600160a01b0316146119775760405162461bcd60e51b8152600401610cd4906143ea565b61198160006137b7565b565b3361198c611dcb565b6001600160a01b0316146119b25760405162461bcd60e51b8152600401610cd4906143ea565b6040516301e9a69560e41b815230600482015260001960248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631e9a695090604401600060405180830381600087803b158015611a1b57600080fd5b505af1158015611a2f573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691506370a0823190611a829030906004016140b4565b602060405180830381865afa158015611a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac391906143d1565b6040805160038082526080820190925291925060009190602082016060803683370190505090507f000000000000000000000000000000000000000000000000000000000000000081600081518110611b1e57611b1e61441f565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600181518110611b7257611b7261441f565b6001600160a01b039283166020918202929092010152600754825191169082906002908110611ba357611ba361441f565b6001600160a01b039283166020918202929092010152611c06907f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000084612eba565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166338ed173984868530611c4642603c61437e565b6040518663ffffffff1660e01b8152600401611c669594939291906146f9565b6000604051808303816000875af1158015611c85573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cad9190810190614735565b905060008160018351611cc091906144d1565b81518110611cd057611cd061441f565b60200260200101519050611d1e600860149054906101000a900460ff167f000000000000000000000000000000000000000000000000000000000000000083612c589092919063ffffffff16565b600d8054600090611d399084906001600160701b03166144e8565b82546001600160701b039182166101009390930a92830291909202199091161790555060125460ff16611d7c57600754611d7c906001600160a01b03168261319e565b60075460408051868152602081018490526001600160a01b03909216917fc003f45bc224d116b6d079100d4ab57a5b9633244c47a5a92a176c5b79a85f28910160405180910390a25050505050565b6006546001600160a01b031690565b6007546040516370a0823160e01b81526000918291611e52916001600160a01b0316906370a0823190611e119033906004016140b4565b602060405180830381865afa158015611e2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2b91906143d1565b905080841115611e60578093505b611e6c600085856135b7565b50949350505050565b60018054610a7a90614396565b6000610b443384846000611568565b6001600160a01b038116600090815260096020526040812081908190819081611ec1670de0b6b3a7640000612cc1565b6001600160a01b0388166000908152600a60205260409020549091505b8254811015611fa6576000838281548110611efb57611efb61441f565b60009182526020909120600c5491018054909250600160e01b900463ffffffff161015611f5c578054600160701b90046001600160701b0316611f3e818a61437e565b9850611f4a8185613809565b611f54908861437e565b965050611f93565b8054611f7890600160701b90046001600160701b03168861437e565b8154909750611f90906001600160701b03168661437e565b94505b5080611f9e8161469a565b915050611ede565b50600854611fe19085907f000000000000000000000000000000000000000000000000000000000000000090600160a01b900460ff16612c58565b60085490945061201e9084907f000000000000000000000000000000000000000000000000000000000000000090600160a01b900460ff16612c58565b925050509193509193565b600033612034611dcb565b6001600160a01b03161461205a5760405162461bcd60e51b8152600401610cd4906143ea565b60408051600180825281830190925260009160208083019080368337505060085482519293506001600160a01b03169183915060009061209c5761209c61441f565b6001600160a01b039283166020918202929092010152604051633111e7b360e01b81527f000000000000000000000000000000000000000000000000000000000000000090911690633111e7b3906120fe9084906000199030906004016147db565b6020604051808303816000875af115801561211d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214191906143d1565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561219e57600080fd5b505af11580156121b2573d6000803e3d6000fd5b505050507f8ca0188d9770b383d1a7a2ddfe5e0c1f029084481a53697d6c51525c47a8d88e826040516121e791815260200190565b60405180910390a15090565b6002546000908181156122185761221361220b61381e565b859084612cec565b61221a565b835b600854909150610f579082907f000000000000000000000000000000000000000000000000000000000000000090600160a01b900460ff16612c58565b600854600090612293908590600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000000612c58565b93506114ea848484613830565b336122a9611dcb565b6001600160a01b0316146122cf5760405162461bcd60e51b8152600401610cd4906143ea565b6007546001600160a01b03838116911614806122f857506008546001600160a01b038381169116145b8061230b57506001600160a01b03821630145b1561232b57816040516339b8549160e01b8152600401610cd491906140b4565b6040516370a0823160e01b81526000906001600160a01b038416906370a082319061235a9030906004016140b4565b602060405180830381865afa158015612377573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239b91906143d1565b90506123b16001600160a01b0384168383613bf4565b816001600160a01b0316836001600160a01b03167fed679328aebf74ede77ae09efcf36e90244f83643dadac1c2d9f0b21a46f6ab7836040516123f691815260200190565b60405180910390a3505050565b6000611e6c61241185612cc1565b8484613830565b33612421611dcb565b6001600160a01b0316146124475760405162461bcd60e51b8152600401610cd4906143ea565b6012805460ff1916831580159190911790915582906124635750805b1561248057600754612480906001600160a01b0316600019612d1a565b60408051831515815282151560208201527f7ac7d23f223201cd219bf262dee0820ebf6aa5ba682fbd5dd9f849bbefd05358910161155c565b336124c2611dcb565b6001600160a01b0316146124e85760405162461bcd60e51b8152600401610cd4906143ea565b601180549082905560408051828152602081018490527fcfb5a454b8aa7dc04ecb5bc1410b2a57969ca1d67f66d565196f60c6f9975404910161155c565b3361252f611dcb565b6001600160a01b0316146125555760405162461bcd60e51b8152600401610cd4906143ea565b6040516370a0823160e01b815260009030906370a082319061257b9083906004016140b4565b602060405180830381865afa158015612598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125bc91906143d1565b905060006125c98261144f565b90506125d53083613c6d565b6125de81613ccf565b600754612615906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000083612eba565b600754600f54604051631ffbe7f960e01b81526001600160a01b0392831660048201526024810191909152604481018390527f000000000000000000000000000000000000000000000000000000000000000090911690631ffbe7f990606401600060405180830381600087803b15801561268f57600080fd5b505af11580156126a3573d6000803e3d6000fd5b5050600e54604080516001600160701b038084168252600160701b90930490921660208301527f393c7eed3c13cd314ecf9287699a4c4737ef3422abf88199b0009cbdbc83e5c8935001905060405180910390a15050600e80546001600160e01b0319169055565b6000610c0161093f83611390565b600854600090612755908390600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000000612c58565b9150610c01826134dd565b33612769611dcb565b6001600160a01b03161461278f5760405162461bcd60e51b8152600401610cd4906143ea565b6001600160a01b0382166000908152600b60205260409020805460ff1916821580159182179092556127ce57506007546001600160a01b038381169116145b156127eb576007546127eb906001600160a01b0316600019612d1a565b5050565b6001600160a01b0381166000908152600960205260408120818061281a670de0b6b3a7640000612cc1565b6001600160a01b0386166000908152600a60205260409020549091505b83548110156128c65760008482815481106128545761285461441f565b60009182526020909120600c5491018054909250600160e01b900463ffffffff161061288a5780546001600160701b03166128a6565b80546128a690600160701b90046001600160701b031684613809565b6128b0908561437e565b93505080806128be9061469a565b915050612837565b506008546114ea9083907f000000000000000000000000000000000000000000000000000000000000000090600160a01b900460ff16612c58565b4284101561294b5760405162461bcd60e51b815260206004820152601760248201527614115493525517d11150511312539157d1561412549151604a1b6044820152606401610cd4565b6000612955610ffb565b6001600160a01b0389811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938c166060840152608083018b905260a083019390935260c08083018a90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa158015612a6e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590612aa45750886001600160a01b0316816001600160a01b0316145b612ae15760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610cd4565b6001600160a01b0390811660009081526004602090815260408083208b8516808552908352928190208a905551898152919350918a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259101610f06565b33612b49611dcb565b6001600160a01b031614612b6f5760405162461bcd60e51b8152600401610cd4906143ea565b601080549082905560408051828152602081018490527f1f21432dd7b8ead64d2e7c06a74baf13783b2d2f7153f099e2c4cabc3c5dbec6910161155c565b6000610c0182612719565b33612bc1611dcb565b6001600160a01b031614612be75760405162461bcd60e51b8152600401610cd4906143ea565b6001600160a01b038116612c4c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cd4565b612c55816137b7565b50565b60008160ff168360ff161415612c6f575082610b44565b8160ff168360ff161015612ca357612c87838361455c565b612c9290600a614663565b612c9c9085614513565b9050610b44565b612c9c84612cb1848661455c565b612cbc90600a614663565b613d02565b6000600254600014612ce857612ce3612cd861381e565b60025484919061356f565b610c01565b5090565b828202811515841585830485141716612d0457600080fd5b6001826001830304018115150290509392505050565b6000612d24613425565b600d54909150600160701b90046001600160701b031680821115612d8c57612d4c81836144d1565b600d8054600090612d679084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b6000612d96610f17565b1115612e8157604051631a4ca37b60e21b81526001600160a01b038581166004830152602482018590523060448301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906369328dec906064016020604051808303816000875af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a91906143d1565b9050846001600160a01b03167f6407790cdabc5d219eaf901091d6beccc475533065c2fbd374c8a32b1c66795882604051612e7791815260200190565b60405180910390a2505b612e89613425565b600d80546001600160701b0392909216600160701b02600160701b600160e01b031990921691909117905550505050565b600060405163095ea7b360e01b81526001600160a01b03841660048201528260248201526000806044836000895af1915050612ef581613d34565b612f325760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610cd4565b50505050565b6040516335ea6a7560e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906335ea6a7590612f879085906004016140b4565b61018060405180830381865afa158015612fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc9919061483b565b5050505097505050505050505060006001600160a01b0316816001600160a01b0316141561300c5781604051630a5c5e7d60e11b8152600401610cd491906140b4565b6000600860149054906101000a900460ff1690506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613060573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613084919061491c565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168160ff1611156130fa57604051630651982f60e11b815260ff80831660048301527f0000000000000000000000000000000000000000000000000000000000000000166024820152604401610cd4565b60ff82161580159061311257508060ff168260ff1614155b15613151576000196011541461313457601154613130908383612c58565b6011555b600019601054146131515760105461314d908383612c58565b6010555b600780546001600160a01b039586166001600160a01b031991821617909155600880549490951660ff909216600160a01b02166001600160a81b0319909316929092179190911790915550565b60006131a8613425565b600d54909150600160701b90046001600160701b031680821115613210576131d081836144d1565b600d80546000906131eb9084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b6001600160a01b0384166000908152600b602052604090205460ff1661324b57836040516386433f2b60e01b8152600401610cd491906140b4565b600d54600160e01b900463ffffffff1661327d57600d80546001600160e01b0316600160e01b4263ffffffff16021790555b6132b16001600160a01b0385167f000000000000000000000000000000000000000000000000000000000000000085612eba565b60405163e8eda9df60e01b81526001600160a01b03858116600483015260248201859052306044830152600060648301527f0000000000000000000000000000000000000000000000000000000000000000169063e8eda9df90608401600060405180830381600087803b15801561332857600080fd5b505af115801561333c573d6000803e3d6000fd5b50505050836001600160a01b03167f3b1270fa6f77c9af94834571cf5274944e8712de6cebea9ec3d8b3452c0533088460405161337b91815260200190565b60405180910390a2612e89613425565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516133bd9190614939565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6008546040516370a0823160e01b815260009182916001600160a01b03909116906370a082319061345a9030906004016140b4565b602060405180830381865afa158015613477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349b91906143d1565b6008549091506134d7908290600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000000612c58565b91505090565b6000806134e861381e565b6002549091508115806134f9575080155b61350d5761350884828461356f565b610f57565b509192915050565b8060026000828254613527919061437e565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481526000805160206149ea83398151915291015b60405180910390a35050565b82820281151584158583048514171661358757600080fd5b0492915050565b600081831161359e576000610b44565b610b4482846144d1565b6000818310610c2c5781610b44565b601254600090819060ff16156135e057604051632f22819760e11b815260040160405180910390fd5b600084116135f9576135f185612bad565b935083613606565b613602846121f3565b9450845b50836136255760405163df46449f60e01b815260040160405180910390fd5b61362e83611390565b851115613661578461363f84611390565b6040516323dc290560e21b815260048101929092526024820152604401610cd4565b600754613679906001600160a01b0316333088613d7b565b6136838385613515565b6001600160a01b038316600090815260096020526040908190208151606081019092526008549091829181906136e5908a90600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000000612c58565b6001600160701b03908116825288811660208084019190915263ffffffff42811660409485015285546001810187556000968752958290208551960180548684015196860151909216600160e01b026001600160e01b03968516600160701b026001600160e01b0319909316979094169690961717939093161790925560075482518981529182018890526001600160a01b03908116929087169133917f5fe47ed6d4225326d3303476197d782ded5a4e9c14f479dc9ec4992af4e85d59910160405180910390a45093949293505050565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000610b448383670de0b6b3a764000061356f565b6000613828613e0f565b610a5e613425565b6001600160a01b03811660009081526003602052604081205481906138685760405163df46449f60e01b815260040160405180910390fd5b846138865760405163332215e760e11b815260040160405180910390fd5b6001600160a01b038316600090815260096020526040812086826138b1670de0b6b3a7640000612cc1565b6001600160a01b0388166000908152600a60205260409020549091505b8354811015613ab35760008482815481106138eb576138eb61441f565b600091825260208220600c5491018054909350600160e01b900463ffffffff161090816139225782546001600160701b031661393e565b825461393e90600160701b90046001600160701b031686613809565b9050600061394c87836135a8565b845490915060009061396f90600160701b90046001600160701b03168385612cec565b9050831561398c578454600160701b600160e01b031685556139ce565b8454829086906000906139a99084906001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b845481908690600e906139f2908490600160701b90046001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550808a613a22919061437e565b9950613a2e82896144d1565b8954909850613a3f906001906144d1565b861480613a4a575087155b15613a9b578454600160701b90046001600160701b0316613a7557613a7086600161437e565b613a77565b855b6001600160a01b038e166000908152600a602052604090205550613ab39350505050565b50505050508080613aab9061469a565b9150506138ce565b50336001600160a01b03881614613b22576001600160a01b03871660009081526004602090815260408083203384529091529020546000198114613b2057613afb85826144d1565b6001600160a01b03891660009081526004602090815260408083203384529091529020555b505b613b2c8785613c6d565b613b36828a6144d1565b600854909950613b73908a907f000000000000000000000000000000000000000000000000000000000000000090600160a01b900460ff16612c58565b9850613b7e89613ccf565b600754613b95906001600160a01b0316898b613bf4565b600754604080518b8152602081018790526001600160a01b03928316928a811692908c16917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a450969791965090945050505050565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af1915050613c2f81613d34565b612f325760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610cd4565b6001600160a01b03821660009081526003602052604081208054839290613c959084906144d1565b90915550506002805482900390556040518181526000906001600160a01b038416906000805160206149ea83398151915290602001613563565b6000613cd9610c33565b9050808211156127eb576007546127eb906001600160a01b0316613cfd83856144d1565b612d1a565b6000613d0e82846149d5565b15613d1a576001613d1d565b60005b60ff16613d2a8385614548565b610b44919061437e565b60003d82613d4657806000803e806000fd5b8060208114613d5e578015613d6f5760009250613d74565b816000803e60005115159250613d74565b600192505b5050919050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260008060648360008a5af1915050613dc581613d34565b613e085760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610cd4565b5050505050565b6007546040516370a0823160e01b815260009182916001600160a01b03909116906370a082319061345a9030906004016140b4565b600060208083528351808285015260005b81811015613e7157858101830151858201604001528201613e55565b81811115613e83576000604083870101525b50601f01601f1916929092016040019392505050565b600060208284031215613eab57600080fd5b5035919050565b6001600160a01b0381168114612c5557600080fd5b60008060408385031215613eda57600080fd5b8235613ee581613eb2565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613f2d57613f2d613ef3565b60405290565b6040516080810167ffffffffffffffff81118282101715613f2d57613f2d613ef3565b6040516060810167ffffffffffffffff81118282101715613f2d57613f2d613ef3565b604051601f8201601f1916810167ffffffffffffffff81118282101715613fa257613fa2613ef3565b604052919050565b60008060006102c08486031215613fc057600080fd5b601f8581860112613fd057600080fd5b613fd8613f09565b80610120870188811115613feb57600080fd5b875b8181101561400e57803561400081613eb2565b845260209384019301613fed565b508196508861013f89011261402257600080fd5b61402a613f33565b92508291506102a088018981111561404157600080fd5b808210156140a45789858301126140585760008081fd5b614060613f56565b80606084018c8111156140735760008081fd5b845b8181101561408d578035845260209384019301614075565b505085525060209093019260609190910190614041565b9699919850509435955050505050565b6001600160a01b0391909116815260200190565b6000806000606084860312156140dd57600080fd5b83356140e881613eb2565b925060208401356140f881613eb2565b929592945050506040919091013590565b60006020828403121561411b57600080fd5b8135610b4481613eb2565b602080825282518282018190526000919060409081850190868401855b8281101561418457815180516001600160701b03908116865287820151168786015285015163ffffffff168585015260609093019290850190600101614143565b5091979650505050505050565b600080604083850312156141a457600080fd5b8235915060208301356141b681613eb2565b809150509250929050565b803580151581146141d157600080fd5b919050565b600080600080608085870312156141ec57600080fd5b84356141f781613eb2565b9350602085013561420781613eb2565b92506040850135915061421c606086016141c1565b905092959194509250565b60008060006060848603121561423c57600080fd5b83359250602084013561424e81613eb2565b9150604084013561425e81613eb2565b809150509250925092565b6000806040838503121561427c57600080fd5b823561428781613eb2565b915060208301356141b681613eb2565b600080604083850312156142aa57600080fd5b6142b3836141c1565b91506142c1602084016141c1565b90509250929050565b600080604083850312156142dd57600080fd5b82356142b381613eb2565b60ff81168114612c5557600080fd5b600080600080600080600060e0888a03121561431257600080fd5b873561431d81613eb2565b9650602088013561432d81613eb2565b95506040880135945060608801359350608088013561434b816142e8565b9699959850939692959460a0840135945060c09093013592915050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561439157614391614368565b500190565b600181811c908216806143aa57607f821691505b602082108114156143cb57634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156143e357600080fd5b5051919050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6102e08101818660005b60098110156144675781516001600160a01b031683526020928301929091019060010161443f565b50505061012082018560005b60048110156144ba5781518360005b60038110156144a1578251825260209283019290910190600101614482565b5050506060929092019160209190910190600101614473565b5050506102a08201939093526102c0015292915050565b6000828210156144e3576144e3614368565b500390565b60006001600160701b0382811684821680830382111561450a5761450a614368565b01949350505050565b600081600019048311821515161561452d5761452d614368565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261455757614557614532565b500490565b600060ff821660ff84168082101561457657614576614368565b90039392505050565b600181815b808511156145ba5781600019048211156145a0576145a0614368565b808516156145ad57918102915b93841c9390800290614584565b509250929050565b6000826145d157506001610c01565b816145de57506000610c01565b81600181146145f457600281146145fe5761461a565b6001915050610c01565b60ff84111561460f5761460f614368565b50506001821b610c01565b5060208310610133831016604e8410600b841016171561463d575081810a610c01565b614647838361457f565b806000190482111561465b5761465b614368565b029392505050565b6000610b4460ff8416836145c2565b60006001600160701b038381169083168181101561469257614692614368565b039392505050565b60006000198214156146ae576146ae614368565b5060010190565b600081518084526020808501945080840160005b838110156146ee5781516001600160a01b0316875295820195908201906001016146c9565b509495945050505050565b85815284602082015260a06040820152600061471860a08301866146b5565b6001600160a01b0394909416606083015250608001529392505050565b6000602080838503121561474857600080fd5b825167ffffffffffffffff8082111561476057600080fd5b818501915085601f83011261477457600080fd5b81518181111561478657614786613ef3565b8060051b9150614797848301613f79565b81815291830184019184810190888411156147b157600080fd5b938501935b838510156147cf578451825293850193908501906147b6565b98975050505050505050565b6060815260006147ee60608301866146b5565b6020830194909452506001600160a01b0391909116604090910152919050565b80516001600160801b03811681146141d157600080fd5b80516141d181613eb2565b80516141d1816142e8565b6000806000806000806000806000806000806101808d8f03121561485e57600080fd5b8c519b5061486e60208e0161480e565b9a5061487c60408e0161480e565b995061488a60608e0161480e565b985061489860808e0161480e565b97506148a660a08e0161480e565b965060c08d015164ffffffffff811681146148c057600080fd5b95506148ce60e08e01614825565b94506148dd6101008e01614825565b93506148ec6101208e01614825565b92506148fb6101408e01614825565b915061490a6101608e01614830565b90509295989b509295989b509295989b565b60006020828403121561492e57600080fd5b8151610b44816142e8565b600080835481600182811c91508083168061495557607f831692505b602080841082141561497557634e487b7160e01b86526022600452602486fd5b818015614989576001811461499a576149c7565b60ff198616895284890196506149c7565b60008a81526020902060005b868110156149bf5781548b8201529085019083016149a6565b505084890196505b509498975050505050505050565b6000826149e4576149e4614532565b50069056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa164736f6c634300080b000a536f6d6d656c696572204161766520563220537461626c65636f696e2043656c6c6172204c5020546f6b656e000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000014000000000000000000000000081c46feca27b31f3adc2b91ee4be9717d1cd3dd7000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a9000000000000000000000000d784927ff2f95ba542bfc824c8a8a98f3495f6b500000000000000000000000069592e6f9d21989a043646fe8225da2600e5a0f70000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f50000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000008000000000000000000000000056fd409e1d7a124bd7017459dfea2f387b6d5cd0000000000000000000000004fabb145d64652a948d72533023f6e7a623c7c53000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000956f47f50a910163d8bf957cf5846d573e7f87ca000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000057ab1ec28d129707052df4df418d58a2d46d5f510000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061039d5760003560e01c806394bf804d116101eb578063bf86d69011610110578063d905777e116100a8578063d905777e1461097d578063dd62ed3e146109a6578063df05a52a146109d1578063e9240c2d146109e4578063e93f566514610a0b578063ecf7085814610a14578063ef8b30f714610a1d578063f2fde38b14610a30578063f82d4d9b14610a4357600080fd5b8063bf86d690146108e2578063c17f6740146108ef578063c2d4160114610902578063c2fbe7bc14610916578063c63d75b61461091e578063c6e6f59214610931578063cab5923814610944578063ce96cb7714610957578063d505accf1461096a57600080fd5b8063ad004e2011610183578063ad004e201461081a578063ad5c464814610822578063af1df25514610849578063b3d7f6b914610870578063b460af9414610883578063b8dc491b14610896578063ba087652146108a9578063bb27280b146108bc578063bdc8144b146108cf57600080fd5b806394bf804d146106a657806395d89b41146106b957806396d64879146106c15780639af1d35a146106e4578063a4da2d021461075f578063a59a997314610786578063a9059cbb146107ad578063abd3f612146107c0578063ac353510146107f357600080fd5b806337a4e834116102d15780636f2293ab116102695780636f2293ab1461061557806370a0823114610628578063715018a61461064857806372163715146106505780637ecebe001461065957806383b4918b146106795780638da5cb5b1461068c5780638e0bae7f14610694578063918f86741461069d57600080fd5b806337a4e8341461055f57806338d52e0f146105675780633982aabd1461057a5780633dc6eabf1461059a578063402d267d146105a257806348ccda3c146105b55780634cdad506146105dc5780636e553f65146105ef5780636e85f1831461060257600080fd5b806318160ddd1161034457806318160ddd146104775780631c17b946146104805780631fc29c011461048857806323b872dd146104bc5780632a5bf6d2146104cf57806330adf81f146104ef578063313ce5671461051657806334fbc9a11461054f5780633644e5151461055757600080fd5b806301e1d114146103a257806306fdde03146103bd57806307a2d13a146103d257806308f43333146103e5578063095ea7b3146104245780630a28a47714610447578063148349381461045a57806315f4c61114610462575b600080fd5b6103aa610a4c565b6040519081526020015b60405180910390f35b6103c5610a6d565b6040516103b49190613e44565b6103aa6103e0366004613e99565b610afb565b6103f86103f3366004613ec7565b610b4b565b604080516001600160701b03948516815293909216602084015263ffffffff16908201526060016103b4565b610437610432366004613ec7565b610b9a565b60405190151581526020016103b4565b6103aa610455366004613e99565b610c07565b6103aa610c33565b610475610470366004613faa565b610ca5565b005b6103aa60025481565b6103aa610f17565b6104af7f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f581565b6040516103b491906140b4565b6104376104ca3660046140c8565b610f48565b6104e26104dd366004614109565b610f5f565b6040516103b49190614126565b6103aa7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b61053d7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff90911681526020016103b4565b6103aa606481565b6103aa610ffb565b610475611051565b6007546104af906001600160a01b031681565b6103aa610588366004614109565b600a6020526000908152604090205481565b6104756112d1565b6103aa6105b0366004614109565b611390565b6104af7f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae981565b6103aa6105ea366004613e99565b61144f565b6103aa6105fd366004614191565b61145a565b610475610610366004613e99565b6114f3565b6104376106233660046141d6565b611568565b6103aa610636366004614109565b60036020526000908152604090205481565b610475611948565b6103aa60105481565b6103aa610667366004614109565b60056020526000908152604090205481565b610475610687366004613e99565b611983565b6104af611dcb565b6103aa600f5481565b6103aa61271081565b6103aa6106b4366004614191565b611dda565b6103c5611e75565b6104376106cf366004614109565b600b6020526000908152604090205460ff1681565b600d54600e5461071f916001600160701b0380821692600160701b808404831693600160e01b900463ffffffff169280831692919091041685565b604080516001600160701b039687168152948616602086015263ffffffff909316928401929092528316606083015291909116608082015260a0016103b4565b6104af7f00000000000000000000000069592e6f9d21989a043646fe8225da2600e5a0f781565b6104af7f0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a981565b6104376107bb366004613ec7565b611e82565b6107d36107ce366004614109565b611e91565b6040805194855260208501939093529183015260608201526080016103b4565b6104af7f00000000000000000000000081c46feca27b31f3adc2b91ee4be9717d1cd3dd781565b6103aa612029565b6104af7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6104af7f000000000000000000000000d784927ff2f95ba542bfc824c8a8a98f3495f6b581565b6103aa61087e366004613e99565b6121f3565b6103aa610891366004614227565b612257565b6104756108a4366004614269565b6122a0565b6103aa6108b7366004614227565b612403565b6104756108ca366004614297565b612418565b6104756108dd366004613e99565b6124b9565b6012546104379060ff1681565b6008546104af906001600160a01b031681565b60085461053d90600160a01b900460ff1681565b610475612526565b6103aa61092c366004614109565b61270b565b6103aa61093f366004613e99565b612719565b6104756109523660046142ca565b612760565b6103aa610965366004614109565b6127ef565b6104756109783660046142f7565b612901565b6103aa61098b366004614109565b6001600160a01b031660009081526003602052604090205490565b6103aa6109b4366004614269565b600460209081526000928352604080842090915290825290205481565b6104756109df366004613e99565b612b40565b6104af7f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f81565b6103aa6103e881565b6103aa60115481565b6103aa610a2b366004613e99565b612bad565b610475610a3e366004614109565b612bb8565b6103aa600c5481565b6000610a56610c33565b610a5e610f17565b610a68919061437e565b905090565b60008054610a7a90614396565b80601f0160208091040260200160405190810160405280929190818152602001828054610aa690614396565b8015610af35780601f10610ac857610100808354040283529160200191610af3565b820191906000526020600020905b815481529060010190602001808311610ad657829003601f168201915b505050505081565b600080610b0783612cc1565b600854909150610b449082907f000000000000000000000000000000000000000000000000000000000000001290600160a01b900460ff16612c58565b9392505050565b60096020528160005260406000208181548110610b6757600080fd5b6000918252602090912001546001600160701b038082169350600160701b8204169150600160e01b900463ffffffff1683565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610bf59086815260200190565b60405180910390a35060015b92915050565b6002546000908015610c2c57610c2781610c1f610a4c565b859190612cec565b610b44565b5090919050565b6007546040516370a0823160e01b81526000916001600160a01b0316906370a0823190610c649030906004016140b4565b602060405180830381865afa158015610c81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6891906143d1565b33610cae611dcb565b6001600160a01b031614610cdd5760405162461bcd60e51b8152600401610cd4906143ea565b60405180910390fd5b60125460ff1615610d0157604051632f22819760e11b815260040160405180910390fd5b6000805b8060081480610d3d5750600085610d1d83600161437e565b60098110610d2d57610d2d61441f565b60200201516001600160a01b0316145b15610d6057848160098110610d5457610d5461441f565b60200201519150610d72565b610d6b60028261437e565b9050610d05565b506007546001600160a01b0382811691161415610da4578060405163a337612b60e01b8152600401610cd491906140b4565b600754610dbc906001600160a01b0316600019612d1a565b6000610dc6610c33565b600754909150610e00906001600160a01b03167f00000000000000000000000081c46feca27b31f3adc2b91ee4be9717d1cd3dd783612eba565b604051630d4f290960e21b81526000906001600160a01b037f00000000000000000000000081c46feca27b31f3adc2b91ee4be9717d1cd3dd7169063353ca42490610e55908990899087908a90600401614435565b6020604051808303816000875af1158015610e74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9891906143d1565b6007549091506001600160a01b0316610eb084612f38565b600754610ec6906001600160a01b03168361319e565b42600c556040518281526001600160a01b0380861691908316907fb0850b8e0f9e8315dde3c9f9f31138283e6bbe16cd29e8552eb1dcdf9fac9e3b906020015b60405180910390a350505050505050565b6008546040516370a0823160e01b81526000916001600160a01b0316906370a0823190610c649030906004016140b4565b6000610f578484846000611568565b949350505050565b6001600160a01b0381166000908152600960209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610ff057600084815260209081902060408051606081018252918501546001600160701b038082168452600160701b82041683850152600160e01b900463ffffffff1690820152825260019092019101610f97565b505050509050919050565b60007f0000000000000000000000000000000000000000000000000000000000000001461461102c57610a6861338b565b507f85258705dc654a0db646767e791009ed916db427d8c70de4546705a69307b9e690565b600061105b613425565b600d54909150600160701b90046001600160701b0316808211156110c35761108381836144d1565b600d805460009061109e9084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b600d546000906110e090600160e01b900463ffffffff16426144d1565b905060006301e133806127106064846110f7613425565b6111019190614513565b61110b9190614513565b6111159190614548565b61111f9190614548565b9050600061112c826134dd565b600d80546001600160e01b0316600160e01b4263ffffffff160217905590506111553082613515565b600d546001600160701b03166000611172826103e861271061356f565b9050600061117f826134dd565b600d80546001600160701b0319169055905061119b3082613515565b600e80548591906000906111b99084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b0316021790555080600d600101600e8282829054906101000a90046001600160701b031661120491906144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055507fbb0dab1b2fba411c08a912a26b307680de2fcebcfa94469607a1a2ca6a5d8bf48460405161125991815260200190565b60405180910390a16040518181527f87ddcf7d00014b95f4de1ab15232c30192eabc2849f9cb6c677a5a79bf74e9ab9060200160405180910390a15050505050506112a2613425565b600d80546001600160701b0392909216600160701b02600160701b600160e01b03199092169190911790555050565b336112da611dcb565b6001600160a01b0316146113005760405162461bcd60e51b8152600401610cd4906143ea565b60125460ff161561132457604051632f22819760e11b815260040160405180910390fd5b600061132e610c33565b600754909150611347906001600160a01b03168261319e565b42600c556007546040518281526001600160a01b03909116907fb6f4b9255ee989b1844a8e6b7da8906b81200c38f7b3f4f1ac31e9a241c757509060200160405180910390a250565b60125460009060ff16156113a657506000919050565b6000196011541480156113bc5750600019601054145b15611414576008546113f890600160a01b900460ff167f000000000000000000000000000000000000000000000000000000000000001261455c565b61140390600a614663565b610c01906001600160701b03614548565b600061142b611422846127ef565b6011549061358e565b9050600061144361143a610a4c565b6010549061358e565b9050610f5782826135a8565b6000610c0182610afb565b6007546040516370a0823160e01b815260009182916001600160a01b03909116906370a082319061148f9033906004016140b4565b602060405180830381865afa1580156114ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d091906143d1565b9050808411156114de578093505b6114ea846000856135b7565b95945050505050565b336114fc611dcb565b6001600160a01b0316146115225760405162461bcd60e51b8152600401610cd4906143ea565b600f80549082905560408051828152602081018490527f513ac19cbbaaad4e450c732ed37635178b7d83bf8e84a940ffe7e052c9c7caa291015b60405180910390a15050565b60006001600160a01b03851633146115d8576001600160a01b038516600090815260046020908152604080832033845290915290205460001981146115d6576115b184826144d1565b6001600160a01b03871660009081526004602090815260408083203384529091529020555b505b6001600160a01b038516600090815260036020526040812080548592906116009084906144d1565b90915550506001600160a01b038085166000908152600360209081526040808320805488019055928816825260098152828220600a9091529190205484905b82548110156118d657600083828154811061165c5761165c61441f565b60009182526020909120600c5491018054909250600160e01b900463ffffffff1610868015611689575080155b156116955750506118c4565b8154600160701b90046001600160701b031660006116b386836135a8565b84549091506000906116cf906001600160701b03168385612cec565b905083156116ec578454600160701b600160e01b0316855561172e565b8454819086906000906117099084906001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b845482908690600e90611752908490600160701b90046001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550600960008d6001600160a01b03166001600160a01b031681526020019081526020016000206040518060600160405280866117b157836117b4565b60005b6001600160701b03168152602001846001600160701b03168152602001866117ea578754600160e01b900463ffffffff166117ed565b60005b63ffffffff9081169091528254600181018455600093845260209384902083519101805494840151604090940151909216600160e01b026001600160e01b036001600160701b03948516600160701b026001600160e01b03199096169490921693909317939093179290921617905561186682886144d1565b9650866118be57896118b4578454600160701b90046001600160701b03166118985761189386600161437e565b61189a565b855b6001600160a01b038e166000908152600a60205260409020555b50505050506118d6565b50505050505b806118ce8161469a565b91505061163f565b5080156119005760405163a09b101160e01b81526004810182905260248101869052604401610cd4565b856001600160a01b0316876001600160a01b03166000805160206149ea8339815191528760405161193391815260200190565b60405180910390a35060019695505050505050565b33611951611dcb565b6001600160a01b0316146119775760405162461bcd60e51b8152600401610cd4906143ea565b61198160006137b7565b565b3361198c611dcb565b6001600160a01b0316146119b25760405162461bcd60e51b8152600401610cd4906143ea565b6040516301e9a69560e41b815230600482015260001960248201527f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031690631e9a695090604401600060405180830381600087803b158015611a1b57600080fd5b505af1158015611a2f573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b037f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae91691506370a0823190611a829030906004016140b4565b602060405180830381865afa158015611a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac391906143d1565b6040805160038082526080820190925291925060009190602082016060803683370190505090507f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae981600081518110611b1e57611b1e61441f565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110611b7257611b7261441f565b6001600160a01b039283166020918202929092010152600754825191169082906002908110611ba357611ba361441f565b6001600160a01b039283166020918202929092010152611c06907f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9167f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f84612eba565b60006001600160a01b037f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f166338ed173984868530611c4642603c61437e565b6040518663ffffffff1660e01b8152600401611c669594939291906146f9565b6000604051808303816000875af1158015611c85573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611cad9190810190614735565b905060008160018351611cc091906144d1565b81518110611cd057611cd061441f565b60200260200101519050611d1e600860149054906101000a900460ff167f000000000000000000000000000000000000000000000000000000000000001283612c589092919063ffffffff16565b600d8054600090611d399084906001600160701b03166144e8565b82546001600160701b039182166101009390930a92830291909202199091161790555060125460ff16611d7c57600754611d7c906001600160a01b03168261319e565b60075460408051868152602081018490526001600160a01b03909216917fc003f45bc224d116b6d079100d4ab57a5b9633244c47a5a92a176c5b79a85f28910160405180910390a25050505050565b6006546001600160a01b031690565b6007546040516370a0823160e01b81526000918291611e52916001600160a01b0316906370a0823190611e119033906004016140b4565b602060405180830381865afa158015611e2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2b91906143d1565b905080841115611e60578093505b611e6c600085856135b7565b50949350505050565b60018054610a7a90614396565b6000610b443384846000611568565b6001600160a01b038116600090815260096020526040812081908190819081611ec1670de0b6b3a7640000612cc1565b6001600160a01b0388166000908152600a60205260409020549091505b8254811015611fa6576000838281548110611efb57611efb61441f565b60009182526020909120600c5491018054909250600160e01b900463ffffffff161015611f5c578054600160701b90046001600160701b0316611f3e818a61437e565b9850611f4a8185613809565b611f54908861437e565b965050611f93565b8054611f7890600160701b90046001600160701b03168861437e565b8154909750611f90906001600160701b03168661437e565b94505b5080611f9e8161469a565b915050611ede565b50600854611fe19085907f000000000000000000000000000000000000000000000000000000000000001290600160a01b900460ff16612c58565b60085490945061201e9084907f000000000000000000000000000000000000000000000000000000000000001290600160a01b900460ff16612c58565b925050509193509193565b600033612034611dcb565b6001600160a01b03161461205a5760405162461bcd60e51b8152600401610cd4906143ea565b60408051600180825281830190925260009160208083019080368337505060085482519293506001600160a01b03169183915060009061209c5761209c61441f565b6001600160a01b039283166020918202929092010152604051633111e7b360e01b81527f000000000000000000000000d784927ff2f95ba542bfc824c8a8a98f3495f6b590911690633111e7b3906120fe9084906000199030906004016147db565b6020604051808303816000875af115801561211d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214191906143d1565b91507f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561219e57600080fd5b505af11580156121b2573d6000803e3d6000fd5b505050507f8ca0188d9770b383d1a7a2ddfe5e0c1f029084481a53697d6c51525c47a8d88e826040516121e791815260200190565b60405180910390a15090565b6002546000908181156122185761221361220b61381e565b859084612cec565b61221a565b835b600854909150610f579082907f000000000000000000000000000000000000000000000000000000000000001290600160a01b900460ff16612c58565b600854600090612293908590600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000012612c58565b93506114ea848484613830565b336122a9611dcb565b6001600160a01b0316146122cf5760405162461bcd60e51b8152600401610cd4906143ea565b6007546001600160a01b03838116911614806122f857506008546001600160a01b038381169116145b8061230b57506001600160a01b03821630145b1561232b57816040516339b8549160e01b8152600401610cd491906140b4565b6040516370a0823160e01b81526000906001600160a01b038416906370a082319061235a9030906004016140b4565b602060405180830381865afa158015612377573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239b91906143d1565b90506123b16001600160a01b0384168383613bf4565b816001600160a01b0316836001600160a01b03167fed679328aebf74ede77ae09efcf36e90244f83643dadac1c2d9f0b21a46f6ab7836040516123f691815260200190565b60405180910390a3505050565b6000611e6c61241185612cc1565b8484613830565b33612421611dcb565b6001600160a01b0316146124475760405162461bcd60e51b8152600401610cd4906143ea565b6012805460ff1916831580159190911790915582906124635750805b1561248057600754612480906001600160a01b0316600019612d1a565b60408051831515815282151560208201527f7ac7d23f223201cd219bf262dee0820ebf6aa5ba682fbd5dd9f849bbefd05358910161155c565b336124c2611dcb565b6001600160a01b0316146124e85760405162461bcd60e51b8152600401610cd4906143ea565b601180549082905560408051828152602081018490527fcfb5a454b8aa7dc04ecb5bc1410b2a57969ca1d67f66d565196f60c6f9975404910161155c565b3361252f611dcb565b6001600160a01b0316146125555760405162461bcd60e51b8152600401610cd4906143ea565b6040516370a0823160e01b815260009030906370a082319061257b9083906004016140b4565b602060405180830381865afa158015612598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125bc91906143d1565b905060006125c98261144f565b90506125d53083613c6d565b6125de81613ccf565b600754612615906001600160a01b03167f00000000000000000000000069592e6f9d21989a043646fe8225da2600e5a0f783612eba565b600754600f54604051631ffbe7f960e01b81526001600160a01b0392831660048201526024810191909152604481018390527f00000000000000000000000069592e6f9d21989a043646fe8225da2600e5a0f790911690631ffbe7f990606401600060405180830381600087803b15801561268f57600080fd5b505af11580156126a3573d6000803e3d6000fd5b5050600e54604080516001600160701b038084168252600160701b90930490921660208301527f393c7eed3c13cd314ecf9287699a4c4737ef3422abf88199b0009cbdbc83e5c8935001905060405180910390a15050600e80546001600160e01b0319169055565b6000610c0161093f83611390565b600854600090612755908390600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000012612c58565b9150610c01826134dd565b33612769611dcb565b6001600160a01b03161461278f5760405162461bcd60e51b8152600401610cd4906143ea565b6001600160a01b0382166000908152600b60205260409020805460ff1916821580159182179092556127ce57506007546001600160a01b038381169116145b156127eb576007546127eb906001600160a01b0316600019612d1a565b5050565b6001600160a01b0381166000908152600960205260408120818061281a670de0b6b3a7640000612cc1565b6001600160a01b0386166000908152600a60205260409020549091505b83548110156128c65760008482815481106128545761285461441f565b60009182526020909120600c5491018054909250600160e01b900463ffffffff161061288a5780546001600160701b03166128a6565b80546128a690600160701b90046001600160701b031684613809565b6128b0908561437e565b93505080806128be9061469a565b915050612837565b506008546114ea9083907f000000000000000000000000000000000000000000000000000000000000001290600160a01b900460ff16612c58565b4284101561294b5760405162461bcd60e51b815260206004820152601760248201527614115493525517d11150511312539157d1561412549151604a1b6044820152606401610cd4565b6000612955610ffb565b6001600160a01b0389811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938c166060840152608083018b905260a083019390935260c08083018a90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa158015612a6e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590612aa45750886001600160a01b0316816001600160a01b0316145b612ae15760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610cd4565b6001600160a01b0390811660009081526004602090815260408083208b8516808552908352928190208a905551898152919350918a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259101610f06565b33612b49611dcb565b6001600160a01b031614612b6f5760405162461bcd60e51b8152600401610cd4906143ea565b601080549082905560408051828152602081018490527f1f21432dd7b8ead64d2e7c06a74baf13783b2d2f7153f099e2c4cabc3c5dbec6910161155c565b6000610c0182612719565b33612bc1611dcb565b6001600160a01b031614612be75760405162461bcd60e51b8152600401610cd4906143ea565b6001600160a01b038116612c4c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cd4565b612c55816137b7565b50565b60008160ff168360ff161415612c6f575082610b44565b8160ff168360ff161015612ca357612c87838361455c565b612c9290600a614663565b612c9c9085614513565b9050610b44565b612c9c84612cb1848661455c565b612cbc90600a614663565b613d02565b6000600254600014612ce857612ce3612cd861381e565b60025484919061356f565b610c01565b5090565b828202811515841585830485141716612d0457600080fd5b6001826001830304018115150290509392505050565b6000612d24613425565b600d54909150600160701b90046001600160701b031680821115612d8c57612d4c81836144d1565b600d8054600090612d679084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b6000612d96610f17565b1115612e8157604051631a4ca37b60e21b81526001600160a01b038581166004830152602482018590523060448301526000917f0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a9909116906369328dec906064016020604051808303816000875af1158015612e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3a91906143d1565b9050846001600160a01b03167f6407790cdabc5d219eaf901091d6beccc475533065c2fbd374c8a32b1c66795882604051612e7791815260200190565b60405180910390a2505b612e89613425565b600d80546001600160701b0392909216600160701b02600160701b600160e01b031990921691909117905550505050565b600060405163095ea7b360e01b81526001600160a01b03841660048201528260248201526000806044836000895af1915050612ef581613d34565b612f325760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610cd4565b50505050565b6040516335ea6a7560e01b81526000906001600160a01b037f0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a916906335ea6a7590612f879085906004016140b4565b61018060405180830381865afa158015612fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc9919061483b565b5050505097505050505050505060006001600160a01b0316816001600160a01b0316141561300c5781604051630a5c5e7d60e11b8152600401610cd491906140b4565b6000600860149054906101000a900460ff1690506000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613060573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613084919061491c565b90507f000000000000000000000000000000000000000000000000000000000000001260ff168160ff1611156130fa57604051630651982f60e11b815260ff80831660048301527f0000000000000000000000000000000000000000000000000000000000000012166024820152604401610cd4565b60ff82161580159061311257508060ff168260ff1614155b15613151576000196011541461313457601154613130908383612c58565b6011555b600019601054146131515760105461314d908383612c58565b6010555b600780546001600160a01b039586166001600160a01b031991821617909155600880549490951660ff909216600160a01b02166001600160a81b0319909316929092179190911790915550565b60006131a8613425565b600d54909150600160701b90046001600160701b031680821115613210576131d081836144d1565b600d80546000906131eb9084906001600160701b03166144e8565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b6001600160a01b0384166000908152600b602052604090205460ff1661324b57836040516386433f2b60e01b8152600401610cd491906140b4565b600d54600160e01b900463ffffffff1661327d57600d80546001600160e01b0316600160e01b4263ffffffff16021790555b6132b16001600160a01b0385167f0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a985612eba565b60405163e8eda9df60e01b81526001600160a01b03858116600483015260248201859052306044830152600060648301527f0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a9169063e8eda9df90608401600060405180830381600087803b15801561332857600080fd5b505af115801561333c573d6000803e3d6000fd5b50505050836001600160a01b03167f3b1270fa6f77c9af94834571cf5274944e8712de6cebea9ec3d8b3452c0533088460405161337b91815260200190565b60405180910390a2612e89613425565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516133bd9190614939565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6008546040516370a0823160e01b815260009182916001600160a01b03909116906370a082319061345a9030906004016140b4565b602060405180830381865afa158015613477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349b91906143d1565b6008549091506134d7908290600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000012612c58565b91505090565b6000806134e861381e565b6002549091508115806134f9575080155b61350d5761350884828461356f565b610f57565b509192915050565b8060026000828254613527919061437e565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481526000805160206149ea83398151915291015b60405180910390a35050565b82820281151584158583048514171661358757600080fd5b0492915050565b600081831161359e576000610b44565b610b4482846144d1565b6000818310610c2c5781610b44565b601254600090819060ff16156135e057604051632f22819760e11b815260040160405180910390fd5b600084116135f9576135f185612bad565b935083613606565b613602846121f3565b9450845b50836136255760405163df46449f60e01b815260040160405180910390fd5b61362e83611390565b851115613661578461363f84611390565b6040516323dc290560e21b815260048101929092526024820152604401610cd4565b600754613679906001600160a01b0316333088613d7b565b6136838385613515565b6001600160a01b038316600090815260096020526040908190208151606081019092526008549091829181906136e5908a90600160a01b900460ff167f0000000000000000000000000000000000000000000000000000000000000012612c58565b6001600160701b03908116825288811660208084019190915263ffffffff42811660409485015285546001810187556000968752958290208551960180548684015196860151909216600160e01b026001600160e01b03968516600160701b026001600160e01b0319909316979094169690961717939093161790925560075482518981529182018890526001600160a01b03908116929087169133917f5fe47ed6d4225326d3303476197d782ded5a4e9c14f479dc9ec4992af4e85d59910160405180910390a45093949293505050565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000610b448383670de0b6b3a764000061356f565b6000613828613e0f565b610a5e613425565b6001600160a01b03811660009081526003602052604081205481906138685760405163df46449f60e01b815260040160405180910390fd5b846138865760405163332215e760e11b815260040160405180910390fd5b6001600160a01b038316600090815260096020526040812086826138b1670de0b6b3a7640000612cc1565b6001600160a01b0388166000908152600a60205260409020549091505b8354811015613ab35760008482815481106138eb576138eb61441f565b600091825260208220600c5491018054909350600160e01b900463ffffffff161090816139225782546001600160701b031661393e565b825461393e90600160701b90046001600160701b031686613809565b9050600061394c87836135a8565b845490915060009061396f90600160701b90046001600160701b03168385612cec565b9050831561398c578454600160701b600160e01b031685556139ce565b8454829086906000906139a99084906001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b031602179055505b845481908690600e906139f2908490600160701b90046001600160701b0316614672565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550808a613a22919061437e565b9950613a2e82896144d1565b8954909850613a3f906001906144d1565b861480613a4a575087155b15613a9b578454600160701b90046001600160701b0316613a7557613a7086600161437e565b613a77565b855b6001600160a01b038e166000908152600a602052604090205550613ab39350505050565b50505050508080613aab9061469a565b9150506138ce565b50336001600160a01b03881614613b22576001600160a01b03871660009081526004602090815260408083203384529091529020546000198114613b2057613afb85826144d1565b6001600160a01b03891660009081526004602090815260408083203384529091529020555b505b613b2c8785613c6d565b613b36828a6144d1565b600854909950613b73908a907f000000000000000000000000000000000000000000000000000000000000001290600160a01b900460ff16612c58565b9850613b7e89613ccf565b600754613b95906001600160a01b0316898b613bf4565b600754604080518b8152602081018790526001600160a01b03928316928a811692908c16917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a450969791965090945050505050565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af1915050613c2f81613d34565b612f325760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610cd4565b6001600160a01b03821660009081526003602052604081208054839290613c959084906144d1565b90915550506002805482900390556040518181526000906001600160a01b038416906000805160206149ea83398151915290602001613563565b6000613cd9610c33565b9050808211156127eb576007546127eb906001600160a01b0316613cfd83856144d1565b612d1a565b6000613d0e82846149d5565b15613d1a576001613d1d565b60005b60ff16613d2a8385614548565b610b44919061437e565b60003d82613d4657806000803e806000fd5b8060208114613d5e578015613d6f5760009250613d74565b816000803e60005115159250613d74565b600192505b5050919050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260008060648360008a5af1915050613dc581613d34565b613e085760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610cd4565b5050505050565b6007546040516370a0823160e01b815260009182916001600160a01b03909116906370a082319061345a9030906004016140b4565b600060208083528351808285015260005b81811015613e7157858101830151858201604001528201613e55565b81811115613e83576000604083870101525b50601f01601f1916929092016040019392505050565b600060208284031215613eab57600080fd5b5035919050565b6001600160a01b0381168114612c5557600080fd5b60008060408385031215613eda57600080fd5b8235613ee581613eb2565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613f2d57613f2d613ef3565b60405290565b6040516080810167ffffffffffffffff81118282101715613f2d57613f2d613ef3565b6040516060810167ffffffffffffffff81118282101715613f2d57613f2d613ef3565b604051601f8201601f1916810167ffffffffffffffff81118282101715613fa257613fa2613ef3565b604052919050565b60008060006102c08486031215613fc057600080fd5b601f8581860112613fd057600080fd5b613fd8613f09565b80610120870188811115613feb57600080fd5b875b8181101561400e57803561400081613eb2565b845260209384019301613fed565b508196508861013f89011261402257600080fd5b61402a613f33565b92508291506102a088018981111561404157600080fd5b808210156140a45789858301126140585760008081fd5b614060613f56565b80606084018c8111156140735760008081fd5b845b8181101561408d578035845260209384019301614075565b505085525060209093019260609190910190614041565b9699919850509435955050505050565b6001600160a01b0391909116815260200190565b6000806000606084860312156140dd57600080fd5b83356140e881613eb2565b925060208401356140f881613eb2565b929592945050506040919091013590565b60006020828403121561411b57600080fd5b8135610b4481613eb2565b602080825282518282018190526000919060409081850190868401855b8281101561418457815180516001600160701b03908116865287820151168786015285015163ffffffff168585015260609093019290850190600101614143565b5091979650505050505050565b600080604083850312156141a457600080fd5b8235915060208301356141b681613eb2565b809150509250929050565b803580151581146141d157600080fd5b919050565b600080600080608085870312156141ec57600080fd5b84356141f781613eb2565b9350602085013561420781613eb2565b92506040850135915061421c606086016141c1565b905092959194509250565b60008060006060848603121561423c57600080fd5b83359250602084013561424e81613eb2565b9150604084013561425e81613eb2565b809150509250925092565b6000806040838503121561427c57600080fd5b823561428781613eb2565b915060208301356141b681613eb2565b600080604083850312156142aa57600080fd5b6142b3836141c1565b91506142c1602084016141c1565b90509250929050565b600080604083850312156142dd57600080fd5b82356142b381613eb2565b60ff81168114612c5557600080fd5b600080600080600080600060e0888a03121561431257600080fd5b873561431d81613eb2565b9650602088013561432d81613eb2565b95506040880135945060608801359350608088013561434b816142e8565b9699959850939692959460a0840135945060c09093013592915050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561439157614391614368565b500190565b600181811c908216806143aa57607f821691505b602082108114156143cb57634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156143e357600080fd5b5051919050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6102e08101818660005b60098110156144675781516001600160a01b031683526020928301929091019060010161443f565b50505061012082018560005b60048110156144ba5781518360005b60038110156144a1578251825260209283019290910190600101614482565b5050506060929092019160209190910190600101614473565b5050506102a08201939093526102c0015292915050565b6000828210156144e3576144e3614368565b500390565b60006001600160701b0382811684821680830382111561450a5761450a614368565b01949350505050565b600081600019048311821515161561452d5761452d614368565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261455757614557614532565b500490565b600060ff821660ff84168082101561457657614576614368565b90039392505050565b600181815b808511156145ba5781600019048211156145a0576145a0614368565b808516156145ad57918102915b93841c9390800290614584565b509250929050565b6000826145d157506001610c01565b816145de57506000610c01565b81600181146145f457600281146145fe5761461a565b6001915050610c01565b60ff84111561460f5761460f614368565b50506001821b610c01565b5060208310610133831016604e8410600b841016171561463d575081810a610c01565b614647838361457f565b806000190482111561465b5761465b614368565b029392505050565b6000610b4460ff8416836145c2565b60006001600160701b038381169083168181101561469257614692614368565b039392505050565b60006000198214156146ae576146ae614368565b5060010190565b600081518084526020808501945080840160005b838110156146ee5781516001600160a01b0316875295820195908201906001016146c9565b509495945050505050565b85815284602082015260a06040820152600061471860a08301866146b5565b6001600160a01b0394909416606083015250608001529392505050565b6000602080838503121561474857600080fd5b825167ffffffffffffffff8082111561476057600080fd5b818501915085601f83011261477457600080fd5b81518181111561478657614786613ef3565b8060051b9150614797848301613f79565b81815291830184019184810190888411156147b157600080fd5b938501935b838510156147cf578451825293850193908501906147b6565b98975050505050505050565b6060815260006147ee60608301866146b5565b6020830194909452506001600160a01b0391909116604090910152919050565b80516001600160801b03811681146141d157600080fd5b80516141d181613eb2565b80516141d1816142e8565b6000806000806000806000806000806000806101808d8f03121561485e57600080fd5b8c519b5061486e60208e0161480e565b9a5061487c60408e0161480e565b995061488a60608e0161480e565b985061489860808e0161480e565b97506148a660a08e0161480e565b965060c08d015164ffffffffff811681146148c057600080fd5b95506148ce60e08e01614825565b94506148dd6101008e01614825565b93506148ec6101208e01614825565b92506148fb6101408e01614825565b915061490a6101608e01614830565b90509295989b509295989b509295989b565b60006020828403121561492e57600080fd5b8151610b44816142e8565b600080835481600182811c91508083168061495557607f831692505b602080841082141561497557634e487b7160e01b86526022600452602486fd5b818015614989576001811461499a576149c7565b60ff198616895284890196506149c7565b60008a81526020902060005b868110156149bf5781548b8201529085019083016149a6565b505084890196505b509498975050505050505050565b6000826149e4576149e4614532565b50069056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa164736f6c634300080b000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000014000000000000000000000000081c46feca27b31f3adc2b91ee4be9717d1cd3dd7000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a9000000000000000000000000d784927ff2f95ba542bfc824c8a8a98f3495f6b500000000000000000000000069592e6f9d21989a043646fe8225da2600e5a0f70000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f50000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000008000000000000000000000000056fd409e1d7a124bd7017459dfea2f387b6d5cd0000000000000000000000004fabb145d64652a948d72533023f6e7a623c7c53000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000956f47f50a910163d8bf957cf5846d573e7f87ca000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000057ab1ec28d129707052df4df418d58a2d46d5f510000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1
-----Decoded View---------------
Arg [0] : _asset (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _approvedPositions (address[]): 0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd,0x4Fabb145d64652a948d72533023f6E7A623C7C53,0xdAC17F958D2ee523a2206206994597C13D831ec7,0x6B175474E89094C44Da98b954EedeAC495271d0F,0x956F47F50A910163D8BF957Cf5846D573E7f87CA,0x853d955aCEf822Db058eb8505911ED77F175b99e,0x57Ab1ec28D129707052df4dF418D58a2D46d5f51,0x8E870D67F660D95d5be530380D0eC0bd388289E1
Arg [2] : _curveRegistryExchange (address): 0x81C46fECa27B31F3ADC2b91eE4be9717d1cd3DD7
Arg [3] : _sushiswapRouter (address): 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F
Arg [4] : _lendingPool (address): 0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9
Arg [5] : _incentivesController (address): 0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5
Arg [6] : _gravityBridge (address): 0x69592e6f9d21989a043646fE8225da2600e5A0f7
Arg [7] : _stkAAVE (address): 0x4da27a545c0c5B758a6BA100e3a049001de870f5
Arg [8] : _AAVE (address): 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9
Arg [9] : _WETH (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
19 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [2] : 00000000000000000000000081c46feca27b31f3adc2b91ee4be9717d1cd3dd7
Arg [3] : 000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f
Arg [4] : 0000000000000000000000007d2768de32b0b80b7a3454c06bdac94a69ddc7a9
Arg [5] : 000000000000000000000000d784927ff2f95ba542bfc824c8a8a98f3495f6b5
Arg [6] : 00000000000000000000000069592e6f9d21989a043646fe8225da2600e5a0f7
Arg [7] : 0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5
Arg [8] : 0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9
Arg [9] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [11] : 000000000000000000000000056fd409e1d7a124bd7017459dfea2f387b6d5cd
Arg [12] : 0000000000000000000000004fabb145d64652a948d72533023f6e7a623c7c53
Arg [13] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [14] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [15] : 000000000000000000000000956f47f50a910163d8bf957cf5846d573e7f87ca
Arg [16] : 000000000000000000000000853d955acef822db058eb8505911ed77f175b99e
Arg [17] : 00000000000000000000000057ab1ec28d129707052df4df418d58a2d46d5f51
Arg [18] : 0000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.999873 | 192.4252 | $192.4 |
Loading...
Loading
[ 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.