ERC-20
Overview
Max Total Supply
1,052.911300831034536999 ERC20 ***
Holders
2
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Balance
1,052.911300831034536999 ERC20 ***Value
$0.00Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
YearnGaugeStrategy
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { BaseStrategy } from "tokenized-strategy/BaseStrategy.sol"; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import { CurveRouterSwapper } from "src/swappers/CurveRouterSwapper.sol"; import { YearnGaugeStrategyBase } from "./YearnGaugeStrategyBase.sol"; import { IYearnStakingDelegate } from "src/interfaces/IYearnStakingDelegate.sol"; import { Errors } from "src/libraries/Errors.sol"; /** * @title YearnGaugeStrategy * @notice Strategy for interacting with Yearn Gauge */ contract YearnGaugeStrategy is BaseStrategy, CurveRouterSwapper, YearnGaugeStrategyBase { // Libraries using SafeERC20 for IERC20; /// @notice Parameters for Curve swap used during harvest CurveSwapParams internal _harvestSwapParams; /// @notice Address of the contract that will be redeeming dYFI for YFI for this strategy address private _dYfiRedeemer; //// events //// event DYfiRedeemerSet(address oldDYfiRedeemer, address newDYfiRedeemer); /** * @notice Initializes the YearnGaugeStrategy * @param asset_ The address of the asset (gauge token) * @param yearnStakingDelegate_ The address of the YearnStakingDelegate * @param curveRouter_ The address of the Curve router */ constructor( address asset_, address yearnStakingDelegate_, address curveRouter_ ) payable BaseStrategy(asset_, "Wrapped YearnV3 Strategy") CurveRouterSwapper(curveRouter_) YearnGaugeStrategyBase(asset_, yearnStakingDelegate_) { _approveTokenForSwap(_YFI); } /** * @notice Sets the parameters for the Curve swap used in the harvest function * @param curveSwapParams The parameters for the Curve swap */ function setHarvestSwapParams(CurveSwapParams calldata curveSwapParams) external onlyManagement { // Checks (includes external view calls) _validateSwapParams(curveSwapParams, _YFI, _VAULT_ASSET); // Effects _harvestSwapParams = curveSwapParams; } /** * @notice Sets the address of the contract that will be redeeming dYFI * @param newDYfiRedeemer The address of the new dYFI redeemer contract */ function setDYfiRedeemer(address newDYfiRedeemer) external onlyManagement { // Checks if (newDYfiRedeemer == address(0)) { revert Errors.ZeroAddress(); } address currentDYfiRedeemer = _dYfiRedeemer; if (newDYfiRedeemer == currentDYfiRedeemer) { revert Errors.SameAddress(); } // Effects _dYfiRedeemer = newDYfiRedeemer; // Interactions emit DYfiRedeemerSet(currentDYfiRedeemer, newDYfiRedeemer); if (currentDYfiRedeemer != address(0)) { IERC20(_DYFI).forceApprove(currentDYfiRedeemer, 0); } IERC20(_DYFI).forceApprove(newDYfiRedeemer, type(uint256).max); } /** * @notice Get the address of the contract that will be redeeming dYFI from this strategy * @return The address of the dYFI redeemer contract */ function dYfiRedeemer() external view returns (address) { return _dYfiRedeemer; } /** * @notice Calculates the available deposit limit for the strategy * @return The strategy's available deposit limit */ function availableDepositLimit(address) public view override returns (uint256) { return IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).availableDepositLimit(address(asset)); } /** * @dev Deploys funds into the YearnStakingDelegate by depositing the asset. * @param _amount The amount of the asset to deposit. */ function _deployFunds(uint256 _amount) internal override { _depositToYSD(address(asset), _amount); } /** * @dev Withdraws funds from the YearnStakingDelegate by withdrawing the asset. * @param _amount The amount of the asset to withdraw. */ function _freeFunds(uint256 _amount) internal override { _withdrawFromYSD(address(asset), _amount); } /** * @dev Performs an emergency withdrawal from the YearnStakingDelegate, withdrawing the asset to the strategy. * @param amount The amount to withdraw in case of an emergency. */ function _emergencyWithdraw(uint256 amount) internal override { uint256 deployedAmount = depositedInYSD(address(asset)); uint256 withdrawAmount = amount > deployedAmount ? deployedAmount : amount; _withdrawFromYSD(address(asset), withdrawAmount); } /** * @notice Harvests dYfi rewards, swaps YFI for the vault asset, and re-deposits or adds to idle balance * @return _totalAssets The total assets after harvest and redeposit/idle balance update */ function _harvestAndReport() internal override returns (uint256 _totalAssets) { // Check for any dYfi that has been redeemed for Yfi uint256 yfiBalance = IERC20(_YFI).balanceOf(address(this)); // If dfi has been redeemed for Yfi, swap it for vault asset and deploy it to the strategy if (yfiBalance > 0) { // This is a dangerous swap call that will get sandwiched if sent to a public network // Must be sent to a private network or use a minAmount derived from a price oracle uint256 receivedBaseTokens = _swap(_harvestSwapParams, yfiBalance, 0, address(this)); uint256 receivedVaultTokens = IERC4626(_VAULT).deposit(receivedBaseTokens, address(this)); uint256 receivedGaugeTokens = IERC4626(address(asset)).deposit(receivedVaultTokens, address(this)); // If the strategy is not shutdown, deploy the funds // Else add the received tokens to the idle balance if (!TokenizedStrategy.isShutdown()) { _deployFunds(receivedGaugeTokens); } } // Return the total idle assets and the deployed assets return asset.balanceOf(address(this)) + depositedInYSD(address(asset)); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.18; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // TokenizedStrategy interface used for internal view delegateCalls. import {ITokenizedStrategy} from "./interfaces/ITokenizedStrategy.sol"; /** * @title YearnV3 Base Strategy * @author yearn.finance * @notice * BaseStrategy implements all of the required functionality to * seamlessly integrate with the `TokenizedStrategy` implementation contract * allowing anyone to easily build a fully permissionless ERC-4626 compliant * Vault by inheriting this contract and overriding three simple functions. * It utilizes an immutable proxy pattern that allows the BaseStrategy * to remain simple and small. All standard logic is held within the * `TokenizedStrategy` and is reused over any n strategies all using the * `fallback` function to delegatecall the implementation so that strategists * can only be concerned with writing their strategy specific code. * * This contract should be inherited and the three main abstract methods * `_deployFunds`, `_freeFunds` and `_harvestAndReport` implemented to adapt * the Strategy to the particular needs it has to generate yield. There are * other optional methods that can be implemented to further customize * the strategy if desired. * * All default storage for the strategy is controlled and updated by the * `TokenizedStrategy`. The implementation holds a storage struct that * contains all needed global variables in a manual storage slot. This * means strategists can feel free to implement their own custom storage * variables as they need with no concern of collisions. All global variables * can be viewed within the Strategy by a simple call using the * `TokenizedStrategy` variable. IE: TokenizedStrategy.globalVariable();. */ abstract contract BaseStrategy { /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /** * @dev Used on TokenizedStrategy callback functions to make sure it is post * a delegateCall from this address to the TokenizedStrategy. */ modifier onlySelf() { _onlySelf(); _; } /** * @dev Use to assure that the call is coming from the strategies management. */ modifier onlyManagement() { TokenizedStrategy.requireManagement(msg.sender); _; } /** * @dev Use to assure that the call is coming from either the strategies * management or the keeper. */ modifier onlyKeepers() { TokenizedStrategy.requireKeeperOrManagement(msg.sender); _; } /** * @dev Use to assure that the call is coming from either the strategies * management or the emergency admin. */ modifier onlyEmergencyAuthorized() { TokenizedStrategy.requireEmergencyAuthorized(msg.sender); _; } /** * @dev Require that the msg.sender is this address. */ function _onlySelf() internal view { require(msg.sender == address(this), "!self"); } /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * @dev This is the address of the TokenizedStrategy implementation * contract that will be used by all strategies to handle the * accounting, logic, storage etc. * * Any external calls to the that don't hit one of the functions * defined in this base or the strategy will end up being forwarded * through the fallback function, which will delegateCall this address. * * This address should be the same for every strategy, never be adjusted * and always be checked before any integration with the Strategy. */ address public constant tokenizedStrategyAddress = 0xBB51273D6c746910C7C06fe718f30c936170feD0; /*////////////////////////////////////////////////////////////// IMMUTABLES //////////////////////////////////////////////////////////////*/ /** * @dev Underlying asset the Strategy is earning yield on. * Stored here for cheap retrievals within the strategy. */ ERC20 internal immutable asset; /** * @dev This variable is set to address(this) during initialization of each strategy. * * This can be used to retrieve storage data within the strategy * contract as if it were a linked library. * * i.e. uint256 totalAssets = TokenizedStrategy.totalAssets() * * Using address(this) will mean any calls using this variable will lead * to a call to itself. Which will hit the fallback function and * delegateCall that to the actual TokenizedStrategy. */ ITokenizedStrategy internal immutable TokenizedStrategy; /** * @notice Used to initialize the strategy on deployment. * * This will set the `TokenizedStrategy` variable for easy * internal view calls to the implementation. As well as * initializing the default storage variables based on the * parameters and using the deployer for the permissioned roles. * * @param _asset Address of the underlying asset. * @param _name Name the strategy will use. */ constructor(address _asset, string memory _name) { asset = ERC20(_asset); // Set instance of the implementation for internal use. TokenizedStrategy = ITokenizedStrategy(address(this)); // Initialize the strategy's storage variables. _delegateCall( abi.encodeCall( ITokenizedStrategy.initialize, (_asset, _name, msg.sender, msg.sender, msg.sender) ) ); // Store the tokenizedStrategyAddress at the standard implementation // address storage slot so etherscan picks up the interface. This gets // stored on initialization and never updated. assembly { sstore( // keccak256('eip1967.proxy.implementation' - 1) 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc, tokenizedStrategyAddress ) } } /*////////////////////////////////////////////////////////////// NEEDED TO BE OVERRIDDEN BY STRATEGIST //////////////////////////////////////////////////////////////*/ /** * @dev Can deploy up to '_amount' of 'asset' in the yield source. * * This function is called at the end of a {deposit} or {mint} * call. Meaning that unless a whitelist is implemented it will * be entirely permissionless and thus can be sandwiched or otherwise * manipulated. * * @param _amount The amount of 'asset' that the strategy can attempt * to deposit in the yield source. */ function _deployFunds(uint256 _amount) internal virtual; /** * @dev Should attempt to free the '_amount' of 'asset'. * * NOTE: The amount of 'asset' that is already loose has already * been accounted for. * * This function is called during {withdraw} and {redeem} calls. * Meaning that unless a whitelist is implemented it will be * entirely permissionless and thus can be sandwiched or otherwise * manipulated. * * Should not rely on asset.balanceOf(address(this)) calls other than * for diff accounting purposes. * * Any difference between `_amount` and what is actually freed will be * counted as a loss and passed on to the withdrawer. This means * care should be taken in times of illiquidity. It may be better to revert * if withdraws are simply illiquid so not to realize incorrect losses. * * @param _amount, The amount of 'asset' to be freed. */ function _freeFunds(uint256 _amount) internal virtual; /** * @dev Internal function to harvest all rewards, redeploy any idle * funds and return an accurate accounting of all funds currently * held by the Strategy. * * This should do any needed harvesting, rewards selling, accrual, * redepositing etc. to get the most accurate view of current assets. * * NOTE: All applicable assets including loose assets should be * accounted for in this function. * * Care should be taken when relying on oracles or swap values rather * than actual amounts as all Strategy profit/loss accounting will * be done based on this returned value. * * This can still be called post a shutdown, a strategist can check * `TokenizedStrategy.isShutdown()` to decide if funds should be * redeployed or simply realize any profits/losses. * * @return _totalAssets A trusted and accurate account for the total * amount of 'asset' the strategy currently holds including idle funds. */ function _harvestAndReport() internal virtual returns (uint256 _totalAssets); /*////////////////////////////////////////////////////////////// OPTIONAL TO OVERRIDE BY STRATEGIST //////////////////////////////////////////////////////////////*/ /** * @dev Optional function for strategist to override that can * be called in between reports. * * If '_tend' is used tendTrigger() will also need to be overridden. * * This call can only be called by a permissioned role so may be * through protected relays. * * This can be used to harvest and compound rewards, deposit idle funds, * perform needed position maintenance or anything else that doesn't need * a full report for. * * EX: A strategy that can not deposit funds without getting * sandwiched can use the tend when a certain threshold * of idle to totalAssets has been reached. * * This will have no effect on PPS of the strategy till report() is called. * * @param _totalIdle The current amount of idle funds that are available to deploy. */ function _tend(uint256 _totalIdle) internal virtual {} /** * @dev Optional trigger to override if tend() will be used by the strategy. * This must be implemented if the strategy hopes to invoke _tend(). * * @return . Should return true if tend() should be called by keeper or false if not. */ function _tendTrigger() internal view virtual returns (bool) { return false; } /** * @notice Returns if tend() should be called by a keeper. * * @return . Should return true if tend() should be called by keeper or false if not. * @return . Calldata for the tend call. */ function tendTrigger() external view virtual returns (bool, bytes memory) { return ( // Return the status of the tend trigger. _tendTrigger(), // And the needed calldata either way. abi.encodeWithSelector(ITokenizedStrategy.tend.selector) ); } /** * @notice Gets the max amount of `asset` that an address can deposit. * @dev Defaults to an unlimited amount for any address. But can * be overridden by strategists. * * This function will be called before any deposit or mints to enforce * any limits desired by the strategist. This can be used for either a * traditional deposit limit or for implementing a whitelist etc. * * EX: * if(isAllowed[_owner]) return super.availableDepositLimit(_owner); * * This does not need to take into account any conversion rates * from shares to assets. But should know that any non max uint256 * amounts may be converted to shares. So it is recommended to keep * custom amounts low enough as not to cause overflow when multiplied * by `totalSupply`. * * @param . The address that is depositing into the strategy. * @return . The available amount the `_owner` can deposit in terms of `asset` */ function availableDepositLimit( address /*_owner*/ ) public view virtual returns (uint256) { return type(uint256).max; } /** * @notice Gets the max amount of `asset` that can be withdrawn. * @dev Defaults to an unlimited amount for any address. But can * be overridden by strategists. * * This function will be called before any withdraw or redeem to enforce * any limits desired by the strategist. This can be used for illiquid * or sandwichable strategies. It should never be lower than `totalIdle`. * * EX: * return TokenIzedStrategy.totalIdle(); * * This does not need to take into account the `_owner`'s share balance * or conversion rates from shares to assets. * * @param . The address that is withdrawing from the strategy. * @return . The available amount that can be withdrawn in terms of `asset` */ function availableWithdrawLimit( address /*_owner*/ ) public view virtual returns (uint256) { return type(uint256).max; } /** * @dev Optional function for a strategist to override that will * allow management to manually withdraw deployed funds from the * yield source if a strategy is shutdown. * * This should attempt to free `_amount`, noting that `_amount` may * be more than is currently deployed. * * NOTE: This will not realize any profits or losses. A separate * {report} will be needed in order to record any profit/loss. If * a report may need to be called after a shutdown it is important * to check if the strategy is shutdown during {_harvestAndReport} * so that it does not simply re-deploy all funds that had been freed. * * EX: * if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) { * depositFunds... * } * * @param _amount The amount of asset to attempt to free. */ function _emergencyWithdraw(uint256 _amount) internal virtual {} /*////////////////////////////////////////////////////////////// TokenizedStrategy HOOKS //////////////////////////////////////////////////////////////*/ /** * @notice Can deploy up to '_amount' of 'asset' in yield source. * @dev Callback for the TokenizedStrategy to call during a {deposit} * or {mint} to tell the strategy it can deploy funds. * * Since this can only be called after a {deposit} or {mint} * delegateCall to the TokenizedStrategy msg.sender == address(this). * * Unless a whitelist is implemented this will be entirely permissionless * and thus can be sandwiched or otherwise manipulated. * * @param _amount The amount of 'asset' that the strategy can * attempt to deposit in the yield source. */ function deployFunds(uint256 _amount) external virtual onlySelf { _deployFunds(_amount); } /** * @notice Should attempt to free the '_amount' of 'asset'. * @dev Callback for the TokenizedStrategy to call during a withdraw * or redeem to free the needed funds to service the withdraw. * * This can only be called after a 'withdraw' or 'redeem' delegateCall * to the TokenizedStrategy so msg.sender == address(this). * * @param _amount The amount of 'asset' that the strategy should attempt to free up. */ function freeFunds(uint256 _amount) external virtual onlySelf { _freeFunds(_amount); } /** * @notice Returns the accurate amount of all funds currently * held by the Strategy. * @dev Callback for the TokenizedStrategy to call during a report to * get an accurate accounting of assets the strategy controls. * * This can only be called after a report() delegateCall to the * TokenizedStrategy so msg.sender == address(this). * * @return . A trusted and accurate account for the total amount * of 'asset' the strategy currently holds including idle funds. */ function harvestAndReport() external virtual onlySelf returns (uint256) { return _harvestAndReport(); } /** * @notice Will call the internal '_tend' when a keeper tends the strategy. * @dev Callback for the TokenizedStrategy to initiate a _tend call in the strategy. * * This can only be called after a tend() delegateCall to the TokenizedStrategy * so msg.sender == address(this). * * We name the function `tendThis` so that `tend` calls are forwarded to * the TokenizedStrategy. * @param _totalIdle The amount of current idle funds that can be * deployed during the tend */ function tendThis(uint256 _totalIdle) external virtual onlySelf { _tend(_totalIdle); } /** * @notice Will call the internal '_emergencyWithdraw' function. * @dev Callback for the TokenizedStrategy during an emergency withdraw. * * This can only be called after a emergencyWithdraw() delegateCall to * the TokenizedStrategy so msg.sender == address(this). * * We name the function `shutdownWithdraw` so that `emergencyWithdraw` * calls are forwarded to the TokenizedStrategy. * * @param _amount The amount of asset to attempt to free. */ function shutdownWithdraw(uint256 _amount) external virtual onlySelf { _emergencyWithdraw(_amount); } /** * @dev Function used to delegate call the TokenizedStrategy with * certain `_calldata` and return any return values. * * This is used to setup the initial storage of the strategy, and * can be used by strategist to forward any other call to the * TokenizedStrategy implementation. * * @param _calldata The abi encoded calldata to use in delegatecall. * @return . The return value if the call was successful in bytes. */ function _delegateCall( bytes memory _calldata ) internal returns (bytes memory) { // Delegate call the tokenized strategy with provided calldata. (bool success, bytes memory result) = tokenizedStrategyAddress .delegatecall(_calldata); // If the call reverted. Return the error. if (!success) { assembly { let ptr := mload(0x40) let size := returndatasize() returndatacopy(ptr, 0, size) revert(ptr, size) } } // Return the result. return result; } /** * @dev Execute a function on the TokenizedStrategy and return any value. * * This fallback function will be executed when any of the standard functions * defined in the TokenizedStrategy are called since they wont be defined in * this contract. * * It will delegatecall the TokenizedStrategy implementation with the exact * calldata and return any relevant values. * */ fallback() external { // load our target address address _tokenizedStrategyAddress = tokenizedStrategyAddress; // Execute external function using delegatecall and return any value. assembly { // Copy function selector and any arguments. calldatacopy(0, 0, calldatasize()) // Execute function delegatecall. let result := delegatecall( gas(), _tokenizedStrategyAddress, 0, calldatasize(), 0, 0 ) // Get any return value returndatacopy(0, 0, returndatasize()) // Return any return value or error back to the caller switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol"; import "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Errors } from "src/libraries/Errors.sol"; import { ICurveRouter } from "src/interfaces/deps/curve/ICurveRouter.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; /** * @title Curve Router Library * @notice Contains helper methods for interacting with Curve Router. * @dev Curve router is deployed on these networks at 0xF0d4c12A5768D806021F80a262B4d39d26C58b8D * - Ethereum * - Optimism * - Gnosis * - Polygon * - Fantom * - Kava * - Arbitrum * - Avalanche * - Base at 0xd6681e74eEA20d196c15038C580f721EF2aB6320 * https://github.com/curvefi/curve-router-ng/tree/master */ contract CurveRouterSwapper { using SafeERC20 for IERC20; /// @notice The address of the Curve Router contract // solhint-disable-next-line var-name-mixedcase // slither-disable-next-line naming-convention address private immutable _CURVE_ROUTER; /// @notice Struct to store parameters for a Curve swap struct CurveSwapParams { address[11] route; uint256[5][5] swapParams; address[5] pools; } /** * @dev Sets the Curve Router address on contract deployment. * @param curveRouter_ The address of the Curve Router. */ constructor(address curveRouter_) payable { // Checks if (curveRouter_ == address(0)) { revert Errors.ZeroAddress(); } // Effects _CURVE_ROUTER = curveRouter_; } /** * @dev Approves the Curve Router to spend the specified token. * @param token The ERC20 token address to approve. */ function _approveTokenForSwap(address token) internal { IERC20(token).forceApprove(_CURVE_ROUTER, type(uint256).max); } /** * @dev Executes a token swap via the Curve Router. * @param curveSwapParams The parameters for the swap. * @param amount The amount of the input token to swap. * @param expected The minimum amount of the output token expected to receive. * @param receiver The address that will receive the output tokens. * @return The amount of the output token received from the swap. */ function _swap( CurveSwapParams memory curveSwapParams, uint256 amount, uint256 expected, address receiver ) internal returns (uint256) { return ICurveRouter(_CURVE_ROUTER).exchange( curveSwapParams.route, curveSwapParams.swapParams, amount, expected, curveSwapParams.pools, receiver ); } /** * @dev Validates the swap parameters against the provided route and tokens. * @param curveSwapParams The parameters for the swap. * @param fromToken The address of the input token. * @param toToken The address of the output token. */ function _validateSwapParams( CurveSwapParams memory curveSwapParams, address fromToken, address toToken ) internal view { // Check if fromToken is in the route if (fromToken != curveSwapParams.route[0]) { revert Errors.InvalidFromToken(fromToken, curveSwapParams.route[0]); } // Check if toToken is in the route address toTokenInRoute = address(0); uint256 routeLength = curveSwapParams.route.length; for (uint256 i = 0; i < routeLength;) { if (curveSwapParams.route[i] == address(0)) { break; } toTokenInRoute = curveSwapParams.route[i]; /// @dev The unchecked block is used here because the loop index `i` is simply incremented in each /// iteration, ensuring that `i` will not exceed the length of the array and cause an overflow. Underflow is /// not a concern as `i` is initialized to 0 and only incremented. unchecked { ++i; } } if (toTokenInRoute != toToken) { revert Errors.InvalidToToken(toToken, toTokenInRoute); } // Note that this does not check whether supplied token exists in the pool since the // get_dy function only relies on the indexes on swaps instead of addresses. try ICurveRouter(_CURVE_ROUTER).get_dy( curveSwapParams.route, curveSwapParams.swapParams, 10 ** IERC20Metadata(fromToken).decimals(), curveSwapParams.pools ) returns (uint256 expected) { if (expected == 0) { revert Errors.ExpectedAmountZero(); } } catch { revert Errors.InvalidSwapParams(); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.18; import { IYearnStakingDelegate } from "src/interfaces/IYearnStakingDelegate.sol"; import { Errors } from "src/libraries/Errors.sol"; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import { IYearnVaultV2 } from "src/interfaces/deps/yearn/veYFI/IYearnVaultV2.sol"; /** * @title YearnGaugeStrategyBase * @notice Abstract base contract for Yearn gauge strategies, handling deposits and withdrawals to the * YearnStakingDelegate. */ abstract contract YearnGaugeStrategyBase { // Libraries using SafeERC20 for IERC20; // Constant storage variables // solhint-disable const-name-snakecase /// @notice Address of the dYFI token address internal constant _DYFI = 0x41252E8691e964f7DE35156B68493bAb6797a275; /// @notice Address of the YFI token address internal constant _YFI = 0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e; // solhint-enable const-name-snakecase // Immutable storage variables // solhint-disable immutable-vars-naming // slither-disable-start naming-convention /// @notice Address of the YearnStakingDelegate contract address internal immutable _YEARN_STAKING_DELEGATE; /// @notice Address of the vault's underlying asset address internal immutable _VAULT_ASSET; /// @notice Address of the Yearn vault address internal immutable _VAULT; // solhint-enable immutable-vars-naming // slither-disable-end naming-convention /** * @dev Sets the initial configuration of the strategy and approves the maximum amount of tokens to the * YearnStakingDelegate. * @param asset_ The address of the asset (gauge token). * @param yearnStakingDelegate_ The address of the Yearn Staking Delegate. */ constructor(address asset_, address yearnStakingDelegate_) { address vault_ = IERC4626(asset_).asset(); address vaultAsset_ = address(0); try IERC4626(vault_).asset() returns (address returnedVaultAsset) { vaultAsset_ = returnedVaultAsset; } catch { vaultAsset_ = IYearnVaultV2(vault_).token(); } // Check for zero addresses if (yearnStakingDelegate_ == address(0) || vault_ == address(0) || vaultAsset_ == address(0)) { revert Errors.ZeroAddress(); } // Effects // Set storage variable values _YEARN_STAKING_DELEGATE = yearnStakingDelegate_; _VAULT = vault_; _VAULT_ASSET = vaultAsset_; // Interactions IERC20(asset_).forceApprove(yearnStakingDelegate_, type(uint256).max); IERC20(vaultAsset_).forceApprove(vault_, type(uint256).max); IERC20(vault_).forceApprove(asset_, type(uint256).max); } /** * @notice Get the address of the YearnStakingDelegate. * @return The address of the YearnStakingDelegate. */ function yearnStakingDelegate() external view returns (address) { return _YEARN_STAKING_DELEGATE; } /** * @notice Get the address of the vault's underlying asset. This is the asset that is deposited into the * vault which then is deposited into the gauge. * @return The address of the vault's underlying asset. */ function vaultAsset() external view returns (address) { return _VAULT_ASSET; } /** * @notice Get the address of the vault. This is the Yearn vault that the gauge is for. * @return The address of the vault. */ function vault() external view returns (address) { return _VAULT; } /** * @dev Internal function to deposit assets into the YearnStakingDelegate. * @param asset The address of the asset to deposit. * @param amount The amount of the asset to deposit. */ function _depositToYSD(address asset, uint256 amount) internal virtual { IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).deposit(asset, amount); } /** * @dev Internal function to withdraw assets from the YearnStakingDelegate. * @param asset The address of the asset to withdraw. * @param amount The amount of the asset to withdraw. */ function _withdrawFromYSD(address asset, uint256 amount) internal virtual { // Withdraw gauge from YSD which transfers to msg.sender IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).withdraw(asset, amount); } /** * @notice Return the amount of the asset deposited by this contract in the YearnStakingDelegate. * @param asset The address of the asset to check. * @return The amount of the asset deposited in the YearnStakingDelegate. */ function depositedInYSD(address asset) public view returns (uint256) { return IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).balanceOf(address(this), asset); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.18; import { IVotingYFI } from "./deps/yearn/veYFI/IVotingYFI.sol"; interface IYearnStakingDelegate { // Struct definitions struct RewardSplit { uint64 treasury; uint64 coveYfi; uint64 user; uint64 lock; } struct ExitRewardSplit { uint128 treasury; uint128 coveYfi; } struct BoostRewardSplit { uint128 treasury; uint128 coveYfi; } function deposit(address gauge, uint256 amount) external; function withdraw(address gauge, uint256 amount) external; function withdraw(address gauge, uint256 amount, address receiver) external; function lockYfi(uint256 amount) external returns (IVotingYFI.LockedBalance memory); function harvest(address vault) external returns (uint256); function setCoveYfiRewardForwarder(address forwarder) external; function setGaugeRewardSplit( address gauge, uint64 treasuryPct, uint64 coveYfiPct, uint64 userPct, uint64 veYfiPct ) external; function setBoostRewardSplit(uint128 treasuryPct, uint128 coveYfiPct) external; function setExitRewardSplit(uint128 treasuryPct, uint128 coveYfiPct) external; function setSwapAndLock(address swapAndLock) external; function balanceOf(address user, address gauge) external view returns (uint256); function totalDeposited(address gauge) external view returns (uint256); function depositLimit(address gauge) external view returns (uint256); function availableDepositLimit(address gauge) external view returns (uint256); function gaugeStakingRewards(address gauge) external view returns (address); function gaugeRewardReceivers(address gauge) external view returns (address); function getGaugeRewardSplit(address gauge) external view returns (RewardSplit memory); function getBoostRewardSplit() external view returns (BoostRewardSplit memory); function getExitRewardSplit() external view returns (ExitRewardSplit memory); function treasury() external view returns (address); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.18; /// @title Errors /// @notice Library containing all custom errors the protocol may revert with. library Errors { //// MASTER REGISTRY //// /// @notice Thrown when the registry name given is empty. error NameEmpty(); /// @notice Thrown when the registry address given is empty. error AddressEmpty(); /// @notice Thrown when the registry name is found when calling addRegistry(). error RegistryNameFound(bytes32 name); /// @notice Thrown when the registry name is not found but is expected to be. error RegistryNameNotFound(bytes32 name); /// @notice Thrown when the registry address is not found but is expected to be. error RegistryAddressNotFound(address registryAddress); /// @notice Thrown when the registry name and version is not found but is expected to be. error RegistryNameVersionNotFound(bytes32 name, uint256 version); /// @notice Thrown when a duplicate registry address is found. error DuplicateRegistryAddress(address registryAddress); //// YEARN STAKING DELEGATE //// /// @notice Error for when an address is zero which is not allowed. error ZeroAddress(); /// @notice Error for when an amount is zero which is not allowed. error ZeroAmount(); /// @notice Error for when a reward split is invalid. error InvalidRewardSplit(); /// @notice Error for when the treasury percentage is too high. error TreasuryPctTooHigh(); /// @notice Error for when perpetual lock is enabled and an action cannot be taken. error PerpetualLockEnabled(); /// @notice Error for when perpetual lock is disabled and an action cannot be taken. error PerpetualLockDisabled(); /// @notice Error for when swap and lock settings are not set. error SwapAndLockNotSet(); /// @notice Error for when gauge rewards have already been added. error GaugeRewardsAlreadyAdded(); /// @notice Error for when gauge rewards have not yet been added. error GaugeRewardsNotYetAdded(); /// @notice Error for when execution of an action is not allowed. error ExecutionNotAllowed(); /// @notice Error for when execution of an action has failed. error ExecutionFailed(); /// @notice Error for when Cove YFI reward forwarder is not set. error CoveYfiRewardForwarderNotSet(); //// STAKING DELEGATE REWARDS //// /// @notice Error for when a rescue operation is not allowed. error RescueNotAllowed(); /// @notice Error for when the previous rewards period has not been completed. error PreviousRewardsPeriodNotCompleted(); /// @notice Error for when only the staking delegate can update a user's balance. error OnlyStakingDelegateCanUpdateUserBalance(); /// @notice Error for when only the staking delegate can add a staking token. error OnlyStakingDelegateCanAddStakingToken(); /// @notice Error for when only the reward distributor can notify the reward amount. error OnlyRewardDistributorCanNotifyRewardAmount(); /// @notice Error for when a staking token has already been added. error StakingTokenAlreadyAdded(); /// @notice Error for when a staking token has not been added. error StakingTokenNotAdded(); /// @notice Error for when the reward rate is too low. error RewardRateTooLow(); /// @notice Error for when the reward duration cannot be zero. error RewardDurationCannotBeZero(); //// WRAPPED STRATEGY CURVE SWAPPER //// /// @notice Error for when slippage is too high. error SlippageTooHigh(); /// @notice Error for when invalid tokens are received. error InvalidTokensReceived(); /// CURVE ROUTER SWAPPER /// /* * @notice Error for when the from token is invalid. * @param intendedFromToken The intended from token address. * @param actualFromToken The actual from token address received. */ error InvalidFromToken(address intendedFromToken, address actualFromToken); /* * @notice Error for when the to token is invalid. * @param intendedToToken The intended to token address. * @param actualToToken The actual to token address received. */ error InvalidToToken(address intendedToToken, address actualToToken); /// @notice Error for when the expected amount is zero. error ExpectedAmountZero(); /// @notice Error for when swap parameters are invalid. error InvalidSwapParams(); /// SWAP AND LOCK /// /// @notice Error for when the same address is used in a context where it is not allowed. error SameAddress(); //// COVEYFI //// /// @notice Error for when only minting is enabled. error OnlyMintingEnabled(); /// RESCUABLE /// /// @notice Error for when an ETH transfer of zero is attempted. error ZeroEthTransfer(); /// @notice Error for when an ETH transfer fails. error EthTransferFailed(); /// @notice Error for when a token transfer of zero is attempted. error ZeroTokenTransfer(); /// GAUGE REWARD RECEIVER /// /// @notice Error for when an action is not authorized. error NotAuthorized(); /// @notice Error for when rescuing a reward token is not allowed. error CannotRescueRewardToken(); /// DYFI REDEEMER /// /// @notice Error for when an array length is invalid. error InvalidArrayLength(); /// @notice Error for when a price feed is outdated. error PriceFeedOutdated(); /// @notice Error for when a price feed round is incorrect. error PriceFeedIncorrectRound(); /// @notice Error for when a price feed returns a zero price. error PriceFeedReturnedZeroPrice(); /// @notice Error for when there is no DYFI to redeem. error NoDYfiToRedeem(); /// @notice Error for when an ETH transfer for caller reward fails. error CallerRewardEthTransferFailed(); /// COVE YEARN GAUGE FACTORY /// /// @notice Error for when a gauge has already been deployed. error GaugeAlreadyDeployed(); /// @notice Error for when a gauge has not been deployed. error GaugeNotDeployed(); /// MINICHEF V3 //// /// @notice Error for when an LP token is invalid. error InvalidLPToken(); /// @notice Error for when an LP token has not been added. error LPTokenNotAdded(); /// @notice Error for when an LP token does not match the pool ID. error LPTokenDoesNotMatchPoolId(); /// @notice Error for when there is an insufficient balance. error InsufficientBalance(); /// @notice Error for when an LP token has already been added. error LPTokenAlreadyAdded(); /// @notice Error for when the reward rate is too high. error RewardRateTooHigh(); /// Yearn4626RouterExt /// /// @notice Error for when there are insufficient shares. error InsufficientShares(); /// @notice Error for when the 'to' address is invalid. error InvalidTo(); /// @notice Error esure the has enough remaining gas. error InsufficientGas(); /// TESTING /// /// @notice Error for when there is not enough balance to take away. error TakeAwayNotEnoughBalance(); /// @notice Error for when a strategy has not been added to a vault. error StrategyNotAddedToVault(); /// COVE TOKEN /// /// @notice Error for when a transfer is attempted before it is allowed. error TransferNotAllowedYet(); /// @notice Error for when an address is being added as both a sender and a receiver. error CannotBeBothSenderAndReceiver(); /// @notice Error for when an unpause is attempted too early. error UnpauseTooEarly(); /// @notice Error for when the pause period is too long. error PausePeriodTooLong(); /// @notice Error for when minting is attempted too early. error MintingAllowedTooEarly(); /// @notice Error for when the mint amount exceeds the cap. error InflationTooLarge(); /* * @notice Error for when an unauthorized account attempts an action requiring a specific role. * @param account The account attempting the unauthorized action. * @param neededRole The role required for the action. */ error AccessControlEnumerableUnauthorizedAccount(address account, bytes32 neededRole); /// @notice Error for when an action is unauthorized. error Unauthorized(); /// @notice Error for when a pause is expected but not enacted. error ExpectedPause(); /// COVE YEARN GAUGE FACTORY /// /// @notice Error for when an address is not a contract. error AddressNotContract(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.18; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; // Interface that implements the 4626 standard and the implementation functions interface ITokenizedStrategy is IERC4626, IERC20Permit { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event StrategyShutdown(); event NewTokenizedStrategy( address indexed strategy, address indexed asset, string apiVersion ); event Reported( uint256 profit, uint256 loss, uint256 protocolFees, uint256 performanceFees ); event UpdatePerformanceFeeRecipient( address indexed newPerformanceFeeRecipient ); event UpdateKeeper(address indexed newKeeper); event UpdatePerformanceFee(uint16 newPerformanceFee); event UpdateManagement(address indexed newManagement); event UpdateEmergencyAdmin(address indexed newEmergencyAdmin); event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime); event UpdatePendingManagement(address indexed newPendingManagement); /*////////////////////////////////////////////////////////////// INITIALIZATION //////////////////////////////////////////////////////////////*/ function initialize( address _asset, string memory _name, address _management, address _performanceFeeRecipient, address _keeper ) external; /*////////////////////////////////////////////////////////////// NON-STANDARD 4626 OPTIONS //////////////////////////////////////////////////////////////*/ function withdraw( uint256 assets, address receiver, address owner, uint256 maxLoss ) external returns (uint256); function redeem( uint256 shares, address receiver, address owner, uint256 maxLoss ) external returns (uint256); /*////////////////////////////////////////////////////////////// MODIFIER HELPERS //////////////////////////////////////////////////////////////*/ function requireManagement(address _sender) external view; function requireKeeperOrManagement(address _sender) external view; function requireEmergencyAuthorized(address _sender) external view; /*////////////////////////////////////////////////////////////// KEEPERS FUNCTIONS //////////////////////////////////////////////////////////////*/ function tend() external; function report() external returns (uint256 _profit, uint256 _loss); /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ function MAX_FEE() external view returns (uint16); function FACTORY() external view returns (address); /*////////////////////////////////////////////////////////////// GETTERS //////////////////////////////////////////////////////////////*/ function apiVersion() external view returns (string memory); function pricePerShare() external view returns (uint256); function management() external view returns (address); function pendingManagement() external view returns (address); function keeper() external view returns (address); function emergencyAdmin() external view returns (address); function performanceFee() external view returns (uint16); function performanceFeeRecipient() external view returns (address); function fullProfitUnlockDate() external view returns (uint256); function profitUnlockingRate() external view returns (uint256); function profitMaxUnlockTime() external view returns (uint256); function lastReport() external view returns (uint256); function isShutdown() external view returns (bool); function unlockedShares() external view returns (uint256); /*////////////////////////////////////////////////////////////// SETTERS //////////////////////////////////////////////////////////////*/ function setPendingManagement(address) external; function acceptManagement() external; function setKeeper(address _keeper) external; function setEmergencyAdmin(address _emergencyAdmin) external; function setPerformanceFee(uint16 _performanceFee) external; function setPerformanceFeeRecipient( address _performanceFeeRecipient ) external; function setProfitMaxUnlockTime(uint256 _profitMaxUnlockTime) external; function shutdownStrategy() external; function emergencyWithdraw(uint256 _amount) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; interface ICurveRouter { /** * @notice Performs an exchange operation. * @dev `route` and `swapParams` should be determined off chain. * @param route An array of [initial token, pool or zap, token, pool or zap, token, ...]. The iteration continues * until a pool address of 0x00, then the last given token is transferred to `_receiver` * @param swapParams A multidimensional array of [i, j, swap type, pool_type, n_coins] where: * i is the index of the input token, * j is the index of the output token, * swap type should be: * - 1 for `exchange`, * - 2 for `exchange_underlying`, * - 3 for underlying exchange via zap: factory stable metapools with lending base pool * `exchange_underlying` and factory crypto-metapools underlying exchange (`exchange` method in zap); * - 4 for coin -> LP token "exchange" (actually `add_liquidity`), * - 5 for lending pool underlying coin -> LP token "exchange" (actually `add_liquidity`), * - 6 for LP token -> coin "exchange" (actually `remove_liquidity_one_coin`), * - 7 for LP token -> lending or fake pool underlying coin "exchange" (actually * `remove_liquidity_one_coin`), * - 8 for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH, * - 9 for SNX swaps (sUSD, sEUR, sETH, sBTC) * Pool type: * - 1 - stable, 2 - crypto, 3 - tricrypto, 4 - llama * `n_coins` indicates the number of coins in the pool * @param amount The amount of `route[0]` to be sent. * @param expected The minimum amount received after the final swap. * @return The received amount of the final output token. */ function exchange( address[11] calldata route, uint256[5][5] calldata swapParams, uint256 amount, uint256 expected ) external payable returns (uint256); /** * @notice Performs up to 5 swaps in a single transaction. * @dev Routing and swap params must be determined off-chain. This functionality is designed for gas efficiency over * ease-of-use. * @param route Array of the route. * @param swapParams Parameters for the swap operation. * @param amount The amount of `route[0]` to be sent. * @param expected The minimum amount expected after all the swaps. * @param pools Array of pool addresses for swaps via zap contracts. Needed only for swap type = 3. * @param receiver The address to transfer the final output token to. * @return The received amount of the final output token. */ function exchange( address[11] calldata route, uint256[5][5] calldata swapParams, uint256 amount, uint256 expected, address[5] calldata pools, address receiver ) external payable returns (uint256); /** * @notice Executes an exchange operation. * @param route Array containing the route for exchange. * @param swapParams Parameters for the swap operation. * @param amount The amount of input token to be sent. * @param expected The minimum amount expected after the exchange. * @param pools Array of pool addresses for swaps via zap contracts. * @return The received amount of the final output token. */ function exchange( address[11] calldata route, uint256[5][5] calldata swapParams, uint256 amount, uint256 expected, address[5] calldata pools ) external payable returns (uint256); function get_dy( address[11] calldata route, uint256[5][5] calldata swapParams, uint256 amount, address[5] calldata pools ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; // @dev YearnVaultV2 does not follow ERC4626 interface for `asset()` instead it uses `token()` interface IYearnVaultV2 { function token() external view returns (address); function deposit(uint256 amount, address recipient) external returns (uint256 shares); function deposit(uint256 amount) external returns (uint256 shares); function withdraw(uint256 shares, address recipient) external returns (uint256 amount); function pricePerShare() external view returns (uint256); function totalSupply() external view returns (uint256); function totalAssets() external view returns (uint256); function lastReport() external view returns (uint256); function lockedProfitDegradation() external view returns (uint256); function lockedProfit() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IVotingYFI is IERC20 { event ModifyLock(address indexed sender, address indexed user, uint256 amount, uint256 locktime, uint256 ts); event Withdraw(address indexed user, uint256 amount, uint256 ts); event Penalty(address indexed user, uint256 amount, uint256 ts); event Supply(uint256 oldSupply, uint256 newSupply, uint256 ts); struct LockedBalance { uint256 amount; uint256 end; } struct Withdrawn { uint256 amount; uint256 penalty; } struct Point { int128 bias; int128 slope; uint256 ts; uint256 blk; } function totalSupply() external view returns (uint256); function locked(address _user) external view returns (LockedBalance memory); function modify_lock( uint256 _amount, uint256 _unlock_time, address _user ) external returns (LockedBalance memory); function withdraw() external returns (Withdrawn memory); function point_history(address user, uint256 epoch) external view returns (Point memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
{ "remappings": [ "@openzeppelin/=lib/openzeppelin-contracts/", "@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "tokenized-strategy/=lib/tokenized-strategy/src/", "yearn-vaults-v3/=lib/yearn-vaults-v3/contracts/", "Yearn-ERC4626-Router/=lib/Yearn-ERC4626-Router/src/", "solmate/=lib/permit2/lib/solmate/src/", "permit2/=lib/permit2/src/", "forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "@crytic/properties/=lib/properties/", "forge-deploy/=lib/forge-deploy/contracts/", "script/=script/", "src/=src/", "test/=test/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"asset_","type":"address"},{"internalType":"address","name":"yearnStakingDelegate_","type":"address"},{"internalType":"address","name":"curveRouter_","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"ExpectedAmountZero","type":"error"},{"inputs":[{"internalType":"address","name":"intendedFromToken","type":"address"},{"internalType":"address","name":"actualFromToken","type":"address"}],"name":"InvalidFromToken","type":"error"},{"inputs":[],"name":"InvalidSwapParams","type":"error"},{"inputs":[{"internalType":"address","name":"intendedToToken","type":"address"},{"internalType":"address","name":"actualToToken","type":"address"}],"name":"InvalidToToken","type":"error"},{"inputs":[],"name":"SameAddress","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldDYfiRedeemer","type":"address"},{"indexed":false,"internalType":"address","name":"newDYfiRedeemer","type":"address"}],"name":"DYfiRedeemerSet","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"availableDepositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"availableWithdrawLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dYfiRedeemer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deployFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"depositedInYSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"freeFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestAndReport","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newDYfiRedeemer","type":"address"}],"name":"setDYfiRedeemer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address[11]","name":"route","type":"address[11]"},{"internalType":"uint256[5][5]","name":"swapParams","type":"uint256[5][5]"},{"internalType":"address[5]","name":"pools","type":"address[5]"}],"internalType":"struct CurveRouterSwapper.CurveSwapParams","name":"curveSwapParams","type":"tuple"}],"name":"setHarvestSwapParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"shutdownWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalIdle","type":"uint256"}],"name":"tendThis","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenizedStrategyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yearnStakingDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101406040526040516200248e3803806200248e833981016040819052620000279162000891565b604080518082018252601881527f5772617070656420596561726e5633205374726174656779000000000000000060208201526001600160a01b0385166080523060a05290518491849184918491620000c6906200009290849084903390819081906024016200092f565b60408051601f198184030181529190526020810180516001600160e01b03908116634b839d7360e11b179091526200038916565b505073bb51273d6c746910c7c06fe718f30c936170fed07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55506001600160a01b038116620001285760405163d92e233d60e01b815260040160405180910390fd5b806001600160a01b031660c0816001600160a01b031681525050506000826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000184573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001aa919062000972565b90506000816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156200020b575060408051601f3d908101601f19168201909252620002089181019062000972565b60015b6200027d57816001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200024f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000275919062000972565b905062000280565b90505b6001600160a01b03831615806200029e57506001600160a01b038216155b80620002b157506001600160a01b038116155b15620002d05760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0383811660e052828116610120528181166101005262000309908516846000196200041d602090811b620006a617901c565b6200033082600019836001600160a01b03166200041d60201b620006a6179092919060201c565b6200035784600019846001600160a01b03166200041d60201b620006a6179092919060201c565b5050505062000380730bc529c00c6401aef6d220be8c6ea1667f6ad93e620004f360201b60201c565b505050620009e7565b606060008073bb51273d6c746910c7c06fe718f30c936170fed06001600160a01b031684604051620003bc919062000990565b600060405180830381855af49150503d8060008114620003f9576040519150601f19603f3d011682016040523d82523d6000602084013e620003fe565b606091505b50915091508162000416576040513d806000833e8082fd5b9392505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526200047790859083906200051f16565b620004ed576040516001600160a01b038416602482015260006044820152620004e190859063095ea7b360e01b9060640160408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b0393841617905290620005d716565b620004ed8482620005d7565b50505050565b6200051c60c051600019836001600160a01b03166200041d60201b620006a6179092919060201c565b50565b6000806000846001600160a01b0316846040516200053e919062000990565b6000604051808303816000865af19150503d80600081146200057d576040519150601f19603f3d011682016040523d82523d6000602084013e62000582565b606091505b5091509150818015620005b0575080511580620005b0575080806020019051810190620005b09190620009ae565b8015620005ce5750620005ce85620006c160201b620007601760201c565b95945050505050565b600062000633826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620006d060201b6200076f179092919060201c565b905080516000148062000657575080806020019051810190620006579190620009ae565b620006bc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b505050565b6001600160a01b03163b151590565b6060620006e18484600085620006e9565b949350505050565b6060824710156200074c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620006b3565b600080866001600160a01b031685876040516200076a919062000990565b60006040518083038185875af1925050503d8060008114620007a9576040519150601f19603f3d011682016040523d82523d6000602084013e620007ae565b606091505b509092509050620007c287838387620007cd565b979650505050505050565b606083156200084157825160000362000839576001600160a01b0385163b620008395760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620006b3565b5081620006e1565b620006e18383815115620008585781518083602001fd5b8060405162461bcd60e51b8152600401620006b39190620009d2565b80516001600160a01b03811681146200088c57600080fd5b919050565b600080600060608486031215620008a757600080fd5b620008b28462000874565b9250620008c26020850162000874565b9150620008d26040850162000874565b90509250925092565b60005b83811015620008f8578181015183820152602001620008de565b50506000910152565b600081518084526200091b816020860160208601620008db565b601f01601f19169290920160200192915050565b600060018060a01b03808816835260a060208401526200095360a084018862000901565b9581166040840152938416606083015250911660809091015292915050565b6000602082840312156200098557600080fd5b620004168262000874565b60008251620009a4818460208701620008db565b9190910192915050565b600060208284031215620009c157600080fd5b815180151581146200041657600080fd5b60208152600062000416602083018462000901565b60805160a05160c05160e05161010051610120516119e762000aa7600039600081816102b401526109990152600081816101b8015261065f0152600081816102600152818161034101528181610584015281816111320152611253015260008181610d0301526111b10152600081816103f2015281816105d20152610aa1015260008181610316015281816107c901528181610a3001528181610b3701528181610b7001528181610bf801528181610e520152610e9001526119e76000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c806391b5810811610097578063d0ad561b11610066578063d0ad561b14610284578063d19a3bb814610297578063fbfa77cf146102b2578063fde813a8146102d857610100565b806391b58108146102255780639a6eb986146102385780639d7fb70c1461024b578063ab91dedb1461025e57610100565b806349317f1d116100d357806349317f1d146101ae5780634ab9e16b146101b6578063503160d9146101dc5780635d265d3f146101ef57610100565b806304bd46291461013b5780630af32db8146101635780633d6cb5751461018857806346aa2f121461019b575b73bb51273d6c746910c7c06fe718f30c936170fed03660008037600080366000845af43d6000803e808015610134573d6000f35b3d6000fd5b005b610150610149366004611335565b5060001990565b6040519081526020015b60405180910390f35b6029546001600160a01b03165b6040516001600160a01b03909116815260200161015a565b610139610196366004611359565b6102eb565b6101506101a9366004611335565b6102ff565b6101506103b5565b7f0000000000000000000000000000000000000000000000000000000000000000610170565b6101396101ea366004611359565b6103cc565b60408051600481526024810182526020810180516001600160e01b031663440368a360e01b179052905161015a916000916113c2565b610139610233366004611335565b6103dd565b610150610246366004611335565b61055c565b610139610259366004611359565b6105b5565b7f0000000000000000000000000000000000000000000000000000000000000000610170565b6101396102923660046113dd565b6105bd565b61017073bb51273d6c746910c7c06fe718f30c936170fed081565b7f0000000000000000000000000000000000000000000000000000000000000000610170565b6101396102e6366004611359565b610695565b6102f3610786565b6102fc816107c4565b50565b604051632355178960e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906346aa2f12906024015b602060405180830381865afa15801561038b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103af91906113f6565b92915050565b60006103bf610786565b6103c76107ee565b905090565b6103d4610786565b6102fc81610bf3565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561043c57600080fd5b505afa158015610450573d6000803e3d6000fd5b5050506001600160a01b038216905061047c5760405163d92e233d60e01b815260040160405180910390fd5b6029546001600160a01b039081169082168190036104ad5760405163367558c360e01b815260040160405180910390fd5b602980546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f018b53fd006eed8c62139c29c665bb88dedb897b7ef2eaa5da2778ea1224e3d0910160405180910390a16001600160a01b03811615610537576105377341252e8691e964f7de35156b68493bab6797a2758260006106a6565b6105587341252e8691e964f7de35156b68493bab6797a275836000196106a6565b5050565b604051633de222bb60e21b81523060048201526001600160a01b0382811660248301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063f7888aec9060440161036e565b6102fc610786565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561061c57600080fd5b505afa158015610630573d6000803e3d6000fd5b50505050610683818036038101906106489190611534565b730bc529c00c6401aef6d220be8c6ea1667f6ad93e7f0000000000000000000000000000000000000000000000000000000000000000610c1d565b806000610690828261165e565b505050565b61069d610786565b6102fc81610e4b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526106f78482610eb5565b61075a57604080516001600160a01b038516602482015260006044808301919091528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610750908590610f5c565b61075a8482610f5c565b50505050565b6001600160a01b03163b151590565b606061077e8484600085611031565b949350505050565b3330146107c25760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b60448201526064015b60405180910390fd5b565b6102fc7f00000000000000000000000000000000000000000000000000000000000000008261110c565b6040516370a0823160e01b81523060048201526000908190730bc529c00c6401aef6d220be8c6ea1667f6ad93e906370a0823190602401602060405180830381865afa158015610842573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086691906113f6565b90508015610b3257604080516101c0810190915260009061096f9082816060810182600b8282826020028201915b81546001600160a01b031681526001909101906020018083116108945750505091835250506040805160a08101909152602090910190600b830160056000835b8282101561091b576040805160a081019182905290600584810287019182845b8154815260200190600101908083116108f4575050505050815260200190600101906108d4565b505050908252506040805160a081019182905260209092019190602484019060059082845b81546001600160a01b03168152600190910190602001808311610940575050505050815250508360003061118b565b604051636e553f6560e01b8152600481018290523060248201529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636e553f65906044016020604051808303816000875af11580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0691906113f6565b604051636e553f6560e01b8152600481018290523060248201529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636e553f65906044016020604051808303816000875af1158015610a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9d91906113f6565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015610afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2191906116f0565b610b2e57610b2e81610bf3565b5050505b610b5b7f000000000000000000000000000000000000000000000000000000000000000061055c565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be391906113f6565b610bed9190611712565b91505090565b6102fc7f00000000000000000000000000000000000000000000000000000000000000008261122d565b8251516001600160a01b03838116911614610c6257825151604051638a26cfc960e01b81526001600160a01b03808516600483015290911660248201526044016107b9565b6000600b815b81811015610cbb57855160009082600b8110610c8657610c86611725565b60200201516001600160a01b031614610cbb57855181600b8110610cac57610cac611725565b60200201519250600101610c68565b50826001600160a01b0316826001600160a01b031614610d0157604051630eb5733160e31b81526001600160a01b038085166004830152831660248201526044016107b9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663637653cb86600001518760200151876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9c919061173b565b610da790600a611842565b89604001516040518563ffffffff1660e01b8152600401610dcb94939291906118fa565b602060405180830381865afa925050508015610e04575060408051601f3d908101601f19168201909252610e01918101906113f6565b60015b610e2157604051635037072d60e01b815260040160405180910390fd5b80600003610e425760405163e6aa89b960e01b815260040160405180910390fd5b505b5050505050565b6000610e767f000000000000000000000000000000000000000000000000000000000000000061055c565b90506000818311610e875782610e89565b815b90506106907f00000000000000000000000000000000000000000000000000000000000000008261110c565b6000806000846001600160a01b031684604051610ed2919061192c565b6000604051808303816000865af19150503d8060008114610f0f576040519150601f19603f3d011682016040523d82523d6000602084013e610f14565b606091505b5091509150818015610f3e575080511580610f3e575080806020019051810190610f3e91906116f0565b8015610f5357506001600160a01b0385163b15155b95945050505050565b6000610fb1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661076f9092919063ffffffff16565b9050805160001480610fd2575080806020019051810190610fd291906116f0565b6106905760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107b9565b6060824710156110925760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016107b9565b600080866001600160a01b031685876040516110ae919061192c565b60006040518083038185875af1925050503d80600081146110eb576040519150601f19603f3d011682016040523d82523d6000602084013e6110f0565b606091505b509150915061110187838387611282565b979650505050505050565b60405163f3fef3a360e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063f3fef3a3906044015b600060405180830381600087803b15801561117757600080fd5b505af1158015610e42573d6000803e3d6000fd5b83516020850151604080870151905163c872a3c560e01b81526000936001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363c872a3c5936111ea938a918a918a90600401611948565b6020604051808303816000875af1158015611209573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5391906113f6565b6040516311f9fbc960e21b81526001600160a01b038381166004830152602482018390527f000000000000000000000000000000000000000000000000000000000000000016906347e7ef249060440161115d565b606083156112f15782516000036112ea576001600160a01b0385163b6112ea5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107b9565b508161077e565b61077e83838151156113065781518083602001fd5b8060405162461bcd60e51b81526004016107b9919061199e565b6001600160a01b03811681146102fc57600080fd5b60006020828403121561134757600080fd5b813561135281611320565b9392505050565b60006020828403121561136b57600080fd5b5035919050565b60005b8381101561138d578181015183820152602001611375565b50506000910152565b600081518084526113ae816020860160208601611372565b601f01601f19169290920160200192915050565b821515815260406020820152600061077e6040830184611396565b600061052082840312156113f057600080fd5b50919050565b60006020828403121561140857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156114485761144861140f565b60405290565b60405160a0810167ffffffffffffffff811182821017156114485761144861140f565b600060405161016080820182811067ffffffffffffffff821117156114985761149861140f565b60405290915081908301848111156114af57600080fd5b835b818110156114d25780356114c481611320565b8352602092830192016114b1565b50505092915050565b600082601f8301126114ec57600080fd5b6114f461144e565b8060a084018581111561150657600080fd5b845b8181101561152957803561151b81611320565b845260209384019301611508565b509095945050505050565b6000610520828403121561154757600080fd5b61154f611425565b601f848185011261155f57600080fd5b6115698585611471565b82528461017f85011261157b57600080fd5b61158361144e565b8061048086018781111561159657600080fd5b61016087015b818110156115fb5788858201126115b35760008081fd5b6115bb61144e565b8060a083018b8111156115ce5760008081fd5b835b818110156115e85780358452602093840193016115d0565b505085525060209093019260a00161159c565b5081602086015261160c88826114db565b604086015250929695505050505050565b634e487b7160e01b600052601160045260246000fd5b8160005b600581101561075a57813561164b81611320565b8382015560209190910190600101611637565b8160005b600b81101561168957813561167681611320565b8382015560209190910190600101611662565b50506101608201600b820160005b60058082106116a657506116dc565b8360005b828110156116c6578135858201556020909101906001016116aa565b505060a093909301929190910190600101611697565b505050610558610480830160248301611633565b60006020828403121561170257600080fd5b8151801515811461135257600080fd5b808201808211156103af576103af61161d565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561174d57600080fd5b815160ff8116811461135257600080fd5b600181815b8085111561179957816000190482111561177f5761177f61161d565b8085161561178c57918102915b93841c9390800290611763565b509250929050565b6000826117b0575060016103af565b816117bd575060006103af565b81600181146117d357600281146117dd576117f9565b60019150506103af565b60ff8411156117ee576117ee61161d565b50506001821b6103af565b5060208310610133831016604e8410600b841016171561181c575081810a6103af565b611826838361175e565b806000190482111561183a5761183a61161d565b029392505050565b600061135260ff8416836117a1565b8060005b600b81101561075a5781516001600160a01b0316845260209384019390910190600101611855565b806000805b60058082106118915750610e44565b835186845b838110156118b4578251825260209283019290910190600101611896565b50505060a095909501945060209290920191600101611882565b8060005b600581101561075a5781516001600160a01b03168452602093840193909101906001016118d2565b61054081016119098287611851565b61191761016083018661187d565b83610480830152610f536104a08301846118ce565b6000825161193e818460208701611372565b9190910192915050565b61058081016119578289611851565b61196561016083018861187d565b85610480830152846104a08301526119816104c08301856118ce565b6001600160a01b0392909216610560919091015295945050505050565b602081526000611352602083018461139656fea26469706673582212205e2f254ff7f7f03e83a008359b65cecfadf674e108d1e967b8162d0122bbe35d64736f6c6343000812003300000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf400000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f00000000000000000000000016c6521dff6bab339122a0fe25a9116693265353
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101005760003560e01c806391b5810811610097578063d0ad561b11610066578063d0ad561b14610284578063d19a3bb814610297578063fbfa77cf146102b2578063fde813a8146102d857610100565b806391b58108146102255780639a6eb986146102385780639d7fb70c1461024b578063ab91dedb1461025e57610100565b806349317f1d116100d357806349317f1d146101ae5780634ab9e16b146101b6578063503160d9146101dc5780635d265d3f146101ef57610100565b806304bd46291461013b5780630af32db8146101635780633d6cb5751461018857806346aa2f121461019b575b73bb51273d6c746910c7c06fe718f30c936170fed03660008037600080366000845af43d6000803e808015610134573d6000f35b3d6000fd5b005b610150610149366004611335565b5060001990565b6040519081526020015b60405180910390f35b6029546001600160a01b03165b6040516001600160a01b03909116815260200161015a565b610139610196366004611359565b6102eb565b6101506101a9366004611335565b6102ff565b6101506103b5565b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f610170565b6101396101ea366004611359565b6103cc565b60408051600481526024810182526020810180516001600160e01b031663440368a360e01b179052905161015a916000916113c2565b610139610233366004611335565b6103dd565b610150610246366004611335565b61055c565b610139610259366004611359565b6105b5565b7f00000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f610170565b6101396102923660046113dd565b6105bd565b61017073bb51273d6c746910c7c06fe718f30c936170fed081565b7f00000000000000000000000092545bce636e6ee91d88d2d017182cd0bd2fc22e610170565b6101396102e6366004611359565b610695565b6102f3610786565b6102fc816107c4565b50565b604051632355178960e11b81526001600160a01b037f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf4811660048301526000917f00000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f909116906346aa2f12906024015b602060405180830381865afa15801561038b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103af91906113f6565b92915050565b60006103bf610786565b6103c76107ee565b905090565b6103d4610786565b6102fc81610bf3565b6040516348e4a64960e01b81523360048201527f0000000000000000000000009cb8c5136ad079d3311f5b766d6fc370bf29e76b6001600160a01b0316906348e4a6499060240160006040518083038186803b15801561043c57600080fd5b505afa158015610450573d6000803e3d6000fd5b5050506001600160a01b038216905061047c5760405163d92e233d60e01b815260040160405180910390fd5b6029546001600160a01b039081169082168190036104ad5760405163367558c360e01b815260040160405180910390fd5b602980546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f018b53fd006eed8c62139c29c665bb88dedb897b7ef2eaa5da2778ea1224e3d0910160405180910390a16001600160a01b03811615610537576105377341252e8691e964f7de35156b68493bab6797a2758260006106a6565b6105587341252e8691e964f7de35156b68493bab6797a275836000196106a6565b5050565b604051633de222bb60e21b81523060048201526001600160a01b0382811660248301526000917f00000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f9091169063f7888aec9060440161036e565b6102fc610786565b6040516348e4a64960e01b81523360048201527f0000000000000000000000009cb8c5136ad079d3311f5b766d6fc370bf29e76b6001600160a01b0316906348e4a6499060240160006040518083038186803b15801561061c57600080fd5b505afa158015610630573d6000803e3d6000fd5b50505050610683818036038101906106489190611534565b730bc529c00c6401aef6d220be8c6ea1667f6ad93e7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f610c1d565b806000610690828261165e565b505050565b61069d610786565b6102fc81610e4b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526106f78482610eb5565b61075a57604080516001600160a01b038516602482015260006044808301919091528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610750908590610f5c565b61075a8482610f5c565b50505050565b6001600160a01b03163b151590565b606061077e8484600085611031565b949350505050565b3330146107c25760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b60448201526064015b60405180910390fd5b565b6102fc7f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf48261110c565b6040516370a0823160e01b81523060048201526000908190730bc529c00c6401aef6d220be8c6ea1667f6ad93e906370a0823190602401602060405180830381865afa158015610842573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086691906113f6565b90508015610b3257604080516101c0810190915260009061096f9082816060810182600b8282826020028201915b81546001600160a01b031681526001909101906020018083116108945750505091835250506040805160a08101909152602090910190600b830160056000835b8282101561091b576040805160a081019182905290600584810287019182845b8154815260200190600101908083116108f4575050505050815260200190600101906108d4565b505050908252506040805160a081019182905260209092019190602484019060059082845b81546001600160a01b03168152600190910190602001808311610940575050505050815250508360003061118b565b604051636e553f6560e01b8152600481018290523060248201529091506000906001600160a01b037f00000000000000000000000092545bce636e6ee91d88d2d017182cd0bd2fc22e1690636e553f65906044016020604051808303816000875af11580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0691906113f6565b604051636e553f6560e01b8152600481018290523060248201529091506000906001600160a01b037f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf41690636e553f65906044016020604051808303816000875af1158015610a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9d91906113f6565b90507f0000000000000000000000009cb8c5136ad079d3311f5b766d6fc370bf29e76b6001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015610afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2191906116f0565b610b2e57610b2e81610bf3565b5050505b610b5b7f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf461055c565b6040516370a0823160e01b81523060048201527f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf46001600160a01b0316906370a0823190602401602060405180830381865afa158015610bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be391906113f6565b610bed9190611712565b91505090565b6102fc7f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf48261122d565b8251516001600160a01b03838116911614610c6257825151604051638a26cfc960e01b81526001600160a01b03808516600483015290911660248201526044016107b9565b6000600b815b81811015610cbb57855160009082600b8110610c8657610c86611725565b60200201516001600160a01b031614610cbb57855181600b8110610cac57610cac611725565b60200201519250600101610c68565b50826001600160a01b0316826001600160a01b031614610d0157604051630eb5733160e31b81526001600160a01b038085166004830152831660248201526044016107b9565b7f00000000000000000000000016c6521dff6bab339122a0fe25a91166932653536001600160a01b031663637653cb86600001518760200151876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9c919061173b565b610da790600a611842565b89604001516040518563ffffffff1660e01b8152600401610dcb94939291906118fa565b602060405180830381865afa925050508015610e04575060408051601f3d908101601f19168201909252610e01918101906113f6565b60015b610e2157604051635037072d60e01b815260040160405180910390fd5b80600003610e425760405163e6aa89b960e01b815260040160405180910390fd5b505b5050505050565b6000610e767f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf461055c565b90506000818311610e875782610e89565b815b90506106907f00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf48261110c565b6000806000846001600160a01b031684604051610ed2919061192c565b6000604051808303816000865af19150503d8060008114610f0f576040519150601f19603f3d011682016040523d82523d6000602084013e610f14565b606091505b5091509150818015610f3e575080511580610f3e575080806020019051810190610f3e91906116f0565b8015610f5357506001600160a01b0385163b15155b95945050505050565b6000610fb1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661076f9092919063ffffffff16565b9050805160001480610fd2575080806020019051810190610fd291906116f0565b6106905760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107b9565b6060824710156110925760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016107b9565b600080866001600160a01b031685876040516110ae919061192c565b60006040518083038185875af1925050503d80600081146110eb576040519150601f19603f3d011682016040523d82523d6000602084013e6110f0565b606091505b509150915061110187838387611282565b979650505050505050565b60405163f3fef3a360e01b81526001600160a01b038381166004830152602482018390527f00000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f169063f3fef3a3906044015b600060405180830381600087803b15801561117757600080fd5b505af1158015610e42573d6000803e3d6000fd5b83516020850151604080870151905163c872a3c560e01b81526000936001600160a01b037f00000000000000000000000016c6521dff6bab339122a0fe25a9116693265353169363c872a3c5936111ea938a918a918a90600401611948565b6020604051808303816000875af1158015611209573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5391906113f6565b6040516311f9fbc960e21b81526001600160a01b038381166004830152602482018390527f00000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f16906347e7ef249060440161115d565b606083156112f15782516000036112ea576001600160a01b0385163b6112ea5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107b9565b508161077e565b61077e83838151156113065781518083602001fd5b8060405162461bcd60e51b81526004016107b9919061199e565b6001600160a01b03811681146102fc57600080fd5b60006020828403121561134757600080fd5b813561135281611320565b9392505050565b60006020828403121561136b57600080fd5b5035919050565b60005b8381101561138d578181015183820152602001611375565b50506000910152565b600081518084526113ae816020860160208601611372565b601f01601f19169290920160200192915050565b821515815260406020820152600061077e6040830184611396565b600061052082840312156113f057600080fd5b50919050565b60006020828403121561140857600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156114485761144861140f565b60405290565b60405160a0810167ffffffffffffffff811182821017156114485761144861140f565b600060405161016080820182811067ffffffffffffffff821117156114985761149861140f565b60405290915081908301848111156114af57600080fd5b835b818110156114d25780356114c481611320565b8352602092830192016114b1565b50505092915050565b600082601f8301126114ec57600080fd5b6114f461144e565b8060a084018581111561150657600080fd5b845b8181101561152957803561151b81611320565b845260209384019301611508565b509095945050505050565b6000610520828403121561154757600080fd5b61154f611425565b601f848185011261155f57600080fd5b6115698585611471565b82528461017f85011261157b57600080fd5b61158361144e565b8061048086018781111561159657600080fd5b61016087015b818110156115fb5788858201126115b35760008081fd5b6115bb61144e565b8060a083018b8111156115ce5760008081fd5b835b818110156115e85780358452602093840193016115d0565b505085525060209093019260a00161159c565b5081602086015261160c88826114db565b604086015250929695505050505050565b634e487b7160e01b600052601160045260246000fd5b8160005b600581101561075a57813561164b81611320565b8382015560209190910190600101611637565b8160005b600b81101561168957813561167681611320565b8382015560209190910190600101611662565b50506101608201600b820160005b60058082106116a657506116dc565b8360005b828110156116c6578135858201556020909101906001016116aa565b505060a093909301929190910190600101611697565b505050610558610480830160248301611633565b60006020828403121561170257600080fd5b8151801515811461135257600080fd5b808201808211156103af576103af61161d565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561174d57600080fd5b815160ff8116811461135257600080fd5b600181815b8085111561179957816000190482111561177f5761177f61161d565b8085161561178c57918102915b93841c9390800290611763565b509250929050565b6000826117b0575060016103af565b816117bd575060006103af565b81600181146117d357600281146117dd576117f9565b60019150506103af565b60ff8411156117ee576117ee61161d565b50506001821b6103af565b5060208310610133831016604e8410600b841016171561181c575081810a6103af565b611826838361175e565b806000190482111561183a5761183a61161d565b029392505050565b600061135260ff8416836117a1565b8060005b600b81101561075a5781516001600160a01b0316845260209384019390910190600101611855565b806000805b60058082106118915750610e44565b835186845b838110156118b4578251825260209283019290910190600101611896565b50505060a095909501945060209290920191600101611882565b8060005b600581101561075a5781516001600160a01b03168452602093840193909101906001016118d2565b61054081016119098287611851565b61191761016083018661187d565b83610480830152610f536104a08301846118ce565b6000825161193e818460208701611372565b9190910192915050565b61058081016119578289611851565b61196561016083018861187d565b85610480830152846104a08301526119816104c08301856118ce565b6001600160a01b0392909216610560919091015295945050505050565b602081526000611352602083018461139656fea26469706673582212205e2f254ff7f7f03e83a008359b65cecfadf674e108d1e967b8162d0122bbe35d64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf400000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f00000000000000000000000016c6521dff6bab339122a0fe25a9116693265353
-----Decoded View---------------
Arg [0] : asset_ (address): 0x38E3d865e34f7367a69f096C80A4fc329DB38BF4
Arg [1] : yearnStakingDelegate_ (address): 0x05dcdBF02F29239D1f8d9797E22589A2DE1C152F
Arg [2] : curveRouter_ (address): 0x16C6521Dff6baB339122a0FE25a9116693265353
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000038e3d865e34f7367a69f096c80a4fc329db38bf4
Arg [1] : 00000000000000000000000005dcdbf02f29239d1f8d9797e22589a2de1c152f
Arg [2] : 00000000000000000000000016c6521dff6bab339122a0fe25a9116693265353
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.