More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 15 from a total of 15 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Approve | 18343584 | 440 days ago | IN | 0 ETH | 0.00021229 | ||||
Approve | 17559597 | 550 days ago | IN | 0 ETH | 0.0005917 | ||||
Approve | 17320417 | 584 days ago | IN | 0 ETH | 0.00235126 | ||||
Approve | 17307056 | 586 days ago | IN | 0 ETH | 0.00130178 | ||||
Approve | 17236033 | 596 days ago | IN | 0 ETH | 0.00414218 | ||||
Approve | 17230167 | 596 days ago | IN | 0 ETH | 0.00493262 | ||||
Approve | 17102822 | 614 days ago | IN | 0 ETH | 0.00086956 | ||||
Approve | 17102821 | 614 days ago | IN | 0 ETH | 0.00155064 | ||||
Approve | 17097222 | 615 days ago | IN | 0 ETH | 0.00208997 | ||||
Transfer | 17092257 | 616 days ago | IN | 0 ETH | 0.00236254 | ||||
Approve | 17092214 | 616 days ago | IN | 0 ETH | 0.00169584 | ||||
Approve | 17092212 | 616 days ago | IN | 0 ETH | 0.0009031 | ||||
Approve | 17092203 | 616 days ago | IN | 0 ETH | 0.00198801 | ||||
Approve | 17089561 | 616 days ago | IN | 0 ETH | 0.00326481 | ||||
Approve | 17089308 | 616 days ago | IN | 0 ETH | 0.00303793 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
16240856 | 735 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
StakeableEulerERC4626
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.13; import {ERC20} from "solmate/tokens/ERC20.sol"; import {Owned} from "solmate/auth/Owned.sol"; import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol"; import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; import {IEulerEToken} from "../external/IEulerEToken.sol"; import {IRewardsDistribution} from "../external/IRewardsDistribution.sol"; import {IStakingRewards} from "../external/IStakingRewards.sol"; import {EulerERC4626} from "../EulerERC4626.sol"; /// @title StakeableEulerERC4626 /// @author Sam Bugs /// @notice A ERC4626 wrapper for Euler Finance, that can handle staking contract StakeableEulerERC4626 is EulerERC4626, Owned { /// ----------------------------------------------------------------------- /// Errors /// ----------------------------------------------------------------------- /// @notice Thrown when trying to assign an invalid rewards contract error StakeableEulerERC4626__InvalidRewardContract(); /// ----------------------------------------------------------------------- /// Libraries usage /// ----------------------------------------------------------------------- using SafeTransferLib for ERC20; /// ----------------------------------------------------------------------- /// Immutable params /// ----------------------------------------------------------------------- /// @notice The rewards distribution address IRewardsDistribution public immutable rewardsDistribution; /// ----------------------------------------------------------------------- /// Mutable params /// ----------------------------------------------------------------------- /// @notice The staking rewards address IStakingRewards public stakingRewards; /// ----------------------------------------------------------------------- /// Constructor /// ----------------------------------------------------------------------- constructor(ERC20 asset_, address euler_, IEulerEToken eToken_, IRewardsDistribution rewardsDistribution_, address owner_) EulerERC4626(asset_, euler_, eToken_) Owned(owner_) { rewardsDistribution = rewardsDistribution_; } /// ----------------------------------------------------------------------- /// ERC4626 overrides /// ----------------------------------------------------------------------- function totalAssets() public view virtual override returns (uint256) { uint256 eTokenStakedBalance = _getStakedBalance(); if (eTokenStakedBalance > 0) { // We add all eToken balance (staked and non-staked) and then convert to underlying // We do this to prevent rounding differences if we converted to underlying and then added the results uint256 eTokenBalanceInContract = eToken.balanceOf(address(this)); return eToken.convertBalanceToUnderlying(eTokenStakedBalance + eTokenBalanceInContract); } return eToken.balanceOfUnderlying(address(this)); } function beforeWithdraw(uint256 assets, uint256 shares) internal virtual override { uint256 underlyingBalanceInContract = eToken.balanceOfUnderlying(address(this)); if (underlyingBalanceInContract < assets) { // Need to unstake to meet the demand uint256 neededUnderlying = assets - underlyingBalanceInContract; uint256 neededEToken = eToken.convertUnderlyingToBalance(neededUnderlying); // We also withdraw 5% of remaining staked eTokens so that we can avoid unstaking again in the next withdraw uint256 eTokenStakedBalance = _getStakedBalance(); uint256 remaining = eTokenStakedBalance - neededEToken; uint256 withdrawAttempt = neededEToken + FixedPointMathLib.mulDivUp(remaining, 5, 100); // We make sure we don't try to withdraw more than available uint256 toWithdraw = eTokenStakedBalance < withdrawAttempt ? eTokenStakedBalance : withdrawAttempt; stakingRewards.withdraw(toWithdraw); } super.beforeWithdraw(assets, shares); } /// ----------------------------------------------------------------------- /// Staking functions /// ----------------------------------------------------------------------- /// @notice Returns how much was earned during staking function reward() public view returns (address rewardsToken, uint256 earned) { return _calculateReward(stakingRewards); } /// @notice Allows owner to set or update a new staking contract. Will claim rewards from previous staking if available function updateStakingAddress(uint256 rewardIndex, address recipient) external onlyOwner { _stopStaking(recipient); IRewardsDistribution.DistributionData memory data = rewardsDistribution.distributions(rewardIndex); IStakingRewards stakingRewards_ = IStakingRewards(data.destination); if (stakingRewards_.stakingToken() != address(eToken)) revert StakeableEulerERC4626__InvalidRewardContract(); stakingRewards = stakingRewards_; ERC20(address(eToken)).safeApprove(address(stakingRewards_), type(uint256).max); } /// @notice Allows owner to claim rewards and stop staking all together function stopStaking(address recipient) external onlyOwner { _stopStaking(recipient); stakingRewards = IStakingRewards(address(0)); } /// @notice Allows owner to stake a certain amount of tokens function stake(uint256 amount) external onlyOwner { stakingRewards.stake(amount); } /// @notice Allows owner to unstake a certain amount of tokens function unstake(uint256 amount) external onlyOwner { stakingRewards.withdraw(amount); } /// @notice Allows owner to claim all staking rewards function claimReward(address recipient) public onlyOwner returns (address rewardsToken, uint256 earned) { (rewardsToken, earned) = reward(); stakingRewards.getReward(); _transferRewardToken(rewardsToken, earned, recipient); } /// ----------------------------------------------------------------------- /// Internal functions /// ----------------------------------------------------------------------- function _getStakedBalance() internal view returns (uint256 eTokenStakedBalance) { IStakingRewards stakingRewards_ = stakingRewards; if (address(stakingRewards_) != address(0)) { return stakingRewards_.balanceOf(address(this)); } } function _calculateReward(IStakingRewards stakingRewards_) public view returns (address rewardToken, uint256 earned) { if (address(stakingRewards_) != address(0)) { rewardToken = stakingRewards_.rewardsToken(); earned = stakingRewards_.earned(address(this)); } } function _stopStaking(address recipient) internal { IStakingRewards stakingRewards_ = stakingRewards; if (address(stakingRewards_) != address(0)) { ERC20(address(eToken)).safeApprove(address(stakingRewards_), 0); (address rewardToken, uint256 earned) = _calculateReward(stakingRewards_); stakingRewards_.exit(); _transferRewardToken(rewardToken, earned, recipient); } } function _transferRewardToken(address rewardToken, uint256 amount, address recipient) internal { if (amount > 0) { ERC20(rewardToken).safeTransfer(recipient, amount); } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Simple single owner authorization mixin. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) abstract contract Owned { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event OwnerUpdated(address indexed user, address indexed newOwner); /*////////////////////////////////////////////////////////////// OWNERSHIP STORAGE //////////////////////////////////////////////////////////////*/ address public owner; modifier onlyOwner() virtual { require(msg.sender == owner, "UNAUTHORIZED"); _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(address _owner) { owner = _owner; emit OwnerUpdated(address(0), _owner); } /*////////////////////////////////////////////////////////////// OWNERSHIP LOGIC //////////////////////////////////////////////////////////////*/ function setOwner(address newOwner) public virtual onlyOwner { owner = newOwner; emit OwnerUpdated(msg.sender, newOwner); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.13; /// @notice Tokenised representation of assets interface IEulerEToken { // @notice Retrieve the current allowance /// @param holder Xor with the desired sub-account ID (if applicable) /// @param spender Trusted address function allowance(address holder, address spender) external view returns (uint); /// @notice Address of underlying asset function underlyingAsset() external view returns (address); /// @notice Balance of a particular account, in underlying units (increases as interest is earned) function balanceOfUnderlying(address account) external view returns (uint256); /// @notice Balance of a particular account function balanceOf(address account) external view returns (uint256); /// @notice Transfer underlying tokens from sender to the Euler pool, and increase account's eTokens /// @param subAccountId 0 for primary, 1-255 for a sub-account /// @param amount In underlying units (use max uint256 for full underlying token balance) function deposit(uint256 subAccountId, uint256 amount) external; /// @notice Transfer underlying tokens from Euler pool to sender, and decrease account's eTokens /// @param subAccountId 0 for primary, 1-255 for a sub-account /// @param amount In underlying units (use max uint256 for full pool balance) function withdraw(uint256 subAccountId, uint256 amount) external; /// @notice Convert an eToken balance to an underlying amount, taking into account current exchange rate /// @param balance eToken balance, in internal book-keeping units (18 decimals) /// @return Amount in underlying units, (same decimals as underlying token) function convertBalanceToUnderlying(uint balance) external view returns (uint); /// @notice Convert an underlying amount to an eToken balance, taking into account current exchange rate /// @param underlyingAmount Amount in underlying units (same decimals as underlying token) /// @return eToken balance, in internal book-keeping units (18 decimals) function convertUnderlyingToBalance(uint underlyingAmount) external view returns (uint); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Original contract can be found under the following link: // https://github.com/Synthetixio/synthetix/blob/master/contracts/interfaces/IRewardsDistribution.sol interface IRewardsDistribution { // Structs struct DistributionData { address destination; uint amount; } // Views function distributions(uint256 index) external view returns (DistributionData memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Original contract can be found under the following link: // https://github.com/Synthetixio/synthetix/blob/master/contracts/interfaces/IStakingRewards.sol interface IStakingRewards { // Views function rewardsToken() external view returns (address); function stakingToken() external view returns (address); function balanceOf(address account) external view returns (uint256); function earned(address account) external view returns (uint256); // Mutative function exit() external; function getReward() external; function stake(uint256 amount) external; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.13; import {ERC20} from "solmate/tokens/ERC20.sol"; import {ERC4626} from "solmate/mixins/ERC4626.sol"; import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol"; import {IEulerEToken} from "./external/IEulerEToken.sol"; /// @title EulerERC4626 /// @author zefram.eth /// @notice ERC4626 wrapper for Euler Finance contract EulerERC4626 is ERC4626 { /// ----------------------------------------------------------------------- /// Libraries usage /// ----------------------------------------------------------------------- using SafeTransferLib for ERC20; /// ----------------------------------------------------------------------- /// Immutable params /// ----------------------------------------------------------------------- /// @notice The Euler main contract address /// @dev Target of ERC20 approval when depositing address public immutable euler; /// @notice The Euler eToken contract IEulerEToken public immutable eToken; /// ----------------------------------------------------------------------- /// Constructor /// ----------------------------------------------------------------------- constructor(ERC20 asset_, address euler_, IEulerEToken eToken_) ERC4626(asset_, _vaultName(asset_), _vaultSymbol(asset_)) { euler = euler_; eToken = eToken_; } /// ----------------------------------------------------------------------- /// ERC4626 overrides /// ----------------------------------------------------------------------- function totalAssets() public view virtual override returns (uint256) { return eToken.balanceOfUnderlying(address(this)); } function beforeWithdraw(uint256 assets, uint256 /*shares*/ ) internal virtual override { /// ----------------------------------------------------------------------- /// Withdraw assets from Euler /// ----------------------------------------------------------------------- eToken.withdraw(0, assets); } function afterDeposit(uint256 assets, uint256 /*shares*/ ) internal virtual override { /// ----------------------------------------------------------------------- /// Deposit assets into Euler /// ----------------------------------------------------------------------- // approve to euler asset.safeApprove(address(euler), assets); // deposit into eToken eToken.deposit(0, assets); } function maxWithdraw(address owner) public view override returns (uint256) { uint256 cash = asset.balanceOf(euler); uint256 assetsBalance = convertToAssets(balanceOf[owner]); return cash < assetsBalance ? cash : assetsBalance; } function maxRedeem(address owner) public view override returns (uint256) { uint256 cash = asset.balanceOf(euler); uint256 cashInShares = convertToShares(cash); uint256 shareBalance = balanceOf[owner]; return cashInShares < shareBalance ? cashInShares : shareBalance; } /// ----------------------------------------------------------------------- /// ERC20 metadata generation /// ----------------------------------------------------------------------- function _vaultName(ERC20 asset_) internal view virtual returns (string memory vaultName) { vaultName = string.concat("ERC4626-Wrapped Euler ", asset_.symbol()); } function _vaultSymbol(ERC20 asset_) internal view virtual returns (string memory vaultSymbol) { vaultSymbol = string.concat("we", asset_.symbol()); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol"; /// @notice Minimal ERC4626 tokenized Vault implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol) abstract contract ERC4626 is ERC20 { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /*////////////////////////////////////////////////////////////// IMMUTABLES //////////////////////////////////////////////////////////////*/ ERC20 public immutable asset; constructor( ERC20 _asset, string memory _name, string memory _symbol ) ERC20(_name, _symbol, _asset.decimals()) { asset = _asset; } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LOGIC //////////////////////////////////////////////////////////////*/ function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { // Check for rounding error since we round down in previewDeposit. require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); // Need to transfer before minting or ERC777s could reenter. asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); } function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) { assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up. // Need to transfer before minting or ERC777s could reenter. asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); } function withdraw( uint256 assets, address receiver, address owner ) public virtual returns (uint256 shares) { shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up. if (msg.sender != owner) { uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; } beforeWithdraw(assets, shares); _burn(owner, shares); emit Withdraw(msg.sender, receiver, owner, assets, shares); asset.safeTransfer(receiver, assets); } function redeem( uint256 shares, address receiver, address owner ) public virtual returns (uint256 assets) { if (msg.sender != owner) { uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; } // Check for rounding error since we round down in previewRedeem. require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS"); beforeWithdraw(assets, shares); _burn(owner, shares); emit Withdraw(msg.sender, receiver, owner, assets, shares); asset.safeTransfer(receiver, assets); } /*////////////////////////////////////////////////////////////// ACCOUNTING LOGIC //////////////////////////////////////////////////////////////*/ function totalAssets() public view virtual returns (uint256); function convertToShares(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); } function convertToAssets(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); } function previewDeposit(uint256 assets) public view virtual returns (uint256) { return convertToShares(assets); } function previewMint(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); } function previewWithdraw(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); } function previewRedeem(uint256 shares) public view virtual returns (uint256) { return convertToAssets(shares); } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LIMIT LOGIC //////////////////////////////////////////////////////////////*/ function maxDeposit(address) public view virtual returns (uint256) { return type(uint256).max; } function maxMint(address) public view virtual returns (uint256) { return type(uint256).max; } function maxWithdraw(address owner) public view virtual returns (uint256) { return convertToAssets(balanceOf[owner]); } function maxRedeem(address owner) public view virtual returns (uint256) { return balanceOf[owner]; } /*////////////////////////////////////////////////////////////// INTERNAL HOOKS LOGIC //////////////////////////////////////////////////////////////*/ function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {} function afterDeposit(uint256 assets, uint256 shares) internal virtual {} }
{ "remappings": [ "create3-factory/=lib/create3-factory/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solmate/=lib/solmate/src/", "src/=src/", "script/=script/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ERC20","name":"asset_","type":"address"},{"internalType":"address","name":"euler_","type":"address"},{"internalType":"contract IEulerEToken","name":"eToken_","type":"address"},{"internalType":"contract IRewardsDistribution","name":"rewardsDistribution_","type":"address"},{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"StakeableEulerERC4626__InvalidRewardContract","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStakingRewards","name":"stakingRewards_","type":"address"}],"name":"_calculateReward","outputs":[{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"earned","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"claimReward","outputs":[{"internalType":"address","name":"rewardsToken","type":"address"},{"internalType":"uint256","name":"earned","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eToken","outputs":[{"internalType":"contract IEulerEToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"euler","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reward","outputs":[{"internalType":"address","name":"rewardsToken","type":"address"},{"internalType":"uint256","name":"earned","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDistribution","outputs":[{"internalType":"contract IRewardsDistribution","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingRewards","outputs":[{"internalType":"contract IStakingRewards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"stopStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardIndex","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"updateStakingAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101606040523480156200001257600080fd5b50604051620036873803806200368783398101604081905262000035916200032f565b808585858262000045816200016a565b6200005085620001fd565b8181846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000091573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000b79190620003af565b6000620000c5848262000480565b506001620000d4838262000480565b5060ff81166080524660a052620000ea6200027a565b60c052505050506001600160a01b0391821660e0525091821661010052811661012052600680546001600160a01b03191691841691821790556040519091506000907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350506001600160a01b031661014052506200071b915050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620001ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001d5919081019062000572565b604051602001620001e791906200062a565b6040516020818303038152906040529050919050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200023e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000268919081019062000572565b604051602001620001e7919062000671565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620002ae91906200069d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b03811681146200032c57600080fd5b50565b600080600080600060a086880312156200034857600080fd5b8551620003558162000316565b6020870151909550620003688162000316565b60408701519094506200037b8162000316565b60608701519093506200038e8162000316565b6080870151909250620003a18162000316565b809150509295509295909350565b600060208284031215620003c257600080fd5b815160ff81168114620003d457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200040657607f821691505b6020821081036200042757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200047b57600081815260208120601f850160051c81016020861015620004565750805b601f850160051c820191505b81811015620004775782815560010162000462565b5050505b505050565b81516001600160401b038111156200049c576200049c620003db565b620004b481620004ad8454620003f1565b846200042d565b602080601f831160018114620004ec5760008415620004d35750858301515b600019600386901b1c1916600185901b17855562000477565b600085815260208120601f198616915b828110156200051d57888601518255948401946001909101908401620004fc565b50858210156200053c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60005b83811015620005695781810151838201526020016200054f565b50506000910152565b6000602082840312156200058557600080fd5b81516001600160401b03808211156200059d57600080fd5b818401915084601f830112620005b257600080fd5b815181811115620005c757620005c7620003db565b604051601f8201601f19908116603f01168101908382118183101715620005f257620005f2620003db565b816040528281528760208487010111156200060c57600080fd5b6200061f8360208301602088016200054c565b979650505050505050565b7f455243343632362d577261707065642045756c65722000000000000000000000815260008251620006648160168501602087016200054c565b9190910160160192915050565b61776560f01b815260008251620006908160028501602087016200054c565b9190910160020192915050565b6000808354620006ad81620003f1565b60018281168015620006c85760018114620006de576200070f565b60ff19841687528215158302870194506200070f565b8760005260208060002060005b85811015620007065781548a820152908401908201620006eb565b50505082870194505b50929695505050505050565b60805160a05160c05160e051610100516101205161014051612e7e620008096000396000818161045b0152611e2601526000818161059401528181610738015281816107d10152818161089401528181611eb201528181611fee0152818161237401528181612423015281816124fb015281816125db01526129860152600081816106810152818161172301528181611c84015261231901526000818161040f01528181610fff0152818161116a015281816114c80152818161169f0152818161175001528181611cb101526122f701526000610e1c01526000610de7015260006103ce0152612e7e6000f3fe608060405234801561001057600080fd5b50600436106102d35760003560e01c80637c6967dc11610186578063ba087652116100e3578063d505accf11610097578063dd62ed3e11610071578063dd62ed3e146106a3578063e0bd6775146106ce578063ef8b30f7146106e157600080fd5b8063d505accf14610656578063d905777e14610669578063db661b711461067c57600080fd5b8063c6e6f592116100c8578063c6e6f5921461061d578063ce96cb7714610630578063d279c1911461064357600080fd5b8063ba0876521461060a578063c63d75b61461047d57600080fd5b806395d89b411161013a578063a9059cbb1161011f578063a9059cbb146105d1578063b3d7f6b9146105e4578063b460af94146105f757600080fd5b806395d89b41146105b6578063a694fc3a146105be57600080fd5b80638da5cb5b1161016b5780638da5cb5b1461055c57806394bf804d1461057c578063953d9cf11461058f57600080fd5b80637c6967dc146105295780637ecebe001461053c57600080fd5b8063313ce56711610234578063497f285d116101e857806364b87a70116101cd57806364b87a70146104d65780636e553f65146104f657806370a082311461050957600080fd5b8063497f285d146104b05780634cdad506146104c357600080fd5b806338d52e0f1161021957806338d52e0f1461040a5780633fc6df6e14610456578063402d267d1461047d57600080fd5b8063313ce567146103c95780633644e5151461040257600080fd5b806313af40351161028b578063228cb73311610270578063228cb7331461036f57806323b872dd146103a35780632e17de78146103b657600080fd5b806313af40351461035157806318160ddd1461036657600080fd5b806307a2d13a116102bc57806307a2d13a14610308578063095ea7b31461031b5780630a28a4771461033e57600080fd5b806301e1d114146102d857806306fdde03146102f3575b600080fd5b6102e06106f4565b6040519081526020015b60405180910390f35b6102fb61091b565b6040516102ea91906129ca565b6102e0610316366004612a36565b6109a9565b61032e610329366004612a74565b6109d6565b60405190151581526020016102ea565b6102e061034c366004612a36565b610a50565b61036461035f366004612aa0565b610a70565b005b6102e060025481565b610377610b67565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016102ea565b61032e6103b1366004612abd565b610b96565b6103646103c4366004612a36565b610cda565b6103f07f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102ea565b6102e0610de3565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102ea565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102e061048b366004612aa0565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6103776104be366004612aa0565b610e3e565b6102e06104d1366004612a36565b610f63565b6007546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e0610504366004612afe565b610f6e565b6102e0610517366004612aa0565b60036020526000908152604090205481565b610364610537366004612aa0565b61108e565b6102e061054a366004612aa0565b60056020526000908152604090205481565b6006546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e061058a366004612afe565b611143565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102fb6111f9565b6103646105cc366004612a36565b611206565b61032e6105df366004612a74565b6112de565b6102e06105f2366004612a36565b611363565b6102e0610605366004612b2e565b611382565b6102e0610618366004612b2e565b6114ef565b6102e061062b366004612a36565b6116c6565b6102e061063e366004612aa0565b6116e6565b610377610651366004612aa0565b611807565b610364610664366004612b70565b611928565b6102e0610677366004612aa0565b611c47565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102e06106b1366004612be7565b600460209081526000928352604080842090915290825290205481565b6103646106dc366004612afe565b611d6a565b6102e06106ef366004612a36565b61203b565b6000806106ff612046565b90508015610866576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190612c15565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663010ad6d16108008385612c5d565b6040518263ffffffff1660e01b815260040161081e91815260200190565b602060405180830381865afa15801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f9190612c15565b9250505090565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633af9e669906024015b602060405180830381865afa1580156108f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109159190612c15565b91505090565b6000805461092890612c70565b80601f016020809104026020016040519081016040528092919081815260200182805461095490612c70565b80156109a15780601f10610976576101008083540402835291602001916109a1565b820191906000526020600020905b81548152906001019060200180831161098457829003601f168201915b505050505081565b60025460009080156109cd576109c86109c06106f4565b8490836120be565b6109cf565b825b9392505050565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a3e9086815260200190565b60405180910390a35060015b92915050565b60025460009080156109cd576109c881610a686106f4565b8591906120dd565b60065473ffffffffffffffffffffffffffffffffffffffff163314610af6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6007546000908190610b8e9073ffffffffffffffffffffffffffffffffffffffff16610e3e565b915091509091565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c2a57610bf88382612cc3565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff851660009081526003602052604081208054859290610c5f908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610cc79087815260200190565b60405180910390a3506001949350505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610d5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d906024015b600060405180830381600087803b158015610dc857600080fd5b505af1158015610ddc573d6000803e3d6000fd5b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610e1957610e1461210b565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b60008073ffffffffffffffffffffffffffffffffffffffff831615610f5e578273ffffffffffffffffffffffffffffffffffffffff1663d1af0c7d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612cd6565b6040517e8cc26200000000000000000000000000000000000000000000000000000000815230600482015290925073ffffffffffffffffffffffffffffffffffffffff841690628cc26290602401602060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5b9190612c15565b90505b915091565b6000610a4a826109a9565b6000610f798361203b565b905080600003610fe5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152606401610aed565b61102773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330866121a5565b6110318282612264565b604080518481526020810183905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a83826122dd565b60065473ffffffffffffffffffffffffffffffffffffffff16331461110f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611118816123ea565b50600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600061114e83611363565b905061119273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846121a5565b61119c8284612264565b604080518281526020810185905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a81846122dd565b6001805461092890612c70565b60065473ffffffffffffffffffffffffffffffffffffffff163314611287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063a694fc3a90602401610dae565b336000908152600360205260408120805483919083906112ff908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610a3e9086815260200190565b60025460009080156109cd576109c861137a6106f4565b8490836120dd565b600061138d84610a50565b90503373ffffffffffffffffffffffffffffffffffffffff8316146114425773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114405761140e8282612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b61144c84826124ca565b6114568282612729565b604080518581526020810183905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684866127b7565b60003373ffffffffffffffffffffffffffffffffffffffff8316146115a45773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146115a2576115708582612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b6115ad84610f63565b905080600003611619576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152606401610aed565b61162381856124ca565b61162d8285612729565b604080518281526020810186905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684836127b7565b60025460009080156109cd576109c8816116de6106f4565b8591906120be565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bb9190612c15565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040812054919250906117ee906109a9565b90508082106117fd57806117ff565b815b949350505050565b600654600090819073ffffffffffffffffffffffffffffffffffffffff16331461188d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611895610b67565b600754604080517f3d18b912000000000000000000000000000000000000000000000000000000008152905193955091935073ffffffffffffffffffffffffffffffffffffffff1691633d18b9129160048082019260009290919082900301818387803b15801561190557600080fd5b505af1158015611919573d6000803e3d6000fd5b50505050610f5e828285612870565b42841015611992576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610aed565b6000600161199e610de3565b73ffffffffffffffffffffffffffffffffffffffff8a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611af0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611b6b57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611bd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610aed565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1c9190612c15565b90506000611d29826116c6565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902054909150808210611d5f5780611d61565b815b95945050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611df4816123ea565b6040517f4487d3df000000000000000000000000000000000000000000000000000000008152600481018390526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690634487d3df906024016040805180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190612cf3565b90506000816000015190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff166372f702f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f569190612cd6565b73ffffffffffffffffffffffffffffffffffffffff1614611fa3576040517f63eea51600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155612035907f000000000000000000000000000000000000000000000000000000000000000016827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612897565b50505050565b6000610a4a826116c6565b60075460009073ffffffffffffffffffffffffffffffffffffffff1680156120ba576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8216906370a08231906024016108d4565b5090565b8282028115158415858304851417166120d657600080fd5b0492915050565b8282028115158415858304851417166120f557600080fd5b6001826001830304018115150290509392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161213d9190612d72565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610ddc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610aed565b80600260008282546122769190612c5d565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a35050565b61233e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000084612897565b6040517fe2bbb15800000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e2bbb158906044015b600060405180830381600087803b1580156123ce57600080fd5b505af11580156123e2573d6000803e3d6000fd5b505050505050565b60075473ffffffffffffffffffffffffffffffffffffffff1680156124c65761244b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016826000612897565b60008061245783610e3e565b915091508273ffffffffffffffffffffffffffffffffffffffff1663e9fad8ee6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156124a357600080fd5b505af11580156124b7573d6000803e3d6000fd5b50505050612035828286612870565b5050565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633af9e66990602401602060405180830381865afa158015612557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257b9190612c15565b90508281101561271a5760006125918285612cc3565b6040517f52eac8af0000000000000000000000000000000000000000000000000000000081526004810182905290915060009073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906352eac8af90602401602060405180830381865afa158015612622573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126469190612c15565b90506000612652612046565b905060006126608383612cc3565b9050600061267182600560646120dd565b61267b9085612c5d565b9050600081841061268c578161268e565b835b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156126fb57600080fd5b505af115801561270f573d6000803e3d6000fd5b505050505050505050505b6127248383612950565b505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805483929061275e908490612cc3565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016122d1565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610aed565b81156127245761272473ffffffffffffffffffffffffffffffffffffffff841682846127b7565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610aed565b6040517f441a3e7000000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063441a3e70906044016123b4565b600060208083528351808285015260005b818110156129f7578581018301518582016040015282016129db565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600060208284031215612a4857600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114612a7157600080fd5b50565b60008060408385031215612a8757600080fd5b8235612a9281612a4f565b946020939093013593505050565b600060208284031215612ab257600080fd5b81356109cf81612a4f565b600080600060608486031215612ad257600080fd5b8335612add81612a4f565b92506020840135612aed81612a4f565b929592945050506040919091013590565b60008060408385031215612b1157600080fd5b823591506020830135612b2381612a4f565b809150509250929050565b600080600060608486031215612b4357600080fd5b833592506020840135612b5581612a4f565b91506040840135612b6581612a4f565b809150509250925092565b600080600080600080600060e0888a031215612b8b57600080fd5b8735612b9681612a4f565b96506020880135612ba681612a4f565b95506040880135945060608801359350608088013560ff81168114612bca57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215612bfa57600080fd5b8235612c0581612a4f565b91506020830135612b2381612a4f565b600060208284031215612c2757600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610a4a57610a4a612c2e565b600181811c90821680612c8457607f821691505b602082108103612cbd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b81810381811115610a4a57610a4a612c2e565b600060208284031215612ce857600080fd5b81516109cf81612a4f565b600060408284031215612d0557600080fd5b6040516040810181811067ffffffffffffffff82111715612d4f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528251612d5d81612a4f565b81526020928301519281019290925250919050565b600080835481600182811c915080831680612d8e57607f831692505b60208084108203612dc6577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b818015612dda5760018114612e0d57612e3a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952841515850289019650612e3a565b60008a81526020902060005b86811015612e325781548b820152908501908301612e19565b505084890196505b50949897505050505050505056fea26469706673582212205b2ec9951b3f843925558c2e058c3dd16626e97babb9bf6e691e03b57940817164736f6c63430008100033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000027182842e098f60e3d576794a5bffb0777e025d3000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da716000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c4300000000000000000000000027d54d93c8f89988e20fc8ffd911218bac44a0f6
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102d35760003560e01c80637c6967dc11610186578063ba087652116100e3578063d505accf11610097578063dd62ed3e11610071578063dd62ed3e146106a3578063e0bd6775146106ce578063ef8b30f7146106e157600080fd5b8063d505accf14610656578063d905777e14610669578063db661b711461067c57600080fd5b8063c6e6f592116100c8578063c6e6f5921461061d578063ce96cb7714610630578063d279c1911461064357600080fd5b8063ba0876521461060a578063c63d75b61461047d57600080fd5b806395d89b411161013a578063a9059cbb1161011f578063a9059cbb146105d1578063b3d7f6b9146105e4578063b460af94146105f757600080fd5b806395d89b41146105b6578063a694fc3a146105be57600080fd5b80638da5cb5b1161016b5780638da5cb5b1461055c57806394bf804d1461057c578063953d9cf11461058f57600080fd5b80637c6967dc146105295780637ecebe001461053c57600080fd5b8063313ce56711610234578063497f285d116101e857806364b87a70116101cd57806364b87a70146104d65780636e553f65146104f657806370a082311461050957600080fd5b8063497f285d146104b05780634cdad506146104c357600080fd5b806338d52e0f1161021957806338d52e0f1461040a5780633fc6df6e14610456578063402d267d1461047d57600080fd5b8063313ce567146103c95780633644e5151461040257600080fd5b806313af40351161028b578063228cb73311610270578063228cb7331461036f57806323b872dd146103a35780632e17de78146103b657600080fd5b806313af40351461035157806318160ddd1461036657600080fd5b806307a2d13a116102bc57806307a2d13a14610308578063095ea7b31461031b5780630a28a4771461033e57600080fd5b806301e1d114146102d857806306fdde03146102f3575b600080fd5b6102e06106f4565b6040519081526020015b60405180910390f35b6102fb61091b565b6040516102ea91906129ca565b6102e0610316366004612a36565b6109a9565b61032e610329366004612a74565b6109d6565b60405190151581526020016102ea565b6102e061034c366004612a36565b610a50565b61036461035f366004612aa0565b610a70565b005b6102e060025481565b610377610b67565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016102ea565b61032e6103b1366004612abd565b610b96565b6103646103c4366004612a36565b610cda565b6103f07f000000000000000000000000000000000000000000000000000000000000000681565b60405160ff90911681526020016102ea565b6102e0610de3565b6104317f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102ea565b6104317f000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c4381565b6102e061048b366004612aa0565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6103776104be366004612aa0565b610e3e565b6102e06104d1366004612a36565b610f63565b6007546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e0610504366004612afe565b610f6e565b6102e0610517366004612aa0565b60036020526000908152604090205481565b610364610537366004612aa0565b61108e565b6102e061054a366004612aa0565b60056020526000908152604090205481565b6006546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e061058a366004612afe565b611143565b6104317f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71681565b6102fb6111f9565b6103646105cc366004612a36565b611206565b61032e6105df366004612a74565b6112de565b6102e06105f2366004612a36565b611363565b6102e0610605366004612b2e565b611382565b6102e0610618366004612b2e565b6114ef565b6102e061062b366004612a36565b6116c6565b6102e061063e366004612aa0565b6116e6565b610377610651366004612aa0565b611807565b610364610664366004612b70565b611928565b6102e0610677366004612aa0565b611c47565b6104317f00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d381565b6102e06106b1366004612be7565b600460209081526000928352604080842090915290825290205481565b6103646106dc366004612afe565b611d6a565b6102e06106ef366004612a36565b61203b565b6000806106ff612046565b90508015610866576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71673ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190612c15565b905073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da7161663010ad6d16108008385612c5d565b6040518263ffffffff1660e01b815260040161081e91815260200190565b602060405180830381865afa15801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f9190612c15565b9250505090565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71673ffffffffffffffffffffffffffffffffffffffff1690633af9e669906024015b602060405180830381865afa1580156108f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109159190612c15565b91505090565b6000805461092890612c70565b80601f016020809104026020016040519081016040528092919081815260200182805461095490612c70565b80156109a15780601f10610976576101008083540402835291602001916109a1565b820191906000526020600020905b81548152906001019060200180831161098457829003601f168201915b505050505081565b60025460009080156109cd576109c86109c06106f4565b8490836120be565b6109cf565b825b9392505050565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a3e9086815260200190565b60405180910390a35060015b92915050565b60025460009080156109cd576109c881610a686106f4565b8591906120dd565b60065473ffffffffffffffffffffffffffffffffffffffff163314610af6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6007546000908190610b8e9073ffffffffffffffffffffffffffffffffffffffff16610e3e565b915091509091565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c2a57610bf88382612cc3565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff851660009081526003602052604081208054859290610c5f908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610cc79087815260200190565b60405180910390a3506001949350505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610d5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d906024015b600060405180830381600087803b158015610dc857600080fd5b505af1158015610ddc573d6000803e3d6000fd5b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000014614610e1957610e1461210b565b905090565b507f701beada56835bfc6de2d6298fdc34e160d9ff620310fa630d062faa0a6b08e590565b60008073ffffffffffffffffffffffffffffffffffffffff831615610f5e578273ffffffffffffffffffffffffffffffffffffffff1663d1af0c7d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612cd6565b6040517e8cc26200000000000000000000000000000000000000000000000000000000815230600482015290925073ffffffffffffffffffffffffffffffffffffffff841690628cc26290602401602060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5b9190612c15565b90505b915091565b6000610a4a826109a9565b6000610f798361203b565b905080600003610fe5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152606401610aed565b61102773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48163330866121a5565b6110318282612264565b604080518481526020810183905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a83826122dd565b60065473ffffffffffffffffffffffffffffffffffffffff16331461110f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611118816123ea565b50600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600061114e83611363565b905061119273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48163330846121a5565b61119c8284612264565b604080518281526020810185905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a81846122dd565b6001805461092890612c70565b60065473ffffffffffffffffffffffffffffffffffffffff163314611287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063a694fc3a90602401610dae565b336000908152600360205260408120805483919083906112ff908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610a3e9086815260200190565b60025460009080156109cd576109c861137a6106f4565b8490836120dd565b600061138d84610a50565b90503373ffffffffffffffffffffffffffffffffffffffff8316146114425773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114405761140e8282612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b61144c84826124ca565b6114568282612729565b604080518581526020810183905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481684866127b7565b60003373ffffffffffffffffffffffffffffffffffffffff8316146115a45773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146115a2576115708582612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b6115ad84610f63565b905080600003611619576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152606401610aed565b61162381856124ca565b61162d8285612729565b604080518281526020810186905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481684836127b7565b60025460009080156109cd576109c8816116de6106f4565b8591906120be565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d38116600483015260009182917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a0823190602401602060405180830381865afa158015611797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bb9190612c15565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040812054919250906117ee906109a9565b90508082106117fd57806117ff565b815b949350505050565b600654600090819073ffffffffffffffffffffffffffffffffffffffff16331461188d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611895610b67565b600754604080517f3d18b912000000000000000000000000000000000000000000000000000000008152905193955091935073ffffffffffffffffffffffffffffffffffffffff1691633d18b9129160048082019260009290919082900301818387803b15801561190557600080fd5b505af1158015611919573d6000803e3d6000fd5b50505050610f5e828285612870565b42841015611992576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610aed565b6000600161199e610de3565b73ffffffffffffffffffffffffffffffffffffffff8a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611af0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611b6b57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611bd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610aed565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d38116600483015260009182917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a0823190602401602060405180830381865afa158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1c9190612c15565b90506000611d29826116c6565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902054909150808210611d5f5780611d61565b815b95945050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611df4816123ea565b6040517f4487d3df000000000000000000000000000000000000000000000000000000008152600481018390526000907f000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c4373ffffffffffffffffffffffffffffffffffffffff1690634487d3df906024016040805180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190612cf3565b90506000816000015190507f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff166372f702f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f569190612cd6565b73ffffffffffffffffffffffffffffffffffffffff1614611fa3576040517f63eea51600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155612035907f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71616827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612897565b50505050565b6000610a4a826116c6565b60075460009073ffffffffffffffffffffffffffffffffffffffff1680156120ba576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8216906370a08231906024016108d4565b5090565b8282028115158415858304851417166120d657600080fd5b0492915050565b8282028115158415858304851417166120f557600080fd5b6001826001830304018115150290509392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161213d9190612d72565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610ddc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610aed565b80600260008282546122769190612c5d565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a35050565b61233e73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d384612897565b6040517fe2bbb15800000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71673ffffffffffffffffffffffffffffffffffffffff169063e2bbb158906044015b600060405180830381600087803b1580156123ce57600080fd5b505af11580156123e2573d6000803e3d6000fd5b505050505050565b60075473ffffffffffffffffffffffffffffffffffffffff1680156124c65761244b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71616826000612897565b60008061245783610e3e565b915091508273ffffffffffffffffffffffffffffffffffffffff1663e9fad8ee6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156124a357600080fd5b505af11580156124b7573d6000803e3d6000fd5b50505050612035828286612870565b5050565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71673ffffffffffffffffffffffffffffffffffffffff1690633af9e66990602401602060405180830381865afa158015612557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257b9190612c15565b90508281101561271a5760006125918285612cc3565b6040517f52eac8af0000000000000000000000000000000000000000000000000000000081526004810182905290915060009073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71616906352eac8af90602401602060405180830381865afa158015612622573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126469190612c15565b90506000612652612046565b905060006126608383612cc3565b9050600061267182600560646120dd565b61267b9085612c5d565b9050600081841061268c578161268e565b835b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156126fb57600080fd5b505af115801561270f573d6000803e3d6000fd5b505050505050505050505b6127248383612950565b505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805483929061275e908490612cc3565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016122d1565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610aed565b81156127245761272473ffffffffffffffffffffffffffffffffffffffff841682846127b7565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610aed565b6040517f441a3e7000000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da71673ffffffffffffffffffffffffffffffffffffffff169063441a3e70906044016123b4565b600060208083528351808285015260005b818110156129f7578581018301518582016040015282016129db565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600060208284031215612a4857600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114612a7157600080fd5b50565b60008060408385031215612a8757600080fd5b8235612a9281612a4f565b946020939093013593505050565b600060208284031215612ab257600080fd5b81356109cf81612a4f565b600080600060608486031215612ad257600080fd5b8335612add81612a4f565b92506020840135612aed81612a4f565b929592945050506040919091013590565b60008060408385031215612b1157600080fd5b823591506020830135612b2381612a4f565b809150509250929050565b600080600060608486031215612b4357600080fd5b833592506020840135612b5581612a4f565b91506040840135612b6581612a4f565b809150509250925092565b600080600080600080600060e0888a031215612b8b57600080fd5b8735612b9681612a4f565b96506020880135612ba681612a4f565b95506040880135945060608801359350608088013560ff81168114612bca57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215612bfa57600080fd5b8235612c0581612a4f565b91506020830135612b2381612a4f565b600060208284031215612c2757600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610a4a57610a4a612c2e565b600181811c90821680612c8457607f821691505b602082108103612cbd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b81810381811115610a4a57610a4a612c2e565b600060208284031215612ce857600080fd5b81516109cf81612a4f565b600060408284031215612d0557600080fd5b6040516040810181811067ffffffffffffffff82111715612d4f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528251612d5d81612a4f565b81526020928301519281019290925250919050565b600080835481600182811c915080831680612d8e57607f831692505b60208084108203612dc6577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b818015612dda5760018114612e0d57612e3a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952841515850289019650612e3a565b60008a81526020902060005b86811015612e325781548b820152908501908301612e19565b505084890196505b50949897505050505050505056fea26469706673582212205b2ec9951b3f843925558c2e058c3dd16626e97babb9bf6e691e03b57940817164736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000027182842e098f60e3d576794a5bffb0777e025d3000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da716000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c4300000000000000000000000027d54d93c8f89988e20fc8ffd911218bac44a0f6
-----Decoded View---------------
Arg [0] : asset_ (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : euler_ (address): 0x27182842E098f60e3D576794A5bFFb0777E025d3
Arg [2] : eToken_ (address): 0xEb91861f8A4e1C12333F42DCE8fB0Ecdc28dA716
Arg [3] : rewardsDistribution_ (address): 0xA9839D52E964d0ed0d6D546c27D2248Fac610c43
Arg [4] : owner_ (address): 0x27d54D93c8F89988E20fC8FFD911218bAc44a0F6
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d3
Arg [2] : 000000000000000000000000eb91861f8a4e1c12333f42dce8fb0ecdc28da716
Arg [3] : 000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c43
Arg [4] : 00000000000000000000000027d54d93c8f89988e20fc8ffd911218bac44a0f6
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.