Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize | 17067658 | 680 days ago | IN | 0 ETH | 0.00284608 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
ConvexCurveLPVault
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma abicoder v2; import {IncentiveVault} from '../../IncentiveVault.sol'; import {IERC20} from '../../../../dependencies/openzeppelin/contracts/IERC20.sol'; import {SafeERC20} from '../../../../dependencies/openzeppelin/contracts/SafeERC20.sol'; import {IERC20Detailed} from '../../../../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; import {IConvexBooster} from '../../../../interfaces/IConvexBooster.sol'; import {IConvexBaseRewardPool} from '../../../../interfaces/IConvexBaseRewardPool.sol'; import {Errors} from '../../../libraries/helpers/Errors.sol'; import {SturdyInternalAsset} from '../../../tokenization/SturdyInternalAsset.sol'; import {PercentageMath} from '../../../libraries/math/PercentageMath.sol'; import {DataTypes} from '../../../libraries/types/DataTypes.sol'; import {ILendingPool} from '../../../../interfaces/ILendingPool.sol'; interface IRewards { function rewardToken() external view returns (address); function getReward() external; } /** * @title ConvexCurveLPVault * @notice Curve LP Token Vault by using Convex on Ethereum * @author Sturdy **/ contract ConvexCurveLPVault is IncentiveVault { using SafeERC20 for IERC20; using PercentageMath for uint256; address public convexBooster; address internal _curveLPToken; address internal _internalAssetToken; uint256 internal _convexPoolId; uint256 internal _incentiveRatio; /** * @dev Emitted on setConfiguration() * @param _curveLpToken The address of Curve LP Token * @param _convexPoolId The convex pool Id * @param _internalToken The address of internal asset */ event SetParameters(address _curveLpToken, uint256 _convexPoolId, address _internalToken); /** * @dev The function to set parameters related to convex/curve * - Caller is only PoolAdmin which is set on LendingPoolAddressesProvider contract * @param _lpToken The address of Curve LP Token which will be used in vault * @param _poolId The convex pool Id for Curve LP Token */ function setConfiguration(address _lpToken, uint256 _poolId) external payable onlyAdmin { require(_lpToken != address(0), Errors.VT_INVALID_CONFIGURATION); require(_internalAssetToken == address(0), Errors.VT_INVALID_CONFIGURATION); convexBooster = 0xF403C135812408BFbE8713b5A23a04b3D48AAE31; _curveLPToken = _lpToken; _convexPoolId = _poolId; SturdyInternalAsset _internalToken = new SturdyInternalAsset( string(abi.encodePacked('Sturdy ', IERC20Detailed(_lpToken).symbol())), string(abi.encodePacked('c', IERC20Detailed(_lpToken).symbol())), IERC20Detailed(_lpToken).decimals() ); _internalAssetToken = address(_internalToken); emit SetParameters(_lpToken, _poolId, _internalAssetToken); } /** * @dev The function to get internal asset address * @return The address of collateral internal asset */ function getInternalAsset() external view returns (address) { return _internalAssetToken; } /** * @dev The function to get rewards token address * @return The address of rewards token */ function getBaseRewardPool() internal view returns (address) { IConvexBooster.PoolInfo memory poolInfo = IConvexBooster(convexBooster).poolInfo(_convexPoolId); return poolInfo.crvRewards; } /** * @dev The function to send rewards to YieldManager & Treasury * @param _asset The rewards token address */ function _transferYield(address _asset) internal { require(_asset != address(0), Errors.VT_PROCESS_YIELD_INVALID); uint256 yieldAmount = IERC20(_asset).balanceOf(address(this)); // Some ERC20 do not allow zero amounts to be sent: if (yieldAmount == 0) return; uint256 incentiveAmount; uint256 fee = _incentiveRatio; bool isIncentiveToken = (getIncentiveToken() == _asset); if (isIncentiveToken && fee != 0) { incentiveAmount = yieldAmount.percentMul(fee); _sendIncentive(incentiveAmount); } // Move some yield to treasury fee = _vaultFee; if (fee != 0) { uint256 treasuryAmount = yieldAmount.percentMul(fee); IERC20(_asset).safeTransfer(_treasuryAddress, treasuryAmount); yieldAmount -= treasuryAmount; } if (incentiveAmount != 0) { yieldAmount -= incentiveAmount; } // transfer to yieldManager if (yieldAmount != 0) { address yieldManager = _addressesProvider.getAddress('YIELD_MANAGER'); IERC20(_asset).safeTransfer(yieldManager, yieldAmount); } emit ProcessYield(_asset, yieldAmount); } /** * @dev Get yield based on strategy and re-deposit * - Caller is anyone */ function processYield() external override { // Claim Rewards(CRV, CVX, Extra incentive tokens) address baseRewardPool = getBaseRewardPool(); IConvexBaseRewardPool(baseRewardPool).getReward(address(this), false); // Transfer CRV to YieldManager _transferYield(IConvexBaseRewardPool(baseRewardPool).rewardToken()); // Transfer CVX to YieldManager _transferYield(IConvexBooster(convexBooster).minter()); } /** * @dev The function to transfer extra incentive token to YieldManager * - Caller is only PoolAdmin which is set on LendingPoolAddressesProvider contract * @param _offset extraRewards start offset. * @param _count extraRewards count */ function processExtraYield(uint256 _offset, uint256 _count) external { address baseRewardPool = getBaseRewardPool(); uint256 extraRewardsLength = IConvexBaseRewardPool(baseRewardPool).extraRewardsLength(); require(_offset + _count <= extraRewardsLength, Errors.VT_EXTRA_REWARDS_INDEX_INVALID); for (uint256 i; i < _count; ++i) { address _extraReward = IConvexBaseRewardPool(baseRewardPool).extraRewards(_offset + i); IRewards(_extraReward).getReward(); address _rewardToken = IRewards(_extraReward).rewardToken(); _transferYield(_rewardToken); } } /** * @dev Get CRV yield amount based on strategy * @return CRV yield amount of collateral internal asset */ function getYieldAmount() external view returns (uint256) { address baseRewardPool = getBaseRewardPool(); return IConvexBaseRewardPool(baseRewardPool).earned(address(this)); } /** * @dev Get price per share based on yield strategy * @return The value of price per share */ function pricePerShare() external view override returns (uint256) { uint256 decimals = IERC20Detailed(_internalAssetToken).decimals(); return 10 ** decimals; } /** * @dev Deposit collateral external asset to yield pool based on strategy and mint collateral internal asset * @param _asset The address of collateral external asset * @param _amount The amount of collateral external asset * @return The address of collateral internal asset * @return The amount of collateral internal asset */ function _depositToYieldPool( address _asset, uint256 _amount ) internal override returns (address, uint256) { // receive Curve LP Token from user address token = _curveLPToken; require(_asset == token, Errors.VT_COLLATERAL_DEPOSIT_INVALID); IERC20(token).safeTransferFrom(msg.sender, address(this), _amount); // deposit Curve LP Token to Convex address convexVault = convexBooster; IERC20(token).safeApprove(convexVault, 0); IERC20(token).safeApprove(convexVault, _amount); IConvexBooster(convexVault).deposit(_convexPoolId, _amount, true); // mint address internalAsset = _internalAssetToken; address lendingPoolAddress = _addressesProvider.getLendingPool(); SturdyInternalAsset(internalAsset).mint(address(this), _amount); IERC20(internalAsset).safeApprove(lendingPoolAddress, 0); IERC20(internalAsset).safeApprove(lendingPoolAddress, _amount); return (internalAsset, _amount); } /** * @dev Get Withdrawal amount of collateral internal asset based on strategy * @param _asset The address of collateral external asset * @param _amount The withdrawal amount of collateral external asset * @return The address of collateral internal asset * @return The withdrawal amount of collateral internal asset */ function _getWithdrawalAmount( address _asset, uint256 _amount ) internal view override returns (address, uint256) { require(_asset == _curveLPToken, Errors.VT_COLLATERAL_WITHDRAW_INVALID); // In this vault, return same amount of asset. return (_internalAssetToken, _amount); } /** * @dev Burn an `_amount` of collateral internal asset and send the required collateral external asset to `_to` * @param _amount The amount of collateral internal asset * @return The amount of collateral external asset */ function _withdraw(uint256 _amount, address _to) internal returns (uint256) { // Withdraw from Convex address baseRewardPool = getBaseRewardPool(); IConvexBaseRewardPool(baseRewardPool).withdrawAndUnwrap(_amount, false); // Burn SturdyInternalAsset(_internalAssetToken).burn(address(this), _amount); // Deliver Curve LP Token IERC20(_curveLPToken).safeTransfer(_to, _amount); return _amount; } /** * @dev Burn an `_amount` of collateral internal asset and send the required collateral external asset to caller on liquidation * - Caller is only LendingPool * @param _asset The address of collateral external asset * @param _amount The amount of collateral internal asset * @return The amount of collateral external asset */ function withdrawOnLiquidation( address _asset, uint256 _amount ) external override returns (uint256) { require(_asset == _curveLPToken, Errors.LP_LIQUIDATION_CALL_FAILED); require(msg.sender == _addressesProvider.getLendingPool(), Errors.LP_LIQUIDATION_CALL_FAILED); return _withdraw(_amount, msg.sender); } /** * @dev Burn an `_amount` of collateral internal asset and deliver required collateral external asset * @param _asset The address of collateral external asset * @param _amount The withdrawal amount of collateral internal asset * @param _to The address of receiving collateral external asset * @return The amount of collateral external asset */ function _withdrawFromYieldPool( address _asset, uint256 _amount, address _to ) internal override returns (uint256) { return _withdraw(_amount, _to); } /** * @dev Get the incentive token address supported on this vault * @return The address of incentive token */ function getIncentiveToken() public view override returns (address) { address baseRewardPool = getBaseRewardPool(); return IConvexBaseRewardPool(baseRewardPool).rewardToken(); } /** * @dev Get current total incentive amount * @return The total amount of incentive token */ function getCurrentTotalIncentiveAmount() external view override returns (uint256) { if (_incentiveRatio != 0) { address baseRewardPool = getBaseRewardPool(); uint256 earned = IConvexBaseRewardPool(baseRewardPool).earned(address(this)); return earned.percentMul(_incentiveRatio); } return 0; } /** * @dev Get Incentive Ratio * @return The incentive ratio value */ function getIncentiveRatio() external view override returns (uint256) { return _incentiveRatio; } /** * @dev Set Incentive Ratio * - Caller is only PoolAdmin which is set on LendingPoolAddressesProvider contract */ function setIncentiveRatio(uint256 _ratio) external override onlyAdmin { require(_vaultFee + _ratio <= PercentageMath.PERCENTAGE_FACTOR, Errors.VT_FEE_TOO_BIG); // Get all available rewards & Send it to YieldDistributor, // so that the changing ratio does not affect asset's cumulative index if (_incentiveRatio != 0) { _clearRewards(); } _incentiveRatio = _ratio; emit SetIncentiveRatio(_ratio); } /** * @dev Get AToken address for the vault * @return The AToken address for the vault */ function _getAToken() internal view override returns (address) { address internalAsset = _internalAssetToken; DataTypes.ReserveData memory reserveData = ILendingPool(_addressesProvider.getLendingPool()) .getReserveData(internalAsset); return reserveData.aTokenAddress; } /** * @dev Claim all rewards and send some to YieldDistributor */ function _clearRewards() internal override { address baseRewardPool = getBaseRewardPool(); IConvexBaseRewardPool(baseRewardPool).getReward(); _transferYield(IConvexBaseRewardPool(baseRewardPool).rewardToken()); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, 'Address: insufficient balance'); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{value: amount}(''); require(success, 'Address: unable to send value, recipient may have reverted'); } }
// SPDX-License-Identifier: MIT 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 GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import './Context.sol'; import './IERC20.sol'; import './Address.sol'; import './IERC20Detailed.sol'; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Detailed { using Address for address; mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string internal _name; string internal _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor(string memory name, string memory symbol) { _name = name; _symbol = symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance( address owner, address spender ) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()] - amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance( address spender, uint256 subtractedValue ) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] - subtractedValue); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), 'ERC20: transfer from the zero address'); require(recipient != address(0), 'ERC20: transfer to the zero address'); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] -= amount; _balances[recipient] += amount; emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), 'ERC20: mint to the zero address'); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), 'ERC20: burn from the zero address'); _beforeTokenTransfer(account, address(0), amount); _balances[account] -= amount; _totalSupply -= amount; emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), 'ERC20: approve from the zero address'); require(spender != address(0), 'ERC20: approve to the zero address'); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, 'ERC20: insufficient allowance'); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import {IERC20} from './IERC20.sol'; interface IERC20Detailed is IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, 'Math: mulDiv overflow'); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import './Context.sol'; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ 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() { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view 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 payable virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = 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 payable virtual onlyOwner { require(newOwner != address(0), 'Ownable: new owner is the zero address'); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC20} from './IERC20.sol'; import {Address} from './Address.sol'; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove( IERC20 token, address spender, uint256 value ) internal { require( (value == 0) || (token.allowance(address(this), spender) == 0), 'SafeERC20: approve from non-zero to non-zero allowance' ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function callOptionalReturn(IERC20 token, bytes memory data) private { require(address(token).isContract(), 'SafeERC20: call to non-contract'); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, 'SafeERC20: low-level call failed'); if (returndata.length != 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed'); } } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma abicoder v2; import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol'; import {VersionedInitializable} from '../protocol/libraries/sturdy-upgradeability/VersionedInitializable.sol'; import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; import {IScaledBalanceToken} from '../interfaces/IScaledBalanceToken.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; import {UserData, AssetData, AggregatedRewardsData} from '../interfaces/IVariableYieldDistribution.sol'; import {IncentiveVault} from '../protocol/vault/IncentiveVault.sol'; import {Errors} from '../protocol/libraries/helpers/Errors.sol'; import {Math} from '../dependencies/openzeppelin/contracts/Math.sol'; /** * @title VariableYieldDistribution * @notice Distributor contract that sends some rewards to borrowers who provide some special tokens such as Curve LP tokens. * @author Sturdy **/ contract VariableYieldDistribution is VersionedInitializable { using SafeERC20 for IERC20; uint256 private constant REVISION = 1; uint8 private constant PRECISION = 27; address public immutable EMISSION_MANAGER; ILendingPoolAddressesProvider internal _addressProvider; mapping(address => AssetData) public assets; event AssetRegistered(address indexed asset, address indexed yieldAddress); event AssetIndexUpdated(address indexed asset, uint256 index, uint256 rewardsAmount); event UserIndexUpdated( address indexed user, address indexed asset, uint256 index, uint256 expectedRewardsAmount ); event RewardsReceived(address indexed asset, address indexed rewardToken, uint256 receivedAmount); event RewardsAccrued(address indexed user, address indexed asset, uint256 amount); event RewardsClaimed( address indexed asset, address indexed user, address indexed to, uint256 amount ); modifier onlyEmissionManager() { require(msg.sender == EMISSION_MANAGER, Errors.CALLER_NOT_EMISSION_MANAGER); _; } modifier onlyIncentiveController() { require( msg.sender == _addressProvider.getIncentiveController(), Errors.CALLER_NOT_INCENTIVE_CONTROLLER ); _; } constructor(address emissionManager) { EMISSION_MANAGER = emissionManager; } /** * @dev Initialize IStakedTokenIncentivesController * @param _provider the address of the corresponding addresses provider **/ function initialize(ILendingPoolAddressesProvider _provider) external initializer { _addressProvider = _provider; } /** * @dev Register an asset with vault which will keep some of yield for borrowers * @param asset The address of the reference asset * @param yieldAddress The address of the vault */ function registerAsset(address asset, address yieldAddress) external payable onlyEmissionManager { AssetData storage assetData = assets[asset]; address rewardToken = IncentiveVault(yieldAddress).getIncentiveToken(); require(assetData.yieldAddress == address(0), Errors.YD_VR_ASSET_ALREADY_IN_USE); require(rewardToken != address(0), Errors.YD_VR_INVALID_VAULT); uint256 totalStaked = IScaledBalanceToken(asset).scaledTotalSupply(); assetData.yieldAddress = yieldAddress; assetData.rewardToken = rewardToken; (uint256 lastAvailableRewards, uint256 increasedRewards) = _getAvailableRewardsAmount( assetData ); _updateAssetStateInternal( asset, assetData, totalStaked, lastAvailableRewards, increasedRewards ); emit AssetRegistered(asset, yieldAddress); } function receivedRewards(address asset, address rewardToken, uint256 amount) external { AssetData storage assetData = assets[asset]; address _rewardToken = assetData.rewardToken; address _yieldAddress = assetData.yieldAddress; uint256 lastAvailableRewards = assetData.lastAvailableRewards; require(msg.sender == _yieldAddress, Errors.YD_VR_CALLER_NOT_VAULT); require(_rewardToken != address(0), Errors.YD_VR_ASSET_NOT_REGISTERED); require(rewardToken == _rewardToken, Errors.YD_VR_REWARD_TOKEN_NOT_VALID); require(amount >= lastAvailableRewards, Errors.YD_VR_INVALID_REWARDS_AMOUNT); uint256 increasedRewards = amount - lastAvailableRewards; uint256 totalStaked = IScaledBalanceToken(asset).scaledTotalSupply(); _updateAssetStateInternal(asset, assetData, totalStaked, 0, increasedRewards); emit RewardsReceived(asset, rewardToken, amount); } function handleAction( address user, address asset, uint256 totalSupply, uint256 userBalance ) external payable onlyIncentiveController { uint256 accruedRewards = _updateUserAssetInternal(user, asset, userBalance, totalSupply); if (accruedRewards != 0) { emit RewardsAccrued(user, asset, accruedRewards); } } function getRewardsBalance( address[] calldata _assets, address _user ) external view returns (AggregatedRewardsData[] memory) { uint256 length = _assets.length; AggregatedRewardsData[] memory rewards = new AggregatedRewardsData[](length); for (uint256 i; i < length; ++i) { (uint256 stakedByUser, ) = IScaledBalanceToken(_assets[i]).getScaledUserBalanceAndSupply( _user ); rewards[i].asset = _assets[i]; (rewards[i].rewardToken, rewards[i].balance) = _getUnclaimedRewards( _user, _assets[i], stakedByUser ); } return rewards; } function claimRewards( address[] calldata _assets, uint256[] calldata _amounts, address _to ) external returns (uint256) { require(_to != address(0), 'INVALID_TO_ADDRESS'); require(_assets.length == _amounts.length, Errors.YD_VR_INVALID_REWARDS_AMOUNT); uint256 claimedAmount; for (uint256 i; i < _assets.length; ++i) { claimedAmount += _claimRewards(_assets[i], _amounts[i], msg.sender, _to); } return claimedAmount; } function getUserAssetData( address user, address asset ) public view returns (uint256, uint256, uint256) { UserData storage userData = assets[asset].users[user]; return (userData.index, userData.expectedRewards, userData.claimableRewards); } function getAssetData(address asset) public view returns (uint256, address, address, uint256) { return ( assets[asset].index, assets[asset].yieldAddress, assets[asset].rewardToken, assets[asset].lastAvailableRewards ); } /** * @dev returns the revision of the implementation contract */ function getRevision() internal pure override returns (uint256) { return REVISION; } /** * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. * @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 _claimRewards( address asset, uint256 amount, address user, address to ) internal returns (uint256) { if (amount == 0) { return 0; } AssetData storage assetData = assets[asset]; UserData storage userData = assetData.users[user]; address rewardToken = assetData.rewardToken; (uint256 stakedByUser, uint256 totalStaked) = IScaledBalanceToken(asset) .getScaledUserBalanceAndSupply(user); _updateUserAssetInternal(user, asset, stakedByUser, totalStaked); uint256 unclaimedRewards = userData.claimableRewards; if (unclaimedRewards == 0) { return 0; } uint256 amountToClaim = amount > unclaimedRewards ? unclaimedRewards : amount; IERC20 stakeToken = IERC20(rewardToken); if (stakeToken.balanceOf(address(this)) >= amountToClaim) { stakeToken.safeTransfer(to, amountToClaim); userData.claimableRewards = unclaimedRewards - amountToClaim; emit RewardsClaimed(asset, user, to, amountToClaim); } return amountToClaim; } /** * @dev Updates the state of one distribution, mainly rewards index and timestamp * @param asset The address of the asset being updated * @param assetData Storage pointer to the distribution's config * @param totalStaked Current total of staked assets for this distribution * @return The new distribution index **/ function _updateAssetStateInternal( address asset, AssetData storage assetData, uint256 totalStaked, uint256 lastAvailableRewards, uint256 increasedRewards ) internal returns (uint256) { uint256 oldIndex = assetData.index; uint256 oldAvailableRewards = assetData.lastAvailableRewards; uint256 newIndex = _getAssetIndex(oldIndex, increasedRewards, totalStaked); if (newIndex != oldIndex || lastAvailableRewards != oldAvailableRewards) { assetData.index = newIndex; assetData.lastAvailableRewards = lastAvailableRewards; if (lastAvailableRewards == 0) assetData.claimableIndex = newIndex; emit AssetIndexUpdated(asset, newIndex, lastAvailableRewards); } return newIndex; } /** * @dev Updates the state of an user in a distribution * @param user The user's address * @param asset The address of the reference asset of the distribution * @param stakedByUser Amount of tokens staked by the user in the distribution at the moment * @param totalStaked Total tokens staked in the distribution * @return The accrued rewards for the user until the moment **/ function _updateUserAssetInternal( address user, address asset, uint256 stakedByUser, uint256 totalStaked ) internal returns (uint256) { AssetData storage assetData = assets[asset]; UserData storage userData = assetData.users[user]; uint256 userIndex = userData.index; uint256 claimableIndex = assetData.claimableIndex; uint256 expectedRewards = userData.expectedRewards; uint256 claimableRewards = userData.claimableRewards; uint256 accruedRewards; (uint256 lastAvailableRewards, uint256 increasedRewards) = _getAvailableRewardsAmount( assetData ); uint256 newIndex = _updateAssetStateInternal( asset, assetData, totalStaked, lastAvailableRewards, increasedRewards ); if (userIndex == newIndex) return accruedRewards; if (claimableIndex >= userIndex) { claimableRewards += expectedRewards; expectedRewards = 0; } if (stakedByUser != 0) { if (claimableIndex >= userIndex) { claimableRewards += _getRewards(stakedByUser, claimableIndex, userIndex); accruedRewards = _getRewards(stakedByUser, newIndex, claimableIndex); } else { accruedRewards = _getRewards(stakedByUser, newIndex, userIndex); } expectedRewards += accruedRewards; } userData.index = newIndex; if (userData.expectedRewards != expectedRewards) userData.expectedRewards = expectedRewards; if (userData.claimableRewards != claimableRewards) userData.claimableRewards = claimableRewards; emit UserIndexUpdated(user, asset, newIndex, expectedRewards); return accruedRewards; } /** * @dev Return the accrued rewards for an user over a list of distribution * @param user The address of the user * @param asset The address of the asset * @param stakedByUser The balance of the user of the asset * @return rewardToken The address of the reward token * @return unclaimedRewards The accrued rewards for the user until the moment **/ function _getUnclaimedRewards( address user, address asset, uint256 stakedByUser ) internal view returns (address rewardToken, uint256 unclaimedRewards) { AssetData storage assetData = assets[asset]; rewardToken = assetData.rewardToken; uint256 claimableIndex = assetData.claimableIndex; UserData storage userData = assetData.users[user]; uint256 userIndex = userData.index; unclaimedRewards = userData.claimableRewards; if (claimableIndex >= userIndex) { unclaimedRewards += userData.expectedRewards; if (stakedByUser != 0) { unclaimedRewards += _getRewards(stakedByUser, claimableIndex, userIndex); } } } /** * @dev Internal function for the calculation of user's rewards on a distribution * @param principalUserBalance Amount staked by the user on a distribution * @param reserveIndex Current index of the distribution * @param userIndex Index stored for the user, representation his staking moment * @return The rewards **/ function _getRewards( uint256 principalUserBalance, uint256 reserveIndex, uint256 userIndex ) internal pure returns (uint256) { return (principalUserBalance * (reserveIndex - userIndex)) / 10 ** uint256(PRECISION); } /** * @dev Calculates the next value of an specific distribution index, with validations * @param currentIndex Current index of the distribution * @param increasedRewards Earned Amount * @param totalBalance of tokens considered for the distribution * @return The new index. **/ function _getAssetIndex( uint256 currentIndex, uint256 increasedRewards, uint256 totalBalance ) internal pure returns (uint256) { if (increasedRewards == 0 || totalBalance == 0) { return currentIndex; } return (increasedRewards * (10 ** uint256(PRECISION))) / totalBalance + currentIndex; } function _getAvailableRewardsAmount( AssetData storage assetData ) internal view returns (uint256 lastAvailableRewards, uint256 increasedRewards) { address vault = assetData.yieldAddress; uint256 oldAmount = assetData.lastAvailableRewards; lastAvailableRewards = IncentiveVault(vault).getCurrentTotalIncentiveAmount(); require(lastAvailableRewards >= oldAmount, Errors.YD_VR_INVALID_REWARDS_AMOUNT); increasedRewards = lastAvailableRewards - oldAmount; } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; interface IConvexBaseRewardPool { function earned(address account) external view returns (uint256); function withdrawAndUnwrap(uint256 amount, bool claim) external; function getReward(address _account, bool _claimExtras) external; function getReward() external; function rewardToken() external view returns (address); function extraRewardsLength() external view returns (uint256); function extraRewards(uint256) external view returns (address); function rewardRate() external view returns (uint256); function totalSupply() external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma abicoder v2; interface IConvexBooster { struct PoolInfo { address lptoken; address token; address gauge; address crvRewards; address stash; bool shutdown; } function minter() external view returns (address); function poolInfo(uint256 _poolId) external view returns (PoolInfo memory); function poolLength() external view returns (uint256); //deposit lp tokens and stake function deposit(uint256 _pid, uint256 _amount, bool _stake) external returns (bool); //withdraw lp tokens function withdraw(uint256 _pid, uint256 _amount) external returns (bool); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma abicoder v2; import {ILendingPoolAddressesProvider} from './ILendingPoolAddressesProvider.sol'; import {DataTypes} from '../protocol/libraries/types/DataTypes.sol'; interface ILendingPool { /** * @dev Emitted on deposit() * @param reserve The address of the underlying asset of the reserve * @param user The address initiating the deposit * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens * @param amount The amount deposited * @param referral The referral code used **/ event Deposit( address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, uint16 indexed referral ); /** * @dev Emitted on withdraw() * @param reserve The address of the underlyng asset being withdrawn * @param user The address initiating the withdrawal, owner of aTokens * @param to Address that will receive the underlying * @param amount The amount to be withdrawn **/ event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); /** * @dev Emitted on borrow() and flashLoan() when debt needs to be opened * @param reserve The address of the underlying asset being borrowed * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just * initiator of the transaction on flashLoan() * @param onBehalfOf The address that will be getting the debt * @param amount The amount borrowed out * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable * @param borrowRate The numeric rate at which the user has borrowed * @param referral The referral code used **/ event Borrow( address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, uint256 borrowRateMode, uint256 borrowRate, uint16 indexed referral ); /** * @dev Emitted on repay() * @param reserve The address of the underlying asset of the reserve * @param user The beneficiary of the repayment, getting his debt reduced * @param repayer The address of the user initiating the repay(), providing the funds * @param amount The amount repaid **/ event Repay( address indexed reserve, address indexed user, address indexed repayer, uint256 amount ); /** * @dev Emitted on setUserUseReserveAsCollateral() * @param reserve The address of the underlying asset of the reserve * @param user The address of the user enabling the usage as collateral **/ event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); /** * @dev Emitted on setUserUseReserveAsCollateral() * @param reserve The address of the underlying asset of the reserve * @param user The address of the user enabling the usage as collateral **/ event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); /** * @dev Emitted on flashLoan() * @param target The address of the flash loan receiver contract * @param initiator The address initiating the flash loan * @param asset The address of the asset being flash borrowed * @param amount The amount flash borrowed * @param premium The fee flash borrowed * @param referralCode The referral code used **/ event FlashLoan( address indexed target, address indexed initiator, address indexed asset, uint256 amount, uint256 premium, uint16 referralCode ); /** * @dev Emitted when the pause is triggered. */ event Paused(); /** * @dev Emitted when the pause is lifted. */ event Unpaused(); /** * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via * LendingPoolCollateral manager using a DELEGATECALL * This allows to have the events in the generated ABI for LendingPool. * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation * @param user The address of the borrower getting liquidated * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator * @param liquidator The address of the liquidator * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants * to receive the underlying collateral asset directly **/ event LiquidationCall( address indexed collateralAsset, address indexed debtAsset, address indexed user, uint256 debtToCover, uint256 liquidatedCollateralAmount, address liquidator, bool receiveAToken ); /** * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal, * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it * gets added to the LendingPool ABI * @param reserve The address of the underlying asset of the reserve * @param liquidityRate The new liquidity rate * @param stableBorrowRate The new stable borrow rate * @param variableBorrowRate The new variable borrow rate * @param liquidityIndex The new liquidity index * @param variableBorrowIndex The new variable borrow index **/ event ReserveDataUpdated( address indexed reserve, uint256 liquidityRate, uint256 stableBorrowRate, uint256 variableBorrowRate, uint256 liquidityIndex, uint256 variableBorrowIndex ); /** * @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 * - Caller is anyone. * @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 Deposits an `amount` of underlying asset into the reserve for supplier from vault * - Caller is only Vault which is registered in this contract * @param asset The address of the underlying asset to deposit * @param amount The amount to be deposited **/ function depositYield(address asset, uint256 amount) external; /** * @dev Grab an Yield `amount` of underlying asset into the vault * - Caller is only Vault which is registered in this contract * @param asset The address of the underlying asset to get yield * @param amount The yield amount **/ function getYield(address asset, uint256 amount) external; /** * @dev Get underlying asset and aToken's total balance * @param asset The address of the underlying asset **/ function getTotalBalanceOfAssetPair(address asset) external view returns (uint256, uint256); /** * @dev Get total underlying asset which is borrowable * and also list of underlying asset **/ function getBorrowingAssetAndVolumes() external view returns (uint256, uint256[] memory, address[] memory, uint256); /** * @dev Register the vault address * - To check if the caller is vault for some functions * - Caller is only LendingPoolConfigurator * @param _vaultAddress The address of the Vault **/ function registerVault(address _vaultAddress) external payable; /** * @dev Unregister the vault address * - To check if the caller is vault for some functions * - Caller is only LendingPoolConfigurator * @param _vaultAddress The address of the Vault **/ function unregisterVault(address _vaultAddress) external payable; /** * @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 * - Caller is anyone * @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 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 * - Caller is anyone * @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 from The address of user who is depositor of underlying asset * @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 withdrawFrom( address asset, uint256 amount, address from, address to ) external returns (uint256); /** * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower * already deposited enough collateral, or he was given enough allowance by a credit delegator on the * corresponding debt token (StableDebtToken or VariableDebtToken) * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet * and 100 stable/variable debt tokens, depending on the `interestRateMode` * - Caller is anyone * @param asset The address of the underlying asset to borrow * @param amount The amount to be borrowed * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable * @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 * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator * if he has been given credit delegation allowance **/ function borrow( address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf ) external; /** * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address * - Caller is anyone * @param asset The address of the borrowed underlying asset previously borrowed * @param amount The amount to repay * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the * user calling the function if he wants to reduce/remove his own debt, or the address of any other * other borrower whose debt should be removed * @return The final amount repaid **/ function repay( address asset, uint256 amount, uint256 rateMode, address onBehalfOf ) external returns (uint256); /** * @dev Allows depositors to enable/disable a specific deposited asset as collateral * @param asset The address of the underlying asset deposited * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise **/ function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; /** * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk * - Caller is anyone * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation * @param user The address of the borrower getting liquidated * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants * to receive the underlying collateral asset directly **/ function liquidationCall( address collateralAsset, address debtAsset, address user, uint256 debtToCover, bool receiveAToken ) external; /** * @dev Returns the user account data across all the reserves * @param user The address of the user * @return totalCollateralETH the total collateral in ETH of the user * @return totalDebtETH the total debt in ETH of the user * @return availableBorrowsETH the borrowing power left of the user * @return currentLiquidationThreshold the liquidation threshold of the user * @return ltv the loan to value of the user * @return healthFactor the current health factor of the user **/ function getUserAccountData( address user ) external view returns ( uint256 totalCollateralETH, uint256 totalDebtETH, uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor ); /** * @dev Initializes a reserve, activating it, assigning an aToken and debt tokens and an * interest rate strategy * - Only callable by the LendingPoolConfigurator contract * - Caller is only LendingPoolConfigurator * @param reserve The address of the underlying asset of the reserve * @param yieldAddress The address of the underlying asset's yield contract of the reserve * @param aTokenAddress The address of the aToken that will be assigned to the reserve * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve * @param interestRateStrategyAddress The address of the interest rate strategy contract **/ function initReserve( address reserve, address yieldAddress, address aTokenAddress, address stableDebtAddress, address variableDebtAddress, address interestRateStrategyAddress ) external payable; /** * @dev Updates the address of the interest rate strategy contract * - Caller is only LendingPoolConfigurator * @param reserve The address of the underlying asset of the reserve * @param rateStrategyAddress The address of the interest rate strategy contract **/ function setReserveInterestRateStrategyAddress( address reserve, address rateStrategyAddress ) external payable; /** * @dev Sets the configuration bitmap of the reserve as a whole * - Caller is only LendingPoolConfigurator * @param reserve The address of the underlying asset of the reserve * @param configuration The new configuration bitmap **/ function setConfiguration(address reserve, uint256 configuration) external payable; /** * @dev Returns the configuration of the reserve * @param asset The address of the underlying asset of the reserve * @return The configuration of the reserve **/ function getConfiguration( address asset ) external view returns (DataTypes.ReserveConfigurationMap memory); /** * @dev Returns the configuration of the user across all the reserves * @param user The user address * @return The configuration of the user **/ function getUserConfiguration( address user ) external view returns (DataTypes.UserConfigurationMap memory); /** * @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 variable debt per unit of asset * @param asset The address of the underlying asset of the reserve * @return The reserve normalized variable debt */ function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); /** * @dev Returns the state and configuration of the reserve * @param asset The address of the underlying asset of the reserve * @return The state of the reserve **/ function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); /** * @dev Validates and finalizes an aToken transfer * - Only callable by the overlying aToken of the `asset` * - Caller is only aToken contract which is storing the underlying asset of depositors * @param asset The address of the underlying asset of the aToken * @param from The user from which the aTokens are transferred * @param to The user receiving the aTokens * @param amount The amount being transferred/withdrawn * @param balanceFromAfter The aToken balance of the `from` user before the transfer * @param balanceToBefore The aToken balance of the `to` user before the transfer */ function finalizeTransfer( address asset, address from, address to, uint256 amount, uint256 balanceFromAfter, uint256 balanceToBefore ) external; /** * @dev Returns the list of the initialized reserves **/ function getReservesList() external view returns (address[] memory); /** * @dev Returns the cached LendingPoolAddressesProvider connected to this contract **/ function getAddressesProvider() external view returns (ILendingPoolAddressesProvider); /** * @dev Set the _pause state of a reserve * - Caller is only LendingPoolConfigurator * @param val `true` to pause the reserve, `false` to un-pause it */ function setPause(bool val) external payable; /** * @dev Returns if the LendingPool is paused */ function paused() external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; /** * @title LendingPoolAddressesProvider contract * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles * - Acting also as factory of proxies and admin of those, so with right to change its implementations * - Owned by the Sturdy Governance * @author Sturdy, inspiration from Aave **/ interface ILendingPoolAddressesProvider { event MarketIdSet(string newMarketId); event LendingPoolUpdated(address indexed newAddress); event IncentiveControllerUpdated(address indexed newAddress); event IncentiveTokenUpdated(address indexed newAddress); event ConfigurationAdminUpdated(address indexed newAddress); event EmergencyAdminUpdated(address indexed newAddress); event LendingPoolConfiguratorUpdated(address indexed newAddress); event LendingPoolCollateralManagerUpdated(address indexed newAddress); event PriceOracleUpdated(address indexed newAddress); event LendingRateOracleUpdated(address indexed newAddress); event ProxyCreated(bytes32 id, address indexed newAddress); event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy); function getMarketId() external view returns (string memory); function setMarketId(string calldata marketId) external payable; function setAddress(bytes32 id, address newAddress) external payable; function setAddressAsProxy(bytes32 id, address impl) external payable; function getAddress(bytes32 id) external view returns (address); function getLendingPool() external view returns (address); function setLendingPoolImpl(address pool) external payable; function getIncentiveController() external view returns (address); function setIncentiveControllerImpl(address incentiveController) external payable; function getIncentiveToken() external view returns (address); function setIncentiveTokenImpl(address incentiveToken) external payable; function getLendingPoolConfigurator() external view returns (address); function setLendingPoolConfiguratorImpl(address configurator) external payable; function getLendingPoolCollateralManager() external view returns (address); function setLendingPoolCollateralManager(address manager) external payable; function getPoolAdmin() external view returns (address); function setPoolAdmin(address admin) external payable; function getEmergencyAdmin() external view returns (address); function setEmergencyAdmin(address admin) external payable; function getPriceOracle() external view returns (address); function setPriceOracle(address priceOracle) external payable; function getLendingRateOracle() external view returns (address); function setLendingRateOracle(address lendingRateOracle) external payable; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; interface IScaledBalanceToken { /** * @dev Returns the scaled balance of the user. The scaled balance is the sum of all the * updated stored balance divided by the reserve's liquidity index at the moment of the update * @param user The user whose balance is calculated * @return The scaled balance of the user **/ function scaledBalanceOf(address user) external view returns (uint256); /** * @dev Returns the scaled balance of the user and the scaled total supply. * @param user The address of the user * @return The scaled balance of the user * @return The scaled balance and the scaled total supply **/ function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256); /** * @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index) * @return The scaled total supply **/ function scaledTotalSupply() external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma abicoder v2; struct UserData { uint256 index; uint256 expectedRewards; uint256 claimableRewards; } struct AssetData { uint256 index; uint256 lastAvailableRewards; address rewardToken; // The address of reward token address yieldAddress; // The address of vault mapping(address => UserData) users; uint256 claimableIndex; } struct AggregatedRewardsData { address asset; address rewardToken; uint256 balance; } interface IVariableYieldDistribution { function claimRewards( address[] calldata assets, uint256[] calldata amounts, address to ) external returns (uint256); function getRewardsBalance( address[] calldata assets, address user ) external view returns (AggregatedRewardsData[] memory); function getAssetData(address asset) external view returns (uint256, address, address, uint256); function getUserAssetData( address user, address asset ) external view returns (uint256, uint256, uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; interface IVaultWhitelist { function whitelistUser(address vault, address user) external view returns (bool); function whitelistUserCount(address vault) external view returns (uint256); function whitelistContract(address vault, address sender) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; /** * @title Errors library * @author Sturdy, inspiration from Aave * @notice Defines the error messages emitted by the different contracts of the Sturdy protocol * @dev Error messages prefix glossary: * - VL = ValidationLogic * - MATH = Math libraries * - CT = Common errors between tokens (AToken, VariableDebtToken and StableDebtToken) * - AT = AToken * - SAT = StaticAToken * - SDT = StableDebtToken * - VDT = VariableDebtToken * - LP = LendingPool * - LPAPR = LendingPoolAddressesProviderRegistry * - LPC = LendingPoolConfiguration * - RL = ReserveLogic * - LPCM = LendingPoolCollateralManager * - P = Pausable */ library Errors { //common errors string internal constant CALLER_NOT_POOL_ADMIN = '33'; // 'The caller must be the pool admin' string internal constant BORROW_ALLOWANCE_NOT_ENOUGH = '59'; // User borrows on behalf, but allowance are too small //contract specific errors string internal constant VL_INVALID_AMOUNT = '1'; // 'Amount must be greater than 0' string internal constant VL_NO_ACTIVE_RESERVE = '2'; // 'Action requires an active reserve' string internal constant VL_RESERVE_FROZEN = '3'; // 'Action cannot be performed because the reserve is frozen' string internal constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = '4'; // 'The current liquidity is not enough' string internal constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = '5'; // 'User cannot withdraw more than the available balance' string internal constant VL_TRANSFER_NOT_ALLOWED = '6'; // 'Transfer cannot be allowed.' string internal constant VL_BORROWING_NOT_ENABLED = '7'; // 'Borrowing is not enabled' string internal constant VL_INVALID_INTEREST_RATE_MODE_SELECTED = '8'; // 'Invalid interest rate mode selected' string internal constant VL_COLLATERAL_BALANCE_IS_0 = '9'; // 'The collateral balance is 0' string internal constant VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '10'; // 'Health factor is lesser than the liquidation threshold' string internal constant VL_COLLATERAL_CANNOT_COVER_NEW_BORROW = '11'; // 'There is not enough collateral to cover a new borrow' string internal constant VL_STABLE_BORROWING_NOT_ENABLED = '12'; // stable borrowing not enabled string internal constant VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY = '13'; // collateral is (mostly) the same currency that is being borrowed string internal constant VL_AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '14'; // 'The requested amount is greater than the max loan size in stable rate mode string internal constant VL_NO_DEBT_OF_SELECTED_TYPE = '15'; // 'for repayment of stable debt, the user needs to have stable debt, otherwise, he needs to have variable debt' string internal constant VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '16'; // 'To repay on behalf of an user an explicit amount to repay is needed' string internal constant VL_NO_STABLE_RATE_LOAN_IN_RESERVE = '17'; // 'User does not have a stable rate loan in progress on this reserve' string internal constant VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE = '18'; // 'User does not have a variable rate loan in progress on this reserve' string internal constant VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = '19'; // 'The underlying balance needs to be greater than 0' string internal constant VL_DEPOSIT_ALREADY_IN_USE = '20'; // 'User deposit is already being used as collateral' string internal constant LP_NOT_ENOUGH_STABLE_BORROW_BALANCE = '21'; // 'User does not have any stable rate loan for this reserve' string internal constant LP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '22'; // 'Interest rate rebalance conditions were not met' string internal constant LP_LIQUIDATION_CALL_FAILED = '23'; // 'Liquidation call failed' string internal constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = '24'; // 'There is not enough liquidity available to borrow' string internal constant LP_REQUESTED_AMOUNT_TOO_SMALL = '25'; // 'The requested amount is too small for a FlashLoan.' string internal constant LP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26'; // 'The actual balance of the protocol is inconsistent' string internal constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The caller of the function is not the lending pool configurator' string internal constant LP_INCONSISTENT_FLASHLOAN_PARAMS = '28'; string internal constant CT_CALLER_MUST_BE_LENDING_POOL = '29'; // 'The caller of this function must be a lending pool' string internal constant CT_CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = '30'; // 'User cannot give allowance to himself' string internal constant CT_TRANSFER_AMOUNT_NOT_GT_0 = '31'; // 'Transferred amount needs to be greater than zero' string internal constant RL_RESERVE_ALREADY_INITIALIZED = '32'; // 'Reserve has already been initialized' string internal constant LPC_RESERVE_LIQUIDITY_NOT_0 = '34'; // 'The liquidity of the reserve needs to be 0' string internal constant LPC_INVALID_ATOKEN_POOL_ADDRESS = '35'; // 'The liquidity of the reserve needs to be 0' string internal constant LPC_INVALID_STABLE_DEBT_TOKEN_POOL_ADDRESS = '36'; // 'The liquidity of the reserve needs to be 0' string internal constant LPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS = '37'; // 'The liquidity of the reserve needs to be 0' string internal constant LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '38'; // 'The liquidity of the reserve needs to be 0' string internal constant LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '39'; // 'The liquidity of the reserve needs to be 0' string internal constant LPC_INVALID_ADDRESSES_PROVIDER_ID = '40'; // 'The liquidity of the reserve needs to be 0' string internal constant LPC_INVALID_CONFIGURATION = '75'; // 'Invalid risk parameters for the reserve' string internal constant LPC_CALLER_NOT_EMERGENCY_ADMIN = '76'; // 'The caller must be the emergency admin' string internal constant LPAPR_PROVIDER_NOT_REGISTERED = '41'; // 'Provider is not registered' string internal constant LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '42'; // 'Health factor is not below the threshold' string internal constant LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = '43'; // 'The collateral chosen cannot be liquidated' string internal constant LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '44'; // 'User did not borrow the specified currency' string internal constant LPCM_NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = '45'; // "There isn't enough liquidity available to liquidate" string internal constant LPCM_NO_ERRORS = '46'; // 'No errors' string internal constant LP_INVALID_FLASHLOAN_MODE = '47'; //Invalid flashloan mode selected string internal constant MATH_MULTIPLICATION_OVERFLOW = '48'; string internal constant MATH_ADDITION_OVERFLOW = '49'; string internal constant MATH_DIVISION_BY_ZERO = '50'; string internal constant RL_LIQUIDITY_INDEX_OVERFLOW = '51'; // Liquidity index overflows uint128 string internal constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = '52'; // Variable borrow index overflows uint128 string internal constant RL_LIQUIDITY_RATE_OVERFLOW = '53'; // Liquidity rate overflows uint128 string internal constant RL_VARIABLE_BORROW_RATE_OVERFLOW = '54'; // Variable borrow rate overflows uint128 string internal constant RL_STABLE_BORROW_RATE_OVERFLOW = '55'; // Stable borrow rate overflows uint128 string internal constant CT_INVALID_MINT_AMOUNT = '56'; //invalid amount to mint string internal constant LP_FAILED_REPAY_WITH_COLLATERAL = '57'; string internal constant CT_INVALID_BURN_AMOUNT = '58'; //invalid amount to burn string internal constant LP_FAILED_COLLATERAL_SWAP = '60'; string internal constant LP_INVALID_EQUAL_ASSETS_TO_SWAP = '61'; string internal constant LP_REENTRANCY_NOT_ALLOWED = '62'; string internal constant LP_CALLER_MUST_BE_AN_ATOKEN = '63'; string internal constant LP_IS_PAUSED = '64'; // 'Pool is paused' string internal constant LP_NO_MORE_RESERVES_ALLOWED = '65'; string internal constant LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN = '66'; string internal constant RC_INVALID_LTV = '67'; string internal constant RC_INVALID_LIQ_THRESHOLD = '68'; string internal constant RC_INVALID_LIQ_BONUS = '69'; string internal constant RC_INVALID_DECIMALS = '70'; string internal constant RC_INVALID_RESERVE_FACTOR = '71'; string internal constant LPAPR_INVALID_ADDRESSES_PROVIDER_ID = '72'; string internal constant VL_INCONSISTENT_FLASHLOAN_PARAMS = '73'; string internal constant LP_INCONSISTENT_PARAMS_LENGTH = '74'; string internal constant UL_INVALID_INDEX = '77'; string internal constant LP_NOT_CONTRACT = '78'; string internal constant SDT_STABLE_DEBT_OVERFLOW = '79'; string internal constant SDT_BURN_EXCEEDS_BALANCE = '80'; string internal constant VT_COLLATERAL_DEPOSIT_REQUIRE_ETH = '81'; //Only accept ETH for collateral deposit string internal constant VT_COLLATERAL_DEPOSIT_INVALID = '82'; //Collateral deposit failed string internal constant VT_LIQUIDITY_DEPOSIT_INVALID = '83'; //Only accept USDC, USDT, DAI for liquidity deposit string internal constant VT_COLLATERAL_WITHDRAW_INVALID = '84'; //Collateral withdraw failed string internal constant VT_COLLATERAL_WITHDRAW_INVALID_AMOUNT = '85'; //Collateral withdraw has not enough amount string internal constant VT_CONVERT_ASSET_BY_CURVE_INVALID = '86'; //Convert asset by curve invalid string internal constant VT_PROCESS_YIELD_INVALID = '87'; //Processing yield is invalid string internal constant VT_TREASURY_INVALID = '88'; //Treasury is invalid string internal constant LP_ATOKEN_INIT_INVALID = '89'; //aToken invalid init string internal constant VT_FEE_TOO_BIG = '90'; //Fee is too big string internal constant VT_COLLATERAL_DEPOSIT_VAULT_UNAVAILABLE = '91'; string internal constant LP_LIQUIDATION_CONVERT_FAILED = '92'; string internal constant VT_DEPLOY_FAILED = '93'; // Vault deploy failed string internal constant VT_INVALID_CONFIGURATION = '94'; // Invalid vault configuration string internal constant VL_OVERFLOW_MAX_RESERVE_CAPACITY = '95'; // overflow max capacity of reserve string internal constant VT_WITHDRAW_AMOUNT_MISMATCH = '96'; // not performed withdraw 100% string internal constant VT_SWAP_MISMATCH_RETURNED_AMOUNT = '97'; //Returned amount is not enough string internal constant CALLER_NOT_YIELD_PROCESSOR = '98'; // 'The caller must be the pool admin' string internal constant VT_EXTRA_REWARDS_INDEX_INVALID = '97'; // Invalid extraRewards index string internal constant VT_SWAP_PATH_LENGTH_INVALID = '100'; // Invalid token or fee length string internal constant VT_SWAP_PATH_TOKEN_INVALID = '101'; // Invalid token information string internal constant CLAIMER_UNAUTHORIZED = '102'; // 'The claimer is not authorized' string internal constant YD_INVALID_CONFIGURATION = '103'; // 'The yield distribution's invalid configuration' string internal constant CALLER_NOT_EMISSION_MANAGER = '104'; // 'The caller must be emission manager' string internal constant CALLER_NOT_INCENTIVE_CONTROLLER = '105'; // 'The caller must be incentive controller' string internal constant YD_VR_ASSET_ALREADY_IN_USE = '106'; // Vault is already registered string internal constant YD_VR_INVALID_VAULT = '107'; // Invalid vault is used for an asset string internal constant YD_VR_INVALID_REWARDS_AMOUNT = '108'; // Rewards amount should be bigger than before string internal constant YD_VR_REWARD_TOKEN_NOT_VALID = '109'; // The reward token must be same with configured address string internal constant YD_VR_ASSET_NOT_REGISTERED = '110'; string internal constant YD_VR_CALLER_NOT_VAULT = '111'; // The caller must be same with configured vault address string internal constant LS_INVALID_CONFIGURATION = '112'; // Invalid Leverage Swapper configuration string internal constant LS_SWAP_AMOUNT_NOT_GT_0 = '113'; // Collateral amount needs to be greater than zero string internal constant LS_STABLE_COIN_NOT_SUPPORTED = '114'; // Doesn't support swap for the stable coin string internal constant LS_SUPPLY_NOT_ALLOWED = '115'; // no sufficient funds string internal constant LS_SUPPLY_FAILED = '116'; // Deposit fails when leverage works string internal constant LS_REMOVE_ITERATION_OVER = '117'; // Withdraw iteration limit over string internal constant CALLER_NOT_WHITELIST_USER = '118'; // 'The caller must be whitelist user' string internal constant SAT_INVALID_OWNER = '119'; string internal constant SAT_INVALID_EXPIRATION = '120'; string internal constant SAT_INVALID_SIGNATURE = '121'; string internal constant SAT_INVALID_DEPOSITOR = '122'; string internal constant SAT_INVALID_RECIPIENT = '123'; string internal constant SAT_ONLY_ONE_AMOUNT_FORMAT_ALLOWED = '125'; string internal constant LS_REPAY_FAILED = '126'; enum CollateralManagerErrors { NO_ERROR, NO_COLLATERAL_AVAILABLE, COLLATERAL_CANNOT_BE_LIQUIDATED, CURRRENCY_NOT_BORROWED, HEALTH_FACTOR_ABOVE_THRESHOLD, NOT_ENOUGH_LIQUIDITY, NO_ACTIVE_RESERVE, HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD, INVALID_EQUAL_ASSETS_TO_SWAP, FROZEN_RESERVE } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import {Errors} from '../helpers/Errors.sol'; /** * @title PercentageMath library * @author Sturdy, inspiration from Aave * @notice Provides functions to perform percentage calculations * @dev Percentages are defined by default with 2 decimals of precision (100.00). The precision is indicated by PERCENTAGE_FACTOR * @dev Operations are rounded half up **/ library PercentageMath { uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2; /** * @dev Executes a percentage multiplication * @param value The value of which the percentage needs to be calculated * @param percentage The percentage of the value to be calculated * @return The percentage of value **/ function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) { if (value == 0 || percentage == 0) { return 0; } return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR; } /** * @dev Executes a percentage division * @param value The value of which the percentage needs to be calculated * @param percentage The percentage of the value to be calculated * @return The value divided the percentage **/ function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) { uint256 halfPercentage = percentage / 2; return (value * PERCENTAGE_FACTOR + halfPercentage) / percentage; } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; /** * @title VersionedInitializable * * @dev Helper contract to implement initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. * * @author Sturdy, inspiration from Aave */ abstract contract VersionedInitializable { /** * @dev Indicates that the contract has been initialized. */ uint256 private lastInitializedRevision; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { uint256 revision = getRevision(); require( initializing || isConstructor() || revision > lastInitializedRevision, 'Contract instance has already been initialized' ); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; lastInitializedRevision = revision; } _; if (isTopLevelCall) { initializing = false; } } /** * @dev returns the revision number of the contract * Needs to be defined in the inherited class as a constant. * @return The revision number **/ function getRevision() internal pure virtual returns (uint256); /** * @dev Returns true if and only if the function is running in the constructor * @return `true` only if the function is running in the constructor **/ function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. uint256 cs; //solium-disable-next-line assembly { cs := extcodesize(address()) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; library DataTypes { // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties. struct ReserveData { //stores the reserve configuration ReserveConfigurationMap 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; //address of the yield contract address yieldAddress; //the id of the reserve. Represents the position in the list of the active reserves uint8 id; } struct ReserveConfigurationMap { //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 data; } struct UserConfigurationMap { uint256 data; } enum InterestRateMode { NONE, STABLE, VARIABLE } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma abicoder v2; import {ERC20} from '../../dependencies/openzeppelin/contracts/ERC20.sol'; import {Ownable} from '../../dependencies/openzeppelin/contracts/Ownable.sol'; /** * @notice implementation of the internal asset token contract * @author Sturdy */ contract SturdyInternalAsset is ERC20, Ownable { constructor(string memory name, string memory symbol, uint8 decimals) ERC20(name, symbol) { _setupDecimals(decimals); } /** * @dev Function to mint token * Caller is only owner which is vault address * @param user The user which token is mint * @param amount The amount of tokens to mint. * @return A boolean that indicates if the operation was successful. */ function mint(address user, uint256 amount) external payable onlyOwner returns (bool) { _mint(user, amount); return true; } /** * @dev Function to burn token * Caller is only owner which is vault address * @param user The user which token is burned * @param amount The amount of tokens to burn */ function burn(address user, uint256 amount) external payable onlyOwner { _burn(user, amount); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; pragma abicoder v2; import {ILendingPool} from '../../interfaces/ILendingPool.sol'; import {PercentageMath} from '../libraries/math/PercentageMath.sol'; import {Errors} from '../libraries/helpers/Errors.sol'; import {VersionedInitializable} from '../../protocol/libraries/sturdy-upgradeability/VersionedInitializable.sol'; import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol'; import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; import {IVaultWhitelist} from '../../interfaces/IVaultWhitelist.sol'; import {Address} from '../../dependencies/openzeppelin/contracts/Address.sol'; /** * @title GeneralVault * @notice Basic feature of vault * @author Sturdy **/ abstract contract GeneralVault is VersionedInitializable { using PercentageMath for uint256; /** * @dev Emitted on processYield() * @param collateralAsset The address of the collateral asset * @param yieldAmount The processed yield amount **/ event ProcessYield(address indexed collateralAsset, uint256 yieldAmount); /** * @dev Emitted on depositCollateral() * @param collateralAsset The address of the collateral asset * @param from The address of depositor * @param amount The deposit amount **/ event DepositCollateral(address indexed collateralAsset, address indexed from, uint256 amount); /** * @dev Emitted on withdrawCollateral() * @param collateralAsset The address of the collateral asset * @param to The address of receiving collateral * @param amount The withdrawal amount **/ event WithdrawCollateral(address indexed collateralAsset, address indexed to, uint256 amount); /** * @dev Emitted on setTreasuryInfo() * @param treasuryAddress The address of treasury * @param fee The vault fee **/ event SetTreasuryInfo(address indexed treasuryAddress, uint256 fee); modifier onlyAdmin() { require(_addressesProvider.getPoolAdmin() == msg.sender, Errors.CALLER_NOT_POOL_ADMIN); _; } modifier onlyYieldProcessor() { require( _addressesProvider.getAddress('YIELD_PROCESSOR') == msg.sender, Errors.CALLER_NOT_YIELD_PROCESSOR ); _; } struct AssetYield { address asset; uint256 amount; } ILendingPoolAddressesProvider internal _addressesProvider; // vault fee 20% uint256 internal _vaultFee; address internal _treasuryAddress; uint256 private constant VAULT_REVISION = 0x3; address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; IVaultWhitelist internal constant VAULT_WHITELIST = IVaultWhitelist(0x88eE44794bAf865E3b0b192d1F9f0AC3Daf1EA0E); /** * @dev Function is invoked by the proxy contract when the Vault contract is deployed. * - Caller is initializer (LendingPoolAddressesProvider or deployer) * @param _provider The address of the provider **/ function initialize(ILendingPoolAddressesProvider _provider) external initializer { require(address(_provider) != address(0), Errors.VT_INVALID_CONFIGURATION); _addressesProvider = _provider; } function getRevision() internal pure override returns (uint256) { return VAULT_REVISION; } /** * @dev Deposits an `_amount` of asset as collateral to borrow other asset. * - Caller is anyone * @param _asset The address for collateral external asset * _asset = 0x0000000000000000000000000000000000000000 means to use ETH as collateral * @param _amount The deposit amount */ function depositCollateral(address _asset, uint256 _amount) external payable virtual { _deposit(_asset, _amount, msg.sender); } /** * @dev Deposits an `_amount` of asset as collateral to borrow other asset. * - Caller is anyone * @param _asset The address for collateral external asset * _asset = 0x0000000000000000000000000000000000000000 means to use ETH as collateral * @param _amount The deposit amount * @param _user The depositor address */ function depositCollateralFrom( address _asset, uint256 _amount, address _user ) external payable virtual { _deposit(_asset, _amount, _user); } /** * @dev Withdraw an `_amount` of asset used as collateral to user. * - Caller is anyone * @param _asset The address for collateral external asset * _asset = 0x0000000000000000000000000000000000000000 means to use ETH as collateral * @param _amount The collateral external asset's amount to be withdrawn * @param _slippage The slippage of the withdrawal amount. 1% = 100 * @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 */ function withdrawCollateral( address _asset, uint256 _amount, uint256 _slippage, address _to ) external virtual { // whitelist checking if (Address.isContract(msg.sender)) { require( VAULT_WHITELIST.whitelistContract(address(this), msg.sender), Errors.CALLER_NOT_WHITELIST_USER ); } else if (VAULT_WHITELIST.whitelistUserCount(address(this)) > 0) { require( VAULT_WHITELIST.whitelistUser(address(this), msg.sender), Errors.CALLER_NOT_WHITELIST_USER ); } // Before withdraw from lending pool, get the stAsset address and withdrawal amount // Ex: In Lido vault, it will return stETH address and same amount (address _stAsset, uint256 _stAssetAmount) = _getWithdrawalAmount(_asset, _amount); // withdraw from lendingPool, it will convert user's aToken to stAsset uint256 _amountToWithdraw = ILendingPool(_addressesProvider.getLendingPool()).withdrawFrom( _stAsset, _stAssetAmount, msg.sender, address(this) ); // Withdraw from vault, it will convert stAsset to asset and send to user // Ex: In Lido vault, it will return ETH or stETH to user uint256 withdrawAmount = _withdrawFromYieldPool(_asset, _amountToWithdraw, _to); if (_amount == type(uint256).max) { uint256 decimal; if (_asset == address(0)) { decimal = 18; } else { decimal = IERC20Detailed(_asset).decimals(); } _amount = (_amountToWithdraw * this.pricePerShare()) / 10 ** decimal; } require( withdrawAmount >= _amount.percentMul(PercentageMath.PERCENTAGE_FACTOR - _slippage), Errors.VT_WITHDRAW_AMOUNT_MISMATCH ); emit WithdrawCollateral(_asset, _to, _amount); } /** * @dev Convert an `_amount` of collateral internal asset to collateral external asset and send to caller on liquidation. * - Caller is only LendingPool * @param _asset The address of collateral external asset * _asset = 0x0000000000000000000000000000000000000000 means to use ETH as collateral * @param _amount The amount of collateral internal asset * @return The amount of collateral external asset */ function withdrawOnLiquidation( address _asset, uint256 _amount ) external virtual returns (uint256); /** * @dev Get yield based on strategy and re-deposit * - Caller is anyone */ function processYield() external virtual; /** * @dev Get price per share based on yield strategy * @return The value of price per share */ function pricePerShare() external view virtual returns (uint256); /** * @dev Get vault Yield per year with wad decimal(=18) * @return The vault yield value per year */ function vaultYieldInPrice() external view virtual returns (uint256) { return 0; } /** * @dev Set treasury address and vault fee * - Caller is only PoolAdmin which is set on LendingPoolAddressesProvider contract * @param _treasury The treasury address * @param _fee The vault fee which has more two decimals, ex: 100% = 100_00 */ function setTreasuryInfo(address _treasury, uint256 _fee) external payable onlyAdmin { require(_treasury != address(0), Errors.VT_TREASURY_INVALID); require(_fee <= 30_00, Errors.VT_FEE_TOO_BIG); _treasuryAddress = _treasury; _vaultFee = _fee; emit SetTreasuryInfo(_treasury, _fee); } /** * @dev deposit collateral asset to lending pool * @param _asset The address of collateral external asset * @param _amount Collateral external asset amount * @param _user The address of user */ function _deposit(address _asset, uint256 _amount, address _user) internal { // whitelist checking if (Address.isContract(msg.sender)) { require( VAULT_WHITELIST.whitelistContract(address(this), msg.sender), Errors.CALLER_NOT_WHITELIST_USER ); } else if (VAULT_WHITELIST.whitelistUserCount(address(this)) > 0) { require( VAULT_WHITELIST.whitelistUser(address(this), _user), Errors.CALLER_NOT_WHITELIST_USER ); } if (_asset != address(0)) { // asset = ERC20 require(msg.value == 0, Errors.VT_COLLATERAL_DEPOSIT_INVALID); } else { // asset = ETH require(msg.value == _amount, Errors.VT_COLLATERAL_DEPOSIT_REQUIRE_ETH); } // Deposit asset to vault and receive stAsset // Ex: if user deposit 100ETH, this will deposit 100ETH to Lido and receive 100stETH (address _stAsset, uint256 _stAssetAmount) = _depositToYieldPool(_asset, _amount); // Deposit stAsset to lendingPool, then user will get aToken of stAsset ILendingPool(_addressesProvider.getLendingPool()).deposit(_stAsset, _stAssetAmount, _user, 0); emit DepositCollateral(_asset, _user, _amount); } /** * @dev Get yield based on strategy and re-deposit * @param _stAsset The address of collateral internal asset * @return yield amount of collateral internal asset */ function _getYield(address _stAsset) internal returns (uint256) { uint256 yieldStAsset = _getYieldAmount(_stAsset); require(yieldStAsset != 0, Errors.VT_PROCESS_YIELD_INVALID); ILendingPool(_addressesProvider.getLendingPool()).getYield(_stAsset, yieldStAsset); return yieldStAsset; } /** * @dev Get yield amount based on strategy * @param _stAsset The address of collateral internal asset * @return yield amount of collateral internal asset */ function _getYieldAmount(address _stAsset) internal view returns (uint256) { (uint256 stAssetBalance, uint256 aTokenBalance) = ILendingPool( _addressesProvider.getLendingPool() ).getTotalBalanceOfAssetPair(_stAsset); // when deposit for collateral, stAssetBalance = aTokenBalance // But stAssetBalance should increase overtime, so vault can grab yield from lendingPool. // yield = stAssetBalance - aTokenBalance if (stAssetBalance > aTokenBalance) return stAssetBalance - aTokenBalance; return 0; } /** * @dev Deposit collateral external asset to yield pool based on strategy and receive collateral internal asset * @param _asset The address of collateral external asset * @param _amount The amount of collateral external asset * @return The address of collateral internal asset * @return The amount of collateral internal asset */ function _depositToYieldPool( address _asset, uint256 _amount ) internal virtual returns (address, uint256); /** * @dev Withdraw collateral internal asset from yield pool based on strategy and deliver collateral external asset * @param _asset The address of collateral external asset * @param _amount The withdrawal amount of collateral internal asset * @param _to The address of receiving collateral external asset * @return The amount of collateral external asset */ function _withdrawFromYieldPool( address _asset, uint256 _amount, address _to ) internal virtual returns (uint256); /** * @dev Get Withdrawal amount of collateral internal asset based on strategy * @param _asset The address of collateral external asset * @param _amount The withdrawal amount of collateral external asset * @return The address of collateral internal asset * @return The withdrawal amount of collateral internal asset */ function _getWithdrawalAmount( address _asset, uint256 _amount ) internal view virtual returns (address, uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import {GeneralVault} from './GeneralVault.sol'; import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol'; import {Errors} from '../libraries/helpers/Errors.sol'; import {VariableYieldDistribution} from '../../incentives/VariableYieldDistribution.sol'; /** * @title IncentiveVault * @notice Basic incentive feature of vault * @author Sturdy **/ abstract contract IncentiveVault is GeneralVault { using SafeERC20 for IERC20; /** * @dev Emitted on setIncentiveRatio() * @param ratio The incentive ratio value, 1% = 100 **/ event SetIncentiveRatio(uint256 ratio); /** * @dev Get the incentive token address supported on this vault * @return The address of incentive token */ function getIncentiveToken() public view virtual returns (address); /** * @dev Get current total incentive amount * @return The total amount of incentive token */ function getCurrentTotalIncentiveAmount() external view virtual returns (uint256); /** * @dev Get Incentive Ratio * @return The incentive ratio value */ function getIncentiveRatio() external view virtual returns (uint256); /** * @dev Set Incentive Ratio * - Caller is only PoolAdmin which is set on LendingPoolAddressesProvider contract */ function setIncentiveRatio(uint256 _ratio) external virtual; /** * @dev Get AToken address for the vault * @return The AToken address for the vault */ function _getAToken() internal view virtual returns (address); /** * @dev Claim all rewards and send some to YieldDistributor */ function _clearRewards() internal virtual; /** * @dev Send incentive to YieldDistribution * @param amount The amount of incentive token */ function _sendIncentive(uint256 amount) internal { address asset = _getAToken(); address incentiveToken = getIncentiveToken(); // transfer to YieldDistributor address yieldDistributor = _addressesProvider.getAddress('VR_YIELD_DISTRIBUTOR'); IERC20(incentiveToken).safeTransfer(yieldDistributor, amount); // notify to YieldDistributor so that it updates asset index VariableYieldDistribution(yieldDistributor).receivedRewards(asset, incentiveToken, amount); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "istanbul", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collateralAsset","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collateralAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"yieldAmount","type":"uint256"}],"name":"ProcessYield","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"ratio","type":"uint256"}],"name":"SetIncentiveRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_curveLpToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_convexPoolId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_internalToken","type":"address"}],"name":"SetParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasuryAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SetTreasuryInfo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collateralAsset","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawCollateral","type":"event"},{"inputs":[],"name":"convexBooster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositCollateral","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"depositCollateralFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getCurrentTotalIncentiveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIncentiveRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIncentiveToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInternalAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getYieldAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILendingPoolAddressesProvider","name":"_provider","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_count","type":"uint256"}],"name":"processExtraYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"processYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_lpToken","type":"address"},{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"setConfiguration","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ratio","type":"uint256"}],"name":"setIncentiveRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setTreasuryInfo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"vaultYieldInPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_slippage","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdrawCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawOnLiquidation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506140c6806100206000396000f3fe6080604052600436106200011f5760003560e01c806369dcdefe11620000a1578063a5fdfc63116200006c578063a5fdfc6314620002bf578063b8d2927614620002e4578063c4d66de814620002fb578063d090cf9b1462000320578063ff42f49d146200033657600080fd5b806369dcdefe14620002465780638954ff3f146200026b57806399530b061462000290578063a5d5db0c14620002a857600080fd5b80632a2234f911620000ee5780632a2234f914620001b15780632cdacb5014620001c85780634451691e14620001ea5780635a242acf146200020a578063616b0646146200022f57600080fd5b8063084f484c14620001245780630e605e7e1462000159578063121a23c11462000180578063259f2d011462000198575b600080fd5b3480156200013157600080fd5b506200013c6200034e565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156200016657600080fd5b5062000171620003c8565b60405190815260200162000150565b3480156200018d57600080fd5b506200017162000476565b620001af620001a936600462002853565b620004ef565b005b620001af620001c23660046200289a565b62000501565b348015620001d557600080fd5b506037546200013c906001600160a01b031681565b348015620001f757600080fd5b506039546001600160a01b03166200013c565b3480156200021757600080fd5b50620001af62000229366004620028c9565b6200069f565b3480156200023c57600080fd5b50603b5462000171565b3480156200025357600080fd5b50620001af62000265366004620028ec565b620008d6565b3480156200027857600080fd5b50620001716200028a3660046200289a565b62000a2d565b3480156200029d57600080fd5b506200017162000b5b565b620001af620002b93660046200289a565b62000bea565b348015620002cc57600080fd5b50620001af620002de36600462002906565b62000bfb565b620001af620002f53660046200289a565b620010fd565b3480156200030857600080fd5b50620001af6200031a36600462002955565b6200149b565b3480156200032d57600080fd5b50600062000171565b3480156200034357600080fd5b50620001af620015b6565b6000806200035b620016e6565b9050806001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200039c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003c291906200298e565b91505090565b6000603b5460001462000470576000620003e1620016e6565b6040516246613160e11b81523060048201529091506000906001600160a01b03831690628cc26290602401602060405180830381865afa1580156200042a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004509190620029ae565b905062000469603b54826200176f90919063ffffffff16565b9250505090565b50600090565b60008062000483620016e6565b6040516246613160e11b81523060048201529091506001600160a01b03821690628cc26290602401602060405180830381865afa158015620004c9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003c29190620029ae565b620004fc838383620017c0565b505050565b603454604080516315d9b46f60e31b8152905133926001600160a01b03169163aecda3789160048083019260209291908290030181865afa1580156200054b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200057191906200298e565b6001600160a01b03161460405180604001604052806002815260200161333360f01b81525090620005c05760405162461bcd60e51b8152600401620005b7919062002a25565b60405180910390fd5b50604080518082019091526002815261070760f31b60208201526001600160a01b038316620006045760405162461bcd60e51b8152600401620005b7919062002a25565b50604080518082019091526002815261039360f41b6020820152610bb8821115620006445760405162461bcd60e51b8152600401620005b7919062002a25565b50603680546001600160a01b0319166001600160a01b03841690811790915560358290556040518281527f36a32a9fd3f860ff83c8cdbf88e1444ef598769478e1fc0c673ebe3cae3e02479060200160405180910390a25050565b6000620006ab620016e6565b90506000816001600160a01b031663d55a23f46040518163ffffffff1660e01b8152600401602060405180830381865afa158015620006ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007149190620029ae565b90508062000723848662002a50565b111560405180604001604052806002815260200161393760f01b81525090620007615760405162461bcd60e51b8152600401620005b7919062002a25565b5060005b83811015620008cf5760006001600160a01b0384166340c354466200078b848962002a50565b6040518263ffffffff1660e01b8152600401620007aa91815260200190565b602060405180830381865afa158015620007c8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007ee91906200298e565b9050806001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200082c57600080fd5b505af115801562000841573d6000803e3d6000fd5b505050506000816001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000886573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008ac91906200298e565b9050620008b98162001bbc565b505080620008c79062002a6b565b905062000765565b5050505050565b603454604080516315d9b46f60e31b8152905133926001600160a01b03169163aecda3789160048083019260209291908290030181865afa15801562000920573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200094691906200298e565b6001600160a01b03161460405180604001604052806002815260200161333360f01b815250906200098c5760405162461bcd60e51b8152600401620005b7919062002a25565b5061271081603554620009a0919062002a50565b111560405180604001604052806002815260200161039360f41b81525090620009de5760405162461bcd60e51b8152600401620005b7919062002a25565b50603b5415620009f257620009f262001e18565b603b8190556040518181527fb40d62f3d788b8050cbc93dc0fd4719dbd16f269b688264d3e5dd71914a6204f9060200160405180910390a150565b603854604080518082019091526002815261323360f01b60208201526000916001600160a01b0385811691161462000a7a5760405162461bcd60e51b8152600401620005b7919062002a25565b50603460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000acf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000af591906200298e565b6001600160a01b0316336001600160a01b03161460405180604001604052806002815260200161323360f01b8152509062000b455760405162461bcd60e51b8152600401620005b7919062002a25565b5062000b52823362001ebe565b90505b92915050565b600080603960009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000bb2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bd8919062002a9b565b60ff169050620003c281600a62002bb6565b62000bf7828233620017c0565b5050565b62000c063362001fb9565b1562000ccc5760405163537084c760e01b81523060048201523360248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063537084c790604401602060405180830381865afa15801562000c62573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c88919062002bd5565b6040518060400160405280600381526020016206262760eb1b8152509062000cc55760405162461bcd60e51b8152600401620005b7919062002a25565b5062000e07565b6040516377783bb760e11b81523060048201526000907388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063eef0776e90602401602060405180830381865afa15801562000d1f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d459190620029ae565b111562000e0757604051632fa8673b60e01b81523060048201523360248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e90632fa8673b90604401602060405180830381865afa15801562000da2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000dc8919062002bd5565b6040518060400160405280600381526020016206262760eb1b8152509062000e055760405162461bcd60e51b8152600401620005b7919062002a25565b505b60008062000e16868662001ff6565b915091506000603460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000e70573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e9691906200298e565b6040516312ade5ad60e01b81526001600160a01b0385811660048301526024820185905233604483015230606483015291909116906312ade5ad906084016020604051808303816000875af115801562000ef4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f1a9190620029ae565b9050600062000f2b8883876200205b565b90506000198714156200104b5760006001600160a01b03891662000f525750601262000fbd565b886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000f91573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000fb7919062002a9b565b60ff1690505b62000fca81600a62002bb6565b306001600160a01b03166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001009573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200102f9190620029ae565b6200103b908562002bf3565b62001047919062002c15565b9750505b620010656200105d8761271062002c38565b88906200176f565b811015604051806040016040528060028152602001611c9b60f11b81525090620010a45760405162461bcd60e51b8152600401620005b7919062002a25565b50846001600160a01b0316886001600160a01b03167f1607da8e9144035d8537941425741e9e3569c81d34a7f8e0c5c44635dc71692189604051620010eb91815260200190565b60405180910390a35050505050505050565b603454604080516315d9b46f60e31b8152905133926001600160a01b03169163aecda3789160048083019260209291908290030181865afa15801562001147573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200116d91906200298e565b6001600160a01b03161460405180604001604052806002815260200161333360f01b81525090620011b35760405162461bcd60e51b8152600401620005b7919062002a25565b506040805180820190915260028152610e4d60f21b60208201526001600160a01b038316620011f75760405162461bcd60e51b8152600401620005b7919062002a25565b506039546040805180820190915260028152610e4d60f21b6020820152906001600160a01b0316156200123f5760405162461bcd60e51b8152600401620005b7919062002a25565b50603780546001600160a01b031990811673f403c135812408bfbe8713b5a23a04b3d48aae3117909155603880546001600160a01b038516921682179055603a829055604080516395d89b4160e01b81529051600092916395d89b4191600480830192869291908290030181865afa158015620012c0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620012ea919081019062002c95565b604051602001620012fc919062002d4e565b604051602081830303815290604052836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200134a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001374919081019062002c95565b60405160200162001386919062002d7f565b604051602081830303815290604052846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620013d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620013fa919062002a9b565b60405162001408906200282f565b620014169392919062002daa565b604051809103906000f08015801562001433573d6000803e3d6000fd5b50603980546001600160a01b0319166001600160a01b03838116918217909255604080519287168352602083018690528201529091507fe1c1d56af4e6e2e3186e52fb85b87b9d6f263f0180f5714c2f5838fd07e598ae9060600160405180910390a1505050565b60015460039060ff1680620014af5750303b155b80620014bc575060005481115b620015215760405162461bcd60e51b815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201526d195b881a5b9a5d1a585b1a5e995960921b6064820152608401620005b7565b60015460ff1615801562001541576001805460ff19168117905560008290555b6040805180820190915260028152610e4d60f21b60208201526001600160a01b038416620015845760405162461bcd60e51b8152600401620005b7919062002a25565b50603480546001600160a01b0319166001600160a01b0385161790558015620004fc576001805460ff19169055505050565b6000620015c2620016e6565b604051637050ccd960e01b8152306004820152600060248201529091506001600160a01b03821690637050ccd990604401600060405180830381600087803b1580156200160e57600080fd5b505af115801562001623573d6000803e3d6000fd5b5050505062001696816001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200166a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200169091906200298e565b62001bbc565b603754604080516303aa30b960e11b81529051620016e3926001600160a01b03169163075461729160048083019260209291908290030181865afa1580156200166a573d6000803e3d6000fd5b50565b603754603a54604051631526fe2760e01b815260009283926001600160a01b0390911691631526fe2791620017219160040190815260200190565b60c060405180830381865afa1580156200173f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001765919062002de7565b6060015192915050565b60008215806200177d575081155b156200178c5750600062000b55565b6127106200179c60028262002c15565b620017a8848662002bf3565b620017b4919062002a50565b62000b52919062002c15565b620017cb3362001fb9565b15620018915760405163537084c760e01b81523060048201523360248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063537084c790604401602060405180830381865afa15801562001827573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200184d919062002bd5565b6040518060400160405280600381526020016206262760eb1b815250906200188a5760405162461bcd60e51b8152600401620005b7919062002a25565b50620019d5565b6040516377783bb760e11b81523060048201526000907388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063eef0776e90602401602060405180830381865afa158015620018e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200190a9190620029ae565b1115620019d557604051632fa8673b60e01b81523060048201526001600160a01b03821660248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e90632fa8673b90604401602060405180830381865afa15801562001970573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001996919062002bd5565b6040518060400160405280600381526020016206262760eb1b81525090620019d35760405162461bcd60e51b8152600401620005b7919062002a25565b505b6001600160a01b0383161562001a27576040805180820190915260028152611c1960f11b6020820152341562001a205760405162461bcd60e51b8152600401620005b7919062002a25565b5062001a65565b604080518082019091526002815261383160f01b602082015234831462001a635760405162461bcd60e51b8152600401620005b7919062002a25565b505b60008062001a74858562002069565b91509150603460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001acc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001af291906200298e565b60405163e8eda9df60e01b81526001600160a01b03848116600483015260248201849052858116604483015260006064830152919091169063e8eda9df90608401600060405180830381600087803b15801562001b4e57600080fd5b505af115801562001b63573d6000803e3d6000fd5b50505050826001600160a01b0316856001600160a01b03167fef12f18e2b6578b91b3c852c423ca8ee530f65f20f770e62a7ce8aa08e1ab7778660405162001bad91815260200190565b60405180910390a35050505050565b604080518082019091526002815261383760f01b60208201526001600160a01b03821662001bff5760405162461bcd60e51b8152600401620005b7919062002a25565b506040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801562001c48573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001c6e9190620029ae565b90508062001c7a575050565b603b54600090816001600160a01b03851662001c956200034e565b6001600160a01b031614905080801562001cae57508115155b1562001ccd5762001cc084836200176f565b925062001ccd83620022b0565b6035549150811562001d1657600062001ce785846200176f565b60365490915062001d06906001600160a01b03888116911683620023e0565b62001d12818662002c38565b9450505b821562001d2c5762001d29838562002c38565b93505b831562001dcd576034546040516321f8a72160e01b81526c2ca4a2a6222fa6a0a720a3a2a960991b60048201526000916001600160a01b0316906321f8a72190602401602060405180830381865afa15801562001d8d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001db391906200298e565b905062001dcb6001600160a01b0387168287620023e0565b505b846001600160a01b03167f12978afa755d72e090b03555cdabccdaf98d608c8271ec2c06a04c29253156738560405162001e0991815260200190565b60405180910390a25050505050565b600062001e24620016e6565b9050806001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562001e6257600080fd5b505af115801562001e77573d6000803e3d6000fd5b50505050620016e3816001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200166a573d6000803e3d6000fd5b60008062001ecb620016e6565b604051636197390160e11b815260048101869052600060248201529091506001600160a01b0382169063c32e720290604401600060405180830381600087803b15801562001f1857600080fd5b505af115801562001f2d573d6000803e3d6000fd5b5050603954604051632770a7eb60e21b8152306004820152602481018890526001600160a01b039091169250639dc29fac9150604401600060405180830381600087803b15801562001f7e57600080fd5b505af115801562001f93573d6000803e3d6000fd5b505060385462001fb192506001600160a01b031690508486620023e0565b509192915050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159062001fee57508115155b949350505050565b6038546040805180820190915260028152610e0d60f21b60208201526000918291906001600160a01b03868116911614620020465760405162461bcd60e51b8152600401620005b7919062002a25565b50506039546001600160a01b03169391925050565b600062001fee838362001ebe565b6038546040805180820190915260028152611c1960f11b602082015260009182916001600160a01b039182169186168214620020ba5760405162461bcd60e51b8152600401620005b7919062002a25565b50620020d26001600160a01b03821633308762002445565b6037546001600160a01b0390811690620020f190831682600062002485565b620021076001600160a01b038316828762002485565b603a546040516321d0683360e11b8152600481019190915260248101869052600160448201526001600160a01b038216906343a0d066906064016020604051808303816000875af115801562002161573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002187919062002bd5565b5060395460345460408051630261bf8b60e01b815290516001600160a01b03938416936000931691630261bf8b9160048083019260209291908290030181865afa158015620021da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200220091906200298e565b6040516340c10f1960e01b8152306004820152602481018990529091506001600160a01b038316906340c10f19906044016020604051808303816000875af115801562002251573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002277919062002bd5565b506200228f6001600160a01b03831682600062002485565b620022a56001600160a01b038316828962002485565b509694955050505050565b6000620022bc620025a2565b90506000620022ca6200034e565b6034546040516321f8a72160e01b8152732b292faca4a2a6222fa224a9aa2924a12aaa27a960611b60048201529192506000916001600160a01b03909116906321f8a72190602401602060405180830381865afa15801562002330573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200235691906200298e565b90506200236e6001600160a01b0383168286620023e0565b6040516349fb82a760e01b81526001600160a01b0384811660048301528381166024830152604482018690528216906349fb82a790606401600060405180830381600087803b158015620023c157600080fd5b505af1158015620023d6573d6000803e3d6000fd5b5050505050505050565b6040516001600160a01b038316602482015260448101829052620004fc90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915262002699565b6040516001600160a01b03808516602483015283166044820152606481018290526200247f9085906323b872dd60e01b906084016200240d565b50505050565b801580620025035750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015620024db573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025019190620029ae565b155b620025705760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401620005b7565b6040516001600160a01b038316602482015260448101829052620004fc90849063095ea7b360e01b906064016200240d565b60395460345460408051630261bf8b60e01b815290516000936001600160a01b03908116938593911691630261bf8b916004808201926020929091908290030181865afa158015620025f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200261e91906200298e565b6040516335ea6a7560e01b81526001600160a01b03848116600483015291909116906335ea6a75906024016101a060405180830381865afa15801562002668573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200268e919062002f1d565b60e001519392505050565b620026ad826001600160a01b031662001fb9565b620026fb5760405162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e7472616374006044820152606401620005b7565b600080836001600160a01b03168360405162002718919062003039565b6000604051808303816000865af19150503d806000811462002757576040519150601f19603f3d011682016040523d82523d6000602084013e6200275c565b606091505b509150915081620027b05760405162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646044820152606401620005b7565b8051156200247f5780806020019051810190620027ce919062002bd5565b6200247f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620005b7565b611039806200305883390190565b6001600160a01b0381168114620016e357600080fd5b6000806000606084860312156200286957600080fd5b833562002876816200283d565b92506020840135915060408401356200288f816200283d565b809150509250925092565b60008060408385031215620028ae57600080fd5b8235620028bb816200283d565b946020939093013593505050565b60008060408385031215620028dd57600080fd5b50508035926020909101359150565b600060208284031215620028ff57600080fd5b5035919050565b600080600080608085870312156200291d57600080fd5b84356200292a816200283d565b9350602085013592506040850135915060608501356200294a816200283d565b939692955090935050565b6000602082840312156200296857600080fd5b813562002975816200283d565b9392505050565b805162002989816200283d565b919050565b600060208284031215620029a157600080fd5b815162002975816200283d565b600060208284031215620029c157600080fd5b5051919050565b60005b83811015620029e5578181015183820152602001620029cb565b838111156200247f5750506000910152565b6000815180845262002a11816020860160208601620029c8565b601f01601f19169290920160200192915050565b60208152600062000b526020830184620029f7565b634e487b7160e01b600052601160045260246000fd5b6000821982111562002a665762002a6662002a3a565b500190565b600060001982141562002a825762002a8262002a3a565b5060010190565b805160ff811681146200298957600080fd5b60006020828403121562002aae57600080fd5b62000b528262002a89565b600181815b8085111562002afa57816000190482111562002ade5762002ade62002a3a565b8085161562002aec57918102915b93841c939080029062002abe565b509250929050565b60008262002b135750600162000b55565b8162002b225750600062000b55565b816001811462002b3b576002811462002b465762002b66565b600191505062000b55565b60ff84111562002b5a5762002b5a62002a3a565b50506001821b62000b55565b5060208310610133831016604e8410600b841016171562002b8b575081810a62000b55565b62002b97838362002ab9565b806000190482111562002bae5762002bae62002a3a565b029392505050565b600062000b52838362002b02565b805180151581146200298957600080fd5b60006020828403121562002be857600080fd5b62000b528262002bc4565b600081600019048311821515161562002c105762002c1062002a3a565b500290565b60008262002c3357634e487b7160e01b600052601260045260246000fd5b500490565b60008282101562002c4d5762002c4d62002a3a565b500390565b634e487b7160e01b600052604160045260246000fd5b6040516101a0810167ffffffffffffffff8111828210171562002c8f5762002c8f62002c52565b60405290565b60006020828403121562002ca857600080fd5b815167ffffffffffffffff8082111562002cc157600080fd5b818401915084601f83011262002cd657600080fd5b81518181111562002ceb5762002ceb62002c52565b604051601f8201601f19908116603f0116810190838211818310171562002d165762002d1662002c52565b8160405282815287602084870101111562002d3057600080fd5b62002d43836020830160208801620029c8565b979650505050505050565b66029ba3ab9323c960cd1b81526000825162002d72816007850160208701620029c8565b9190910160070192915050565b606360f81b81526000825162002d9d816001850160208701620029c8565b9190910160010192915050565b60608152600062002dbf6060830186620029f7565b828103602084015262002dd38186620029f7565b91505060ff83166040830152949350505050565b600060c0828403121562002dfa57600080fd5b60405160c0810181811067ffffffffffffffff8211171562002e205762002e2062002c52565b604052825162002e30816200283d565b8152602083015162002e42816200283d565b6020820152604083015162002e57816200283d565b6040820152606083015162002e6c816200283d565b6060820152608083015162002e81816200283d565b608082015262002e9460a0840162002bc4565b60a08201529392505050565b60006020828403121562002eb357600080fd5b6040516020810181811067ffffffffffffffff8211171562002ed95762002ed962002c52565b6040529151825250919050565b80516fffffffffffffffffffffffffffffffff811681146200298957600080fd5b805164ffffffffff811681146200298957600080fd5b60006101a0828403121562002f3157600080fd5b62002f3b62002c68565b62002f47848462002ea0565b815262002f576020840162002ee6565b602082015262002f6a6040840162002ee6565b604082015262002f7d6060840162002ee6565b606082015262002f906080840162002ee6565b608082015262002fa360a0840162002ee6565b60a082015262002fb660c0840162002f07565b60c082015262002fc960e084016200297c565b60e082015261010062002fde8185016200297c565b9082015261012062002ff28482016200297c565b90820152610140620030068482016200297c565b908201526101606200301a8482016200297c565b908201526101806200302e84820162002a89565b908201529392505050565b600082516200304d818460208701620029c8565b919091019291505056fe60806040523480156200001157600080fd5b50604051620010393803806200103983398101604081905262000034916200025e565b8251839083906200004d906003906020850190620000eb565b50805162000063906004906020840190620000eb565b50506005805460ff191660121790555060006200007d3390565b60058054610100600160a81b0319166101006001600160a01b03841690810291909117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506005805460ff191660ff831617905550505062000320565b828054620000f990620002e3565b90600052602060002090601f0160209004810192826200011d576000855562000168565b82601f106200013857805160ff191683800117855562000168565b8280016001018555821562000168579182015b82811115620001685782518255916020019190600101906200014b565b50620001769291506200017a565b5090565b5b808211156200017657600081556001016200017b565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001b957600080fd5b81516001600160401b0380821115620001d657620001d662000191565b604051601f8301601f19908116603f0116810190828211818310171562000201576200020162000191565b816040528381526020925086838588010111156200021e57600080fd5b600091505b8382101562000242578582018301518183018401529082019062000223565b83821115620002545760008385830101525b9695505050505050565b6000806000606084860312156200027457600080fd5b83516001600160401b03808211156200028c57600080fd5b6200029a87838801620001a7565b94506020860151915080821115620002b157600080fd5b50620002c086828701620001a7565b925050604084015160ff81168114620002d857600080fd5b809150509250925092565b600181811c90821680620002f857607f821691505b602082108114156200031a57634e487b7160e01b600052602260045260246000fd5b50919050565b610d0980620003306000396000f3fe6080604052600436106100f35760003560e01c8063715018a61161008a578063a457c2d711610059578063a457c2d714610285578063a9059cbb146102a5578063dd62ed3e146102c5578063f2fde38b1461030b57600080fd5b8063715018a61461021d5780638da5cb5b1461022757806395d89b411461025d5780639dc29fac1461027257600080fd5b8063313ce567116100c6578063313ce5671461019257806339509351146101b457806340c10f19146101d457806370a08231146101e757600080fd5b806306fdde03146100f8578063095ea7b31461012357806318160ddd1461015357806323b872dd14610172575b600080fd5b34801561010457600080fd5b5061010d61031e565b60405161011a9190610af2565b60405180910390f35b34801561012f57600080fd5b5061014361013e366004610b63565b6103b0565b604051901515815260200161011a565b34801561015f57600080fd5b506002545b60405190815260200161011a565b34801561017e57600080fd5b5061014361018d366004610b8d565b6103c6565b34801561019e57600080fd5b5060055460405160ff909116815260200161011a565b3480156101c057600080fd5b506101436101cf366004610b63565b610418565b6101436101e2366004610b63565b61044f565b3480156101f357600080fd5b50610164610202366004610bc9565b6001600160a01b031660009081526020819052604090205490565b610225610495565b005b34801561023357600080fd5b5060055461010090046001600160a01b03166040516001600160a01b03909116815260200161011a565b34801561026957600080fd5b5061010d610515565b610225610280366004610b63565b610524565b34801561029157600080fd5b506101436102a0366004610b63565b610562565b3480156102b157600080fd5b506101436102c0366004610b63565b610599565b3480156102d157600080fd5b506101646102e0366004610beb565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610225610319366004610bc9565b6105a6565b60606003805461032d90610c1e565b80601f016020809104026020016040519081016040528092919081815260200182805461035990610c1e565b80156103a65780601f1061037b576101008083540402835291602001916103a6565b820191906000526020600020905b81548152906001019060200180831161038957829003601f168201915b5050505050905090565b60006103bd3384846106a2565b50600192915050565b60006103d38484846107c7565b6001600160a01b03841660009081526001602090815260408083203380855292529091205461040e918691610409908690610c6f565b6106a2565b5060019392505050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916103bd918590610409908690610c86565b6005546000906001600160a01b0361010090910416331461048b5760405162461bcd60e51b815260040161048290610c9e565b60405180910390fd5b6103bd838361092e565b6005546001600160a01b036101009091041633146104c55760405162461bcd60e51b815260040161048290610c9e565b60055460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a360058054610100600160a81b0319169055565b60606004805461032d90610c1e565b6005546001600160a01b036101009091041633146105545760405162461bcd60e51b815260040161048290610c9e565b61055e8282610a0e565b5050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916103bd918590610409908690610c6f565b60006103bd3384846107c7565b6005546001600160a01b036101009091041633146105d65760405162461bcd60e51b815260040161048290610c9e565b6001600160a01b03811661063b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610482565b6005546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6001600160a01b0383166107045760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610482565b6001600160a01b0382166107655760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610482565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03831661082b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610482565b6001600160a01b03821661088d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610482565b6001600160a01b038316600090815260208190526040812080548392906108b5908490610c6f565b90915550506001600160a01b038216600090815260208190526040812080548392906108e2908490610c86565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516107ba91815260200190565b6001600160a01b0382166109845760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610482565b80600260008282546109969190610c86565b90915550506001600160a01b038216600090815260208190526040812080548392906109c3908490610c86565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b6001600160a01b038216610a6e5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610482565b6001600160a01b03821660009081526020819052604081208054839290610a96908490610c6f565b925050819055508060026000828254610aaf9190610c6f565b90915550506040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610a02565b600060208083528351808285015260005b81811015610b1f57858101830151858201604001528201610b03565b81811115610b31576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b0381168114610b5e57600080fd5b919050565b60008060408385031215610b7657600080fd5b610b7f83610b47565b946020939093013593505050565b600080600060608486031215610ba257600080fd5b610bab84610b47565b9250610bb960208501610b47565b9150604084013590509250925092565b600060208284031215610bdb57600080fd5b610be482610b47565b9392505050565b60008060408385031215610bfe57600080fd5b610c0783610b47565b9150610c1560208401610b47565b90509250929050565b600181811c90821680610c3257607f821691505b60208210811415610c5357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600082821015610c8157610c81610c59565b500390565b60008219821115610c9957610c99610c59565b500190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea26469706673582212203f5d3e5051f3ddb98888ac56ab6fec4ac8eb8afb69fcdef98e20fb5e2ed93d7d64736f6c634300080a0033a2646970667358221220aa9b1c34294789a1208a432bed544e8e1477f16b6d8fdd81f29d08ea2aa49e5f64736f6c634300080a0033
Deployed Bytecode
0x6080604052600436106200011f5760003560e01c806369dcdefe11620000a1578063a5fdfc63116200006c578063a5fdfc6314620002bf578063b8d2927614620002e4578063c4d66de814620002fb578063d090cf9b1462000320578063ff42f49d146200033657600080fd5b806369dcdefe14620002465780638954ff3f146200026b57806399530b061462000290578063a5d5db0c14620002a857600080fd5b80632a2234f911620000ee5780632a2234f914620001b15780632cdacb5014620001c85780634451691e14620001ea5780635a242acf146200020a578063616b0646146200022f57600080fd5b8063084f484c14620001245780630e605e7e1462000159578063121a23c11462000180578063259f2d011462000198575b600080fd5b3480156200013157600080fd5b506200013c6200034e565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156200016657600080fd5b5062000171620003c8565b60405190815260200162000150565b3480156200018d57600080fd5b506200017162000476565b620001af620001a936600462002853565b620004ef565b005b620001af620001c23660046200289a565b62000501565b348015620001d557600080fd5b506037546200013c906001600160a01b031681565b348015620001f757600080fd5b506039546001600160a01b03166200013c565b3480156200021757600080fd5b50620001af62000229366004620028c9565b6200069f565b3480156200023c57600080fd5b50603b5462000171565b3480156200025357600080fd5b50620001af62000265366004620028ec565b620008d6565b3480156200027857600080fd5b50620001716200028a3660046200289a565b62000a2d565b3480156200029d57600080fd5b506200017162000b5b565b620001af620002b93660046200289a565b62000bea565b348015620002cc57600080fd5b50620001af620002de36600462002906565b62000bfb565b620001af620002f53660046200289a565b620010fd565b3480156200030857600080fd5b50620001af6200031a36600462002955565b6200149b565b3480156200032d57600080fd5b50600062000171565b3480156200034357600080fd5b50620001af620015b6565b6000806200035b620016e6565b9050806001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200039c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003c291906200298e565b91505090565b6000603b5460001462000470576000620003e1620016e6565b6040516246613160e11b81523060048201529091506000906001600160a01b03831690628cc26290602401602060405180830381865afa1580156200042a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004509190620029ae565b905062000469603b54826200176f90919063ffffffff16565b9250505090565b50600090565b60008062000483620016e6565b6040516246613160e11b81523060048201529091506001600160a01b03821690628cc26290602401602060405180830381865afa158015620004c9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003c29190620029ae565b620004fc838383620017c0565b505050565b603454604080516315d9b46f60e31b8152905133926001600160a01b03169163aecda3789160048083019260209291908290030181865afa1580156200054b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200057191906200298e565b6001600160a01b03161460405180604001604052806002815260200161333360f01b81525090620005c05760405162461bcd60e51b8152600401620005b7919062002a25565b60405180910390fd5b50604080518082019091526002815261070760f31b60208201526001600160a01b038316620006045760405162461bcd60e51b8152600401620005b7919062002a25565b50604080518082019091526002815261039360f41b6020820152610bb8821115620006445760405162461bcd60e51b8152600401620005b7919062002a25565b50603680546001600160a01b0319166001600160a01b03841690811790915560358290556040518281527f36a32a9fd3f860ff83c8cdbf88e1444ef598769478e1fc0c673ebe3cae3e02479060200160405180910390a25050565b6000620006ab620016e6565b90506000816001600160a01b031663d55a23f46040518163ffffffff1660e01b8152600401602060405180830381865afa158015620006ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007149190620029ae565b90508062000723848662002a50565b111560405180604001604052806002815260200161393760f01b81525090620007615760405162461bcd60e51b8152600401620005b7919062002a25565b5060005b83811015620008cf5760006001600160a01b0384166340c354466200078b848962002a50565b6040518263ffffffff1660e01b8152600401620007aa91815260200190565b602060405180830381865afa158015620007c8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007ee91906200298e565b9050806001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200082c57600080fd5b505af115801562000841573d6000803e3d6000fd5b505050506000816001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000886573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008ac91906200298e565b9050620008b98162001bbc565b505080620008c79062002a6b565b905062000765565b5050505050565b603454604080516315d9b46f60e31b8152905133926001600160a01b03169163aecda3789160048083019260209291908290030181865afa15801562000920573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200094691906200298e565b6001600160a01b03161460405180604001604052806002815260200161333360f01b815250906200098c5760405162461bcd60e51b8152600401620005b7919062002a25565b5061271081603554620009a0919062002a50565b111560405180604001604052806002815260200161039360f41b81525090620009de5760405162461bcd60e51b8152600401620005b7919062002a25565b50603b5415620009f257620009f262001e18565b603b8190556040518181527fb40d62f3d788b8050cbc93dc0fd4719dbd16f269b688264d3e5dd71914a6204f9060200160405180910390a150565b603854604080518082019091526002815261323360f01b60208201526000916001600160a01b0385811691161462000a7a5760405162461bcd60e51b8152600401620005b7919062002a25565b50603460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000acf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000af591906200298e565b6001600160a01b0316336001600160a01b03161460405180604001604052806002815260200161323360f01b8152509062000b455760405162461bcd60e51b8152600401620005b7919062002a25565b5062000b52823362001ebe565b90505b92915050565b600080603960009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000bb2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bd8919062002a9b565b60ff169050620003c281600a62002bb6565b62000bf7828233620017c0565b5050565b62000c063362001fb9565b1562000ccc5760405163537084c760e01b81523060048201523360248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063537084c790604401602060405180830381865afa15801562000c62573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c88919062002bd5565b6040518060400160405280600381526020016206262760eb1b8152509062000cc55760405162461bcd60e51b8152600401620005b7919062002a25565b5062000e07565b6040516377783bb760e11b81523060048201526000907388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063eef0776e90602401602060405180830381865afa15801562000d1f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d459190620029ae565b111562000e0757604051632fa8673b60e01b81523060048201523360248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e90632fa8673b90604401602060405180830381865afa15801562000da2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000dc8919062002bd5565b6040518060400160405280600381526020016206262760eb1b8152509062000e055760405162461bcd60e51b8152600401620005b7919062002a25565b505b60008062000e16868662001ff6565b915091506000603460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000e70573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000e9691906200298e565b6040516312ade5ad60e01b81526001600160a01b0385811660048301526024820185905233604483015230606483015291909116906312ade5ad906084016020604051808303816000875af115801562000ef4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f1a9190620029ae565b9050600062000f2b8883876200205b565b90506000198714156200104b5760006001600160a01b03891662000f525750601262000fbd565b886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000f91573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000fb7919062002a9b565b60ff1690505b62000fca81600a62002bb6565b306001600160a01b03166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001009573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200102f9190620029ae565b6200103b908562002bf3565b62001047919062002c15565b9750505b620010656200105d8761271062002c38565b88906200176f565b811015604051806040016040528060028152602001611c9b60f11b81525090620010a45760405162461bcd60e51b8152600401620005b7919062002a25565b50846001600160a01b0316886001600160a01b03167f1607da8e9144035d8537941425741e9e3569c81d34a7f8e0c5c44635dc71692189604051620010eb91815260200190565b60405180910390a35050505050505050565b603454604080516315d9b46f60e31b8152905133926001600160a01b03169163aecda3789160048083019260209291908290030181865afa15801562001147573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200116d91906200298e565b6001600160a01b03161460405180604001604052806002815260200161333360f01b81525090620011b35760405162461bcd60e51b8152600401620005b7919062002a25565b506040805180820190915260028152610e4d60f21b60208201526001600160a01b038316620011f75760405162461bcd60e51b8152600401620005b7919062002a25565b506039546040805180820190915260028152610e4d60f21b6020820152906001600160a01b0316156200123f5760405162461bcd60e51b8152600401620005b7919062002a25565b50603780546001600160a01b031990811673f403c135812408bfbe8713b5a23a04b3d48aae3117909155603880546001600160a01b038516921682179055603a829055604080516395d89b4160e01b81529051600092916395d89b4191600480830192869291908290030181865afa158015620012c0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620012ea919081019062002c95565b604051602001620012fc919062002d4e565b604051602081830303815290604052836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200134a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001374919081019062002c95565b60405160200162001386919062002d7f565b604051602081830303815290604052846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620013d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620013fa919062002a9b565b60405162001408906200282f565b620014169392919062002daa565b604051809103906000f08015801562001433573d6000803e3d6000fd5b50603980546001600160a01b0319166001600160a01b03838116918217909255604080519287168352602083018690528201529091507fe1c1d56af4e6e2e3186e52fb85b87b9d6f263f0180f5714c2f5838fd07e598ae9060600160405180910390a1505050565b60015460039060ff1680620014af5750303b155b80620014bc575060005481115b620015215760405162461bcd60e51b815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201526d195b881a5b9a5d1a585b1a5e995960921b6064820152608401620005b7565b60015460ff1615801562001541576001805460ff19168117905560008290555b6040805180820190915260028152610e4d60f21b60208201526001600160a01b038416620015845760405162461bcd60e51b8152600401620005b7919062002a25565b50603480546001600160a01b0319166001600160a01b0385161790558015620004fc576001805460ff19169055505050565b6000620015c2620016e6565b604051637050ccd960e01b8152306004820152600060248201529091506001600160a01b03821690637050ccd990604401600060405180830381600087803b1580156200160e57600080fd5b505af115801562001623573d6000803e3d6000fd5b5050505062001696816001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200166a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200169091906200298e565b62001bbc565b603754604080516303aa30b960e11b81529051620016e3926001600160a01b03169163075461729160048083019260209291908290030181865afa1580156200166a573d6000803e3d6000fd5b50565b603754603a54604051631526fe2760e01b815260009283926001600160a01b0390911691631526fe2791620017219160040190815260200190565b60c060405180830381865afa1580156200173f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001765919062002de7565b6060015192915050565b60008215806200177d575081155b156200178c5750600062000b55565b6127106200179c60028262002c15565b620017a8848662002bf3565b620017b4919062002a50565b62000b52919062002c15565b620017cb3362001fb9565b15620018915760405163537084c760e01b81523060048201523360248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063537084c790604401602060405180830381865afa15801562001827573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200184d919062002bd5565b6040518060400160405280600381526020016206262760eb1b815250906200188a5760405162461bcd60e51b8152600401620005b7919062002a25565b50620019d5565b6040516377783bb760e11b81523060048201526000907388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e9063eef0776e90602401602060405180830381865afa158015620018e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200190a9190620029ae565b1115620019d557604051632fa8673b60e01b81523060048201526001600160a01b03821660248201527388ee44794baf865e3b0b192d1f9f0ac3daf1ea0e90632fa8673b90604401602060405180830381865afa15801562001970573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001996919062002bd5565b6040518060400160405280600381526020016206262760eb1b81525090620019d35760405162461bcd60e51b8152600401620005b7919062002a25565b505b6001600160a01b0383161562001a27576040805180820190915260028152611c1960f11b6020820152341562001a205760405162461bcd60e51b8152600401620005b7919062002a25565b5062001a65565b604080518082019091526002815261383160f01b602082015234831462001a635760405162461bcd60e51b8152600401620005b7919062002a25565b505b60008062001a74858562002069565b91509150603460009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001acc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001af291906200298e565b60405163e8eda9df60e01b81526001600160a01b03848116600483015260248201849052858116604483015260006064830152919091169063e8eda9df90608401600060405180830381600087803b15801562001b4e57600080fd5b505af115801562001b63573d6000803e3d6000fd5b50505050826001600160a01b0316856001600160a01b03167fef12f18e2b6578b91b3c852c423ca8ee530f65f20f770e62a7ce8aa08e1ab7778660405162001bad91815260200190565b60405180910390a35050505050565b604080518082019091526002815261383760f01b60208201526001600160a01b03821662001bff5760405162461bcd60e51b8152600401620005b7919062002a25565b506040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801562001c48573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001c6e9190620029ae565b90508062001c7a575050565b603b54600090816001600160a01b03851662001c956200034e565b6001600160a01b031614905080801562001cae57508115155b1562001ccd5762001cc084836200176f565b925062001ccd83620022b0565b6035549150811562001d1657600062001ce785846200176f565b60365490915062001d06906001600160a01b03888116911683620023e0565b62001d12818662002c38565b9450505b821562001d2c5762001d29838562002c38565b93505b831562001dcd576034546040516321f8a72160e01b81526c2ca4a2a6222fa6a0a720a3a2a960991b60048201526000916001600160a01b0316906321f8a72190602401602060405180830381865afa15801562001d8d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001db391906200298e565b905062001dcb6001600160a01b0387168287620023e0565b505b846001600160a01b03167f12978afa755d72e090b03555cdabccdaf98d608c8271ec2c06a04c29253156738560405162001e0991815260200190565b60405180910390a25050505050565b600062001e24620016e6565b9050806001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562001e6257600080fd5b505af115801562001e77573d6000803e3d6000fd5b50505050620016e3816001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200166a573d6000803e3d6000fd5b60008062001ecb620016e6565b604051636197390160e11b815260048101869052600060248201529091506001600160a01b0382169063c32e720290604401600060405180830381600087803b15801562001f1857600080fd5b505af115801562001f2d573d6000803e3d6000fd5b5050603954604051632770a7eb60e21b8152306004820152602481018890526001600160a01b039091169250639dc29fac9150604401600060405180830381600087803b15801562001f7e57600080fd5b505af115801562001f93573d6000803e3d6000fd5b505060385462001fb192506001600160a01b031690508486620023e0565b509192915050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159062001fee57508115155b949350505050565b6038546040805180820190915260028152610e0d60f21b60208201526000918291906001600160a01b03868116911614620020465760405162461bcd60e51b8152600401620005b7919062002a25565b50506039546001600160a01b03169391925050565b600062001fee838362001ebe565b6038546040805180820190915260028152611c1960f11b602082015260009182916001600160a01b039182169186168214620020ba5760405162461bcd60e51b8152600401620005b7919062002a25565b50620020d26001600160a01b03821633308762002445565b6037546001600160a01b0390811690620020f190831682600062002485565b620021076001600160a01b038316828762002485565b603a546040516321d0683360e11b8152600481019190915260248101869052600160448201526001600160a01b038216906343a0d066906064016020604051808303816000875af115801562002161573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002187919062002bd5565b5060395460345460408051630261bf8b60e01b815290516001600160a01b03938416936000931691630261bf8b9160048083019260209291908290030181865afa158015620021da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200220091906200298e565b6040516340c10f1960e01b8152306004820152602481018990529091506001600160a01b038316906340c10f19906044016020604051808303816000875af115801562002251573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002277919062002bd5565b506200228f6001600160a01b03831682600062002485565b620022a56001600160a01b038316828962002485565b509694955050505050565b6000620022bc620025a2565b90506000620022ca6200034e565b6034546040516321f8a72160e01b8152732b292faca4a2a6222fa224a9aa2924a12aaa27a960611b60048201529192506000916001600160a01b03909116906321f8a72190602401602060405180830381865afa15801562002330573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200235691906200298e565b90506200236e6001600160a01b0383168286620023e0565b6040516349fb82a760e01b81526001600160a01b0384811660048301528381166024830152604482018690528216906349fb82a790606401600060405180830381600087803b158015620023c157600080fd5b505af1158015620023d6573d6000803e3d6000fd5b5050505050505050565b6040516001600160a01b038316602482015260448101829052620004fc90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915262002699565b6040516001600160a01b03808516602483015283166044820152606481018290526200247f9085906323b872dd60e01b906084016200240d565b50505050565b801580620025035750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015620024db573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025019190620029ae565b155b620025705760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401620005b7565b6040516001600160a01b038316602482015260448101829052620004fc90849063095ea7b360e01b906064016200240d565b60395460345460408051630261bf8b60e01b815290516000936001600160a01b03908116938593911691630261bf8b916004808201926020929091908290030181865afa158015620025f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200261e91906200298e565b6040516335ea6a7560e01b81526001600160a01b03848116600483015291909116906335ea6a75906024016101a060405180830381865afa15801562002668573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200268e919062002f1d565b60e001519392505050565b620026ad826001600160a01b031662001fb9565b620026fb5760405162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e7472616374006044820152606401620005b7565b600080836001600160a01b03168360405162002718919062003039565b6000604051808303816000865af19150503d806000811462002757576040519150601f19603f3d011682016040523d82523d6000602084013e6200275c565b606091505b509150915081620027b05760405162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646044820152606401620005b7565b8051156200247f5780806020019051810190620027ce919062002bd5565b6200247f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620005b7565b611039806200305883390190565b6001600160a01b0381168114620016e357600080fd5b6000806000606084860312156200286957600080fd5b833562002876816200283d565b92506020840135915060408401356200288f816200283d565b809150509250925092565b60008060408385031215620028ae57600080fd5b8235620028bb816200283d565b946020939093013593505050565b60008060408385031215620028dd57600080fd5b50508035926020909101359150565b600060208284031215620028ff57600080fd5b5035919050565b600080600080608085870312156200291d57600080fd5b84356200292a816200283d565b9350602085013592506040850135915060608501356200294a816200283d565b939692955090935050565b6000602082840312156200296857600080fd5b813562002975816200283d565b9392505050565b805162002989816200283d565b919050565b600060208284031215620029a157600080fd5b815162002975816200283d565b600060208284031215620029c157600080fd5b5051919050565b60005b83811015620029e5578181015183820152602001620029cb565b838111156200247f5750506000910152565b6000815180845262002a11816020860160208601620029c8565b601f01601f19169290920160200192915050565b60208152600062000b526020830184620029f7565b634e487b7160e01b600052601160045260246000fd5b6000821982111562002a665762002a6662002a3a565b500190565b600060001982141562002a825762002a8262002a3a565b5060010190565b805160ff811681146200298957600080fd5b60006020828403121562002aae57600080fd5b62000b528262002a89565b600181815b8085111562002afa57816000190482111562002ade5762002ade62002a3a565b8085161562002aec57918102915b93841c939080029062002abe565b509250929050565b60008262002b135750600162000b55565b8162002b225750600062000b55565b816001811462002b3b576002811462002b465762002b66565b600191505062000b55565b60ff84111562002b5a5762002b5a62002a3a565b50506001821b62000b55565b5060208310610133831016604e8410600b841016171562002b8b575081810a62000b55565b62002b97838362002ab9565b806000190482111562002bae5762002bae62002a3a565b029392505050565b600062000b52838362002b02565b805180151581146200298957600080fd5b60006020828403121562002be857600080fd5b62000b528262002bc4565b600081600019048311821515161562002c105762002c1062002a3a565b500290565b60008262002c3357634e487b7160e01b600052601260045260246000fd5b500490565b60008282101562002c4d5762002c4d62002a3a565b500390565b634e487b7160e01b600052604160045260246000fd5b6040516101a0810167ffffffffffffffff8111828210171562002c8f5762002c8f62002c52565b60405290565b60006020828403121562002ca857600080fd5b815167ffffffffffffffff8082111562002cc157600080fd5b818401915084601f83011262002cd657600080fd5b81518181111562002ceb5762002ceb62002c52565b604051601f8201601f19908116603f0116810190838211818310171562002d165762002d1662002c52565b8160405282815287602084870101111562002d3057600080fd5b62002d43836020830160208801620029c8565b979650505050505050565b66029ba3ab9323c960cd1b81526000825162002d72816007850160208701620029c8565b9190910160070192915050565b606360f81b81526000825162002d9d816001850160208701620029c8565b9190910160010192915050565b60608152600062002dbf6060830186620029f7565b828103602084015262002dd38186620029f7565b91505060ff83166040830152949350505050565b600060c0828403121562002dfa57600080fd5b60405160c0810181811067ffffffffffffffff8211171562002e205762002e2062002c52565b604052825162002e30816200283d565b8152602083015162002e42816200283d565b6020820152604083015162002e57816200283d565b6040820152606083015162002e6c816200283d565b6060820152608083015162002e81816200283d565b608082015262002e9460a0840162002bc4565b60a08201529392505050565b60006020828403121562002eb357600080fd5b6040516020810181811067ffffffffffffffff8211171562002ed95762002ed962002c52565b6040529151825250919050565b80516fffffffffffffffffffffffffffffffff811681146200298957600080fd5b805164ffffffffff811681146200298957600080fd5b60006101a0828403121562002f3157600080fd5b62002f3b62002c68565b62002f47848462002ea0565b815262002f576020840162002ee6565b602082015262002f6a6040840162002ee6565b604082015262002f7d6060840162002ee6565b606082015262002f906080840162002ee6565b608082015262002fa360a0840162002ee6565b60a082015262002fb660c0840162002f07565b60c082015262002fc960e084016200297c565b60e082015261010062002fde8185016200297c565b9082015261012062002ff28482016200297c565b90820152610140620030068482016200297c565b908201526101606200301a8482016200297c565b908201526101806200302e84820162002a89565b908201529392505050565b600082516200304d818460208701620029c8565b919091019291505056fe60806040523480156200001157600080fd5b50604051620010393803806200103983398101604081905262000034916200025e565b8251839083906200004d906003906020850190620000eb565b50805162000063906004906020840190620000eb565b50506005805460ff191660121790555060006200007d3390565b60058054610100600160a81b0319166101006001600160a01b03841690810291909117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506005805460ff191660ff831617905550505062000320565b828054620000f990620002e3565b90600052602060002090601f0160209004810192826200011d576000855562000168565b82601f106200013857805160ff191683800117855562000168565b8280016001018555821562000168579182015b82811115620001685782518255916020019190600101906200014b565b50620001769291506200017a565b5090565b5b808211156200017657600081556001016200017b565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001b957600080fd5b81516001600160401b0380821115620001d657620001d662000191565b604051601f8301601f19908116603f0116810190828211818310171562000201576200020162000191565b816040528381526020925086838588010111156200021e57600080fd5b600091505b8382101562000242578582018301518183018401529082019062000223565b83821115620002545760008385830101525b9695505050505050565b6000806000606084860312156200027457600080fd5b83516001600160401b03808211156200028c57600080fd5b6200029a87838801620001a7565b94506020860151915080821115620002b157600080fd5b50620002c086828701620001a7565b925050604084015160ff81168114620002d857600080fd5b809150509250925092565b600181811c90821680620002f857607f821691505b602082108114156200031a57634e487b7160e01b600052602260045260246000fd5b50919050565b610d0980620003306000396000f3fe6080604052600436106100f35760003560e01c8063715018a61161008a578063a457c2d711610059578063a457c2d714610285578063a9059cbb146102a5578063dd62ed3e146102c5578063f2fde38b1461030b57600080fd5b8063715018a61461021d5780638da5cb5b1461022757806395d89b411461025d5780639dc29fac1461027257600080fd5b8063313ce567116100c6578063313ce5671461019257806339509351146101b457806340c10f19146101d457806370a08231146101e757600080fd5b806306fdde03146100f8578063095ea7b31461012357806318160ddd1461015357806323b872dd14610172575b600080fd5b34801561010457600080fd5b5061010d61031e565b60405161011a9190610af2565b60405180910390f35b34801561012f57600080fd5b5061014361013e366004610b63565b6103b0565b604051901515815260200161011a565b34801561015f57600080fd5b506002545b60405190815260200161011a565b34801561017e57600080fd5b5061014361018d366004610b8d565b6103c6565b34801561019e57600080fd5b5060055460405160ff909116815260200161011a565b3480156101c057600080fd5b506101436101cf366004610b63565b610418565b6101436101e2366004610b63565b61044f565b3480156101f357600080fd5b50610164610202366004610bc9565b6001600160a01b031660009081526020819052604090205490565b610225610495565b005b34801561023357600080fd5b5060055461010090046001600160a01b03166040516001600160a01b03909116815260200161011a565b34801561026957600080fd5b5061010d610515565b610225610280366004610b63565b610524565b34801561029157600080fd5b506101436102a0366004610b63565b610562565b3480156102b157600080fd5b506101436102c0366004610b63565b610599565b3480156102d157600080fd5b506101646102e0366004610beb565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610225610319366004610bc9565b6105a6565b60606003805461032d90610c1e565b80601f016020809104026020016040519081016040528092919081815260200182805461035990610c1e565b80156103a65780601f1061037b576101008083540402835291602001916103a6565b820191906000526020600020905b81548152906001019060200180831161038957829003601f168201915b5050505050905090565b60006103bd3384846106a2565b50600192915050565b60006103d38484846107c7565b6001600160a01b03841660009081526001602090815260408083203380855292529091205461040e918691610409908690610c6f565b6106a2565b5060019392505050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916103bd918590610409908690610c86565b6005546000906001600160a01b0361010090910416331461048b5760405162461bcd60e51b815260040161048290610c9e565b60405180910390fd5b6103bd838361092e565b6005546001600160a01b036101009091041633146104c55760405162461bcd60e51b815260040161048290610c9e565b60055460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a360058054610100600160a81b0319169055565b60606004805461032d90610c1e565b6005546001600160a01b036101009091041633146105545760405162461bcd60e51b815260040161048290610c9e565b61055e8282610a0e565b5050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916103bd918590610409908690610c6f565b60006103bd3384846107c7565b6005546001600160a01b036101009091041633146105d65760405162461bcd60e51b815260040161048290610c9e565b6001600160a01b03811661063b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610482565b6005546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6001600160a01b0383166107045760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610482565b6001600160a01b0382166107655760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610482565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03831661082b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610482565b6001600160a01b03821661088d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610482565b6001600160a01b038316600090815260208190526040812080548392906108b5908490610c6f565b90915550506001600160a01b038216600090815260208190526040812080548392906108e2908490610c86565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516107ba91815260200190565b6001600160a01b0382166109845760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610482565b80600260008282546109969190610c86565b90915550506001600160a01b038216600090815260208190526040812080548392906109c3908490610c86565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b6001600160a01b038216610a6e5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610482565b6001600160a01b03821660009081526020819052604081208054839290610a96908490610c6f565b925050819055508060026000828254610aaf9190610c6f565b90915550506040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610a02565b600060208083528351808285015260005b81811015610b1f57858101830151858201604001528201610b03565b81811115610b31576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b0381168114610b5e57600080fd5b919050565b60008060408385031215610b7657600080fd5b610b7f83610b47565b946020939093013593505050565b600080600060608486031215610ba257600080fd5b610bab84610b47565b9250610bb960208501610b47565b9150604084013590509250925092565b600060208284031215610bdb57600080fd5b610be482610b47565b9392505050565b60008060408385031215610bfe57600080fd5b610c0783610b47565b9150610c1560208401610b47565b90509250929050565b600181811c90821680610c3257607f821691505b60208210811415610c5357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600082821015610c8157610c81610c59565b500390565b60008219821115610c9957610c99610c59565b500190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea26469706673582212203f5d3e5051f3ddb98888ac56ab6fec4ac8eb8afb69fcdef98e20fb5e2ed93d7d64736f6c634300080a0033a2646970667358221220aa9b1c34294789a1208a432bed544e8e1477f16b6d8fdd81f29d08ea2aa49e5f64736f6c634300080a0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.