Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 19 from a total of 19 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deploy | 14313365 | 1078 days ago | IN | 0 ETH | 0.0139121 | ||||
Deploy | 14313364 | 1078 days ago | IN | 0 ETH | 0.01328965 | ||||
Deploy | 14313364 | 1078 days ago | IN | 0 ETH | 0.01420444 | ||||
Deploy | 14313364 | 1078 days ago | IN | 0 ETH | 0.01420444 | ||||
Deploy | 14313364 | 1078 days ago | IN | 0 ETH | 0.01342339 | ||||
Deploy | 14313364 | 1078 days ago | IN | 0 ETH | 0.01342339 | ||||
Deploy | 14313364 | 1078 days ago | IN | 0 ETH | 0.01342339 | ||||
Deploy | 14313364 | 1078 days ago | IN | 0 ETH | 0.01244132 | ||||
Deploy | 14313360 | 1078 days ago | IN | 0 ETH | 0.01152103 | ||||
Deploy | 14313360 | 1078 days ago | IN | 0 ETH | 0.01152103 | ||||
Deploy | 14313356 | 1078 days ago | IN | 0 ETH | 0.01199711 | ||||
Deploy | 14313356 | 1078 days ago | IN | 0 ETH | 0.01199711 | ||||
Deploy | 14313355 | 1078 days ago | IN | 0 ETH | 0.01254016 | ||||
Deploy | 14313355 | 1078 days ago | IN | 0 ETH | 0.01254016 | ||||
Deploy | 14313355 | 1078 days ago | IN | 0 ETH | 0.01345477 | ||||
Deploy | 14313355 | 1078 days ago | IN | 0 ETH | 0.01253816 | ||||
Deploy | 14313355 | 1078 days ago | IN | 0 ETH | 0.01345477 | ||||
Deploy | 14313355 | 1078 days ago | IN | 0 ETH | 0.01253816 | ||||
Deploy | 14313352 | 1078 days ago | IN | 0 ETH | 0.01237979 |
Latest 20 internal transactions
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
14313365 | 1078 days ago | Contract Creation | 0 ETH | |||
14313364 | 1078 days ago | Contract Creation | 0 ETH | |||
14313364 | 1078 days ago | Contract Creation | 0 ETH | |||
14313364 | 1078 days ago | Contract Creation | 0 ETH | |||
14313364 | 1078 days ago | Contract Creation | 0 ETH | |||
14313364 | 1078 days ago | Contract Creation | 0 ETH | |||
14313364 | 1078 days ago | Contract Creation | 0 ETH | |||
14313364 | 1078 days ago | Contract Creation | 0 ETH | |||
14313360 | 1078 days ago | Contract Creation | 0 ETH | |||
14313360 | 1078 days ago | Contract Creation | 0 ETH | |||
14313356 | 1078 days ago | Contract Creation | 0 ETH | |||
14313356 | 1078 days ago | Contract Creation | 0 ETH | |||
14313355 | 1078 days ago | Contract Creation | 0 ETH | |||
14313355 | 1078 days ago | Contract Creation | 0 ETH | |||
14313355 | 1078 days ago | Contract Creation | 0 ETH | |||
14313355 | 1078 days ago | Contract Creation | 0 ETH | |||
14313355 | 1078 days ago | Contract Creation | 0 ETH | |||
14313355 | 1078 days ago | Contract Creation | 0 ETH | |||
14313352 | 1078 days ago | Contract Creation | 0 ETH | |||
14312509 | 1078 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
ConvexCurveLpStakingWrapperFactory
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "../../../../persistent/dispatcher/IDispatcher.sol"; import "../../../utils/beacon-proxy/BeaconProxyFactory.sol"; import "./ConvexCurveLpStakingWrapperLib.sol"; /// @title ConvexCurveLpStakingWrapperFactory Contract /// @author Enzyme Council <[email protected]> /// @notice A contract factory for ConvexCurveLpStakingWrapper instances contract ConvexCurveLpStakingWrapperFactory is BeaconProxyFactory { event WrapperDeployed(uint256 indexed pid, address wrapperProxy, address curveLpToken); IDispatcher private immutable DISPATCHER_CONTRACT; mapping(uint256 => address) private pidToWrapper; // Handy cache for interacting contracts mapping(address => address) private wrapperToCurveLpToken; modifier onlyOwner { require(msg.sender == getOwner(), "Only the owner can call this function"); _; } constructor( address _dispatcher, address _convexBooster, address _crvToken, address _cvxToken ) public BeaconProxyFactory(address(0)) { DISPATCHER_CONTRACT = IDispatcher(_dispatcher); __setCanonicalLib( address( new ConvexCurveLpStakingWrapperLib( address(this), _convexBooster, _crvToken, _cvxToken ) ) ); } /// @notice Deploys a staking wrapper for a given Convex pool /// @param _pid The Convex Curve pool id /// @return wrapperProxy_ The staking wrapper proxy contract address function deploy(uint256 _pid) external returns (address wrapperProxy_) { require(getWrapperForConvexPool(_pid) == address(0), "deploy: Wrapper already exists"); bytes memory constructData = abi.encodeWithSelector( ConvexCurveLpStakingWrapperLib.init.selector, _pid ); wrapperProxy_ = deployProxy(constructData); pidToWrapper[_pid] = wrapperProxy_; address lpToken = ConvexCurveLpStakingWrapperLib(wrapperProxy_).getCurveLpToken(); wrapperToCurveLpToken[wrapperProxy_] = lpToken; emit WrapperDeployed(_pid, wrapperProxy_, lpToken); return wrapperProxy_; } /// @notice Pause deposits and harvesting new rewards for the given wrappers /// @param _wrappers The wrappers to pause function pauseWrappers(address[] calldata _wrappers) external onlyOwner { for (uint256 i; i < _wrappers.length; i++) { ConvexCurveLpStakingWrapperLib(_wrappers[i]).togglePause(true); } } /// @notice Unpauses deposits and harvesting new rewards for the given wrappers /// @param _wrappers The wrappers to unpause function unpauseWrappers(address[] calldata _wrappers) external onlyOwner { for (uint256 i; i < _wrappers.length; i++) { ConvexCurveLpStakingWrapperLib(_wrappers[i]).togglePause(false); } } //////////////////////////////////// // BEACON PROXY FACTORY OVERRIDES // //////////////////////////////////// /// @notice Gets the contract owner /// @return owner_ The contract owner function getOwner() public view override returns (address owner_) { return DISPATCHER_CONTRACT.getOwner(); } /////////////////// // STATE GETTERS // /////////////////// // EXTERNAL FUNCTIONS /// @notice Gets the Curve LP token address for a given wrapper /// @param _wrapper The wrapper proxy address /// @return lpToken_ The Curve LP token address function getCurveLpTokenForWrapper(address _wrapper) external view returns (address lpToken_) { return wrapperToCurveLpToken[_wrapper]; } // PUBLIC FUNCTIONS /// @notice Gets the wrapper address for a given Convex pool /// @param _pid The Convex pool id /// @return wrapper_ The wrapper proxy address function getWrapperForConvexPool(uint256 _pid) public view returns (address wrapper_) { return pidToWrapper[_pid]; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../../utils/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @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: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(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 Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; /// @title IDispatcher Interface /// @author Enzyme Council <[email protected]> interface IDispatcher { function cancelMigration(address _vaultProxy, bool _bypassFailure) external; function claimOwnership() external; function deployVaultProxy( address _vaultLib, address _owner, address _vaultAccessor, string calldata _fundName ) external returns (address vaultProxy_); function executeMigration(address _vaultProxy, bool _bypassFailure) external; function getCurrentFundDeployer() external view returns (address currentFundDeployer_); function getFundDeployerForVaultProxy(address _vaultProxy) external view returns (address fundDeployer_); function getMigrationRequestDetailsForVaultProxy(address _vaultProxy) external view returns ( address nextFundDeployer_, address nextVaultAccessor_, address nextVaultLib_, uint256 executableTimestamp_ ); function getMigrationTimelock() external view returns (uint256 migrationTimelock_); function getNominatedOwner() external view returns (address nominatedOwner_); function getOwner() external view returns (address owner_); function getSharesTokenSymbol() external view returns (string memory sharesTokenSymbol_); function getTimelockRemainingForMigrationRequest(address _vaultProxy) external view returns (uint256 secondsRemaining_); function hasExecutableMigrationRequest(address _vaultProxy) external view returns (bool hasExecutableRequest_); function hasMigrationRequest(address _vaultProxy) external view returns (bool hasMigrationRequest_); function removeNominatedOwner() external; function setCurrentFundDeployer(address _nextFundDeployer) external; function setMigrationTimelock(uint256 _nextTimelock) external; function setNominatedOwner(address _nextNominatedOwner) external; function setSharesTokenSymbol(string calldata _nextSymbol) external; function signalMigration( address _vaultProxy, address _nextVaultAccessor, address _nextVaultLib, bool _bypassFailure ) external; }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; pragma experimental ABIEncoderV2; /// @title IStakingWrapper interface /// @author Enzyme Council <[email protected]> interface IStakingWrapper { struct TotalHarvestData { uint128 integral; uint128 lastCheckpointBalance; } struct UserHarvestData { uint128 integral; uint128 claimableReward; } function claimRewardsFor(address _for) external returns (address[] memory rewardTokens_, uint256[] memory claimedAmounts_); function deposit(uint256 _amount) external; function depositTo(address _to, uint256 _amount) external; function withdraw(uint256 _amount, bool _claimRewards) external returns (address[] memory rewardTokens_, uint256[] memory claimedAmounts_); function withdrawTo( address _to, uint256 _amount, bool _claimRewardsToHolder ) external; function withdrawToOnBehalf( address _onBehalf, address _to, uint256 _amount, bool _claimRewardsToHolder ) external; // STATE GETTERS function getRewardTokenAtIndex(uint256 _index) external view returns (address rewardToken_); function getRewardTokenCount() external view returns (uint256 count_); function getRewardTokens() external view returns (address[] memory rewardTokens_); function getTotalHarvestDataForRewardToken(address _rewardToken) external view returns (TotalHarvestData memory totalHarvestData_); function getUserHarvestDataForRewardToken(address _user, address _rewardToken) external view returns (UserHarvestData memory userHarvestData_); function isPaused() external view returns (bool isPaused_); }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "../../utils/AddressArrayLib.sol"; import "./IStakingWrapper.sol"; /// @title StakingWrapperBase Contract /// @author Enzyme Council <[email protected]> /// @notice A base contract for staking wrappers /// @dev Can be used as a base for both standard deployments and proxy targets. /// Draws on Convex's ConvexStakingWrapper implementation (https://github.com/convex-eth/platform/blob/main/contracts/contracts/wrappers/ConvexStakingWrapper.sol), /// which is based on Curve.fi gauge wrappers (https://github.com/curvefi/curve-dao-contracts/tree/master/contracts/gauges/wrappers) abstract contract StakingWrapperBase is IStakingWrapper, ERC20, ReentrancyGuard { using AddressArrayLib for address[]; using SafeERC20 for ERC20; using SafeMath for uint256; event Deposited(address indexed from, address indexed to, uint256 amount); event PauseToggled(bool isPaused); event RewardsClaimed( address caller, address indexed user, address[] rewardTokens, uint256[] claimedAmounts ); event RewardTokenAdded(address token); event TotalHarvestIntegralUpdated(address indexed rewardToken, uint256 integral); event TotalHarvestLastCheckpointBalanceUpdated( address indexed rewardToken, uint256 lastCheckpointBalance ); event UserHarvestUpdated( address indexed user, address indexed rewardToken, uint256 integral, uint256 claimableReward ); event Withdrawn( address indexed caller, address indexed from, address indexed to, uint256 amount ); uint256 private constant INTEGRAL_PRECISION = 1e18; address internal immutable OWNER; // Paused stops new deposits and checkpoints bool private paused; address[] private rewardTokens; mapping(address => TotalHarvestData) private rewardTokenToTotalHarvestData; mapping(address => mapping(address => UserHarvestData)) private rewardTokenToUserToHarvestData; modifier onlyOwner() { require(msg.sender == OWNER, "Only owner callable"); _; } constructor( address _owner, string memory _tokenName, string memory _tokenSymbol ) public ERC20(_tokenName, _tokenSymbol) { OWNER = _owner; } /// @notice Toggles pause for deposit and harvesting new rewards /// @param _isPaused True if next state is paused, false if unpaused function togglePause(bool _isPaused) external onlyOwner { paused = _isPaused; emit PauseToggled(_isPaused); } //////////////////////////// // DEPOSITOR INTERACTIONS // //////////////////////////// // CLAIM REWARDS /// @notice Claims all rewards for a given account /// @param _for The account for which to claim rewards /// @return rewardTokens_ The reward tokens /// @return claimedAmounts_ The reward token amounts claimed /// @dev Can be called off-chain to simulate the total harvestable rewards for a particular user function claimRewardsFor(address _for) external override nonReentrant returns (address[] memory rewardTokens_, uint256[] memory claimedAmounts_) { return __checkpointAndClaim(_for); } // DEPOSIT /// @notice Deposits tokens to be staked, minting staking token to sender /// @param _amount The amount of tokens to deposit function deposit(uint256 _amount) external override { __deposit(msg.sender, msg.sender, _amount); } /// @notice Deposits tokens to be staked, minting staking token to a specified account /// @param _to The account to receive staking tokens /// @param _amount The amount of tokens to deposit function depositTo(address _to, uint256 _amount) external override { __deposit(msg.sender, _to, _amount); } /// @dev Helper to deposit tokens to be staked function __deposit( address _from, address _to, uint256 _amount ) private nonReentrant { require(!isPaused(), "__deposit: Paused"); // Checkpoint before minting __checkpoint([_to, address(0)]); _mint(_to, _amount); __depositLogic(_from, _amount); emit Deposited(_from, _to, _amount); } // WITHDRAWAL /// @notice Withdraws staked tokens, returning tokens to the sender, and optionally claiming rewards /// @param _amount The amount of tokens to withdraw /// @param _claimRewards True if accrued rewards should be claimed /// @return rewardTokens_ The reward tokens /// @return claimedAmounts_ The reward token amounts claimed /// @dev Setting `_claimRewards` to true will save gas over separate calls to withdraw + claim function withdraw(uint256 _amount, bool _claimRewards) external override returns (address[] memory rewardTokens_, uint256[] memory claimedAmounts_) { return __withdraw(msg.sender, msg.sender, _amount, _claimRewards); } /// @notice Withdraws staked tokens, returning tokens to a specified account, /// and optionally claims rewards to the staked token holder /// @param _to The account to receive tokens /// @param _amount The amount of tokens to withdraw function withdrawTo( address _to, uint256 _amount, bool _claimRewardsToHolder ) external override { __withdraw(msg.sender, _to, _amount, _claimRewardsToHolder); } /// @notice Withdraws staked tokens on behalf of AccountA, returning tokens to a specified AccountB, /// and optionally claims rewards to the staked token holder /// @param _onBehalf The account on behalf to withdraw /// @param _to The account to receive tokens /// @param _amount The amount of tokens to withdraw /// @dev The caller must have an adequate ERC20.allowance() for _onBehalf function withdrawToOnBehalf( address _onBehalf, address _to, uint256 _amount, bool _claimRewardsToHolder ) external override { // Validate and reduce sender approval _approve(_onBehalf, msg.sender, allowance(_onBehalf, msg.sender).sub(_amount)); __withdraw(_onBehalf, _to, _amount, _claimRewardsToHolder); } /// @dev Helper to withdraw staked tokens function __withdraw( address _from, address _to, uint256 _amount, bool _claimRewards ) private nonReentrant returns (address[] memory rewardTokens_, uint256[] memory claimedAmounts_) { // Checkpoint before burning if (_claimRewards) { (rewardTokens_, claimedAmounts_) = __checkpointAndClaim(_from); } else { __checkpoint([_from, address(0)]); } _burn(_from, _amount); __withdrawLogic(_to, _amount); emit Withdrawn(msg.sender, _from, _to, _amount); return (rewardTokens_, claimedAmounts_); } ///////////// // REWARDS // ///////////// // Rewards tokens are added by the inheriting contract. Rewards tokens should be added, but not removed. // If new rewards tokens need to be added over time, that logic must be handled by the inheriting contract, // and can make use of __harvestRewardsLogic() if necessary // INTERNAL FUNCTIONS /// @dev Helper to add new reward tokens. Silently ignores duplicates. function __addRewardToken(address _rewardToken) internal { if (!rewardTokens.contains(_rewardToken)) { rewardTokens.push(_rewardToken); emit RewardTokenAdded(_rewardToken); } } // PRIVATE FUNCTIONS /// @dev Helper to calculate an unaccounted for reward amount due to a user based on integral values function __calcClaimableRewardForIntegralDiff( address _account, uint256 _totalHarvestIntegral, uint256 _userHarvestIntegral ) private view returns (uint256 claimableReward_) { return balanceOf(_account).mul(_totalHarvestIntegral.sub(_userHarvestIntegral)).div( INTEGRAL_PRECISION ); } /// @dev Helper to calculate an unaccounted for integral amount based on checkpoint balance diff function __calcIntegralForBalDiff( uint256 _supply, uint256 _currentBalance, uint256 _lastCheckpointBalance ) private pure returns (uint256 integral_) { if (_supply > 0) { uint256 balDiff = _currentBalance.sub(_lastCheckpointBalance); if (balDiff > 0) { return balDiff.mul(INTEGRAL_PRECISION).div(_supply); } } return 0; } /// @dev Helper to checkpoint harvest data for specified accounts. /// Harvests all rewards prior to checkpoint. function __checkpoint(address[2] memory _accounts) private { // If paused, continue to checkpoint, but don't attempt to get new rewards if (!isPaused()) { __harvestRewardsLogic(); } uint256 supply = totalSupply(); uint256 rewardTokensLength = rewardTokens.length; for (uint256 i; i < rewardTokensLength; i++) { __updateHarvest(rewardTokens[i], _accounts, supply); } } /// @dev Helper to checkpoint harvest data for specified accounts. /// Harvests all rewards prior to checkpoint. function __checkpointAndClaim(address _account) private returns (address[] memory rewardTokens_, uint256[] memory claimedAmounts_) { // If paused, continue to checkpoint, but don't attempt to get new rewards if (!isPaused()) { __harvestRewardsLogic(); } uint256 supply = totalSupply(); rewardTokens_ = rewardTokens; claimedAmounts_ = new uint256[](rewardTokens_.length); for (uint256 i; i < rewardTokens_.length; i++) { claimedAmounts_[i] = __updateHarvestAndClaim(rewardTokens_[i], _account, supply); } emit RewardsClaimed(msg.sender, _account, rewardTokens_, claimedAmounts_); return (rewardTokens_, claimedAmounts_); } /// @dev Helper to update harvest data function __updateHarvest( address _rewardToken, address[2] memory _accounts, uint256 _supply ) private { TotalHarvestData storage totalHarvestData = rewardTokenToTotalHarvestData[_rewardToken]; uint256 totalIntegral = totalHarvestData.integral; uint256 bal = ERC20(_rewardToken).balanceOf(address(this)); uint256 integralToAdd = __calcIntegralForBalDiff( _supply, bal, totalHarvestData.lastCheckpointBalance ); if (integralToAdd > 0) { totalIntegral = totalIntegral.add(integralToAdd); totalHarvestData.integral = uint128(totalIntegral); emit TotalHarvestIntegralUpdated(_rewardToken, totalIntegral); totalHarvestData.lastCheckpointBalance = uint128(bal); emit TotalHarvestLastCheckpointBalanceUpdated(_rewardToken, bal); } for (uint256 i; i < _accounts.length; i++) { // skip address(0), passed in upon mint and burn if (_accounts[i] == address(0)) continue; UserHarvestData storage userHarvestData = rewardTokenToUserToHarvestData[_rewardToken][_accounts[i]]; uint256 userIntegral = userHarvestData.integral; if (userIntegral < totalIntegral) { uint256 claimableReward = uint256(userHarvestData.claimableReward).add( __calcClaimableRewardForIntegralDiff(_accounts[i], totalIntegral, userIntegral) ); userHarvestData.claimableReward = uint128(claimableReward); userHarvestData.integral = uint128(totalIntegral); emit UserHarvestUpdated( _accounts[i], _rewardToken, totalIntegral, claimableReward ); } } } /// @dev Helper to update harvest data and claim all rewards to holder function __updateHarvestAndClaim( address _rewardToken, address _account, uint256 _supply ) private returns (uint256 claimedAmount_) { TotalHarvestData storage totalHarvestData = rewardTokenToTotalHarvestData[_rewardToken]; uint256 totalIntegral = totalHarvestData.integral; uint256 integralToAdd = __calcIntegralForBalDiff( _supply, ERC20(_rewardToken).balanceOf(address(this)), totalHarvestData.lastCheckpointBalance ); if (integralToAdd > 0) { totalIntegral = totalIntegral.add(integralToAdd); totalHarvestData.integral = uint128(totalIntegral); emit TotalHarvestIntegralUpdated(_rewardToken, totalIntegral); } UserHarvestData storage userHarvestData = rewardTokenToUserToHarvestData[_rewardToken][_account]; uint256 userIntegral = userHarvestData.integral; claimedAmount_ = userHarvestData.claimableReward; if (userIntegral < totalIntegral) { userHarvestData.integral = uint128(totalIntegral); claimedAmount_ = claimedAmount_.add( __calcClaimableRewardForIntegralDiff(_account, totalIntegral, userIntegral) ); emit UserHarvestUpdated(_account, _rewardToken, totalIntegral, claimedAmount_); } if (claimedAmount_ > 0) { userHarvestData.claimableReward = 0; ERC20(_rewardToken).safeTransfer(_account, claimedAmount_); emit UserHarvestUpdated(_account, _rewardToken, totalIntegral, 0); } // Repeat balance lookup since the reward token could have irregular transfer behavior uint256 finalBal = ERC20(_rewardToken).balanceOf(address(this)); if (finalBal < totalHarvestData.lastCheckpointBalance) { totalHarvestData.lastCheckpointBalance = uint128(finalBal); emit TotalHarvestLastCheckpointBalanceUpdated(_rewardToken, finalBal); } return claimedAmount_; } //////////////////////////////// // REQUIRED VIRTUAL FUNCTIONS // //////////////////////////////// /// @dev Logic to be run during a deposit, specific to the integrated protocol. /// Do not mint staking tokens, which already happens during __deposit(). function __depositLogic(address _onBehalf, uint256 _amount) internal virtual; /// @dev Logic to be run during a checkpoint to harvest new rewards, specific to the integrated protocol. /// Can also be used to add new rewards tokens dynamically. /// Do not checkpoint, only harvest the rewards. function __harvestRewardsLogic() internal virtual; /// @dev Logic to be run during a withdrawal, specific to the integrated protocol. /// Do not burn staking tokens, which already happens during __withdraw(). function __withdrawLogic(address _to, uint256 _amount) internal virtual; ///////////////////// // ERC20 OVERRIDES // ///////////////////// /// @dev Overrides ERC20._transfer() in order to checkpoint sender and recipient pre-transfer rewards function _transfer( address _from, address _to, uint256 _amount ) internal override nonReentrant { __checkpoint([_from, _to]); super._transfer(_from, _to, _amount); } /////////////////// // STATE GETTERS // /////////////////// /// @notice Gets the reward token at a particular index /// @return rewardToken_ The reward token address function getRewardTokenAtIndex(uint256 _index) public view override returns (address rewardToken_) { return rewardTokens[_index]; } /// @notice Gets the count of reward tokens being harvested /// @return count_ The count function getRewardTokenCount() public view override returns (uint256 count_) { return rewardTokens.length; } /// @notice Gets all reward tokens being harvested /// @return rewardTokens_ The reward tokens function getRewardTokens() public view override returns (address[] memory rewardTokens_) { return rewardTokens; } /// @notice Gets the TotalHarvestData for a specified reward token /// @param _rewardToken The reward token /// @return totalHarvestData_ The TotalHarvestData function getTotalHarvestDataForRewardToken(address _rewardToken) public view override returns (TotalHarvestData memory totalHarvestData_) { return rewardTokenToTotalHarvestData[_rewardToken]; } /// @notice Gets the UserHarvestData for a specified account and reward token /// @param _user The account /// @param _rewardToken The reward token /// @return userHarvestData_ The UserHarvestData function getUserHarvestDataForRewardToken(address _user, address _rewardToken) public view override returns (UserHarvestData memory userHarvestData_) { return rewardTokenToUserToHarvestData[_rewardToken][_user]; } /// @notice Checks if deposits and new reward harvesting are paused /// @return isPaused_ True if paused function isPaused() public view override returns (bool isPaused_) { return paused; } }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; import "./StakingWrapperBase.sol"; /// @title StakingWrapperLibBase Contract /// @author Enzyme Council <[email protected]> /// @notice A staking wrapper base for proxy targets, extending StakingWrapperBase abstract contract StakingWrapperLibBase is StakingWrapperBase { event TokenNameSet(string name); event TokenSymbolSet(string symbol); string private tokenName; string private tokenSymbol; /// @dev Helper function to set token name function __setTokenName(string memory _name) internal { tokenName = _name; emit TokenNameSet(_name); } /// @dev Helper function to set token symbol function __setTokenSymbol(string memory _symbol) internal { tokenSymbol = _symbol; emit TokenSymbolSet(_symbol); } ///////////////////// // ERC20 OVERRIDES // ///////////////////// /// @notice Gets the token name /// @return name_ The token name /// @dev Overrides the constructor-set storage for use in proxies function name() public view override returns (string memory name_) { return tokenName; } /// @notice Gets the token symbol /// @return symbol_ The token symbol /// @dev Overrides the constructor-set storage for use in proxies function symbol() public view override returns (string memory symbol_) { return tokenSymbol; } }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "../../../interfaces/IConvexBaseRewardPool.sol"; import "../../../interfaces/IConvexBooster.sol"; import "../../../interfaces/IConvexVirtualBalanceRewardPool.sol"; import "../StakingWrapperLibBase.sol"; /// @title ConvexCurveLpStakingWrapperLib Contract /// @author Enzyme Council <[email protected]> /// @notice A library contract for ConvexCurveLpStakingWrapper instances contract ConvexCurveLpStakingWrapperLib is StakingWrapperLibBase { IConvexBooster private immutable CONVEX_BOOSTER_CONTRACT; address private immutable CRV_TOKEN; address private immutable CVX_TOKEN; address private convexPool; uint256 private convexPoolId; address private curveLPToken; constructor( address _owner, address _convexBooster, address _crvToken, address _cvxToken ) public StakingWrapperBase(_owner, "", "") { CONVEX_BOOSTER_CONTRACT = IConvexBooster(_convexBooster); CRV_TOKEN = _crvToken; CVX_TOKEN = _cvxToken; } /// @notice Initializes the proxy /// @param _pid The Convex pool id for which to use the proxy function init(uint256 _pid) external { // Can validate with any variable set here require(getCurveLpToken() == address(0), "init: Initialized"); IConvexBooster.PoolInfo memory poolInfo = CONVEX_BOOSTER_CONTRACT.poolInfo(_pid); // Set ERC20 info on proxy __setTokenName(string(abi.encodePacked("Enzyme Staked: ", ERC20(poolInfo.token).name()))); __setTokenSymbol(string(abi.encodePacked("stk", ERC20(poolInfo.token).symbol()))); curveLPToken = poolInfo.lptoken; convexPool = poolInfo.crvRewards; convexPoolId = _pid; __addRewardToken(CRV_TOKEN); __addRewardToken(CVX_TOKEN); addExtraRewards(); setApprovals(); } /// @notice Adds rewards tokens that have not yet been added to the wrapper /// @dev Anybody can call, in case more pool tokens are added. /// Is called prior to every new harvest. function addExtraRewards() public { IConvexBaseRewardPool convexPoolContract = IConvexBaseRewardPool(getConvexPool()); // Could probably exit early after validating that extraRewardsCount + 2 <= rewardsTokens.length, // but this protects against a reward token being removed that still needs to be paid out uint256 extraRewardsCount = convexPoolContract.extraRewardsLength(); for (uint256 i; i < extraRewardsCount; i++) { // __addRewardToken silently ignores duplicates __addRewardToken( IConvexVirtualBalanceRewardPool(convexPoolContract.extraRewards(i)).rewardToken() ); } } /// @notice Sets necessary ERC20 approvals, as-needed function setApprovals() public { ERC20(getCurveLpToken()).safeApprove(address(CONVEX_BOOSTER_CONTRACT), type(uint256).max); } //////////////////////////////// // STAKING WRAPPER BASE LOGIC // //////////////////////////////// /// @dev Logic to be run during a deposit, specific to the integrated protocol. /// Do not mint staking tokens, which already happens during __deposit(). function __depositLogic(address _from, uint256 _amount) internal override { ERC20(getCurveLpToken()).safeTransferFrom(_from, address(this), _amount); CONVEX_BOOSTER_CONTRACT.deposit(convexPoolId, _amount, true); } /// @dev Logic to be run during a checkpoint to harvest new rewards, specific to the integrated protocol. /// Can also be used to add new rewards tokens dynamically. /// Do not checkpoint, only harvest the rewards. function __harvestRewardsLogic() internal override { // It's probably overly-cautious to check rewards on every call, // but even when the pool has 1 extra reward token (most have 0) it only adds ~10-15k gas units, // so more convenient to always check than to monitor for rewards changes. addExtraRewards(); IConvexBaseRewardPool(getConvexPool()).getReward(); } /// @dev Logic to be run during a withdrawal, specific to the integrated protocol. /// Do not burn staking tokens, which already happens during __withdraw(). function __withdrawLogic(address _to, uint256 _amount) internal override { IConvexBaseRewardPool(getConvexPool()).withdrawAndUnwrap(_amount, false); ERC20(getCurveLpToken()).safeTransfer(_to, _amount); } /////////////////// // STATE GETTERS // /////////////////// /// @notice Gets the associated Convex reward pool address /// @return convexPool_ The reward pool function getConvexPool() public view returns (address convexPool_) { return convexPool; } /// @notice Gets the associated Convex reward pool id (pid) /// @return convexPoolId_ The pid function getConvexPoolId() public view returns (uint256 convexPoolId_) { return convexPoolId; } /// @notice Gets the associated Curve LP token /// @return curveLPToken_ The Curve LP token function getCurveLpToken() public view returns (address curveLPToken_) { return curveLPToken; } }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; /// @title IConvexBaseRewardPool Interface /// @author Enzyme Council <[email protected]> interface IConvexBaseRewardPool { function extraRewards(uint256) external view returns (address); function extraRewardsLength() external view returns (uint256); function getReward() external returns (bool); function withdrawAndUnwrap(uint256, bool) external returns (bool); }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; pragma experimental ABIEncoderV2; /// @title IConvexBooster Interface /// @author Enzyme Council <[email protected]> interface IConvexBooster { struct PoolInfo { address lptoken; address token; address gauge; address crvRewards; address stash; bool shutdown; } function deposit( uint256, uint256, bool ) external returns (bool); function poolInfo(uint256) external view returns (PoolInfo memory); }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; /// @title IConvexVirtualBalanceRewardPool Interface /// @author Enzyme Council <[email protected]> interface IConvexVirtualBalanceRewardPool { function rewardToken() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; /// @title AddressArray Library /// @author Enzyme Council <[email protected]> /// @notice A library to extend the address array data type library AddressArrayLib { ///////////// // STORAGE // ///////////// /// @dev Helper to remove an item from a storage array function removeStorageItem(address[] storage _self, address _itemToRemove) internal returns (bool removed_) { uint256 itemCount = _self.length; for (uint256 i; i < itemCount; i++) { if (_self[i] == _itemToRemove) { if (i < itemCount - 1) { _self[i] = _self[itemCount - 1]; } _self.pop(); removed_ = true; break; } } return removed_; } //////////// // MEMORY // //////////// /// @dev Helper to add an item to an array. Does not assert uniqueness of the new item. function addItem(address[] memory _self, address _itemToAdd) internal pure returns (address[] memory nextArray_) { nextArray_ = new address[](_self.length + 1); for (uint256 i; i < _self.length; i++) { nextArray_[i] = _self[i]; } nextArray_[_self.length] = _itemToAdd; return nextArray_; } /// @dev Helper to add an item to an array, only if it is not already in the array. function addUniqueItem(address[] memory _self, address _itemToAdd) internal pure returns (address[] memory nextArray_) { if (contains(_self, _itemToAdd)) { return _self; } return addItem(_self, _itemToAdd); } /// @dev Helper to verify if an array contains a particular value function contains(address[] memory _self, address _target) internal pure returns (bool doesContain_) { for (uint256 i; i < _self.length; i++) { if (_target == _self[i]) { return true; } } return false; } /// @dev Helper to merge the unique items of a second array. /// Does not consider uniqueness of either array, only relative uniqueness. /// Preserves ordering. function mergeArray(address[] memory _self, address[] memory _arrayToMerge) internal pure returns (address[] memory nextArray_) { uint256 newUniqueItemCount; for (uint256 i; i < _arrayToMerge.length; i++) { if (!contains(_self, _arrayToMerge[i])) { newUniqueItemCount++; } } if (newUniqueItemCount == 0) { return _self; } nextArray_ = new address[](_self.length + newUniqueItemCount); for (uint256 i; i < _self.length; i++) { nextArray_[i] = _self[i]; } uint256 nextArrayIndex = _self.length; for (uint256 i; i < _arrayToMerge.length; i++) { if (!contains(_self, _arrayToMerge[i])) { nextArray_[nextArrayIndex] = _arrayToMerge[i]; nextArrayIndex++; } } return nextArray_; } /// @dev Helper to verify if array is a set of unique values. /// Does not assert length > 0. function isUniqueSet(address[] memory _self) internal pure returns (bool isUnique_) { if (_self.length <= 1) { return true; } uint256 arrayLength = _self.length; for (uint256 i; i < arrayLength; i++) { for (uint256 j = i + 1; j < arrayLength; j++) { if (_self[i] == _self[j]) { return false; } } } return true; } /// @dev Helper to remove items from an array. Removes all matching occurrences of each item. /// Does not assert uniqueness of either array. function removeItems(address[] memory _self, address[] memory _itemsToRemove) internal pure returns (address[] memory nextArray_) { if (_itemsToRemove.length == 0) { return _self; } bool[] memory indexesToRemove = new bool[](_self.length); uint256 remainingItemsCount = _self.length; for (uint256 i; i < _self.length; i++) { if (contains(_itemsToRemove, _self[i])) { indexesToRemove[i] = true; remainingItemsCount--; } } if (remainingItemsCount == _self.length) { nextArray_ = _self; } else if (remainingItemsCount > 0) { nextArray_ = new address[](remainingItemsCount); uint256 nextArrayIndex; for (uint256 i; i < _self.length; i++) { if (!indexesToRemove[i]) { nextArray_[nextArrayIndex] = _self[i]; nextArrayIndex++; } } } return nextArray_; } }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; import "./IBeacon.sol"; /// @title BeaconProxy Contract /// @author Enzyme Council <[email protected]> /// @notice A proxy contract that uses the beacon pattern for instant upgrades contract BeaconProxy { address private immutable BEACON; constructor(bytes memory _constructData, address _beacon) public { BEACON = _beacon; (bool success, bytes memory returnData) = IBeacon(_beacon).getCanonicalLib().delegatecall( _constructData ); require(success, string(returnData)); } // solhint-disable-next-line no-complex-fallback fallback() external payable { address contractLogic = IBeacon(BEACON).getCanonicalLib(); assembly { calldatacopy(0x0, 0x0, calldatasize()) let success := delegatecall( sub(gas(), 10000), contractLogic, 0x0, calldatasize(), 0, 0 ) let retSz := returndatasize() returndatacopy(0, 0, retSz) switch success case 0 { revert(0, retSz) } default { return(0, retSz) } } } receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; import "./BeaconProxy.sol"; import "./IBeaconProxyFactory.sol"; /// @title BeaconProxyFactory Contract /// @author Enzyme Council <[email protected]> /// @notice Factory contract that deploys beacon proxies abstract contract BeaconProxyFactory is IBeaconProxyFactory { event CanonicalLibSet(address nextCanonicalLib); event ProxyDeployed(address indexed caller, address proxy, bytes constructData); address private canonicalLib; constructor(address _canonicalLib) public { __setCanonicalLib(_canonicalLib); } /// @notice Deploys a new proxy instance /// @param _constructData The constructor data with which to call `init()` on the deployed proxy /// @return proxy_ The proxy address function deployProxy(bytes memory _constructData) public override returns (address proxy_) { proxy_ = address(new BeaconProxy(_constructData, address(this))); emit ProxyDeployed(msg.sender, proxy_, _constructData); return proxy_; } /// @notice Gets the canonical lib used by all proxies /// @return canonicalLib_ The canonical lib function getCanonicalLib() public view override returns (address canonicalLib_) { return canonicalLib; } /// @notice Gets the contract owner /// @return owner_ The contract owner function getOwner() public view virtual returns (address owner_); /// @notice Sets the next canonical lib used by all proxies /// @param _nextCanonicalLib The next canonical lib function setCanonicalLib(address _nextCanonicalLib) public override { require( msg.sender == getOwner(), "setCanonicalLib: Only the owner can call this function" ); __setCanonicalLib(_nextCanonicalLib); } /// @dev Helper to set the next canonical lib function __setCanonicalLib(address _nextCanonicalLib) internal { canonicalLib = _nextCanonicalLib; emit CanonicalLibSet(_nextCanonicalLib); } }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ pragma solidity 0.6.12; /// @title IBeacon interface /// @author Enzyme Council <[email protected]> interface IBeacon { function getCanonicalLib() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0 /* This file is part of the Enzyme Protocol. (c) Enzyme Council <[email protected]> For the full license information, please view the LICENSE file that was distributed with this source code. */ import "./IBeacon.sol"; pragma solidity 0.6.12; /// @title IBeaconProxyFactory interface /// @author Enzyme Council <[email protected]> interface IBeaconProxyFactory is IBeacon { function deployProxy(bytes memory _constructData) external returns (address proxy_); function setCanonicalLib(address _canonicalLib) external; }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "details": { "constantOptimizer": true, "cse": true, "deduplicate": true, "jumpdestRemover": true, "orderLiterals": true, "peephole": true, "yul": false }, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_dispatcher","type":"address"},{"internalType":"address","name":"_convexBooster","type":"address"},{"internalType":"address","name":"_crvToken","type":"address"},{"internalType":"address","name":"_cvxToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nextCanonicalLib","type":"address"}],"name":"CanonicalLibSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"bytes","name":"constructData","type":"bytes"}],"name":"ProxyDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"address","name":"wrapperProxy","type":"address"},{"indexed":false,"internalType":"address","name":"curveLpToken","type":"address"}],"name":"WrapperDeployed","type":"event"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"deploy","outputs":[{"internalType":"address","name":"wrapperProxy_","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_constructData","type":"bytes"}],"name":"deployProxy","outputs":[{"internalType":"address","name":"proxy_","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCanonicalLib","outputs":[{"internalType":"address","name":"canonicalLib_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wrapper","type":"address"}],"name":"getCurveLpTokenForWrapper","outputs":[{"internalType":"address","name":"lpToken_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getWrapperForConvexPool","outputs":[{"internalType":"address","name":"wrapper_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_wrappers","type":"address[]"}],"name":"pauseWrappers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nextCanonicalLib","type":"address"}],"name":"setCanonicalLib","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_wrappers","type":"address[]"}],"name":"unpauseWrappers","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620047653803806200476583398101604081905262000034916200012b565b60006200004181620000b2565b50836001600160a01b03166080816001600160a01b031660601b81525050620000a83084848460405162000075906200010a565b620000849493929190620001b6565b604051809103906000f080158015620000a1573d6000803e3d6000fd5b50620000b2565b5050505062000228565b600080546001600160a01b0319166001600160a01b0383161790556040517f9007c6c0b3b1622c381c19563620e3ce8b824e958af3020495bd6654e8a0310a90620000ff908390620001a6565b60405180910390a150565b61357f80620011e683390190565b805162000125816200020e565b92915050565b600080600080608085870312156200014257600080fd5b600062000150878762000118565b9450506020620001638782880162000118565b9350506040620001768782880162000118565b9250506060620001898782880162000118565b91505092959194509250565b620001a081620001fc565b82525050565b6020810162000125828462000195565b60808101620001c6828762000195565b620001d5602083018662000195565b620001e4604083018562000195565b620001f3606083018462000195565b95945050505050565b60006001600160a01b03821662000125565b6200021981620001fc565b81146200022557600080fd5b50565b60805160601c610fa0620002466000398061023a5250610fa06000f3fe60806040523480156200001157600080fd5b5060043610620000a05760003560e01c80638aeb8b84116200006f5780638aeb8b84146200010c57806397b02f0c146200012557806398a7c4c7146200013c578063a5e387511462000146578063d0ac1a8d146200015d57620000a0565b80630c0872f514620000a55780631c25201c14620000d4578063456b4a3714620000eb578063893d20e81462000102575b600080fd5b620000bc620000b636600462000866565b62000174565b604051620000cb919062000a05565b60405180910390f35b620000bc620000e53660046200089f565b620001fd565b620000bc620000fc366004620007d6565b62000218565b620000bc62000236565b620001236200011d36600462000820565b620002d2565b005b620001236200013636600462000820565b620003bc565b620000bc62000498565b620000bc620001573660046200089f565b620004a7565b620001236200016e366004620007d6565b62000650565b600081306040516200018690620006f3565b6200019392919062000a6f565b604051809103906000f080158015620001b0573d6000803e3d6000fd5b509050336001600160a01b03167f8f1eab90fee81d885732c2e07a3a9b9f6c32278756471123fa57486858c3f7018284604051620001f092919062000a3b565b60405180910390a2919050565b6000908152600160205260409020546001600160a01b031690565b6001600160a01b039081166000908152600260205260409020541690565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663893d20e86040518163ffffffff1660e01b815260040160206040518083038186803b1580156200029257600080fd5b505afa158015620002a7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002cd9190620007ff565b905090565b620002dc62000236565b6001600160a01b0316336001600160a01b031614620003185760405162461bcd60e51b81526004016200030f9062000a93565b60405180910390fd5b60005b81811015620003b7578282828181106200033157fe5b9050602002016020810190620003489190620007d6565b6001600160a01b03166357d159c660006040518263ffffffff1660e01b815260040162000376919062000a5f565b600060405180830381600087803b1580156200039157600080fd5b505af1158015620003a6573d6000803e3d6000fd5b5050600190920191506200031b9050565b505050565b620003c662000236565b6001600160a01b0316336001600160a01b031614620003f95760405162461bcd60e51b81526004016200030f9062000a93565b60005b81811015620003b7578282828181106200041257fe5b9050602002016020810190620004299190620007d6565b6001600160a01b03166357d159c660016040518263ffffffff1660e01b815260040162000457919062000a5f565b600060405180830381600087803b1580156200047257600080fd5b505af115801562000487573d6000803e3d6000fd5b505060019092019150620003fc9050565b6000546001600160a01b031690565b600080620004b583620001fd565b6001600160a01b031614620004de5760405162461bcd60e51b81526004016200030f9062000aa5565b606063b7b0422d60e01b83604051602401620004fb919062000ac9565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290506200053a8162000174565b600084815260016020908152604080832080546001600160a01b0319166001600160a01b0386169081179091558151632e266ba960e21b81529151949650929363b899aea492600480840193919291829003018186803b1580156200059e57600080fd5b505afa158015620005b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005d99190620007ff565b6001600160a01b038481166000908152600260205260409081902080546001600160a01b031916928416929092179091555190915084907fe547dfbae0eb3c2c335669b841fa076eb2a1a64eab9bd2fb49868b5e624586f19062000641908690859062000a15565b60405180910390a25050919050565b6200065a62000236565b6001600160a01b0316336001600160a01b0316146200068d5760405162461bcd60e51b81526004016200030f9062000ab7565b62000698816200069b565b50565b600080546001600160a01b0319166001600160a01b0383161790556040517f9007c6c0b3b1622c381c19563620e3ce8b824e958af3020495bd6654e8a0310a90620006e890839062000a05565b60405180910390a150565b6103a78062000bc483390190565b80356200070e8162000ba1565b92915050565b80516200070e8162000ba1565b60008083601f8401126200073457600080fd5b50813567ffffffffffffffff8111156200074d57600080fd5b6020830191508360208202830111156200076657600080fd5b9250929050565b600082601f8301126200077f57600080fd5b813562000796620007908262000b01565b62000ad9565b91508082526020830160208301858383011115620007b357600080fd5b620007c083828462000b58565b50505092915050565b80356200070e8162000bb8565b600060208284031215620007e957600080fd5b6000620007f7848462000701565b949350505050565b6000602082840312156200081257600080fd5b6000620007f7848462000714565b600080602083850312156200083457600080fd5b823567ffffffffffffffff8111156200084c57600080fd5b6200085a8582860162000721565b92509250509250929050565b6000602082840312156200087957600080fd5b813567ffffffffffffffff8111156200089157600080fd5b620007f7848285016200076d565b600060208284031215620008b257600080fd5b6000620007f78484620007c9565b620008cb8162000b37565b82525050565b620008cb8162000b44565b6000620008e98262000b2a565b620008f5818562000b2e565b93506200090781856020860162000b64565b620009128162000b97565b9093019392505050565b60006200092b60258362000b2e565b7f4f6e6c7920746865206f776e65722063616e2063616c6c20746869732066756e81526431ba34b7b760d91b602082015260400192915050565b600062000974601e8362000b2e565b7f6465706c6f793a205772617070657220616c7265616479206578697374730000815260200192915050565b6000620009af60368362000b2e565b7f73657443616e6f6e6963616c4c69623a204f6e6c7920746865206f776e65722081527531b0b71031b0b636103a3434b990333ab731ba34b7b760511b602082015260400192915050565b620008cb8162000b55565b602081016200070e8284620008c0565b6040810162000a258285620008c0565b62000a346020830184620008c0565b9392505050565b6040810162000a4b8285620008c0565b8181036020830152620007f78184620008dc565b602081016200070e8284620008d1565b6040808252810162000a828185620008dc565b905062000a346020830184620008c0565b602080825281016200070e816200091c565b602080825281016200070e8162000965565b602080825281016200070e81620009a0565b602081016200070e8284620009fa565b60405181810167ffffffffffffffff8111828210171562000af957600080fd5b604052919050565b600067ffffffffffffffff82111562000b1957600080fd5b506020601f91909101601f19160190565b5190565b90815260200190565b60006200070e8262000b49565b151590565b6001600160a01b031690565b90565b82818337506000910152565b60005b8381101562000b8157818101518382015260200162000b67565b8381111562000b91576000848401525b50505050565b601f01601f191690565b62000bac8162000b37565b81146200069857600080fd5b62000bac8162000b5556fe60a060405234801561001057600080fd5b506040516103a73803806103a78339818101604052604081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825164010000000081118282018810171561008257600080fd5b82525081516020918201929091019080838360005b838110156100af578181015183820152602001610097565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b506040818152602092830151606081811b6001600160601b0319166080526398a7c4c760e01b845291519095506000945090926001600160a01b038616926398a7c4c79260048083019392829003018186803b15801561013b57600080fd5b505afa15801561014f573d6000803e3d6000fd5b505050506040513d602081101561016557600080fd5b505160405185516001600160a01b0390921691869190819060208401908083835b602083106101a55780518252601f199092019160209182019101610186565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114610205576040519150601f19603f3d011682016040523d82523d6000602084013e61020a565b606091505b509150915081819061029a5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561025f578181015183820152602001610247565b50505050905090810190601f16801561028c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050505060805160601c60ee6102b960003980600e525060ee6000f3fe608060405236600a57005b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166398a7c4c76040518163ffffffff1660e01b815260040160206040518083038186803b158015606457600080fd5b505afa1580156077573d6000803e3d6000fd5b505050506040513d6020811015608c57600080fd5b505190503660008037600080366000846127105a03f43d806000803e81801560b357816000f35b816000fdfea26469706673582212209a2062a062ba495cf18ec0c812d8c737e96be9cba7dae39d1b5ab98efe85b85764736f6c634300060c0033a264697066735822122032d315117304e289ab7dc4c6ed7d722c289d06698e282c86a8c6bcae2d42e7e164736f6c634300060c00336101006040523480156200001257600080fd5b506040516200357f3803806200357f833981016040819052620000359162000174565b604080516020808201808452600080845284519283019094529281528151879383918391620000689160039190620000c5565b5080516200007e906004906020840190620000c5565b50506005805460ff1916601217905550506001600655506001600160601b0319606091821b811660805293811b841660a05291821b831660c052901b1660e052506200020a565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200010857805160ff191683800117855562000138565b8280016001018555821562000138579182015b82811115620001385782518255916020019190600101906200011b565b50620001469291506200014a565b5090565b5b808211156200014657600081556001016200014b565b80516200016e81620001f0565b92915050565b600080600080608085870312156200018b57600080fd5b600062000199878762000161565b9450506020620001ac8782880162000161565b9350506040620001bf8782880162000161565b9250506060620001d28782880162000161565b91505092959194509250565b60006001600160a01b0382166200016e565b620001fb81620001de565b81146200020757600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c6133296200025660003980610d16525080610ced5250806108f65280610ae95280611dd152508061083752506133296000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c806382e5d07311610104578063b187bd26116100a2578063c4f59f9b11610071578063c4f59f9b146103c6578063d12f8df0146103db578063dd62ed3e146103e3578063ffaad6a5146103f6576101da565b8063b187bd2614610390578063b6b55f2514610398578063b7b0422d146103ab578063b899aea4146103be576101da565b80639655dd61116100de5780639655dd6114610344578063a457c2d714610357578063a7d2793f1461036a578063a9059cbb1461037d576101da565b806382e5d0731461032c5780638757b15b1461033457806395d89b411461033c576101da565b806323b872dd1161017c578063395093511161014b57806339509351146102e057806357d159c6146102f357806370a082311461030657806373e2290c14610319576101da565b806323b872dd146102925780632cfafabe146102a5578063313ce567146102b857806338d07436146102cd576101da565b8063095ea7b3116101b8578063095ea7b31461022757806318160ddd146102475780631ac6d19d1461025c57806320c718101461027d576101da565b80630663b22c146101df57806306fdde03146101e9578063093f636514610207575b600080fd5b6101e7610409565b005b6101f1610597565b6040516101fe9190612f82565b60405180910390f35b61021a6102153660046125cd565b61062d565b6040516101fe91906130b3565b61023a6102353660046126b5565b610688565b6040516101fe9190612f74565b61024f6106a5565b6040516101fe91906130c1565b61026f61026a366004612591565b6106ab565b6040516101fe929190612f4f565b6102856106f7565b6040516101fe9190612e95565b61023a6102a0366004612607565b610706565b6101e76102b3366004612654565b61078e565b6102c06107bb565b6040516101fe919061313b565b61026f6102db3660046127f3565b6107c4565b61023a6102ee3660046126b5565b6107de565b6101e7610301366004612728565b61082c565b61024f610314366004612591565b6108bd565b6101e76103273660046126e5565b6108d8565b61024f6108eb565b6101e76108f1565b6101f1610932565b61021a610352366004612591565b610993565b61023a6103653660046126b5565b6109dd565b6102856103783660046127b7565b610a45565b61023a61038b3660046126b5565b610a6f565b61023a610a83565b6101e76103a63660046127b7565b610a8c565b6101e76103b93660046127b7565b610a9a565b610285610d4e565b6103ce610d5d565b6040516101fe9190612f3e565b61024f610dbe565b61024f6103f13660046125cd565b610dc4565b6101e76104043660046126b5565b610def565b60006104136106f7565b90506000816001600160a01b031663d55a23f46040518163ffffffff1660e01b815260040160206040518083038186803b15801561045057600080fd5b505afa158015610464573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048891906127d5565b905060005b8181101561059257604051632061aa2360e11b815261058a906001600160a01b038516906340c35446906104c59085906004016130c1565b60206040518083038186803b1580156104dd57600080fd5b505afa1580156104f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051591906125af565b6001600160a01b031663f7c618c16040518163ffffffff1660e01b815260040160206040518083038186803b15801561054d57600080fd5b505afa158015610561573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061058591906125af565b610dfa565b60010161048d565b505050565b600b8054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106235780601f106105f857610100808354040283529160200191610623565b820191906000526020600020905b81548152906001019060200180831161060657829003601f168201915b5050505050905090565b610635612385565b506001600160a01b038082166000908152600a602090815260408083209386168352928152908290208251808401909352546001600160801b038082168452600160801b90910416908201525b92915050565b600061069c610695610ee6565b8484610eea565b50600192915050565b60025490565b606080600260065414156106da5760405162461bcd60e51b81526004016106d190613083565b60405180910390fd5b60026006556106e883610f9e565b60016006559094909350915050565b600d546001600160a01b031690565b60006107138484846110f3565b6107838461071f610ee6565b61077e856040518060600160405280602881526020016132a7602891396001600160a01b038a1660009081526001602052604081209061075d610ee6565b6001600160a01b031681526020810191909152604001600020549190611157565b610eea565b5060015b9392505050565b6107a7843361077e856107a18933610dc4565b90611183565b6107b3848484846111ab565b505050505050565b60055460ff1690565b6060806107d3333386866111ab565b915091509250929050565b600061069c6107eb610ee6565b8461077e85600160006107fc610ee6565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549061128e565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146108745760405162461bcd60e51b81526004016106d190612fa3565b6007805460ff19168215151790556040517f9077d36bc00859b5c3f320310707208543dd35092cb0a0fe117d0c6a558b148b906108b2908390612f74565b60405180910390a150565b6001600160a01b031660009081526020819052604090205490565b6108e4338484846111ab565b5050505050565b60085490565b6109307f0000000000000000000000000000000000000000000000000000000000000000600019610920610d4e565b6001600160a01b031691906112b3565b565b600c8054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106235780601f106105f857610100808354040283529160200191610623565b61099b612385565b506001600160a01b03166000908152600960209081526040918290208251808401909352546001600160801b038082168452600160801b909104169082015290565b600061069c6109ea610ee6565b8461077e856040518060600160405280602581526020016132cf6025913960016000610a14610ee6565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190611157565b600060088281548110610a5457fe5b6000918252602090912001546001600160a01b031692915050565b600061069c610a7c610ee6565b84846110f3565b60075460ff1690565b610a973333836113ad565b50565b6000610aa4610d4e565b6001600160a01b031614610aca5760405162461bcd60e51b81526004016106d190613023565b610ad261239c565b604051631526fe2760e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631526fe2790610b1e9085906004016130c1565b60c06040518083038186803b158015610b3657600080fd5b505afa158015610b4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6e9190612799565b9050610c1081602001516001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610bb057600080fd5b505afa158015610bc4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bec9190810190612764565b604051602001610bfc9190612e73565b604051602081830303815290604052611489565b610cb081602001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610c5057600080fd5b505afa158015610c64573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c8c9190810190612764565b604051602001610c9c9190612e8a565b6040516020818303038152906040526114cc565b8051600f80546001600160a01b039283166001600160a01b0319918216179091556060830151600d8054919093169116179055600e829055610d117f0000000000000000000000000000000000000000000000000000000000000000610dfa565b610d3a7f0000000000000000000000000000000000000000000000000000000000000000610dfa565b610d42610409565b610d4a6108f1565b5050565b600f546001600160a01b031690565b6060600880548060200260200160405190810160405280929190818152602001828054801561062357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610d97575050505050905090565b600e5490565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610d4a3383836113ad565b610e67816008805480602002602001604051908101604052809291908181526020018280548015610e5457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e36575b505050505061150f90919063ffffffff16565b610a9757600880546001810182556000919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b0319166001600160a01b0383161790556040517ff3e4c2c64e71e6ba2eaab9a599bced62f9eb91d2cda610bf41aa8c80ff2cf826906108b2908390612e95565b3390565b6001600160a01b038316610f105760405162461bcd60e51b81526004016106d190613053565b6001600160a01b038216610f365760405162461bcd60e51b81526004016106d190612fc3565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610f919085906130c1565b60405180910390a3505050565b606080610fa9610a83565b610fb557610fb5611565565b6000610fbf6106a5565b600880546040805160208084028201810190925282815293945083018282801561101257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610ff4575b50505050509250825167ffffffffffffffff8111801561103157600080fd5b5060405190808252806020026020018201604052801561105b578160200160208202803683370190505b50915060005b83518110156110a75761108884828151811061107957fe5b602002602001015186846115e7565b83828151811061109457fe5b6020908102919091010152600101611061565b50836001600160a01b03167fc17f1458d7773c19369fc6c68a3b4c44b675c86c50c997d58853aed5e38de6cd3385856040516110e593929190612ea3565b60405180910390a250915091565b600260065414156111165760405162461bcd60e51b81526004016106d190613083565b6002600655604080518082019091526001600160a01b038085168252831660208201526111429061194f565b61114d8383836119b8565b5050600160065550565b6000818484111561117b5760405162461bcd60e51b81526004016106d19190612f82565b505050900390565b6000828211156111a55760405162461bcd60e51b81526004016106d190612fe3565b50900390565b606080600260065414156111d15760405162461bcd60e51b81526004016106d190613083565b600260065582156111ef576111e586610f9e565b9092509050611215565b604080518082019091526001600160a01b0387168152600060208201526112159061194f565b61121f8685611acd565b6112298585611baf565b846001600160a01b0316866001600160a01b0316336001600160a01b03167fa4195c37c2947bbe89165f03e320b6903116f0b10d8cfdb522330f7ce6f9fa248760405161127691906130c1565b60405180910390a46001600655909590945092505050565b6000828201838110156107875760405162461bcd60e51b81526004016106d190612fd3565b80158061133b5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906112e99030908690600401612ee0565b60206040518083038186803b15801561130157600080fd5b505afa158015611315573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133991906127d5565b155b6113575760405162461bcd60e51b81526004016106d190613093565b6105928363095ea7b360e01b8484604051602401611376929190612f23565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611c55565b600260065414156113d05760405162461bcd60e51b81526004016106d190613083565b60026006556113dd610a83565b156113fa5760405162461bcd60e51b81526004016106d190612f93565b604080518082019091526001600160a01b0383168152600060208201526114209061194f565b61142a8282611ce4565b6114348382611d98565b816001600160a01b0316836001600160a01b03167f8752a472e571a816aea92eec8dae9baf628e840f4929fbcc2d155e6233ff68a78360405161147791906130c1565b60405180910390a35050600160065550565b805161149c90600b9060208401906123d1565b507f12e9cab73c0c48661414f76e810af7d10c67f0db958722bf9f26b28a4b4afd69816040516108b29190612f82565b80516114df90600c9060208401906123d1565b507f862f26027c5033c09d43eacd856547decb3227c210f6eb7b6bdc0cf5edaa3f4b816040516108b29190612f82565b6000805b835181101561155b5783818151811061152857fe5b60200260200101516001600160a01b0316836001600160a01b03161415611553576001915050610682565b600101611513565b5060009392505050565b61156d610409565b6115756106f7565b6001600160a01b0316633d18b9126040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156115af57600080fd5b505af11580156115c3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a979190612746565b6001600160a01b038316600081815260096020526040808220805491516370a0823160e01b8152929390926001600160801b039092169184916116a2918791906370a082319061163b903090600401612e95565b60206040518083038186803b15801561165357600080fd5b505afa158015611667573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168b91906127d5565b8554600160801b90046001600160801b0316611e5c565b90508015611714576116b4828261128e565b83546001600160801b0319166001600160801b0382161784556040519092506001600160a01b038816907f64dcb34f2e45bc61753d72992aa4199ec96717158435e8085568ff38844bcd1c9061170b9085906130c1565b60405180910390a25b6001600160a01b038781166000908152600a60209081526040808320938a1683529290522080546001600160801b03600160801b82048116965016838110156117d55781546001600160801b0319166001600160801b03851617825561178561177e898684611ea7565b879061128e565b9550886001600160a01b0316886001600160a01b03167fe3bdf7e684a4024370a702abfcca4a32b08642aadc27065f3356458bd23e977e86896040516117cc929190613105565b60405180910390a35b851561184b5781546001600160801b031682556117fc6001600160a01b038a168988611ed9565b886001600160a01b0316886001600160a01b03167fe3bdf7e684a4024370a702abfcca4a32b08642aadc27065f3356458bd23e977e8660006040516118429291906130ea565b60405180910390a35b6040516370a0823160e01b81526000906001600160a01b038b16906370a082319061187a903090600401612e95565b60206040518083038186803b15801561189257600080fd5b505afa1580156118a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ca91906127d5565b8654909150600160801b90046001600160801b03168110156119425785546001600160801b03808316600160801b0291161786556040516001600160a01b038b16907fdeb2652df61fdedd2d231dc4d777175097cc26369032d339be2a6db36d7754f2906119399084906130c1565b60405180910390a25b5050505050509392505050565b611957610a83565b61196357611963611565565b600061196d6106a5565b60085490915060005b818110156119b2576119aa6008828154811061198e57fe5b6000918252602090912001546001600160a01b03168585611ef8565b600101611976565b50505050565b6001600160a01b0383166119de5760405162461bcd60e51b81526004016106d190613043565b6001600160a01b038216611a045760405162461bcd60e51b81526004016106d190612fb3565b611a0f838383610592565b611a4c81604051806060016040528060268152602001613281602691396001600160a01b0386166000908152602081905260409020549190611157565b6001600160a01b038085166000908152602081905260408082209390935590841681522054611a7b908261128e565b6001600160a01b0380841660008181526020819052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610f919085906130c1565b6001600160a01b038216611af35760405162461bcd60e51b81526004016106d190613033565b611aff82600083610592565b611b3c8160405180606001604052806022815260200161325f602291396001600160a01b0385166000908152602081905260409020549190611157565b6001600160a01b038316600090815260208190526040902055600254611b629082611183565b6002556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611ba39085906130c1565b60405180910390a35050565b611bb76106f7565b6001600160a01b031663c32e72028260006040518363ffffffff1660e01b8152600401611be59291906130cf565b602060405180830381600087803b158015611bff57600080fd5b505af1158015611c13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c379190612746565b50610d4a8282611c45610d4e565b6001600160a01b03169190611ed9565b6060611caa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166121e99092919063ffffffff16565b8051909150156105925780806020019051810190611cc89190612746565b6105925760405162461bcd60e51b81526004016106d190613073565b6001600160a01b038216611d0a5760405162461bcd60e51b81526004016106d1906130a3565b611d1660008383610592565b600254611d23908261128e565b6002556001600160a01b038216600090815260208190526040902054611d49908261128e565b6001600160a01b0383166000818152602081905260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611ba39085906130c1565b611db7823083611da6610d4e565b6001600160a01b03169291906121f8565b600e546040516321d0683360e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916343a0d06691611e0a91908590600190600401613113565b602060405180830381600087803b158015611e2457600080fd5b505af1158015611e38573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105929190612746565b6000831561155b576000611e708484611183565b90508015611e9c57611e9485611e8e83670de0b6b3a7640000612219565b90612253565b915050610787565b505060009392505050565b6000611ed1670de0b6b3a7640000611e8e611ec28686611183565b611ecb886108bd565b90612219565b949350505050565b6105928363a9059cbb60e01b8484604051602401611376929190612f23565b6001600160a01b038316600081815260096020526040808220805491516370a0823160e01b815290936001600160801b039092169291906370a0823190611f43903090600401612e95565b60206040518083038186803b158015611f5b57600080fd5b505afa158015611f6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9391906127d5565b8354909150600090611fb89086908490600160801b90046001600160801b0316611e5c565b9050801561208557611fca838261128e565b84546001600160801b0319166001600160801b0382161785556040519093506001600160a01b038816907f64dcb34f2e45bc61753d72992aa4199ec96717158435e8085568ff38844bcd1c906120219086906130c1565b60405180910390a283546001600160801b03808416600160801b0291161784556040516001600160a01b038816907fdeb2652df61fdedd2d231dc4d777175097cc26369032d339be2a6db36d7754f29061207c9085906130c1565b60405180910390a25b60005b60028110156121df57600087826002811061209f57fe5b60200201516001600160a01b031614156120b8576121d7565b6001600160a01b0388166000908152600a60205260408120818984600281106120dd57fe5b602090810291909101516001600160a01b0316825281019190915260400160002080549091506001600160801b0316858110156121d457600061214c6121348b866002811061212857fe5b60200201518985611ea7565b8454600160801b90046001600160801b03169061128e565b83546001600160801b03196001600160801b03918216600160801b84841602171690891617845590506001600160a01b038b168a856002811061218b57fe5b60200201516001600160a01b03167fe3bdf7e684a4024370a702abfcca4a32b08642aadc27065f3356458bd23e977e89846040516121ca929190613105565b60405180910390a3505b50505b600101612088565b5050505050505050565b6060611ed18484600085612285565b6119b2846323b872dd60e01b85858560405160240161137693929190612efb565b60008261222857506000610682565b8282028284828161223557fe5b04146107875760405162461bcd60e51b81526004016106d190613013565b60008082116122745760405162461bcd60e51b81526004016106d190613003565b81838161227d57fe5b049392505050565b6060824710156122a75760405162461bcd60e51b81526004016106d190612ff3565b6122b085612346565b6122cc5760405162461bcd60e51b81526004016106d190613063565b60006060866001600160a01b031685876040516122e99190612e67565b60006040518083038185875af1925050503d8060008114612326576040519150601f19603f3d011682016040523d82523d6000602084013e61232b565b606091505b509150915061233b82828661234c565b979650505050505050565b3b151590565b6060831561235b575081610787565b82511561236b5782518084602001fd5b8160405162461bcd60e51b81526004016106d19190612f82565b604080518082019091526000808252602082015290565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061241257805160ff191683800117855561243f565b8280016001018555821561243f579182015b8281111561243f578251825591602001919060010190612424565b5061244b92915061244f565b5090565b5b8082111561244b5760008155600101612450565b803561068281613238565b805161068281613238565b80356106828161324c565b80516106828161324c565b600082601f8301126124a157600080fd5b81516124b46124af82613170565b613149565b915080825260208301602083018583830111156124d057600080fd5b6124db838284613202565b50505092915050565b600060c082840312156124f657600080fd5b61250060c0613149565b9050600061250e848461246f565b825250602061251f8484830161246f565b60208301525060406125338482850161246f565b60408301525060606125478482850161246f565b606083015250608061255b8482850161246f565b60808301525060a061256f84828501612485565b60a08301525092915050565b803561068281613255565b805161068281613255565b6000602082840312156125a357600080fd5b6000611ed18484612464565b6000602082840312156125c157600080fd5b6000611ed1848461246f565b600080604083850312156125e057600080fd5b60006125ec8585612464565b92505060206125fd85828601612464565b9150509250929050565b60008060006060848603121561261c57600080fd5b60006126288686612464565b935050602061263986828701612464565b925050604061264a8682870161257b565b9150509250925092565b6000806000806080858703121561266a57600080fd5b60006126768787612464565b945050602061268787828801612464565b93505060406126988782880161257b565b92505060606126a98782880161247a565b91505092959194509250565b600080604083850312156126c857600080fd5b60006126d48585612464565b92505060206125fd8582860161257b565b6000806000606084860312156126fa57600080fd5b60006127068686612464565b93505060206127178682870161257b565b925050604061264a8682870161247a565b60006020828403121561273a57600080fd5b6000611ed1848461247a565b60006020828403121561275857600080fd5b6000611ed18484612485565b60006020828403121561277657600080fd5b815167ffffffffffffffff81111561278d57600080fd5b611ed184828501612490565b600060c082840312156127ab57600080fd5b6000611ed184846124e4565b6000602082840312156127c957600080fd5b6000611ed1848461257b565b6000602082840312156127e757600080fd5b6000611ed18484612586565b6000806040838503121561280657600080fd5b6000612812858561257b565b92505060206125fd8582860161247a565b600061282f8383612852565b505060200190565b600061282f8383612e55565b61284c816131e1565b82525050565b61284c816131b0565b60006128668261319e565b61287081856131a2565b935061287b83613198565b8060005b838110156128a95781516128938882612823565b975061289e83613198565b92505060010161287f565b509495945050505050565b60006128bf8261319e565b6128c981856131a2565b93506128d483613198565b8060005b838110156128a95781516128ec8882612837565b97506128f783613198565b9250506001016128d8565b61284c816131bb565b60006129168261319e565b61292081856131ab565b9350612930818560208601613202565b9290920192915050565b61284c816131ec565b600061294e8261319e565b61295881856131a2565b9350612968818560208601613202565b6129718161322e565b9093019392505050565b60006129886011836131a2565b7017d7d9195c1bdcda5d0e8814185d5cd959607a1b815260200192915050565b60006129b56013836131a2565b724f6e6c79206f776e65722063616c6c61626c6560681b815260200192915050565b60006129e46023836131a2565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647281526265737360e81b602082015260400192915050565b6000612a29600f836131ab565b6e022b73d3cb6b29029ba30b5b2b21d1608d1b8152600f0192915050565b6000612a546022836131a2565b7f45524332303a20617070726f766520746f20746865207a65726f206164647265815261737360f01b602082015260400192915050565b6000612a98601b836131a2565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612ad1601e836131a2565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000612b0a6026836131a2565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f8152651c8818d85b1b60d21b602082015260400192915050565b6000612b52601a836131a2565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b6000612b8b6021836131a2565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612bce6011836131a2565b701a5b9a5d0e88125b9a5d1a585b1a5e9959607a1b815260200192915050565b6000612bfb6021836131a2565b7f45524332303a206275726e2066726f6d20746865207a65726f206164647265738152607360f81b602082015260400192915050565b6000612c3e6025836131a2565b7f45524332303a207472616e736665722066726f6d20746865207a65726f206164815264647265737360d81b602082015260400192915050565b6000612c856003836131ab565b6273746b60e81b815260030192915050565b6000612ca46024836131a2565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164648152637265737360e01b602082015260400192915050565b6000612cea601d836131a2565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000815260200192915050565b6000612d23602a836131a2565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000612d6f601f836131a2565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000612da86036836131a2565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b6000612e00601f836131a2565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300815260200192915050565b80516040830190612e3d8482612e4c565b5060208201516119b260208501825b61284c816131c0565b61284c816131d8565b61284c816131db565b6000610787828461290b565b6000612e7e82612a1c565b9150610787828461290b565b6000612e7e82612c78565b602081016106828284612852565b60608101612eb18286612843565b8181036020830152612ec3818561285b565b90508181036040830152612ed781846128b4565b95945050505050565b60408101612eee8285612852565b6107876020830184612852565b60608101612f098286612852565b612f166020830185612852565b611ed16040830184612e55565b60408101612f318285612852565b6107876020830184612e55565b60208082528101610787818461285b565b60408082528101612f60818561285b565b90508181036020830152611ed181846128b4565b602081016106828284612902565b602080825281016107878184612943565b602080825281016106828161297b565b60208082528101610682816129a8565b60208082528101610682816129d7565b6020808252810161068281612a47565b6020808252810161068281612a8b565b6020808252810161068281612ac4565b6020808252810161068281612afd565b6020808252810161068281612b45565b6020808252810161068281612b7e565b6020808252810161068281612bc1565b6020808252810161068281612bee565b6020808252810161068281612c31565b6020808252810161068281612c97565b6020808252810161068281612cdd565b6020808252810161068281612d16565b6020808252810161068281612d62565b6020808252810161068281612d9b565b6020808252810161068281612df3565b604081016106828284612e2c565b602081016106828284612e55565b604081016130dd8285612e55565b6107876020830184612902565b604081016130f88285612e55565b610787602083018461293a565b60408101612f318285612e55565b606081016131218286612e55565b61312e6020830185612e55565b611ed16040830184612902565b602081016106828284612e5e565b60405181810167ffffffffffffffff8111828210171561316857600080fd5b604052919050565b600067ffffffffffffffff82111561318757600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610682826131cc565b151590565b6001600160801b031690565b6001600160a01b031690565b90565b60ff1690565b6000610682826131f7565b6000610682826131d8565b6000610682826131b0565b60005b8381101561321d578181015183820152602001613205565b838111156119b25750506000910152565b601f01601f191690565b613241816131b0565b8114610a9757600080fd5b613241816131bb565b613241816131d856fe45524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220beb03a49a663a5c5bc955d20932772d8faaacb4d38a5916285fc9db4a02465f664736f6c634300060c0033000000000000000000000000c3dc853dd716bd5754f421ef94fdcbac3902ab32000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae31000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd520000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000a05760003560e01c80638aeb8b84116200006f5780638aeb8b84146200010c57806397b02f0c146200012557806398a7c4c7146200013c578063a5e387511462000146578063d0ac1a8d146200015d57620000a0565b80630c0872f514620000a55780631c25201c14620000d4578063456b4a3714620000eb578063893d20e81462000102575b600080fd5b620000bc620000b636600462000866565b62000174565b604051620000cb919062000a05565b60405180910390f35b620000bc620000e53660046200089f565b620001fd565b620000bc620000fc366004620007d6565b62000218565b620000bc62000236565b620001236200011d36600462000820565b620002d2565b005b620001236200013636600462000820565b620003bc565b620000bc62000498565b620000bc620001573660046200089f565b620004a7565b620001236200016e366004620007d6565b62000650565b600081306040516200018690620006f3565b6200019392919062000a6f565b604051809103906000f080158015620001b0573d6000803e3d6000fd5b509050336001600160a01b03167f8f1eab90fee81d885732c2e07a3a9b9f6c32278756471123fa57486858c3f7018284604051620001f092919062000a3b565b60405180910390a2919050565b6000908152600160205260409020546001600160a01b031690565b6001600160a01b039081166000908152600260205260409020541690565b60007f000000000000000000000000c3dc853dd716bd5754f421ef94fdcbac3902ab326001600160a01b031663893d20e86040518163ffffffff1660e01b815260040160206040518083038186803b1580156200029257600080fd5b505afa158015620002a7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002cd9190620007ff565b905090565b620002dc62000236565b6001600160a01b0316336001600160a01b031614620003185760405162461bcd60e51b81526004016200030f9062000a93565b60405180910390fd5b60005b81811015620003b7578282828181106200033157fe5b9050602002016020810190620003489190620007d6565b6001600160a01b03166357d159c660006040518263ffffffff1660e01b815260040162000376919062000a5f565b600060405180830381600087803b1580156200039157600080fd5b505af1158015620003a6573d6000803e3d6000fd5b5050600190920191506200031b9050565b505050565b620003c662000236565b6001600160a01b0316336001600160a01b031614620003f95760405162461bcd60e51b81526004016200030f9062000a93565b60005b81811015620003b7578282828181106200041257fe5b9050602002016020810190620004299190620007d6565b6001600160a01b03166357d159c660016040518263ffffffff1660e01b815260040162000457919062000a5f565b600060405180830381600087803b1580156200047257600080fd5b505af115801562000487573d6000803e3d6000fd5b505060019092019150620003fc9050565b6000546001600160a01b031690565b600080620004b583620001fd565b6001600160a01b031614620004de5760405162461bcd60e51b81526004016200030f9062000aa5565b606063b7b0422d60e01b83604051602401620004fb919062000ac9565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290506200053a8162000174565b600084815260016020908152604080832080546001600160a01b0319166001600160a01b0386169081179091558151632e266ba960e21b81529151949650929363b899aea492600480840193919291829003018186803b1580156200059e57600080fd5b505afa158015620005b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005d99190620007ff565b6001600160a01b038481166000908152600260205260409081902080546001600160a01b031916928416929092179091555190915084907fe547dfbae0eb3c2c335669b841fa076eb2a1a64eab9bd2fb49868b5e624586f19062000641908690859062000a15565b60405180910390a25050919050565b6200065a62000236565b6001600160a01b0316336001600160a01b0316146200068d5760405162461bcd60e51b81526004016200030f9062000ab7565b62000698816200069b565b50565b600080546001600160a01b0319166001600160a01b0383161790556040517f9007c6c0b3b1622c381c19563620e3ce8b824e958af3020495bd6654e8a0310a90620006e890839062000a05565b60405180910390a150565b6103a78062000bc483390190565b80356200070e8162000ba1565b92915050565b80516200070e8162000ba1565b60008083601f8401126200073457600080fd5b50813567ffffffffffffffff8111156200074d57600080fd5b6020830191508360208202830111156200076657600080fd5b9250929050565b600082601f8301126200077f57600080fd5b813562000796620007908262000b01565b62000ad9565b91508082526020830160208301858383011115620007b357600080fd5b620007c083828462000b58565b50505092915050565b80356200070e8162000bb8565b600060208284031215620007e957600080fd5b6000620007f7848462000701565b949350505050565b6000602082840312156200081257600080fd5b6000620007f7848462000714565b600080602083850312156200083457600080fd5b823567ffffffffffffffff8111156200084c57600080fd5b6200085a8582860162000721565b92509250509250929050565b6000602082840312156200087957600080fd5b813567ffffffffffffffff8111156200089157600080fd5b620007f7848285016200076d565b600060208284031215620008b257600080fd5b6000620007f78484620007c9565b620008cb8162000b37565b82525050565b620008cb8162000b44565b6000620008e98262000b2a565b620008f5818562000b2e565b93506200090781856020860162000b64565b620009128162000b97565b9093019392505050565b60006200092b60258362000b2e565b7f4f6e6c7920746865206f776e65722063616e2063616c6c20746869732066756e81526431ba34b7b760d91b602082015260400192915050565b600062000974601e8362000b2e565b7f6465706c6f793a205772617070657220616c7265616479206578697374730000815260200192915050565b6000620009af60368362000b2e565b7f73657443616e6f6e6963616c4c69623a204f6e6c7920746865206f776e65722081527531b0b71031b0b636103a3434b990333ab731ba34b7b760511b602082015260400192915050565b620008cb8162000b55565b602081016200070e8284620008c0565b6040810162000a258285620008c0565b62000a346020830184620008c0565b9392505050565b6040810162000a4b8285620008c0565b8181036020830152620007f78184620008dc565b602081016200070e8284620008d1565b6040808252810162000a828185620008dc565b905062000a346020830184620008c0565b602080825281016200070e816200091c565b602080825281016200070e8162000965565b602080825281016200070e81620009a0565b602081016200070e8284620009fa565b60405181810167ffffffffffffffff8111828210171562000af957600080fd5b604052919050565b600067ffffffffffffffff82111562000b1957600080fd5b506020601f91909101601f19160190565b5190565b90815260200190565b60006200070e8262000b49565b151590565b6001600160a01b031690565b90565b82818337506000910152565b60005b8381101562000b8157818101518382015260200162000b67565b8381111562000b91576000848401525b50505050565b601f01601f191690565b62000bac8162000b37565b81146200069857600080fd5b62000bac8162000b5556fe60a060405234801561001057600080fd5b506040516103a73803806103a78339818101604052604081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825164010000000081118282018810171561008257600080fd5b82525081516020918201929091019080838360005b838110156100af578181015183820152602001610097565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b506040818152602092830151606081811b6001600160601b0319166080526398a7c4c760e01b845291519095506000945090926001600160a01b038616926398a7c4c79260048083019392829003018186803b15801561013b57600080fd5b505afa15801561014f573d6000803e3d6000fd5b505050506040513d602081101561016557600080fd5b505160405185516001600160a01b0390921691869190819060208401908083835b602083106101a55780518252601f199092019160209182019101610186565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114610205576040519150601f19603f3d011682016040523d82523d6000602084013e61020a565b606091505b509150915081819061029a5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561025f578181015183820152602001610247565b50505050905090810190601f16801561028c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050505060805160601c60ee6102b960003980600e525060ee6000f3fe608060405236600a57005b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166398a7c4c76040518163ffffffff1660e01b815260040160206040518083038186803b158015606457600080fd5b505afa1580156077573d6000803e3d6000fd5b505050506040513d6020811015608c57600080fd5b505190503660008037600080366000846127105a03f43d806000803e81801560b357816000f35b816000fdfea26469706673582212209a2062a062ba495cf18ec0c812d8c737e96be9cba7dae39d1b5ab98efe85b85764736f6c634300060c0033a264697066735822122032d315117304e289ab7dc4c6ed7d722c289d06698e282c86a8c6bcae2d42e7e164736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c3dc853dd716bd5754f421ef94fdcbac3902ab32000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae31000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd520000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b
-----Decoded View---------------
Arg [0] : _dispatcher (address): 0xC3DC853dD716bd5754f421ef94fdCbac3902ab32
Arg [1] : _convexBooster (address): 0xF403C135812408BFbE8713b5A23a04b3D48AAE31
Arg [2] : _crvToken (address): 0xD533a949740bb3306d119CC777fa900bA034cd52
Arg [3] : _cvxToken (address): 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000c3dc853dd716bd5754f421ef94fdcbac3902ab32
Arg [1] : 000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae31
Arg [2] : 000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52
Arg [3] : 0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.