Overview
MATIC Balance
0 MATIC
MATIC Value
$0.00More Info
Private Name Tags
ContractCreator:
Sponsored
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x61010060 | 39874101 | 392 days ago | IN | Create: BalancerV2LiquidityAdapter | 0 MATIC | 0.53825496 |
Loading...
Loading
Contract Name:
BalancerV2LiquidityAdapter
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 "../../../../interfaces/IBalancerV2LiquidityGauge.sol"; import "../utils/actions/CurveGaugeV2RewardsHandlerMixin.sol"; import "../utils/bases/BalancerV2LiquidityAdapterBase.sol"; /// @title BalancerV2LiquidityAdapter Contract /// @author Enzyme Council <[email protected]> /// @notice Adapter for Balancer V2 pool liquidity provision and native staking contract BalancerV2LiquidityAdapter is BalancerV2LiquidityAdapterBase, CurveGaugeV2RewardsHandlerMixin { constructor( address _integrationManager, address _balancerVault, address _balancerMinter, address _balToken ) public BalancerV2LiquidityAdapterBase(_integrationManager, _balancerVault) CurveGaugeV2RewardsHandlerMixin(_balancerMinter, _balToken) {} //////////////////////////////// // REQUIRED VIRTUAL FUNCTIONS // //////////////////////////////// /// @dev Logic to claim rewards for a given staking token function __claimRewards(address _vaultProxy, address _stakingToken) internal override { __curveGaugeV2ClaimAllRewards(_stakingToken, _vaultProxy); } /// @dev Logic to get the BPT address for a given staking token. /// For this adapter, the staking token is not validated herein to be a real Balancer gauge, /// only to have the required interface. function __getBptForStakingToken(address _stakingToken) internal view override returns (address bpt_) { return IBalancerV2LiquidityGauge(_stakingToken).lp_token(); } /// @dev Logic to stake BPT to a given staking token. /// Staking is always the last action and thus always sent to the _vaultProxy /// (rather than a more generically-named `_recipient`). function __stake( address _vaultProxy, address _stakingToken, uint256 _bptAmount ) internal override { __curveGaugeV2Stake(_stakingToken, __getBptForStakingToken(_stakingToken), _bptAmount); ERC20(_stakingToken).safeTransfer(_vaultProxy, _bptAmount); } /// @dev Logic to unstake BPT from a given staking token function __unstake( address, address _recipient, address _stakingToken, uint256 _bptAmount ) internal override { __curveGaugeV2Unstake(_stakingToken, _bptAmount); if (_recipient != address(this)) { ERC20(__getBptForStakingToken(_stakingToken)).safeTransfer(_recipient, _bptAmount); } } /////////////////// // EXTRA ACTIONS // /////////////////// /// @notice Lends assets for pool tokens on BalancerV2 /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action function lend( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { ( bytes32 poolId, , address[] memory spendAssets, uint256[] memory spendAssetAmounts, IBalancerV2Vault.PoolBalanceChange memory request ) = __decodeLpActionCallArgs(_actionData); __lend(_vaultProxy, poolId, spendAssets, spendAssetAmounts, request); // There can be different join/exit options per Balancer pool type, // some of which involve spending only up-to-max amounts __pushFullAssetBalances(_vaultProxy, spendAssets); } /// @notice Redeems pool tokens on BalancerV2 /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action function redeem( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { ( bytes32 poolId, uint256 spendBptAmount, address[] memory expectedIncomingTokens, , IBalancerV2Vault.PoolBalanceChange memory request ) = __decodeLpActionCallArgs(_actionData); __redeem(_vaultProxy, poolId, spendBptAmount, expectedIncomingTokens, request); // There can be different join/exit options per Balancer pool type, // some of which involve spending only up-to-max amounts __pushFullAssetBalance(_vaultProxy, __parseBalancerPoolAddress(poolId)); } ///////////////////////////// // PARSE ASSETS FOR ACTION // ///////////////////////////// /// @notice Parses the expected assets to receive from a call on integration /// @param _vaultProxy The VaultProxy of the calling fund /// @param _selector The function selector for the callOnIntegration /// @param _actionData The encoded parameters for the callOnIntegration /// @return spendAssetsHandleType_ A type that dictates how to handle granting /// the adapter access to spend assets (`None` by default) /// @return spendAssets_ The assets to spend in the call /// @return spendAssetAmounts_ The max asset amounts to spend in the call /// @return incomingAssets_ The assets to receive in the call /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call function parseAssetsForAction( address _vaultProxy, bytes4 _selector, bytes calldata _actionData ) public view override returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { if (_selector == LEND_SELECTOR) { return __parseAssetsForLend(_actionData); } else if (_selector == REDEEM_SELECTOR) { return __parseAssetsForRedeem(_actionData); } return super.parseAssetsForAction(_vaultProxy, _selector, _actionData); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during lend() calls function __parseAssetsForLend(bytes calldata _encodedCallArgs) private pure returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { incomingAssets_ = new address[](1); minIncomingAssetAmounts_ = new uint256[](1); bytes32 poolId; IBalancerV2Vault.PoolBalanceChange memory request; ( poolId, minIncomingAssetAmounts_[0], spendAssets_, spendAssetAmounts_, request ) = __decodeLpActionCallArgs(_encodedCallArgs); __validateNoInternalBalances(request.useInternalBalance); incomingAssets_[0] = __parseBalancerPoolAddress(poolId); return ( IIntegrationManager.SpendAssetsHandleType.Transfer, spendAssets_, spendAssetAmounts_, incomingAssets_, minIncomingAssetAmounts_ ); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during redeem() calls function __parseAssetsForRedeem(bytes calldata _encodedCallArgs) private pure returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { spendAssets_ = new address[](1); spendAssetAmounts_ = new uint256[](1); bytes32 poolId; IBalancerV2Vault.PoolBalanceChange memory request; ( poolId, spendAssetAmounts_[0], incomingAssets_, minIncomingAssetAmounts_, request ) = __decodeLpActionCallArgs(_encodedCallArgs); __validateNoInternalBalances(request.useInternalBalance); spendAssets_[0] = __parseBalancerPoolAddress(poolId); return ( IIntegrationManager.SpendAssetsHandleType.Transfer, spendAssets_, spendAssetAmounts_, incomingAssets_, minIncomingAssetAmounts_ ); } ////////////// // DECODERS // ////////////// /// @dev Helper to decode callArgs for lend and redeem function __decodeLpActionCallArgs(bytes memory _encodedCallArgs) private pure returns ( bytes32 poolId_, uint256 bptAmount_, address[] memory usedTokens_, // only the assets that will actually be spent/received uint256[] memory usedTokenAmounts_, // only the assets that will actually be spent/received IBalancerV2Vault.PoolBalanceChange memory request_ ) { return abi.decode( _encodedCallArgs, (bytes32, uint256, address[], uint256[], IBalancerV2Vault.PoolBalanceChange) ); } }
// 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: 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 IIntegrationManager interface /// @author Enzyme Council <[email protected]> /// @notice Interface for the IntegrationManager interface IIntegrationManager { enum SpendAssetsHandleType { None, Approve, Transfer } }
// 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 "../IIntegrationManager.sol"; /// @title Integration Adapter interface /// @author Enzyme Council <[email protected]> /// @notice Interface for all integration adapters interface IIntegrationAdapter { function parseAssetsForAction( address _vaultProxy, bytes4 _selector, bytes calldata _encodedCallArgs ) external view returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ); }
// 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 "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "../../../../utils/AssetHelpers.sol"; import "../IIntegrationAdapter.sol"; import "./IntegrationSelectors.sol"; /// @title AdapterBase Contract /// @author Enzyme Council <[email protected]> /// @notice A base contract for integration adapters abstract contract AdapterBase is IIntegrationAdapter, IntegrationSelectors, AssetHelpers { using SafeERC20 for ERC20; address internal immutable INTEGRATION_MANAGER; /// @dev Provides a standard implementation for transferring incoming assets /// from an adapter to a VaultProxy at the end of an adapter action modifier postActionIncomingAssetsTransferHandler( address _vaultProxy, bytes memory _assetData ) { _; (, , address[] memory incomingAssets) = __decodeAssetData(_assetData); __pushFullAssetBalances(_vaultProxy, incomingAssets); } /// @dev Provides a standard implementation for transferring unspent spend assets /// from an adapter to a VaultProxy at the end of an adapter action modifier postActionSpendAssetsTransferHandler(address _vaultProxy, bytes memory _assetData) { _; (address[] memory spendAssets, , ) = __decodeAssetData(_assetData); __pushFullAssetBalances(_vaultProxy, spendAssets); } modifier onlyIntegrationManager() { require( msg.sender == INTEGRATION_MANAGER, "Only the IntegrationManager can call this function" ); _; } constructor(address _integrationManager) public { INTEGRATION_MANAGER = _integrationManager; } // INTERNAL FUNCTIONS /// @dev Helper to decode the _assetData param passed to adapter call function __decodeAssetData(bytes memory _assetData) internal pure returns ( address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_ ) { return abi.decode(_assetData, (address[], uint256[], address[])); } /////////////////// // STATE GETTERS // /////////////////// /// @notice Gets the `INTEGRATION_MANAGER` variable /// @return integrationManager_ The `INTEGRATION_MANAGER` variable value function getIntegrationManager() external view returns (address integrationManager_) { return INTEGRATION_MANAGER; } }
// 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 IntegrationSelectors Contract /// @author Enzyme Council <[email protected]> /// @notice Selectors for integration actions /// @dev Selectors are created from their signatures rather than hardcoded for easy verification abstract contract IntegrationSelectors { // Trading bytes4 public constant TAKE_MULTIPLE_ORDERS_SELECTOR = bytes4(keccak256("takeMultipleOrders(address,bytes,bytes)")); bytes4 public constant TAKE_ORDER_SELECTOR = bytes4(keccak256("takeOrder(address,bytes,bytes)")); // Lending bytes4 public constant LEND_SELECTOR = bytes4(keccak256("lend(address,bytes,bytes)")); bytes4 public constant REDEEM_SELECTOR = bytes4(keccak256("redeem(address,bytes,bytes)")); // Staking bytes4 public constant STAKE_SELECTOR = bytes4(keccak256("stake(address,bytes,bytes)")); bytes4 public constant UNSTAKE_SELECTOR = bytes4(keccak256("unstake(address,bytes,bytes)")); // Rewards bytes4 public constant CLAIM_REWARDS_SELECTOR = bytes4(keccak256("claimRewards(address,bytes,bytes)")); // Combined bytes4 public constant LEND_AND_STAKE_SELECTOR = bytes4(keccak256("lendAndStake(address,bytes,bytes)")); bytes4 public constant UNSTAKE_AND_REDEEM_SELECTOR = bytes4(keccak256("unstakeAndRedeem(address,bytes,bytes)")); }
// 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 "../../../../../interfaces/IBalancerV2Vault.sol"; /// @title BalancerV2ActionsMixin Contract /// @author Enzyme Council <[email protected]> /// @notice Mixin contract for interacting with BalancerV2 abstract contract BalancerV2ActionsMixin { IBalancerV2Vault internal immutable BALANCER_VAULT_CONTRACT; constructor(address _balancerVault) public { BALANCER_VAULT_CONTRACT = IBalancerV2Vault(_balancerVault); } /// @dev Helper to execute batchSwap() on BalancerV2. /// Sender must have already approved allowances to the Balancer Vault. function __balancerV2BatchSwap( address _sender, address _recipient, IBalancerV2Vault.SwapKind _kind, IBalancerV2Vault.BatchSwapStep[] memory _swaps, address[] memory _assets, int256[] memory _limits ) internal returns (int256[] memory assetDeltas_) { IBalancerV2Vault.FundManagement memory funds = IBalancerV2Vault.FundManagement({ sender: _sender, fromInternalBalance: false, recipient: payable(_recipient), toInternalBalance: false }); return BALANCER_VAULT_CONTRACT.batchSwap({ _kind: _kind, _swaps: _swaps, _assets: _assets, _funds: funds, _limits: _limits, _deadline: block.timestamp }); } /// @dev Helper to add liquidity function __balancerV2Lend( bytes32 _poolId, address _sender, address _recipient, IBalancerV2Vault.PoolBalanceChange memory _request ) internal { BALANCER_VAULT_CONTRACT.joinPool(_poolId, _sender, _recipient, _request); } /// @dev Helper to remove liquidity function __balancerV2Redeem( bytes32 _poolId, address _sender, address payable _recipient, IBalancerV2Vault.PoolBalanceChange memory _request ) internal { BALANCER_VAULT_CONTRACT.exitPool(_poolId, _sender, _recipient, _request); } }
// 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 "../../../../../interfaces/ICurveLiquidityGaugeV2.sol"; import "../../../../../utils/AssetHelpers.sol"; /// @title CurveGaugeV2ActionsMixin Contract /// @author Enzyme Council <[email protected]> /// @notice Mixin contract for interacting with any Curve LiquidityGaugeV2 contract abstract contract CurveGaugeV2ActionsMixin is AssetHelpers { uint256 private constant CURVE_GAUGE_V2_MAX_REWARDS = 8; /// @dev Helper to claim pool-specific rewards function __curveGaugeV2ClaimRewards(address _gauge, address _target) internal { ICurveLiquidityGaugeV2(_gauge).claim_rewards(_target); } /// @dev Helper to get list of pool-specific rewards tokens function __curveGaugeV2GetRewardsTokens(address _gauge) internal view returns (address[] memory rewardsTokens_) { address[] memory lpRewardsTokensWithEmpties = new address[](CURVE_GAUGE_V2_MAX_REWARDS); uint256 rewardsTokensCount; for (uint256 i; i < CURVE_GAUGE_V2_MAX_REWARDS; i++) { address rewardToken = ICurveLiquidityGaugeV2(_gauge).reward_tokens(i); if (rewardToken != address(0)) { lpRewardsTokensWithEmpties[i] = rewardToken; rewardsTokensCount++; } else { break; } } rewardsTokens_ = new address[](rewardsTokensCount); for (uint256 i; i < rewardsTokensCount; i++) { rewardsTokens_[i] = lpRewardsTokensWithEmpties[i]; } return rewardsTokens_; } /// @dev Helper to stake LP tokens function __curveGaugeV2Stake( address _gauge, address _lpToken, uint256 _amount ) internal { __approveAssetMaxAsNeeded(_lpToken, _gauge, _amount); ICurveLiquidityGaugeV2(_gauge).deposit(_amount, address(this)); } /// @dev Helper to unstake LP tokens function __curveGaugeV2Unstake(address _gauge, uint256 _amount) internal { ICurveLiquidityGaugeV2(_gauge).withdraw(_amount); } }
// 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 "../../../../../interfaces/ICurveMinter.sol"; import "../../../../../utils/AddressArrayLib.sol"; import "./CurveGaugeV2ActionsMixin.sol"; /// @title CurveGaugeV2RewardsHandlerMixin Contract /// @author Enzyme Council <[email protected]> /// @notice Mixin contract for handling claiming and reinvesting rewards for a Curve pool /// that uses the LiquidityGaugeV2 contract abstract contract CurveGaugeV2RewardsHandlerMixin is CurveGaugeV2ActionsMixin { using AddressArrayLib for address[]; address private immutable CURVE_GAUGE_V2_REWARDS_HANDLER_CRV_TOKEN; address private immutable CURVE_GAUGE_V2_REWARDS_HANDLER_MINTER; constructor(address _minter, address _crvToken) public { CURVE_GAUGE_V2_REWARDS_HANDLER_CRV_TOKEN = _crvToken; CURVE_GAUGE_V2_REWARDS_HANDLER_MINTER = _minter; } /// @dev Helper to claim all rewards (CRV and pool-specific). /// Requires contract to be approved to use ICurveMinter.mint_for(). function __curveGaugeV2ClaimAllRewards(address _gauge, address _target) internal { if (__curveGaugeV2MinterExists()) { // Claim owed $CRV via Minter (only on Ethereum mainnet) ICurveMinter(CURVE_GAUGE_V2_REWARDS_HANDLER_MINTER).mint_for(_gauge, _target); } // Claim owed pool-specific rewards __curveGaugeV2ClaimRewards(_gauge, _target); } /// @dev Helper to check if the Curve Minter contract is used on the network function __curveGaugeV2MinterExists() internal view returns (bool exists_) { return CURVE_GAUGE_V2_REWARDS_HANDLER_MINTER != address(0); } /////////////////// // STATE GETTERS // /////////////////// /// @notice Gets the `CURVE_GAUGE_V2_REWARDS_HANDLER_CRV_TOKEN` variable /// @return crvToken_ The `CURVE_GAUGE_V2_REWARDS_HANDLER_CRV_TOKEN` variable value function getCurveGaugeV2RewardsHandlerCrvToken() public view returns (address crvToken_) { return CURVE_GAUGE_V2_REWARDS_HANDLER_CRV_TOKEN; } /// @notice Gets the `CURVE_GAUGE_V2_REWARDS_HANDLER_MINTER` variable /// @return minter_ The `CURVE_GAUGE_V2_REWARDS_HANDLER_MINTER` variable value function getCurveGaugeV2RewardsHandlerMinter() public view returns (address minter_) { return CURVE_GAUGE_V2_REWARDS_HANDLER_MINTER; } }
// 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/IBalancerV2Vault.sol"; import "../../../../../utils/AddressArrayLib.sol"; import "../../utils/actions/BalancerV2ActionsMixin.sol"; import "../../utils/AdapterBase.sol"; /// @title BalancerV2LiquidityAdapterBase Contract /// @author Enzyme Council <[email protected]> /// @notice Base adapter for liquidity provision in Balancer V2 pools. /// Implementing contracts can allow staking via Balancer gauges, Aura, etc. /// @dev Rewards tokens are not included as incoming assets for claimRewards() abstract contract BalancerV2LiquidityAdapterBase is AdapterBase, BalancerV2ActionsMixin { using AddressArrayLib for address[]; constructor(address _integrationManager, address _balancerVault) public AdapterBase(_integrationManager) BalancerV2ActionsMixin(_balancerVault) {} //////////////////////////////// // REQUIRED VIRTUAL FUNCTIONS // //////////////////////////////// /// @dev Logic to claim rewards for a given staking token function __claimRewards(address _vaultProxy, address _stakingToken) internal virtual; /// @dev Logic to get the BPT address for a given staking token. /// Implementations should pre-validate whether the staking token is valid, /// when reasonable. function __getBptForStakingToken(address _stakingToken) internal view virtual returns (address bpt_); /// @dev Logic to stake BPT to a given staking token. /// Staking is always the last action and thus always sent to the _vaultProxy /// (rather than a more generically-named `_recipient`). function __stake( address _vaultProxy, address _stakingToken, uint256 _bptAmount ) internal virtual; /// @dev Logic to unstake BPT from a given staking token function __unstake( address _from, address _recipient, address _stakingToken, uint256 _bptAmount ) internal virtual; ///////////// // ACTIONS // ///////////// // EXTERNAL FUNCTIONS /// @notice Claims all rewards /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action /// @dev Needs `onlyIntegrationManager` because Minter claiming permission is given by the fund function claimRewards( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { __claimRewards(_vaultProxy, __decodeClaimRewardsCallArgs(_actionData)); } /// @notice Lends assets for LP tokens, then stakes the received LP tokens /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action function lendAndStake( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { ( address stakingToken, bytes32 poolId, , address[] memory spendAssets, uint256[] memory spendAssetAmounts, IBalancerV2Vault.PoolBalanceChange memory request ) = __decodeCombinedActionCallArgs(_actionData); __lend(address(this), poolId, spendAssets, spendAssetAmounts, request); __stake( _vaultProxy, stakingToken, ERC20(__parseBalancerPoolAddress(poolId)).balanceOf(address(this)) ); // There can be different join/exit options per Balancer pool type, // some of which involve spending only up-to-max amounts __pushFullAssetBalances(_vaultProxy, spendAssets); } /// @notice Stakes LP tokens /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action function stake( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { (address stakingToken, uint256 bptAmount) = __decodeStakingActionCallArgs(_actionData); __stake(_vaultProxy, stakingToken, bptAmount); } /// @notice Swaps assets on Balancer via batchSwap() /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action /// @dev All `_actionData` inputs are Balancer `batchSwap()` params, with the exception of `stakingTokens`. /// "Spend assets" and "incoming assets" are parsed from the `limits` values corresponding to `assets`: /// - limit > 0 is a spend asset /// - limit < 0 is an incoming asset (including a partially-consumed intermediary asset) /// - limit == 0 is an intermediary asset that is completely consumed in the swap /// This function can also used for "LPing" with ComposableStablePool instances, /// since those pools contain their own BPT as an underlying asset. /// `stakingTokens` facilitates "lend and stake" and "unstake and redeem"-like functionality for such pools. /// If `stakingTokens[i]` is non-empty, it is considered to be the actual spend/incoming asset /// that must be unstaked to / staked from the BPT specified in `assets[i]` before/after the batchSawp(). function takeOrder( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { ( IBalancerV2Vault.SwapKind kind, IBalancerV2Vault.BatchSwapStep[] memory swaps, address[] memory assets, int256[] memory limits, address[] memory stakingTokens ) = __decodeTakeOrderCallArgs(_actionData); // Pre-process spend and incoming assets bool hasIncomingStakedBpt; uint256 assetCount = assets.length; for (uint256 i; i < assetCount; i++) { if (limits[i] > 0) { uint256 spendAssetAmount = uint256(limits[i]); // Unstake BPT if (stakingTokens[i] != address(0)) { __unstake({ _from: address(this), _recipient: address(this), _stakingToken: stakingTokens[i], _bptAmount: spendAssetAmount }); } // Grant allowances __approveAssetMaxAsNeeded({ _asset: assets[i], _target: address(BALANCER_VAULT_CONTRACT), _neededAmount: spendAssetAmount }); } else if (limits[i] < 0 && stakingTokens[i] != address(0)) { hasIncomingStakedBpt = true; } } // Execute batch swap int256[] memory assetDeltas = __balancerV2BatchSwap({ _sender: address(this), _recipient: hasIncomingStakedBpt ? address(this) : _vaultProxy, _kind: kind, _swaps: swaps, _assets: assets, _limits: limits }); // Post-process spend and incoming assets for (uint256 i; i < assetCount; i++) { if (limits[i] > 0) { // Re-stake any unused BPT, // only if partial spend was intentional due to specifying exact swap output amounts. // Prevents griefing edge case if `__stake()` reverts. if ( stakingTokens[i] != address(0) && kind == IBalancerV2Vault.SwapKind.GIVEN_OUT ) { uint256 bptAmount = ERC20(assets[i]).balanceOf(address(this)); if (bptAmount > 0) { __stake({ _vaultProxy: _vaultProxy, _stakingToken: stakingTokens[i], _bptAmount: bptAmount }); } } // Push any remaining spend asset balance back to the vault __pushFullAssetBalance({_target: _vaultProxy, _asset: assets[i]}); } else if (limits[i] < 0) { if (stakingTokens[i] != address(0)) { __stake({ _vaultProxy: _vaultProxy, _stakingToken: stakingTokens[i], _bptAmount: ERC20(assets[i]).balanceOf(address(this)) }); } else if (hasIncomingStakedBpt) { // Push any remaining incoming asset balance back to the vault __pushFullAssetBalance({_target: _vaultProxy, _asset: assets[i]}); } } else { // Validate no leftover balance for assets assumed to be purely intermediary require(assetDeltas[i] == 0, "takeOrder: leftover intermediary"); } } } /// @notice Unstakes LP tokens /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action function unstake( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { (address stakingToken, uint256 bptAmount) = __decodeStakingActionCallArgs(_actionData); __unstake(_vaultProxy, _vaultProxy, stakingToken, bptAmount); } /// @notice Unstakes LP tokens, then redeems them /// @param _vaultProxy The VaultProxy of the calling fund /// @param _actionData Data specific to this action function unstakeAndRedeem( address _vaultProxy, bytes calldata _actionData, bytes calldata ) external onlyIntegrationManager { ( address stakingToken, bytes32 poolId, uint256 bptAmount, address[] memory expectedIncomingTokens, , IBalancerV2Vault.PoolBalanceChange memory request ) = __decodeCombinedActionCallArgs(_actionData); __unstake(_vaultProxy, address(this), stakingToken, bptAmount); __redeem(_vaultProxy, poolId, bptAmount, expectedIncomingTokens, request); // The full amount of unstaked bpt might not be used in a redemption for exact underlyings // (with max bpt specified). In that case, re-stake the unused bpt. address bpt = __parseBalancerPoolAddress(poolId); uint256 remainingBpt = ERC20(bpt).balanceOf(address(this)); if (remainingBpt > 0) { __stake(_vaultProxy, stakingToken, remainingBpt); } // The full amount of staked bpt will always have been used } // INTERNAL FUNCTIONS /// @dev Helper to perform all logic to LP on Balancer function __lend( address _recipient, bytes32 _poolId, address[] memory _spendAssets, uint256[] memory _spendAssetAmounts, IBalancerV2Vault.PoolBalanceChange memory _request ) internal { for (uint256 i; i < _spendAssets.length; i++) { __approveAssetMaxAsNeeded( _spendAssets[i], address(BALANCER_VAULT_CONTRACT), _spendAssetAmounts[i] ); } __balancerV2Lend(_poolId, address(this), _recipient, _request); } /// @dev Helper to perform all logic to redeem Balancer BPTs function __redeem( address _vaultProxy, bytes32 _poolId, uint256 _spendBptAmount, address[] memory _expectedIncomingTokens, IBalancerV2Vault.PoolBalanceChange memory _request ) internal { __approveAssetMaxAsNeeded( __parseBalancerPoolAddress(_poolId), address(BALANCER_VAULT_CONTRACT), _spendBptAmount ); // Since we are not parsing request.userData, we do not know with certainty which tokens // will be received. We are relying on the user-input _expectedIncomingTokens up to this point. // But, to guarantee that no unexpected tokens are received, we need to monitor those balances. uint256 unusedTokensCount = _request.assets.length - _expectedIncomingTokens.length; uint256[] memory preTxTokenBalancesIfUnused; if (unusedTokensCount > 0) { preTxTokenBalancesIfUnused = new uint256[](_request.assets.length); uint256 remainingCount = unusedTokensCount; for (uint256 i; remainingCount > 0; i++) { if (!_expectedIncomingTokens.contains(_request.assets[i])) { preTxTokenBalancesIfUnused[i] = ERC20(_request.assets[i]).balanceOf( _vaultProxy ); remainingCount--; } } } __balancerV2Redeem(_poolId, address(this), payable(_vaultProxy), _request); if (unusedTokensCount > 0) { for (uint256 i; unusedTokensCount > 0; i++) { if (!_expectedIncomingTokens.contains(_request.assets[i])) { require( ERC20(_request.assets[i]).balanceOf(_vaultProxy) == preTxTokenBalancesIfUnused[i], "__balancerRedeem: Unexpected asset received" ); unusedTokensCount--; } } } } ///////////////////////////// // PARSE ASSETS FOR METHOD // ///////////////////////////// /// @notice Parses the expected assets to receive from a call on integration /// @param _selector The function selector for the callOnIntegration /// @param _actionData The encoded parameters for the callOnIntegration /// @return spendAssetsHandleType_ A type that dictates how to handle granting /// the adapter access to spend assets (`None` by default) /// @return spendAssets_ The assets to spend in the call /// @return spendAssetAmounts_ The max asset amounts to spend in the call /// @return incomingAssets_ The assets to receive in the call /// @return minIncomingAssetAmounts_ The min asset amounts to receive in the call function parseAssetsForAction( address, bytes4 _selector, bytes calldata _actionData ) public view virtual override returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { if (_selector == CLAIM_REWARDS_SELECTOR) { return __parseAssetsForClaimRewards(); } else if (_selector == LEND_AND_STAKE_SELECTOR) { return __parseAssetsForLendAndStake(_actionData); } else if (_selector == UNSTAKE_AND_REDEEM_SELECTOR) { return __parseAssetsForUnstakeAndRedeem(_actionData); } else if (_selector == TAKE_ORDER_SELECTOR) { return __parseAssetsForTakeOrder(_actionData); } else if (_selector == STAKE_SELECTOR) { return __parseAssetsForStake(_actionData); } else if (_selector == UNSTAKE_SELECTOR) { return __parseAssetsForUnstake(_actionData); } revert("parseAssetsForAction: _selector invalid"); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during claimRewards() calls. /// No action required, all values empty. function __parseAssetsForClaimRewards() internal pure virtual returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { return ( IIntegrationManager.SpendAssetsHandleType.None, new address[](0), new uint256[](0), new address[](0), new uint256[](0) ); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during lend() calls function __parseAssetsForLendAndStake(bytes calldata _encodedCallArgs) internal view virtual returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { incomingAssets_ = new address[](1); minIncomingAssetAmounts_ = new uint256[](1); bytes32 poolId; address stakingToken; IBalancerV2Vault.PoolBalanceChange memory request; ( stakingToken, poolId, minIncomingAssetAmounts_[0], spendAssets_, spendAssetAmounts_, request ) = __decodeCombinedActionCallArgs(_encodedCallArgs); __validatePoolForStakingToken(stakingToken, poolId); __validateNoInternalBalances(request.useInternalBalance); incomingAssets_[0] = stakingToken; return ( IIntegrationManager.SpendAssetsHandleType.Transfer, spendAssets_, spendAssetAmounts_, incomingAssets_, minIncomingAssetAmounts_ ); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during stake() calls function __parseAssetsForStake(bytes calldata _encodedCallArgs) internal view virtual returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { (address stakingToken, uint256 bptAmount) = __decodeStakingActionCallArgs( _encodedCallArgs ); spendAssets_ = new address[](1); spendAssetAmounts_ = new uint256[](1); incomingAssets_ = new address[](1); minIncomingAssetAmounts_ = new uint256[](1); spendAssets_[0] = __getBptForStakingToken(stakingToken); spendAssetAmounts_[0] = bptAmount; incomingAssets_[0] = stakingToken; minIncomingAssetAmounts_[0] = bptAmount; return ( IIntegrationManager.SpendAssetsHandleType.Transfer, spendAssets_, spendAssetAmounts_, incomingAssets_, minIncomingAssetAmounts_ ); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during takeOrder() calls function __parseAssetsForTakeOrder(bytes calldata _encodedCallArgs) private view returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { ( , , address[] memory assets, int256[] memory limits, address[] memory stakingTokens ) = __decodeTakeOrderCallArgs(_encodedCallArgs); // See takeOrder() comments for how spend and incoming assets are parsed uint256 spendAssetsCount; uint256 incomingAssetsCount; for (uint256 i; i < assets.length; i++) { if (limits[i] > 0) { spendAssetsCount++; } else if (limits[i] < 0) { incomingAssetsCount++; } } spendAssets_ = new address[](spendAssetsCount); spendAssetAmounts_ = new uint256[](spendAssetsCount); incomingAssets_ = new address[](incomingAssetsCount); minIncomingAssetAmounts_ = new uint256[](incomingAssetsCount); for (uint256 i; i < assets.length; i++) { int256 limit = limits[i]; if (limit > 0) { address spendAsset = assets[i]; address stakingToken = stakingTokens[i]; if (stakingToken != address(0)) { require( spendAsset == __getBptForStakingToken(stakingToken), "__parseAssetsForTakeOrder: BPT mismatch" ); spendAsset = stakingToken; } spendAssetsCount--; spendAssets_[spendAssetsCount] = spendAsset; spendAssetAmounts_[spendAssetsCount] = uint256(limit); } else if (limit < 0) { address incomingAsset = assets[i]; address stakingToken = stakingTokens[i]; if (stakingToken != address(0)) { require( incomingAsset == __getBptForStakingToken(stakingToken), "__parseAssetsForTakeOrder: BPT mismatch" ); incomingAsset = stakingToken; } incomingAssetsCount--; incomingAssets_[incomingAssetsCount] = incomingAsset; minIncomingAssetAmounts_[incomingAssetsCount] = uint256(-limit); } } return ( IIntegrationManager.SpendAssetsHandleType.Transfer, spendAssets_, spendAssetAmounts_, incomingAssets_, minIncomingAssetAmounts_ ); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during unstake() calls function __parseAssetsForUnstake(bytes calldata _encodedCallArgs) internal view virtual returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { (address stakingToken, uint256 bptAmount) = __decodeStakingActionCallArgs( _encodedCallArgs ); spendAssets_ = new address[](1); spendAssetAmounts_ = new uint256[](1); incomingAssets_ = new address[](1); minIncomingAssetAmounts_ = new uint256[](1); spendAssets_[0] = stakingToken; spendAssetAmounts_[0] = bptAmount; incomingAssets_[0] = __getBptForStakingToken(stakingToken); minIncomingAssetAmounts_[0] = bptAmount; return ( IIntegrationManager.SpendAssetsHandleType.Transfer, spendAssets_, spendAssetAmounts_, incomingAssets_, minIncomingAssetAmounts_ ); } /// @dev Helper function to parse spend and incoming assets from encoded call args /// during unstakeAndRedeem() calls function __parseAssetsForUnstakeAndRedeem(bytes calldata _encodedCallArgs) internal view virtual returns ( IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_, address[] memory spendAssets_, uint256[] memory spendAssetAmounts_, address[] memory incomingAssets_, uint256[] memory minIncomingAssetAmounts_ ) { spendAssets_ = new address[](1); spendAssetAmounts_ = new uint256[](1); bytes32 poolId; address stakingToken; IBalancerV2Vault.PoolBalanceChange memory request; ( stakingToken, poolId, spendAssetAmounts_[0], incomingAssets_, minIncomingAssetAmounts_, request ) = __decodeCombinedActionCallArgs(_encodedCallArgs); __validatePoolForStakingToken(stakingToken, poolId); __validateNoInternalBalances(request.useInternalBalance); spendAssets_[0] = stakingToken; return ( IIntegrationManager.SpendAssetsHandleType.Transfer, spendAssets_, spendAssetAmounts_, incomingAssets_, minIncomingAssetAmounts_ ); } /// @dev Helper to get a Balancer pool address (i.e., Balancer Pool Token) for a given id. /// See: https://github.com/balancer-labs/balancer-v2-monorepo/blob/42906226223f29e4489975eb3c0d5014dea83b66/pkg/vault/contracts/PoolRegistry.sol#L130-L139 function __parseBalancerPoolAddress(bytes32 _poolId) internal pure returns (address poolAddress_) { return address(uint256(_poolId) >> (12 * 8)); } /// @dev Helper to validate a given poolId for a given staking token. /// Does not validate the staking token itself, unless handled in the implementing contract /// during __getBptForStakingToken(). function __validatePoolForStakingToken(address _stakingToken, bytes32 _poolId) internal view { require( __getBptForStakingToken(_stakingToken) == __parseBalancerPoolAddress(_poolId), "__validateBptForStakingToken: Invalid" ); } /// @dev Helper to validate Balancer internal balances are not used function __validateNoInternalBalances(bool _useInternalBalances) internal pure { require(!_useInternalBalances, "__validateNoInternalBalances: Invalid"); } ////////////// // DECODERS // ////////////// /// @dev Helper to decode callArgs for lend and redeem function __decodeCombinedActionCallArgs(bytes memory _encodedCallArgs) internal pure returns ( address stakingToken_, bytes32 poolId_, uint256 bptAmount_, address[] memory usedTokens_, // only the assets that will actually be spent/received uint256[] memory usedTokenAmounts_, // only the assets that will actually be spent/received IBalancerV2Vault.PoolBalanceChange memory request_ ) { return abi.decode( _encodedCallArgs, ( address, bytes32, uint256, address[], uint256[], IBalancerV2Vault.PoolBalanceChange ) ); } /// @dev Helper to decode the encoded call arguments for claiming rewards function __decodeClaimRewardsCallArgs(bytes memory _actionData) internal pure returns (address stakingToken_) { return abi.decode(_actionData, (address)); } /// @dev Helper to decode callArgs for stake and unstake function __decodeStakingActionCallArgs(bytes memory _encodedCallArgs) internal pure returns (address stakingToken_, uint256 bptAmount_) { return abi.decode(_encodedCallArgs, (address, uint256)); } /// @dev Helper to decode callArgs for takeOrder(). /// See takeOrder() comments for args explanation. function __decodeTakeOrderCallArgs(bytes memory _encodedCallArgs) private pure returns ( IBalancerV2Vault.SwapKind kind_, IBalancerV2Vault.BatchSwapStep[] memory swaps_, address[] memory assets_, int256[] memory limits_, address[] memory stakingTokens_ ) { return abi.decode( _encodedCallArgs, ( IBalancerV2Vault.SwapKind, IBalancerV2Vault.BatchSwapStep[], address[], int256[], 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 IBalancerV2LiquidityGauge interface /// @author Enzyme Council <[email protected]> /// @dev Applies to both LiquidityGauge (L1) and ChildChainLiquidityGauge (L2/sidechains) interface IBalancerV2LiquidityGauge { function lp_token() external view returns (address lpToken_); }
// 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 IBalancerV2Vault interface /// @author Enzyme Council <[email protected]> interface IBalancerV2Vault { struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } // JoinPoolRequest and ExitPoolRequest are just differently labeled versions of PoolBalanceChange. // See: https://github.com/balancer-labs/balancer-v2-monorepo/blob/42906226223f29e4489975eb3c0d5014dea83b66/pkg/vault/contracts/PoolBalances.sol#L70 struct PoolBalanceChange { address[] assets; uint256[] limits; bytes userData; bool useInternalBalance; } enum SwapKind { GIVEN_IN, GIVEN_OUT } function batchSwap( SwapKind _kind, BatchSwapStep[] memory _swaps, address[] memory _assets, FundManagement memory _funds, int256[] memory _limits, uint256 _deadline ) external returns (int256[] memory assetDeltas_); function exitPool( bytes32 _poolId, address _sender, address payable _recipient, PoolBalanceChange memory _request ) external; function getPoolTokens(bytes32 _poolId) external view returns ( address[] memory tokens_, uint256[] memory balances_, uint256 lastChangeBlock_ ); function joinPool( bytes32 _poolId, address _sender, address _recipient, PoolBalanceChange memory _request ) external payable; function setRelayerApproval( address _sender, address _relayer, bool _approved ) 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; /// @title ICurveLiquidityGaugeV2 interface /// @author Enzyme Council <[email protected]> interface ICurveLiquidityGaugeV2 { function claim_rewards(address) external; function deposit(uint256, address) external; function reward_tokens(uint256) external view returns (address); function withdraw(uint256) 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; /// @title ICurveMinter interface /// @author Enzyme Council <[email protected]> interface ICurveMinter { function mint_for(address, address) 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; /// @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_; } /// @dev Helper to verify if a storage array contains a particular value function storageArrayContains(address[] storage _self, address _target) internal view returns (bool doesContain_) { uint256 arrLength = _self.length; for (uint256 i; i < arrLength; i++) { if (_target == _self[i]) { return true; } } return false; } //////////// // 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 "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; /// @title AssetHelpers Contract /// @author Enzyme Council <[email protected]> /// @notice A util contract for common token actions abstract contract AssetHelpers { using SafeERC20 for ERC20; using SafeMath for uint256; /// @dev Helper to aggregate amounts of the same assets function __aggregateAssetAmounts(address[] memory _rawAssets, uint256[] memory _rawAmounts) internal pure returns (address[] memory aggregatedAssets_, uint256[] memory aggregatedAmounts_) { if (_rawAssets.length == 0) { return (aggregatedAssets_, aggregatedAmounts_); } uint256 aggregatedAssetCount = 1; for (uint256 i = 1; i < _rawAssets.length; i++) { bool contains; for (uint256 j; j < i; j++) { if (_rawAssets[i] == _rawAssets[j]) { contains = true; break; } } if (!contains) { aggregatedAssetCount++; } } aggregatedAssets_ = new address[](aggregatedAssetCount); aggregatedAmounts_ = new uint256[](aggregatedAssetCount); uint256 aggregatedAssetIndex; for (uint256 i; i < _rawAssets.length; i++) { bool contains; for (uint256 j; j < aggregatedAssetIndex; j++) { if (_rawAssets[i] == aggregatedAssets_[j]) { contains = true; aggregatedAmounts_[j] += _rawAmounts[i]; break; } } if (!contains) { aggregatedAssets_[aggregatedAssetIndex] = _rawAssets[i]; aggregatedAmounts_[aggregatedAssetIndex] = _rawAmounts[i]; aggregatedAssetIndex++; } } return (aggregatedAssets_, aggregatedAmounts_); } /// @dev Helper to approve a target account with the max amount of an asset. /// This is helpful for fully trusted contracts, such as adapters that /// interact with external protocol like Uniswap, Compound, etc. function __approveAssetMaxAsNeeded( address _asset, address _target, uint256 _neededAmount ) internal { uint256 allowance = ERC20(_asset).allowance(address(this), _target); if (allowance < _neededAmount) { if (allowance > 0) { ERC20(_asset).safeApprove(_target, 0); } ERC20(_asset).safeApprove(_target, type(uint256).max); } } /// @dev Helper to transfer full asset balance from the current contract to a target function __pushFullAssetBalance(address _target, address _asset) internal returns (uint256 amountTransferred_) { amountTransferred_ = ERC20(_asset).balanceOf(address(this)); if (amountTransferred_ > 0) { ERC20(_asset).safeTransfer(_target, amountTransferred_); } return amountTransferred_; } /// @dev Helper to transfer full asset balances from the current contract to a target function __pushFullAssetBalances(address _target, address[] memory _assets) internal returns (uint256[] memory amountsTransferred_) { amountsTransferred_ = new uint256[](_assets.length); for (uint256 i; i < _assets.length; i++) { ERC20 assetContract = ERC20(_assets[i]); amountsTransferred_[i] = assetContract.balanceOf(address(this)); if (amountsTransferred_[i] > 0) { assetContract.safeTransfer(_target, amountsTransferred_[i]); } } return amountsTransferred_; } }
{ "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":"_integrationManager","type":"address"},{"internalType":"address","name":"_balancerVault","type":"address"},{"internalType":"address","name":"_balancerMinter","type":"address"},{"internalType":"address","name":"_balToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CLAIM_REWARDS_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LEND_AND_STAKE_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LEND_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REDEEM_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKE_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TAKE_MULTIPLE_ORDERS_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TAKE_ORDER_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSTAKE_AND_REDEEM_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSTAKE_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurveGaugeV2RewardsHandlerCrvToken","outputs":[{"internalType":"address","name":"crvToken_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurveGaugeV2RewardsHandlerMinter","outputs":[{"internalType":"address","name":"minter_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIntegrationManager","outputs":[{"internalType":"address","name":"integrationManager_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"lend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"lendAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes4","name":"_selector","type":"bytes4"},{"internalType":"bytes","name":"_actionData","type":"bytes"}],"name":"parseAssetsForAction","outputs":[{"internalType":"enum IIntegrationManager.SpendAssetsHandleType","name":"spendAssetsHandleType_","type":"uint8"},{"internalType":"address[]","name":"spendAssets_","type":"address[]"},{"internalType":"uint256[]","name":"spendAssetAmounts_","type":"uint256[]"},{"internalType":"address[]","name":"incomingAssets_","type":"address[]"},{"internalType":"uint256[]","name":"minIncomingAssetAmounts_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"takeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultProxy","type":"address"},{"internalType":"bytes","name":"_actionData","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"unstakeAndRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101006040523480156200001257600080fd5b5060405162003dba38038062003dba833981016040819052620000359162000077565b6001600160601b0319606094851b811660805292841b831660a052831b821660c05290911b1660e0526200010d565b80516200007181620000f3565b92915050565b600080600080608085870312156200008e57600080fd5b60006200009c878762000064565b9450506020620000af8782880162000064565b9350506040620000c28782880162000064565b9250506060620000d58782880162000064565b91505092959194509250565b60006001600160a01b03821662000071565b620000fe81620000e1565b81146200010a57600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c613c206200019a60003980610e195280611d6552806127525250806109435250806103ca5280611067528061121c52806114355280611c305280611d065250806102885280610747528061084f52806109b85280610a5b5280610c095280610ca05280610df55280610e6a5250613c206000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80638334eb99116100b8578063c32990a21161007c578063c32990a214610226578063c54efee51461022e578063e7c4569014610252578063f003eb851461025a578063f7d882b514610262578063fa7dd04d1461026a57610137565b80638334eb99146101dd578063863e5ad0146101f0578063b23228cf146101f8578063b9dfbacc14610200578063c29fa9dd1461021357610137565b806329fa046e116100ff57806329fa046e14610192578063332d709f146101a55780633ffc1591146101ba57806340da225d146101c257806368e30677146101ca57610137565b806303e38a2b1461013c578063080456c114610151578063099f75151461016f578063131461c014610182578063257cb1a31461018a575b600080fd5b61014f61014a366004612ecc565b61027d565b005b610159610718565b60405161016691906138e1565b60405180910390f35b61014f61017d366004612ecc565b61073c565b6101596107fc565b610159610820565b61014f6101a0366004612ecc565b610844565b6101ad610941565b6040516101669190613859565b610159610965565b610159610989565b61014f6101d8366004612ecc565b6109ad565b61014f6101eb366004612ecc565b610a50565b610159610bb6565b610159610bda565b61014f61020e366004612ecc565b610bfe565b61014f610221366004612ecc565b610c95565b610159610d51565b61024161023c366004612e65565b610d75565b6040516101669594939291906138ef565b6101ad610df3565b6101ad610e17565b610159610e3b565b61014f610278366004612ecc565b610e5f565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102ce5760405162461bcd60e51b81526004016102c590613a02565b60405180910390fd5b600060608060608061031589898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ef892505050565b945094509450945094506000808451905060005b8181101561045057600085828151811061033f57fe5b602002602001015113156103f557600085828151811061035b57fe5b6020026020010151905060006001600160a01b031685838151811061037c57fe5b60200260200101516001600160a01b0316146103b1576103b130308785815181106103a357fe5b602002602001015184610f26565b6103ef8783815181106103c057fe5b60200260200101517f000000000000000000000000000000000000000000000000000000000000000083610f64565b50610448565b600085828151811061040357fe5b602002602001015112801561043e575060006001600160a01b031684828151811061042a57fe5b60200260200101516001600160a01b031614155b1561044857600192505b600101610329565b50606061046d3084610462578e610464565b305b8a8a8a8a611020565b905060005b8281101561070857600086828151811061048857fe5b602002602001015113156105b85760006001600160a01b03168582815181106104ad57fe5b60200260200101516001600160a01b0316141580156104d7575060018960018111156104d557fe5b145b156105955760008782815181106104ea57fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161051d9190613859565b60206040518083038186803b15801561053557600080fd5b505afa158015610549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056d9190613121565b90508015610593576105938f87848151811061058557fe5b602002602001015183611108565b505b6105b28e8883815181106105a557fe5b6020026020010151611134565b50610700565b60008682815181106105c657fe5b602002602001015112156106cd5760006001600160a01b03168582815181106105eb57fe5b60200260200101516001600160a01b0316146106b2576106ad8e86838151811061061157fe5b602002602001015189848151811061062557fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016106589190613859565b60206040518083038186803b15801561067057600080fd5b505afa158015610684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a89190613121565b611108565b6106c8565b83156106c8576105b28e8883815181106105a557fe5b610700565b8181815181106106d957fe5b60200260200101516000146107005760405162461bcd60e51b81526004016102c590613a12565b600101610472565b5050505050505050505050505050565b7f8334eb99be0145865eba9889fca2ee920288090caefff4cc776038e20ad9259a81565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107845760405162461bcd60e51b81526004016102c590613a02565b6000606080610791612905565b6107d088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b9450945094505093506107e689858585856111f7565b6107f08984611269565b50505050505050505050565b7f29fa046e79524c3c5ac4c01df692c35e217802b2b13b21121b76cf0ef02b138c81565b7f099f75155f0e997bf83a7993a71d5e7e7540bd386fe1e84643a09ce6b412521981565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461088c5760405162461bcd60e51b81526004016102c590613a02565b60008060608061089a612905565b6108d989898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b95509550955050945094506108f130858585856111f7565b61092a8a866108ff876113fc565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016106589190613859565b6109348a84611269565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000090565b7ffa7dd04da627f433da73c4355ead9c75682a67a8fc84d3f6170ef0922f402d2481565b7fb9dfbaccbe5cd2a84fdcf1d15f23ef25d23086f5afbaa99516065ed4a5bbc7a381565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109f55760405162461bcd60e51b81526004016102c590613a02565b600080610a3786868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b91509150610a4787888484610f26565b50505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a985760405162461bcd60e51b81526004016102c590613a02565b60008060006060610aa7612905565b610ae689898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b9550509450945094509450610afd8a308786610f26565b610b0a8a85858585611427565b6000610b15856113fc565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b459190613859565b60206040518083038186803b158015610b5d57600080fd5b505afa158015610b71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b959190613121565b90508015610ba857610ba88c8883611108565b505050505050505050505050565b7f03e38a2bd7063d45c897edeafc330e71657502dd86434d3c37a489caf116af6981565b7f68e30677f607df46e87da13e15b637784cfa62374b653f35ab43d10361a2f83081565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c465760405162461bcd60e51b81526004016102c590613a02565b610c8e85610c8986868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506116c792505050565b6116dd565b5050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cdd5760405162461bcd60e51b81526004016102c590613a02565b6000806060610cea612905565b610d2988888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b945050935093509350610d3f8985858585611427565b6107f089610d4c866113fc565b611134565b7f0e7f692dad5b88fdee426250d6eae91207e56a2e8112b7364579bed1790e5bf481565b600060608080806001600160e01b0319881663099f751560e01b1415610dae57610d9f87876116eb565b94509450945094509450610de8565b6001600160e01b0319881663c29fa9dd60e01b1415610dd157610d9f87876117f8565b610ddd898989896118d5565b945094509450945094505b945094509450945094565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b7fc29fa9dde84204c2908778afd0613d802d31cf046179b88f6d2b4a4e507ea2d581565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610ea75760405162461bcd60e51b81526004016102c590613a02565b600080610ee986868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b91509150610a47878383611108565b600060608060608085806020019051810190610f14919061305d565b939a9299509097509550909350915050565b610f3082826119c4565b6001600160a01b0383163014610f5e57610f5e8382610f4e85611a26565b6001600160a01b03169190611a99565b50505050565b604051636eb1769f60e11b81526000906001600160a01b0385169063dd62ed3e90610f959030908790600401613867565b60206040518083038186803b158015610fad57600080fd5b505afa158015610fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe59190613121565b905081811015610f5e57801561100a5761100a6001600160a01b038516846000611aef565b610f5e6001600160a01b03851684600019611aef565b606061102a61292f565b50604080516080810182526001600160a01b03808a168252600060208301819052898216838501526060830152915163945bcec960e01b815290917f0000000000000000000000000000000000000000000000000000000000000000169063945bcec9906110a69089908990899087908a90429060040161394b565b600060405180830381600087803b1580156110c057600080fd5b505af11580156110d4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110fc9190810190612f51565b98975050505050505050565b61111b8261111584611a26565b83611bb2565b61112f6001600160a01b0383168483611a99565b505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190611163903090600401613859565b60206040518083038186803b15801561117b57600080fd5b505afa15801561118f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b39190613121565b905080156111cf576111cf6001600160a01b0383168483611a99565b92915050565b6000806060806111e3612905565b85806020019051810190610f149190612fa3565b60005b835181101561125c5761125484828151811061121257fe5b60200260200101517f000000000000000000000000000000000000000000000000000000000000000085848151811061124757fe5b6020026020010151610f64565b6001016111fa565b50610c8e84308784611c19565b606081516001600160401b038111801561128257600080fd5b506040519080825280602002602001820160405280156112ac578160200160208202803683370190505b50905060005b82518110156113bd5760008382815181106112c957fe5b60200260200101519050806001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112ff9190613859565b60206040518083038186803b15801561131757600080fd5b505afa15801561132b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134f9190613121565b83838151811061135b57fe5b602002602001018181525050600083838151811061137557fe5b602002602001015111156113b4576113b48584848151811061139357fe5b6020026020010151836001600160a01b0316611a999092919063ffffffff16565b506001016112b2565b5092915050565b60008060006060806113d4612905565b868060200190518101906113e89190612d5f565b949c939b5091995097509550909350915050565b606081901c5b919050565b6000808280602001905181019061141e9190612e2b565b91509150915091565b61145a611433856113fc565b7f000000000000000000000000000000000000000000000000000000000000000085610f64565b815181515103606081156115a0578251516001600160401b038111801561148057600080fd5b506040519080825280602002602001820160405280156114aa578160200160208202803683370190505b5090508160005b811561159d576114e1856000015182815181106114ca57fe5b602002602001015187611c9990919063ffffffff16565b6115955784518051829081106114f357fe5b60200260200101516001600160a01b03166370a082318a6040518263ffffffff1660e01b81526004016115269190613859565b60206040518083038186803b15801561153e57600080fd5b505afa158015611552573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115769190613121565b83828151811061158257fe5b6020908102919091010152600019909101905b6001016114b1565b50505b6115ac86308986611cef565b8115610a475760005b82156116bd576115e5846000015182815181106115ce57fe5b602002602001015186611c9990919063ffffffff16565b6116b5578181815181106115f557fe5b60200260200101518460000151828151811061160d57fe5b60200260200101516001600160a01b03166370a082318a6040518263ffffffff1660e01b81526004016116409190613859565b60206040518083038186803b15801561165857600080fd5b505afa15801561166c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116909190613121565b146116ad5760405162461bcd60e51b81526004016102c5906139c2565b600019909201915b6001016115b5565b5050505050505050565b6000818060200190518101906111cf9190612d39565b6116e78183611d41565b5050565b6040805160018082528183019092526000916060918291829182916020808301908036833750506040805160018082528183019092529294509050602080830190803683370190505090506000611740612905565b61177f89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b8760008151811061178c57fe5b60209081029190910101939093526060830151919950975091935091506117b290611dd9565b6117bb826113fc565b846000815181106117c857fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506002965050509295509295909350565b604080516001808252818301909252600091606091829182918291602080830190803683375050604080516001808252818301909252929650905060208083019080368337019050509250600061184d612905565b61188c89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b8960008151811061189957fe5b60209081029190910101939093526060830151919750955091935091506118bf90611dd9565b6118c8826113fc565b866000815181106117c857fe5b600060608080806001600160e01b03198816632e77eeb360e21b14156118fd57610d9f611dfa565b6001600160e01b031988166314fd023760e11b141561192057610d9f8787611e5a565b6001600160e01b03198816638334eb9960e01b141561194357610d9f8787611f6d565b6001600160e01b031988166303e38a2b60e01b141561196657610d9f878761204f565b6001600160e01b0319881663fa7dd04d60e01b141561198957610d9f878761241d565b6001600160e01b031988166368e3067760e01b14156119ac57610d9f8787612594565b60405162461bcd60e51b81526004016102c590613a62565b604051632e1a7d4d60e01b81526001600160a01b03831690632e1a7d4d906119f0908490600401613a72565b600060405180830381600087803b158015611a0a57600080fd5b505af1158015611a1e573d6000803e3d6000fd5b505050505050565b6000816001600160a01b03166382c630666040518163ffffffff1660e01b815260040160206040518083038186803b158015611a6157600080fd5b505afa158015611a75573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111cf9190612d39565b61112f8363a9059cbb60e01b8484604051602401611ab8929190613882565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526126c1565b801580611b775750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b259030908690600401613867565b60206040518083038186803b158015611b3d57600080fd5b505afa158015611b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b759190613121565b155b611b935760405162461bcd60e51b81526004016102c590613a52565b61112f8363095ea7b360e01b8484604051602401611ab8929190613882565b611bbd828483610f64565b604051636e553f6560e01b81526001600160a01b03841690636e553f6590611beb9084903090600401613a80565b600060405180830381600087803b158015611c0557600080fd5b505af1158015610a47573d6000803e3d6000fd5b60405163172b958560e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b95cac2890611c6b90879087908790879060040161389d565b600060405180830381600087803b158015611c8557600080fd5b505af11580156116bd573d6000803e3d6000fd5b6000805b8351811015611ce557838181518110611cb257fe5b60200260200101516001600160a01b0316836001600160a01b03161415611cdd5760019150506111cf565b600101611c9d565b5060009392505050565b604051638bdb391360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638bdb391390611c6b90879087908790879060040161389d565b611d49612750565b15611dcf576040516327f18ae360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906327f18ae390611d9c9085908590600401613867565b600060405180830381600087803b158015611db657600080fd5b505af1158015611dca573d6000803e3d6000fd5b505050505b6116e7828261277f565b8015611df75760405162461bcd60e51b81526004016102c590613a22565b50565b600060608080808480604051908082528060200260200182016040528015611e2c578160200160208202803683370190505b5060408051600080825260208201818152828401918252606083019093529399929850965094509092509050565b604080516001808252818301909252600091606091829182918291602080830190803683375050604080516001808252818301909252929450905060208083019080368337019050509050600080611eb0612905565b611eef8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b89600081518110611efc57fe5b6020908102919091010193909352909a5098509094509092509050611f2182846127ab565b611f2e8160600151611dd9565b8185600081518110611f3c57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600297505050509295509295909350565b604080516001808252818301909252600091606091829182918291602080830190803683375050604080516001808252818301909252929650905060208083019080368337019050509250600080611fc3612905565b6120028a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b8b60008151811061200f57fe5b60209081029190910101939093529098509650909450909250905061203482846127ab565b6120418160600151611dd9565b8187600081518110611f3c57fe5b6000606080606080606080606061209b8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ef892505050565b945094509450505060008060005b85518110156121045760008582815181106120c057fe5b602002602001015113156120d9576001909201916120fc565b60008582815181106120e757fe5b602002602001015112156120fc576001909101905b6001016120a9565b50816001600160401b038111801561211b57600080fd5b50604051908082528060200260200182016040528015612145578160200160208202803683370190505b509850816001600160401b038111801561215e57600080fd5b50604051908082528060200260200182016040528015612188578160200160208202803683370190505b509750806001600160401b03811180156121a157600080fd5b506040519080825280602002602001820160405280156121cb578160200160208202803683370190505b509650806001600160401b03811180156121e457600080fd5b5060405190808252806020026020018201604052801561220e578160200160208202803683370190505b50955060005b855181101561240957600085828151811061222b57fe5b60200260200101519050600081131561231b57600087838151811061224c57fe5b60200260200101519050600086848151811061226457fe5b6020026020010151905060006001600160a01b0316816001600160a01b0316146122c55761229181611a26565b6001600160a01b0316826001600160a01b0316146122c15760405162461bcd60e51b81526004016102c5906139d2565b8091505b858060019003965050818d87815181106122db57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050828c878151811061230857fe5b6020026020010181815250505050612400565b600081121561240057600087838151811061233257fe5b60200260200101519050600086848151811061234a57fe5b6020026020010151905060006001600160a01b0316816001600160a01b0316146123ab5761237781611a26565b6001600160a01b0316826001600160a01b0316146123a75760405162461bcd60e51b81526004016102c5906139d2565b8091505b848060019003955050818b86815181106123c157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050826000038a86815181106123f157fe5b60200260200101818152505050505b50600101612214565b506002995050505050509295509295909350565b600060608060608060008061246789898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b604080516001808252818301909252929450909250602080830190803683375050604080516001808252818301909252929850905060208083019080368337505060408051600180825281830190925292975090506020808301908036833750506040805160018082528183019092529296509050602080830190803683370190505092506124f582611a26565b8660008151811061250257fe5b60200260200101906001600160a01b031690816001600160a01b031681525050808560008151811061253057fe5b602002602001018181525050818460008151811061254a57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050808360008151811061257857fe5b6020026020010181815250506002965050509295509295909350565b60006060806060806000806125de89898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b60408051600180825281830190925292945090925060208083019080368337505060408051600180825281830190925292985090506020808301908036833750506040805160018082528183019092529297509050602080830190803683375050604080516001808252818301909252929650905060208083019080368337019050509250818660008151811061267157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050808560008151811061269f57fe5b6020026020010181815250506126b482611a26565b8460008151811061254a57fe5b6060612716826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166127ec9092919063ffffffff16565b80519091501561112f57808060200190518101906127349190612f85565b61112f5760405162461bcd60e51b81526004016102c590613a42565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316151590565b604051634274debf60e11b81526001600160a01b038316906384e9bd7e906119f0908490600401613859565b6127b4816113fc565b6001600160a01b03166127c683611a26565b6001600160a01b0316146116e75760405162461bcd60e51b81526004016102c5906139e2565b60606127fb8484600085612805565b90505b9392505050565b6060824710156128275760405162461bcd60e51b81526004016102c5906139f2565b612830856128c6565b61284c5760405162461bcd60e51b81526004016102c590613a32565b60006060866001600160a01b03168587604051612869919061384d565b60006040518083038185875af1925050503d80600081146128a6576040519150601f19603f3d011682016040523d82523d6000602084013e6128ab565b606091505b50915091506128bb8282866128cc565b979650505050505050565b3b151590565b606083156128db5750816127fe565b8251156128eb5782518084602001fd5b8160405162461bcd60e51b81526004016102c591906139b1565b60405180608001604052806060815260200160608152602001606081526020016000151581525090565b60408051608081018252600080825260208201819052918101829052606081019190915290565b80356111cf81613bae565b80516111cf81613bae565b600082601f83011261297d57600080fd5b815161299061298b82613ab4565b613a8e565b915081818352602084019350602081019050838560208402820111156129b557600080fd5b60005b838110156129e157816129cb8882612961565b84525060209283019291909101906001016129b8565b5050505092915050565b600082601f8301126129fc57600080fd5b8151612a0a61298b82613ab4565b91508181835260208401935060208101905083856020840282011115612a2f57600080fd5b60005b838110156129e15781612a458882612b33565b8452506020928301929190910190600101612a32565b600082601f830112612a6c57600080fd5b8151612a7a61298b82613ab4565b81815260209384019390925082018360005b838110156129e15781518601612aa28882612beb565b8452506020928301929190910190600101612a8c565b600082601f830112612ac957600080fd5b8151612ad761298b82613ab4565b91508181835260208401935060208101905083856020840282011115612afc57600080fd5b60005b838110156129e15781612b128882612b33565b8452506020928301929190910190600101612aff565b80516111cf81613bc2565b80516111cf81613bcb565b80356111cf81613bd4565b60008083601f840112612b5b57600080fd5b5081356001600160401b03811115612b7257600080fd5b602083019150836001820283011115612b8a57600080fd5b9250929050565b600082601f830112612ba257600080fd5b8151612bb061298b82613ad4565b91508082526020830160208301858383011115612bcc57600080fd5b612bd7838284613b64565b50505092915050565b80516111cf81613bdd565b600060a08284031215612bfd57600080fd5b612c0760a0613a8e565b90506000612c158484612b33565b8252506020612c2684848301612b33565b6020830152506040612c3a84828501612b33565b6040830152506060612c4e84828501612b33565b60608301525060808201516001600160401b03811115612c6d57600080fd5b612c7984828501612b91565b60808301525092915050565b600060808284031215612c9757600080fd5b612ca16080613a8e565b82519091506001600160401b03811115612cba57600080fd5b612cc68482850161296c565b82525060208201516001600160401b03811115612ce257600080fd5b612cee84828501612ab8565b60208301525060408201516001600160401b03811115612d0d57600080fd5b612d1984828501612b91565b6040830152506060612d2d84828501612b28565b60608301525092915050565b600060208284031215612d4b57600080fd5b6000612d578484612961565b949350505050565b60008060008060008060c08789031215612d7857600080fd5b6000612d848989612961565b9650506020612d9589828a01612b33565b9550506040612da689828a01612b33565b94505060608701516001600160401b03811115612dc257600080fd5b612dce89828a0161296c565b93505060808701516001600160401b03811115612dea57600080fd5b612df689828a01612ab8565b92505060a08701516001600160401b03811115612e1257600080fd5b612e1e89828a01612c85565b9150509295509295509295565b60008060408385031215612e3e57600080fd5b6000612e4a8585612961565b9250506020612e5b85828601612b33565b9150509250929050565b60008060008060608587031215612e7b57600080fd5b6000612e878787612956565b9450506020612e9887828801612b3e565b93505060408501356001600160401b03811115612eb457600080fd5b612ec087828801612b49565b95989497509550505050565b600080600080600060608688031215612ee457600080fd5b6000612ef08888612956565b95505060208601356001600160401b03811115612f0c57600080fd5b612f1888828901612b49565b945094505060408601356001600160401b03811115612f3657600080fd5b612f4288828901612b49565b92509250509295509295909350565b600060208284031215612f6357600080fd5b81516001600160401b03811115612f7957600080fd5b612d57848285016129eb565b600060208284031215612f9757600080fd5b6000612d578484612b28565b600080600080600060a08688031215612fbb57600080fd5b6000612fc78888612b33565b9550506020612fd888828901612b33565b94505060408601516001600160401b03811115612ff457600080fd5b6130008882890161296c565b93505060608601516001600160401b0381111561301c57600080fd5b61302888828901612ab8565b92505060808601516001600160401b0381111561304457600080fd5b61305088828901612c85565b9150509295509295909350565b600080600080600060a0868803121561307557600080fd5b60006130818888612be0565b95505060208601516001600160401b0381111561309d57600080fd5b6130a988828901612a5b565b94505060408601516001600160401b038111156130c557600080fd5b6130d18882890161296c565b93505060608601516001600160401b038111156130ed57600080fd5b6130f9888289016129eb565b92505060808601516001600160401b0381111561311557600080fd5b6130508882890161296c565b60006020828403121561313357600080fd5b6000612d578484612b33565b600061314b838361316b565b505060200190565b600061314b8383613382565b60006127fe838361372c565b61317481613b0e565b82525050565b600061318582613b01565b61318f8185613b05565b935061319a83613afb565b8060005b838110156131c85781516131b2888261313f565b97506131bd83613afb565b92505060010161319e565b509495945050505050565b60006131de82613b01565b6131e88185613b05565b93506131f383613afb565b8060005b838110156131c857815161320b888261313f565b975061321683613afb565b9250506001016131f7565b600061322c82613b01565b6132368185613b05565b935061324183613afb565b8060005b838110156131c85781516132598882613153565b975061326483613afb565b925050600101613245565b600061327a82613b01565b6132848185613b05565b93508360208202850161329685613afb565b8060005b858110156132d057848403895281516132b3858261315f565b94506132be83613afb565b60209a909a019992505060010161329a565b5091979650505050505050565b60006132e882613b01565b6132f28185613b05565b93506132fd83613afb565b8060005b838110156131c85781516133158882613153565b975061332083613afb565b925050600101613301565b600061333682613b01565b6133408185613b05565b935061334b83613afb565b8060005b838110156131c85781516133638882613153565b975061336e83613afb565b92505060010161334f565b61317481613b19565b61317481613b1e565b61317481613b21565b600061339f82613b01565b6133a98185613b05565b93506133b9818560208601613b64565b6133c281613b90565b9093019392505050565b60006133d782613b01565b6133e18185611402565b93506133f1818560208601613b64565b9290920192915050565b61317481613b4e565b61317481613b59565b600061341a602b83613b05565b7f5f5f62616c616e63657252656465656d3a20556e65787065637465642061737381526a195d081c9958d95a5d995960aa1b602082015260400192915050565b6000613467602783613b05565b7f5f5f7061727365417373657473466f7254616b654f726465723a20425054206d8152660d2e6dac2e8c6d60cb1b602082015260400192915050565b60006134b0602583613b05565b7f5f5f76616c6964617465427074466f725374616b696e67546f6b656e3a20496e8152641d985b1a5960da1b602082015260400192915050565b60006134f7602683613b05565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f8152651c8818d85b1b60d21b602082015260400192915050565b600061353f603283613b05565b7f4f6e6c792074686520496e746567726174696f6e4d616e616765722063616e2081527131b0b636103a3434b990333ab731ba34b7b760711b602082015260400192915050565b6000613593602083613b05565b7f74616b654f726465723a206c6566746f76657220696e7465726d656469617279815260200192915050565b60006135cc602583613b05565b7f5f5f76616c69646174654e6f496e7465726e616c42616c616e6365733a20496e8152641d985b1a5960da1b602082015260400192915050565b6000613613601d83613b05565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000815260200192915050565b600061364c602a83613b05565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000613698603683613b05565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b60006136f0602783613b05565b7f7061727365417373657473466f72416374696f6e3a205f73656c6563746f72208152661a5b9d985b1a5960ca1b602082015260400192915050565b805160009060a08401906137408582613382565b5060208301516137536020860182613382565b5060408301516137666040860182613382565b5060608301516137796060860182613382565b50608083015184820360808601526137918282613394565b95945050505050565b805160808301906137ab848261316b565b5060208201516137be6020850182613379565b5060408201516137d1604085018261316b565b506060820151610f5e6060850182613379565b80516080808452600091908401906137fc828261317a565b9150506020830151848203602086015261381682826132dd565b915050604083015184820360408601526138308282613394565b91505060608301516138456060860182613379565b509392505050565b60006127fe82846133cc565b602081016111cf828461316b565b60408101613875828561316b565b6127fe602083018461316b565b60408101613890828561316b565b6127fe6020830184613382565b608081016138ab8287613382565b6138b8602083018661316b565b6138c5604083018561316b565b81810360608301526138d781846137e4565b9695505050505050565b602081016111cf828461338b565b60a081016138fd82886133fb565b818103602083015261390f81876131d3565b90508181036040830152613923818661332b565b9050818103606083015261393781856131d3565b905081810360808301526128bb818461332b565b610120810161395a8289613404565b818103602083015261396c818861326f565b9050818103604083015261398081876131d3565b905061398f606083018661379a565b81810360e08301526139a18185613221565b90506128bb610100830184613382565b602080825281016127fe8184613394565b602080825281016111cf8161340d565b602080825281016111cf8161345a565b602080825281016111cf816134a3565b602080825281016111cf816134ea565b602080825281016111cf81613532565b602080825281016111cf81613586565b602080825281016111cf816135bf565b602080825281016111cf81613606565b602080825281016111cf8161363f565b602080825281016111cf8161368b565b602080825281016111cf816136e3565b602081016111cf8284613382565b604081016138758285613382565b6040518181016001600160401b0381118282101715613aac57600080fd5b604052919050565b60006001600160401b03821115613aca57600080fd5b5060209081020190565b60006001600160401b03821115613aea57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b60006111cf82613b42565b151590565b90565b6001600160e01b03191690565b8061140281613b9a565b8061140281613ba4565b6001600160a01b031690565b60006111cf82613b2e565b60006111cf82613b38565b60005b83811015613b7f578181015183820152602001613b67565b83811115610f5e5750506000910152565b601f01601f191690565b60038110611df757fe5b60028110611df757fe5b613bb781613b0e565b8114611df757600080fd5b613bb781613b19565b613bb781613b1e565b613bb781613b21565b60028110611df757600080fdfea2646970667358221220daf676ef7163f005c63110a9edbf95d041ce974af0889be98645ce6f00b9326264736f6c634300060c003300000000000000000000000092fcde09790671cf085864182b9670c77da0884b000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000009a71012b13ca4d3d0cdc72a177df3ef03b0e76a3
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101375760003560e01c80638334eb99116100b8578063c32990a21161007c578063c32990a214610226578063c54efee51461022e578063e7c4569014610252578063f003eb851461025a578063f7d882b514610262578063fa7dd04d1461026a57610137565b80638334eb99146101dd578063863e5ad0146101f0578063b23228cf146101f8578063b9dfbacc14610200578063c29fa9dd1461021357610137565b806329fa046e116100ff57806329fa046e14610192578063332d709f146101a55780633ffc1591146101ba57806340da225d146101c257806368e30677146101ca57610137565b806303e38a2b1461013c578063080456c114610151578063099f75151461016f578063131461c014610182578063257cb1a31461018a575b600080fd5b61014f61014a366004612ecc565b61027d565b005b610159610718565b60405161016691906138e1565b60405180910390f35b61014f61017d366004612ecc565b61073c565b6101596107fc565b610159610820565b61014f6101a0366004612ecc565b610844565b6101ad610941565b6040516101669190613859565b610159610965565b610159610989565b61014f6101d8366004612ecc565b6109ad565b61014f6101eb366004612ecc565b610a50565b610159610bb6565b610159610bda565b61014f61020e366004612ecc565b610bfe565b61014f610221366004612ecc565b610c95565b610159610d51565b61024161023c366004612e65565b610d75565b6040516101669594939291906138ef565b6101ad610df3565b6101ad610e17565b610159610e3b565b61014f610278366004612ecc565b610e5f565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b16146102ce5760405162461bcd60e51b81526004016102c590613a02565b60405180910390fd5b600060608060608061031589898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ef892505050565b945094509450945094506000808451905060005b8181101561045057600085828151811061033f57fe5b602002602001015113156103f557600085828151811061035b57fe5b6020026020010151905060006001600160a01b031685838151811061037c57fe5b60200260200101516001600160a01b0316146103b1576103b130308785815181106103a357fe5b602002602001015184610f26565b6103ef8783815181106103c057fe5b60200260200101517f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c883610f64565b50610448565b600085828151811061040357fe5b602002602001015112801561043e575060006001600160a01b031684828151811061042a57fe5b60200260200101516001600160a01b031614155b1561044857600192505b600101610329565b50606061046d3084610462578e610464565b305b8a8a8a8a611020565b905060005b8281101561070857600086828151811061048857fe5b602002602001015113156105b85760006001600160a01b03168582815181106104ad57fe5b60200260200101516001600160a01b0316141580156104d7575060018960018111156104d557fe5b145b156105955760008782815181106104ea57fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161051d9190613859565b60206040518083038186803b15801561053557600080fd5b505afa158015610549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056d9190613121565b90508015610593576105938f87848151811061058557fe5b602002602001015183611108565b505b6105b28e8883815181106105a557fe5b6020026020010151611134565b50610700565b60008682815181106105c657fe5b602002602001015112156106cd5760006001600160a01b03168582815181106105eb57fe5b60200260200101516001600160a01b0316146106b2576106ad8e86838151811061061157fe5b602002602001015189848151811061062557fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016106589190613859565b60206040518083038186803b15801561067057600080fd5b505afa158015610684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a89190613121565b611108565b6106c8565b83156106c8576105b28e8883815181106105a557fe5b610700565b8181815181106106d957fe5b60200260200101516000146107005760405162461bcd60e51b81526004016102c590613a12565b600101610472565b5050505050505050505050505050565b7f8334eb99be0145865eba9889fca2ee920288090caefff4cc776038e20ad9259a81565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b16146107845760405162461bcd60e51b81526004016102c590613a02565b6000606080610791612905565b6107d088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b9450945094505093506107e689858585856111f7565b6107f08984611269565b50505050505050505050565b7f29fa046e79524c3c5ac4c01df692c35e217802b2b13b21121b76cf0ef02b138c81565b7f099f75155f0e997bf83a7993a71d5e7e7540bd386fe1e84643a09ce6b412521981565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b161461088c5760405162461bcd60e51b81526004016102c590613a02565b60008060608061089a612905565b6108d989898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b95509550955050945094506108f130858585856111f7565b61092a8a866108ff876113fc565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016106589190613859565b6109348a84611269565b5050505050505050505050565b7f0000000000000000000000009a71012b13ca4d3d0cdc72a177df3ef03b0e76a390565b7ffa7dd04da627f433da73c4355ead9c75682a67a8fc84d3f6170ef0922f402d2481565b7fb9dfbaccbe5cd2a84fdcf1d15f23ef25d23086f5afbaa99516065ed4a5bbc7a381565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b16146109f55760405162461bcd60e51b81526004016102c590613a02565b600080610a3786868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b91509150610a4787888484610f26565b50505050505050565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b1614610a985760405162461bcd60e51b81526004016102c590613a02565b60008060006060610aa7612905565b610ae689898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b9550509450945094509450610afd8a308786610f26565b610b0a8a85858585611427565b6000610b15856113fc565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b459190613859565b60206040518083038186803b158015610b5d57600080fd5b505afa158015610b71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b959190613121565b90508015610ba857610ba88c8883611108565b505050505050505050505050565b7f03e38a2bd7063d45c897edeafc330e71657502dd86434d3c37a489caf116af6981565b7f68e30677f607df46e87da13e15b637784cfa62374b653f35ab43d10361a2f83081565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b1614610c465760405162461bcd60e51b81526004016102c590613a02565b610c8e85610c8986868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506116c792505050565b6116dd565b5050505050565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b1614610cdd5760405162461bcd60e51b81526004016102c590613a02565b6000806060610cea612905565b610d2988888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b945050935093509350610d3f8985858585611427565b6107f089610d4c866113fc565b611134565b7f0e7f692dad5b88fdee426250d6eae91207e56a2e8112b7364579bed1790e5bf481565b600060608080806001600160e01b0319881663099f751560e01b1415610dae57610d9f87876116eb565b94509450945094509450610de8565b6001600160e01b0319881663c29fa9dd60e01b1415610dd157610d9f87876117f8565b610ddd898989896118d5565b945094509450945094505b945094509450945094565b7f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b90565b7f000000000000000000000000000000000000000000000000000000000000000090565b7fc29fa9dde84204c2908778afd0613d802d31cf046179b88f6d2b4a4e507ea2d581565b336001600160a01b037f00000000000000000000000092fcde09790671cf085864182b9670c77da0884b1614610ea75760405162461bcd60e51b81526004016102c590613a02565b600080610ee986868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b91509150610a47878383611108565b600060608060608085806020019051810190610f14919061305d565b939a9299509097509550909350915050565b610f3082826119c4565b6001600160a01b0383163014610f5e57610f5e8382610f4e85611a26565b6001600160a01b03169190611a99565b50505050565b604051636eb1769f60e11b81526000906001600160a01b0385169063dd62ed3e90610f959030908790600401613867565b60206040518083038186803b158015610fad57600080fd5b505afa158015610fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe59190613121565b905081811015610f5e57801561100a5761100a6001600160a01b038516846000611aef565b610f5e6001600160a01b03851684600019611aef565b606061102a61292f565b50604080516080810182526001600160a01b03808a168252600060208301819052898216838501526060830152915163945bcec960e01b815290917f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8169063945bcec9906110a69089908990899087908a90429060040161394b565b600060405180830381600087803b1580156110c057600080fd5b505af11580156110d4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110fc9190810190612f51565b98975050505050505050565b61111b8261111584611a26565b83611bb2565b61112f6001600160a01b0383168483611a99565b505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190611163903090600401613859565b60206040518083038186803b15801561117b57600080fd5b505afa15801561118f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b39190613121565b905080156111cf576111cf6001600160a01b0383168483611a99565b92915050565b6000806060806111e3612905565b85806020019051810190610f149190612fa3565b60005b835181101561125c5761125484828151811061121257fe5b60200260200101517f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c885848151811061124757fe5b6020026020010151610f64565b6001016111fa565b50610c8e84308784611c19565b606081516001600160401b038111801561128257600080fd5b506040519080825280602002602001820160405280156112ac578160200160208202803683370190505b50905060005b82518110156113bd5760008382815181106112c957fe5b60200260200101519050806001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112ff9190613859565b60206040518083038186803b15801561131757600080fd5b505afa15801561132b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134f9190613121565b83838151811061135b57fe5b602002602001018181525050600083838151811061137557fe5b602002602001015111156113b4576113b48584848151811061139357fe5b6020026020010151836001600160a01b0316611a999092919063ffffffff16565b506001016112b2565b5092915050565b60008060006060806113d4612905565b868060200190518101906113e89190612d5f565b949c939b5091995097509550909350915050565b606081901c5b919050565b6000808280602001905181019061141e9190612e2b565b91509150915091565b61145a611433856113fc565b7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c885610f64565b815181515103606081156115a0578251516001600160401b038111801561148057600080fd5b506040519080825280602002602001820160405280156114aa578160200160208202803683370190505b5090508160005b811561159d576114e1856000015182815181106114ca57fe5b602002602001015187611c9990919063ffffffff16565b6115955784518051829081106114f357fe5b60200260200101516001600160a01b03166370a082318a6040518263ffffffff1660e01b81526004016115269190613859565b60206040518083038186803b15801561153e57600080fd5b505afa158015611552573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115769190613121565b83828151811061158257fe5b6020908102919091010152600019909101905b6001016114b1565b50505b6115ac86308986611cef565b8115610a475760005b82156116bd576115e5846000015182815181106115ce57fe5b602002602001015186611c9990919063ffffffff16565b6116b5578181815181106115f557fe5b60200260200101518460000151828151811061160d57fe5b60200260200101516001600160a01b03166370a082318a6040518263ffffffff1660e01b81526004016116409190613859565b60206040518083038186803b15801561165857600080fd5b505afa15801561166c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116909190613121565b146116ad5760405162461bcd60e51b81526004016102c5906139c2565b600019909201915b6001016115b5565b5050505050505050565b6000818060200190518101906111cf9190612d39565b6116e78183611d41565b5050565b6040805160018082528183019092526000916060918291829182916020808301908036833750506040805160018082528183019092529294509050602080830190803683370190505090506000611740612905565b61177f89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b8760008151811061178c57fe5b60209081029190910101939093526060830151919950975091935091506117b290611dd9565b6117bb826113fc565b846000815181106117c857fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506002965050509295509295909350565b604080516001808252818301909252600091606091829182918291602080830190803683375050604080516001808252818301909252929650905060208083019080368337019050509250600061184d612905565b61188c89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111d592505050565b8960008151811061189957fe5b60209081029190910101939093526060830151919750955091935091506118bf90611dd9565b6118c8826113fc565b866000815181106117c857fe5b600060608080806001600160e01b03198816632e77eeb360e21b14156118fd57610d9f611dfa565b6001600160e01b031988166314fd023760e11b141561192057610d9f8787611e5a565b6001600160e01b03198816638334eb9960e01b141561194357610d9f8787611f6d565b6001600160e01b031988166303e38a2b60e01b141561196657610d9f878761204f565b6001600160e01b0319881663fa7dd04d60e01b141561198957610d9f878761241d565b6001600160e01b031988166368e3067760e01b14156119ac57610d9f8787612594565b60405162461bcd60e51b81526004016102c590613a62565b604051632e1a7d4d60e01b81526001600160a01b03831690632e1a7d4d906119f0908490600401613a72565b600060405180830381600087803b158015611a0a57600080fd5b505af1158015611a1e573d6000803e3d6000fd5b505050505050565b6000816001600160a01b03166382c630666040518163ffffffff1660e01b815260040160206040518083038186803b158015611a6157600080fd5b505afa158015611a75573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111cf9190612d39565b61112f8363a9059cbb60e01b8484604051602401611ab8929190613882565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526126c1565b801580611b775750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b259030908690600401613867565b60206040518083038186803b158015611b3d57600080fd5b505afa158015611b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b759190613121565b155b611b935760405162461bcd60e51b81526004016102c590613a52565b61112f8363095ea7b360e01b8484604051602401611ab8929190613882565b611bbd828483610f64565b604051636e553f6560e01b81526001600160a01b03841690636e553f6590611beb9084903090600401613a80565b600060405180830381600087803b158015611c0557600080fd5b505af1158015610a47573d6000803e3d6000fd5b60405163172b958560e31b81526001600160a01b037f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8169063b95cac2890611c6b90879087908790879060040161389d565b600060405180830381600087803b158015611c8557600080fd5b505af11580156116bd573d6000803e3d6000fd5b6000805b8351811015611ce557838181518110611cb257fe5b60200260200101516001600160a01b0316836001600160a01b03161415611cdd5760019150506111cf565b600101611c9d565b5060009392505050565b604051638bdb391360e01b81526001600160a01b037f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c81690638bdb391390611c6b90879087908790879060040161389d565b611d49612750565b15611dcf576040516327f18ae360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906327f18ae390611d9c9085908590600401613867565b600060405180830381600087803b158015611db657600080fd5b505af1158015611dca573d6000803e3d6000fd5b505050505b6116e7828261277f565b8015611df75760405162461bcd60e51b81526004016102c590613a22565b50565b600060608080808480604051908082528060200260200182016040528015611e2c578160200160208202803683370190505b5060408051600080825260208201818152828401918252606083019093529399929850965094509092509050565b604080516001808252818301909252600091606091829182918291602080830190803683375050604080516001808252818301909252929450905060208083019080368337019050509050600080611eb0612905565b611eef8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b89600081518110611efc57fe5b6020908102919091010193909352909a5098509094509092509050611f2182846127ab565b611f2e8160600151611dd9565b8185600081518110611f3c57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600297505050509295509295909350565b604080516001808252818301909252600091606091829182918291602080830190803683375050604080516001808252818301909252929650905060208083019080368337019050509250600080611fc3612905565b6120028a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113c492505050565b8b60008151811061200f57fe5b60209081029190910101939093529098509650909450909250905061203482846127ab565b6120418160600151611dd9565b8187600081518110611f3c57fe5b6000606080606080606080606061209b8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ef892505050565b945094509450505060008060005b85518110156121045760008582815181106120c057fe5b602002602001015113156120d9576001909201916120fc565b60008582815181106120e757fe5b602002602001015112156120fc576001909101905b6001016120a9565b50816001600160401b038111801561211b57600080fd5b50604051908082528060200260200182016040528015612145578160200160208202803683370190505b509850816001600160401b038111801561215e57600080fd5b50604051908082528060200260200182016040528015612188578160200160208202803683370190505b509750806001600160401b03811180156121a157600080fd5b506040519080825280602002602001820160405280156121cb578160200160208202803683370190505b509650806001600160401b03811180156121e457600080fd5b5060405190808252806020026020018201604052801561220e578160200160208202803683370190505b50955060005b855181101561240957600085828151811061222b57fe5b60200260200101519050600081131561231b57600087838151811061224c57fe5b60200260200101519050600086848151811061226457fe5b6020026020010151905060006001600160a01b0316816001600160a01b0316146122c55761229181611a26565b6001600160a01b0316826001600160a01b0316146122c15760405162461bcd60e51b81526004016102c5906139d2565b8091505b858060019003965050818d87815181106122db57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050828c878151811061230857fe5b6020026020010181815250505050612400565b600081121561240057600087838151811061233257fe5b60200260200101519050600086848151811061234a57fe5b6020026020010151905060006001600160a01b0316816001600160a01b0316146123ab5761237781611a26565b6001600160a01b0316826001600160a01b0316146123a75760405162461bcd60e51b81526004016102c5906139d2565b8091505b848060019003955050818b86815181106123c157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050826000038a86815181106123f157fe5b60200260200101818152505050505b50600101612214565b506002995050505050509295509295909350565b600060608060608060008061246789898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b604080516001808252818301909252929450909250602080830190803683375050604080516001808252818301909252929850905060208083019080368337505060408051600180825281830190925292975090506020808301908036833750506040805160018082528183019092529296509050602080830190803683370190505092506124f582611a26565b8660008151811061250257fe5b60200260200101906001600160a01b031690816001600160a01b031681525050808560008151811061253057fe5b602002602001018181525050818460008151811061254a57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050808360008151811061257857fe5b6020026020010181815250506002965050509295509295909350565b60006060806060806000806125de89898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140792505050565b60408051600180825281830190925292945090925060208083019080368337505060408051600180825281830190925292985090506020808301908036833750506040805160018082528183019092529297509050602080830190803683375050604080516001808252818301909252929650905060208083019080368337019050509250818660008151811061267157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050808560008151811061269f57fe5b6020026020010181815250506126b482611a26565b8460008151811061254a57fe5b6060612716826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166127ec9092919063ffffffff16565b80519091501561112f57808060200190518101906127349190612f85565b61112f5760405162461bcd60e51b81526004016102c590613a42565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316151590565b604051634274debf60e11b81526001600160a01b038316906384e9bd7e906119f0908490600401613859565b6127b4816113fc565b6001600160a01b03166127c683611a26565b6001600160a01b0316146116e75760405162461bcd60e51b81526004016102c5906139e2565b60606127fb8484600085612805565b90505b9392505050565b6060824710156128275760405162461bcd60e51b81526004016102c5906139f2565b612830856128c6565b61284c5760405162461bcd60e51b81526004016102c590613a32565b60006060866001600160a01b03168587604051612869919061384d565b60006040518083038185875af1925050503d80600081146128a6576040519150601f19603f3d011682016040523d82523d6000602084013e6128ab565b606091505b50915091506128bb8282866128cc565b979650505050505050565b3b151590565b606083156128db5750816127fe565b8251156128eb5782518084602001fd5b8160405162461bcd60e51b81526004016102c591906139b1565b60405180608001604052806060815260200160608152602001606081526020016000151581525090565b60408051608081018252600080825260208201819052918101829052606081019190915290565b80356111cf81613bae565b80516111cf81613bae565b600082601f83011261297d57600080fd5b815161299061298b82613ab4565b613a8e565b915081818352602084019350602081019050838560208402820111156129b557600080fd5b60005b838110156129e157816129cb8882612961565b84525060209283019291909101906001016129b8565b5050505092915050565b600082601f8301126129fc57600080fd5b8151612a0a61298b82613ab4565b91508181835260208401935060208101905083856020840282011115612a2f57600080fd5b60005b838110156129e15781612a458882612b33565b8452506020928301929190910190600101612a32565b600082601f830112612a6c57600080fd5b8151612a7a61298b82613ab4565b81815260209384019390925082018360005b838110156129e15781518601612aa28882612beb565b8452506020928301929190910190600101612a8c565b600082601f830112612ac957600080fd5b8151612ad761298b82613ab4565b91508181835260208401935060208101905083856020840282011115612afc57600080fd5b60005b838110156129e15781612b128882612b33565b8452506020928301929190910190600101612aff565b80516111cf81613bc2565b80516111cf81613bcb565b80356111cf81613bd4565b60008083601f840112612b5b57600080fd5b5081356001600160401b03811115612b7257600080fd5b602083019150836001820283011115612b8a57600080fd5b9250929050565b600082601f830112612ba257600080fd5b8151612bb061298b82613ad4565b91508082526020830160208301858383011115612bcc57600080fd5b612bd7838284613b64565b50505092915050565b80516111cf81613bdd565b600060a08284031215612bfd57600080fd5b612c0760a0613a8e565b90506000612c158484612b33565b8252506020612c2684848301612b33565b6020830152506040612c3a84828501612b33565b6040830152506060612c4e84828501612b33565b60608301525060808201516001600160401b03811115612c6d57600080fd5b612c7984828501612b91565b60808301525092915050565b600060808284031215612c9757600080fd5b612ca16080613a8e565b82519091506001600160401b03811115612cba57600080fd5b612cc68482850161296c565b82525060208201516001600160401b03811115612ce257600080fd5b612cee84828501612ab8565b60208301525060408201516001600160401b03811115612d0d57600080fd5b612d1984828501612b91565b6040830152506060612d2d84828501612b28565b60608301525092915050565b600060208284031215612d4b57600080fd5b6000612d578484612961565b949350505050565b60008060008060008060c08789031215612d7857600080fd5b6000612d848989612961565b9650506020612d9589828a01612b33565b9550506040612da689828a01612b33565b94505060608701516001600160401b03811115612dc257600080fd5b612dce89828a0161296c565b93505060808701516001600160401b03811115612dea57600080fd5b612df689828a01612ab8565b92505060a08701516001600160401b03811115612e1257600080fd5b612e1e89828a01612c85565b9150509295509295509295565b60008060408385031215612e3e57600080fd5b6000612e4a8585612961565b9250506020612e5b85828601612b33565b9150509250929050565b60008060008060608587031215612e7b57600080fd5b6000612e878787612956565b9450506020612e9887828801612b3e565b93505060408501356001600160401b03811115612eb457600080fd5b612ec087828801612b49565b95989497509550505050565b600080600080600060608688031215612ee457600080fd5b6000612ef08888612956565b95505060208601356001600160401b03811115612f0c57600080fd5b612f1888828901612b49565b945094505060408601356001600160401b03811115612f3657600080fd5b612f4288828901612b49565b92509250509295509295909350565b600060208284031215612f6357600080fd5b81516001600160401b03811115612f7957600080fd5b612d57848285016129eb565b600060208284031215612f9757600080fd5b6000612d578484612b28565b600080600080600060a08688031215612fbb57600080fd5b6000612fc78888612b33565b9550506020612fd888828901612b33565b94505060408601516001600160401b03811115612ff457600080fd5b6130008882890161296c565b93505060608601516001600160401b0381111561301c57600080fd5b61302888828901612ab8565b92505060808601516001600160401b0381111561304457600080fd5b61305088828901612c85565b9150509295509295909350565b600080600080600060a0868803121561307557600080fd5b60006130818888612be0565b95505060208601516001600160401b0381111561309d57600080fd5b6130a988828901612a5b565b94505060408601516001600160401b038111156130c557600080fd5b6130d18882890161296c565b93505060608601516001600160401b038111156130ed57600080fd5b6130f9888289016129eb565b92505060808601516001600160401b0381111561311557600080fd5b6130508882890161296c565b60006020828403121561313357600080fd5b6000612d578484612b33565b600061314b838361316b565b505060200190565b600061314b8383613382565b60006127fe838361372c565b61317481613b0e565b82525050565b600061318582613b01565b61318f8185613b05565b935061319a83613afb565b8060005b838110156131c85781516131b2888261313f565b97506131bd83613afb565b92505060010161319e565b509495945050505050565b60006131de82613b01565b6131e88185613b05565b93506131f383613afb565b8060005b838110156131c857815161320b888261313f565b975061321683613afb565b9250506001016131f7565b600061322c82613b01565b6132368185613b05565b935061324183613afb565b8060005b838110156131c85781516132598882613153565b975061326483613afb565b925050600101613245565b600061327a82613b01565b6132848185613b05565b93508360208202850161329685613afb565b8060005b858110156132d057848403895281516132b3858261315f565b94506132be83613afb565b60209a909a019992505060010161329a565b5091979650505050505050565b60006132e882613b01565b6132f28185613b05565b93506132fd83613afb565b8060005b838110156131c85781516133158882613153565b975061332083613afb565b925050600101613301565b600061333682613b01565b6133408185613b05565b935061334b83613afb565b8060005b838110156131c85781516133638882613153565b975061336e83613afb565b92505060010161334f565b61317481613b19565b61317481613b1e565b61317481613b21565b600061339f82613b01565b6133a98185613b05565b93506133b9818560208601613b64565b6133c281613b90565b9093019392505050565b60006133d782613b01565b6133e18185611402565b93506133f1818560208601613b64565b9290920192915050565b61317481613b4e565b61317481613b59565b600061341a602b83613b05565b7f5f5f62616c616e63657252656465656d3a20556e65787065637465642061737381526a195d081c9958d95a5d995960aa1b602082015260400192915050565b6000613467602783613b05565b7f5f5f7061727365417373657473466f7254616b654f726465723a20425054206d8152660d2e6dac2e8c6d60cb1b602082015260400192915050565b60006134b0602583613b05565b7f5f5f76616c6964617465427074466f725374616b696e67546f6b656e3a20496e8152641d985b1a5960da1b602082015260400192915050565b60006134f7602683613b05565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f8152651c8818d85b1b60d21b602082015260400192915050565b600061353f603283613b05565b7f4f6e6c792074686520496e746567726174696f6e4d616e616765722063616e2081527131b0b636103a3434b990333ab731ba34b7b760711b602082015260400192915050565b6000613593602083613b05565b7f74616b654f726465723a206c6566746f76657220696e7465726d656469617279815260200192915050565b60006135cc602583613b05565b7f5f5f76616c69646174654e6f496e7465726e616c42616c616e6365733a20496e8152641d985b1a5960da1b602082015260400192915050565b6000613613601d83613b05565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000815260200192915050565b600061364c602a83613b05565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000613698603683613b05565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b60006136f0602783613b05565b7f7061727365417373657473466f72416374696f6e3a205f73656c6563746f72208152661a5b9d985b1a5960ca1b602082015260400192915050565b805160009060a08401906137408582613382565b5060208301516137536020860182613382565b5060408301516137666040860182613382565b5060608301516137796060860182613382565b50608083015184820360808601526137918282613394565b95945050505050565b805160808301906137ab848261316b565b5060208201516137be6020850182613379565b5060408201516137d1604085018261316b565b506060820151610f5e6060850182613379565b80516080808452600091908401906137fc828261317a565b9150506020830151848203602086015261381682826132dd565b915050604083015184820360408601526138308282613394565b91505060608301516138456060860182613379565b509392505050565b60006127fe82846133cc565b602081016111cf828461316b565b60408101613875828561316b565b6127fe602083018461316b565b60408101613890828561316b565b6127fe6020830184613382565b608081016138ab8287613382565b6138b8602083018661316b565b6138c5604083018561316b565b81810360608301526138d781846137e4565b9695505050505050565b602081016111cf828461338b565b60a081016138fd82886133fb565b818103602083015261390f81876131d3565b90508181036040830152613923818661332b565b9050818103606083015261393781856131d3565b905081810360808301526128bb818461332b565b610120810161395a8289613404565b818103602083015261396c818861326f565b9050818103604083015261398081876131d3565b905061398f606083018661379a565b81810360e08301526139a18185613221565b90506128bb610100830184613382565b602080825281016127fe8184613394565b602080825281016111cf8161340d565b602080825281016111cf8161345a565b602080825281016111cf816134a3565b602080825281016111cf816134ea565b602080825281016111cf81613532565b602080825281016111cf81613586565b602080825281016111cf816135bf565b602080825281016111cf81613606565b602080825281016111cf8161363f565b602080825281016111cf8161368b565b602080825281016111cf816136e3565b602081016111cf8284613382565b604081016138758285613382565b6040518181016001600160401b0381118282101715613aac57600080fd5b604052919050565b60006001600160401b03821115613aca57600080fd5b5060209081020190565b60006001600160401b03821115613aea57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b60006111cf82613b42565b151590565b90565b6001600160e01b03191690565b8061140281613b9a565b8061140281613ba4565b6001600160a01b031690565b60006111cf82613b2e565b60006111cf82613b38565b60005b83811015613b7f578181015183820152602001613b67565b83811115610f5e5750506000910152565b601f01601f191690565b60038110611df757fe5b60028110611df757fe5b613bb781613b0e565b8114611df757600080fd5b613bb781613b19565b613bb781613b1e565b613bb781613b21565b60028110611df757600080fdfea2646970667358221220daf676ef7163f005c63110a9edbf95d041ce974af0889be98645ce6f00b9326264736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000092fcde09790671cf085864182b9670c77da0884b000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000009a71012b13ca4d3d0cdc72a177df3ef03b0e76a3
-----Decoded View---------------
Arg [0] : _integrationManager (address): 0x92fCdE09790671cf085864182B9670c77da0884B
Arg [1] : _balancerVault (address): 0xBA12222222228d8Ba445958a75a0704d566BF2C8
Arg [2] : _balancerMinter (address): 0x0000000000000000000000000000000000000000
Arg [3] : _balToken (address): 0x9a71012B13CA4d3D0Cdc72A177DF3ef03b0E76A3
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000092fcde09790671cf085864182b9670c77da0884b
Arg [1] : 000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 0000000000000000000000009a71012b13ca4d3d0cdc72a177df3ef03b0e76a3
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.