Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 6 from a total of 6 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create ERC4626 | 16784422 | 678 days ago | IN | 0 ETH | 0.07411136 | ||||
Create ERC4626 | 16722336 | 686 days ago | IN | 0 ETH | 0.07858546 | ||||
Create ERC4626 | 16241125 | 754 days ago | IN | 0 ETH | 0.05188018 | ||||
Create ERC4626 | 16241119 | 754 days ago | IN | 0 ETH | 0.05514559 | ||||
Create ERC4626 | 16241114 | 754 days ago | IN | 0 ETH | 0.05588182 | ||||
Create ERC4626 | 16240856 | 754 days ago | IN | 0 ETH | 0.0621975 |
Latest 6 internal transactions
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
16784422 | 678 days ago | Contract Creation | 0 ETH | |||
16722336 | 686 days ago | Contract Creation | 0 ETH | |||
16241125 | 754 days ago | Contract Creation | 0 ETH | |||
16241119 | 754 days ago | Contract Creation | 0 ETH | |||
16241114 | 754 days ago | Contract Creation | 0 ETH | |||
16240856 | 754 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
StakeableEulerERC4626Factory
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 {ERC4626} from "solmate/mixins/ERC4626.sol"; import {Owned} from "solmate/auth/Owned.sol"; import {ERC4626Factory} from "../../base/ERC4626Factory.sol"; import {IEulerEToken} from "../external/IEulerEToken.sol"; import {IEulerMarkets} from "../external/IEulerMarkets.sol"; import {IRewardsDistribution} from "../external/IRewardsDistribution.sol"; import {StakeableEulerERC4626} from "./StakeableEulerERC4626.sol"; /// @title EulerERC4626Factory /// @author Sam Bugs /// @notice Factory for creating EulerERC4626 contracts, that can handle staking contract StakeableEulerERC4626Factory is ERC4626Factory, Owned { /// ----------------------------------------------------------------------- /// Errors /// ----------------------------------------------------------------------- /// @notice Thrown when trying to deploy an EulerERC4626 vault using an asset without an eToken error StakeableEulerERC4626Factory__ETokenNonexistent(); /// ----------------------------------------------------------------------- /// Immutable params /// ----------------------------------------------------------------------- /// @notice The Euler main contract address /// @dev Target of ERC20 approval when depositing address public immutable euler; /// @notice The Euler markets module address IEulerMarkets public immutable markets; /// @notice The rewards distribution address IRewardsDistribution public immutable rewardsDistribution; /// ----------------------------------------------------------------------- /// Constructor /// ----------------------------------------------------------------------- constructor(address euler_, IEulerMarkets markets_, IRewardsDistribution rewardsDistribution_, address owner_) Owned(owner_) { euler = euler_; markets = markets_; rewardsDistribution = rewardsDistribution_; } /// ----------------------------------------------------------------------- /// Staking functions /// ----------------------------------------------------------------------- /// @notice Returns how much was earned during staking function reward(StakeableEulerERC4626 vault) public view returns (address rewardsToken, uint256 earned) { return vault.reward(); } /// @notice Allows owner to set or update a new staking contract. Will claim rewards from previous staking if available function updateStakingAddress(StakeableEulerERC4626 vault, uint256 rewardIndex, address recipient) external onlyOwner { vault.updateStakingAddress(rewardIndex, recipient); } /// @notice Allows owner to claim rewards and stop staking all together function stopStaking(StakeableEulerERC4626 vault, address recipient) external onlyOwner { vault.stopStaking(recipient); } /// @notice Allows owner to stake a certain amount of tokens function stake(StakeableEulerERC4626 vault, uint256 amount) external onlyOwner { vault.stake(amount); } /// @notice Allows owner to unstake a certain amount of tokens function unstake(StakeableEulerERC4626 vault, uint256 amount) external onlyOwner { vault.unstake(amount); } /// @notice Allows owner to claim all staking rewards function claimReward(StakeableEulerERC4626 vault, address recipient) public onlyOwner returns (address rewardsToken, uint256 earned) { return vault.claimReward(recipient); } /// ----------------------------------------------------------------------- /// External functions /// ----------------------------------------------------------------------- /// @inheritdoc ERC4626Factory function createERC4626(ERC20 asset) external virtual override returns (ERC4626 vault) { address eTokenAddress = markets.underlyingToEToken(address(asset)); if (eTokenAddress == address(0)) { revert StakeableEulerERC4626Factory__ETokenNonexistent(); } vault = new StakeableEulerERC4626{salt: bytes32(0)}(asset, euler, IEulerEToken(eTokenAddress), rewardsDistribution, address(this)); emit CreateERC4626(asset, vault); } /// @inheritdoc ERC4626Factory function computeERC4626Address(ERC20 asset) external view virtual override returns (ERC4626 vault) { vault = ERC4626( _computeCreate2Address( keccak256( abi.encodePacked( // Deployment bytecode: type(StakeableEulerERC4626).creationCode, // Constructor arguments: abi.encode(asset, euler, IEulerEToken(markets.underlyingToEToken(address(asset))), rewardsDistribution, address(this)) ) ) ) ); } }
// 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; 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 {} }
// 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 pragma solidity ^0.8.13; import {ERC20} from "solmate/tokens/ERC20.sol"; import {ERC4626} from "solmate/mixins/ERC4626.sol"; import {Bytes32AddressLib} from "solmate/utils/Bytes32AddressLib.sol"; /// @title ERC4626Factory /// @author zefram.eth /// @notice Abstract base contract for deploying ERC4626 wrappers /// @dev Uses CREATE2 deterministic deployment, so there can only be a single /// vault for each asset. abstract contract ERC4626Factory { /// ----------------------------------------------------------------------- /// Library usage /// ----------------------------------------------------------------------- using Bytes32AddressLib for bytes32; /// ----------------------------------------------------------------------- /// Events /// ----------------------------------------------------------------------- /// @notice Emitted when a new ERC4626 vault has been created /// @param asset The base asset used by the vault /// @param vault The vault that was created event CreateERC4626(ERC20 indexed asset, ERC4626 vault); /// ----------------------------------------------------------------------- /// External functions /// ----------------------------------------------------------------------- /// @notice Creates an ERC4626 vault for an asset /// @dev Uses CREATE2 deterministic deployment, so there can only be a single /// vault for each asset. Will revert if a vault has already been deployed for the asset. /// @param asset The base asset used by the vault /// @return vault The vault that was created function createERC4626(ERC20 asset) external virtual returns (ERC4626 vault); /// @notice Computes the address of the ERC4626 vault corresponding to an asset. Returns /// a valid result regardless of whether the vault has already been deployed. /// @param asset The base asset used by the vault /// @return vault The vault corresponding to the asset function computeERC4626Address(ERC20 asset) external view virtual returns (ERC4626 vault); /// ----------------------------------------------------------------------- /// Internal functions /// ----------------------------------------------------------------------- /// @notice Computes the address of a contract deployed by this factory using CREATE2, given /// the bytecode hash of the contract. Can also be used to predict addresses of contracts yet to /// be deployed. /// @dev Always uses bytes32(0) as the salt /// @param bytecodeHash The keccak256 hash of the creation code of the contract being deployed concatenated /// with the ABI-encoded constructor arguments. /// @return The address of the deployed contract function _computeCreate2Address(bytes32 bytecodeHash) internal view virtual returns (address) { return keccak256(abi.encodePacked(bytes1(0xFF), address(this), bytes32(0), bytecodeHash)) // Prefix: // Creator: // Salt: // Bytecode hash: .fromLast20Bytes(); // Convert the CREATE2 hash into an address. } }
// 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: AGPL-3.0 pragma solidity ^0.8.13; /// @notice Activating and querying markets, and maintaining entered markets lists interface IEulerMarkets { /// @notice Given an underlying, lookup the associated EToken /// @param underlying Token address /// @return EToken address, or address(0) if not activated function underlyingToEToken(address underlying) external view returns (address); }
// 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: 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; 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-only pragma solidity >=0.8.0; /// @notice Library for converting between addresses and bytes32 values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Bytes32AddressLib.sol) library Bytes32AddressLib { function fromLast20Bytes(bytes32 bytesValue) internal pure returns (address) { return address(uint160(uint256(bytesValue))); } function fillLast12Bytes(address addressValue) internal pure returns (bytes32) { return bytes32(bytes20(addressValue)); } }
// 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()); } }
{ "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":"address","name":"euler_","type":"address"},{"internalType":"contract IEulerMarkets","name":"markets_","type":"address"},{"internalType":"contract IRewardsDistribution","name":"rewardsDistribution_","type":"address"},{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"StakeableEulerERC4626Factory__ETokenNonexistent","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ERC20","name":"asset","type":"address"},{"indexed":false,"internalType":"contract ERC4626","name":"vault","type":"address"}],"name":"CreateERC4626","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"},{"inputs":[{"internalType":"contract StakeableEulerERC4626","name":"vault","type":"address"},{"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":"contract ERC20","name":"asset","type":"address"}],"name":"computeERC4626Address","outputs":[{"internalType":"contract ERC4626","name":"vault","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"asset","type":"address"}],"name":"createERC4626","outputs":[{"internalType":"contract ERC4626","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"euler","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"markets","outputs":[{"internalType":"contract IEulerMarkets","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract StakeableEulerERC4626","name":"vault","type":"address"}],"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":"contract StakeableEulerERC4626","name":"vault","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract StakeableEulerERC4626","name":"vault","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"stopStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract StakeableEulerERC4626","name":"vault","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract StakeableEulerERC4626","name":"vault","type":"address"},{"internalType":"uint256","name":"rewardIndex","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"updateStakingAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60e060405234801561001057600080fd5b506040516200476e3803806200476e833981016040819052610031916100b0565b600080546001600160a01b0319166001600160a01b03831690811782556040518392907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350506001600160a01b0392831660805290821660a0521660c05261010f565b6001600160a01b03811681146100ad57600080fd5b50565b600080600080608085870312156100c657600080fd5b84516100d181610098565b60208601519094506100e281610098565b60408601519093506100f381610098565b606086015190925061010481610098565b939692955090935050565b60805160a05160c0516146056200016960003960008181610167015281816107b2015261097301526000818161011501528181610713015261088c015260008181610295015281816106f1015261095101526146056000f3fe60806040523480156200001157600080fd5b5060043610620000f15760003560e01c806380cfde3c1162000097578063adc9772e116200006e578063adc9772e146200024a578063af44af5b1462000261578063c2a672e01462000278578063db661b71146200028f57600080fd5b806380cfde3c14620001fb5780638da5cb5b1462000212578063abeccaa4146200023357600080fd5b80634953c78211620000cc5780634953c78214620001895780636353586b14620001cd5780637dc353e114620001e457600080fd5b806313af403514620000f65780633ac2a032146200010f5780633fc6df6e1462000161575b600080fd5b6200010d6200010736600462000dc9565b620002b7565b005b620001377f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b620001377f000000000000000000000000000000000000000000000000000000000000000081565b620001a06200019a36600462000df0565b620003ae565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520162000158565b620001a0620001de36600462000dc9565b620004d3565b6200010d620001f536600462000e2e565b62000550565b620001376200020c36600462000dc9565b62000662565b600054620001379073ffffffffffffffffffffffffffffffffffffffff1681565b620001376200024436600462000dc9565b62000842565b6200010d6200025b36600462000e75565b62000a56565b6200010d6200027236600462000df0565b62000b60565b6200010d6200028936600462000e75565b62000c38565b620001377f000000000000000000000000000000000000000000000000000000000000000081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146200033e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331462000434576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517fd279c19100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015285169063d279c1919060240160408051808303816000875af1158015620004a2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c8919062000ea4565b915091509250929050565b6000808273ffffffffffffffffffffffffffffffffffffffff1663228cb7336040518163ffffffff1660e01b81526004016040805180830381865afa15801562000521573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000547919062000ea4565b91509150915091565b60005473ffffffffffffffffffffffffffffffffffffffff163314620005d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517fe0bd67750000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff828116602483015284169063e0bd677590604401600060405180830381600087803b1580156200064457600080fd5b505af115801562000659573d6000803e3d6000fd5b50505050505050565b60006200083c604051806020016200067a9062000d95565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f9091011660408190527f8948874900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015285917f0000000000000000000000000000000000000000000000000000000000000000917f00000000000000000000000000000000000000000000000000000000000000001690638948874990602401602060405180830381865afa1580156200075b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000781919062000ed5565b6040805173ffffffffffffffffffffffffffffffffffffffff948516602082015292841690830152821660608201527f000000000000000000000000000000000000000000000000000000000000000090911660808201523060a082015260c001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905262000820929160200162000f27565b6040516020818303038152906040528051906020012062000d0f565b92915050565b6040517f8948874900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690638948874990602401602060405180830381865afa158015620008d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008fa919062000ed5565b905073ffffffffffffffffffffffffffffffffffffffff81166200094a576040517f3cfea2b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000801b837f0000000000000000000000000000000000000000000000000000000000000000837f000000000000000000000000000000000000000000000000000000000000000030604051620009a19062000d95565b73ffffffffffffffffffffffffffffffffffffffff95861681529385166020850152918416604084015283166060830152909116608082015260a0018190604051809103906000f5905080158015620009fe573d6000803e3d6000fd5b5060405173ffffffffffffffffffffffffffffffffffffffff8083168252919350908416907fcbd4e5d1362721c7fd10daaabb1a046344447d4798be55684b8a6b4fc1765d729060200160405180910390a250919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000ad9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810182905273ffffffffffffffffffffffffffffffffffffffff83169063a694fc3a906024015b600060405180830381600087803b15801562000b4357600080fd5b505af115801562000b58573d6000803e3d6000fd5b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517f7c6967dc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690637c6967dc9060240162000b28565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517f2e17de780000000000000000000000000000000000000000000000000000000081526004810182905273ffffffffffffffffffffffffffffffffffffffff831690632e17de789060240162000b28565b6040517fff0000000000000000000000000000000000000000000000000000000000000060208201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b16602182015260006035820181905260558201839052906200083c906075016040516020818303038152906040528051906020012090565b6136878062000f4983390190565b73ffffffffffffffffffffffffffffffffffffffff8116811462000dc657600080fd5b50565b60006020828403121562000ddc57600080fd5b813562000de98162000da3565b9392505050565b6000806040838503121562000e0457600080fd5b823562000e118162000da3565b9150602083013562000e238162000da3565b809150509250929050565b60008060006060848603121562000e4457600080fd5b833562000e518162000da3565b925060208401359150604084013562000e6a8162000da3565b809150509250925092565b6000806040838503121562000e8957600080fd5b823562000e968162000da3565b946020939093013593505050565b6000806040838503121562000eb857600080fd5b825162000ec58162000da3565b6020939093015192949293505050565b60006020828403121562000ee857600080fd5b815162000de98162000da3565b6000815160005b8181101562000f18576020818501810151868301520162000efc565b50600093019283525090919050565b600062000f4062000f39838662000ef5565b8462000ef5565b94935050505056fe6101606040523480156200001257600080fd5b50604051620036873803806200368783398101604081905262000035916200032f565b808585858262000045816200016a565b6200005085620001fd565b8181846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000091573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000b79190620003af565b6000620000c5848262000480565b506001620000d4838262000480565b5060ff81166080524660a052620000ea6200027a565b60c052505050506001600160a01b0391821660e0525091821661010052811661012052600680546001600160a01b03191691841691821790556040519091506000907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350506001600160a01b031661014052506200071b915050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620001ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001d5919081019062000572565b604051602001620001e791906200062a565b6040516020818303038152906040529050919050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200023e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000268919081019062000572565b604051602001620001e7919062000671565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620002ae91906200069d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b03811681146200032c57600080fd5b50565b600080600080600060a086880312156200034857600080fd5b8551620003558162000316565b6020870151909550620003688162000316565b60408701519094506200037b8162000316565b60608701519093506200038e8162000316565b6080870151909250620003a18162000316565b809150509295509295909350565b600060208284031215620003c257600080fd5b815160ff81168114620003d457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200040657607f821691505b6020821081036200042757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200047b57600081815260208120601f850160051c81016020861015620004565750805b601f850160051c820191505b81811015620004775782815560010162000462565b5050505b505050565b81516001600160401b038111156200049c576200049c620003db565b620004b481620004ad8454620003f1565b846200042d565b602080601f831160018114620004ec5760008415620004d35750858301515b600019600386901b1c1916600185901b17855562000477565b600085815260208120601f198616915b828110156200051d57888601518255948401946001909101908401620004fc565b50858210156200053c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60005b83811015620005695781810151838201526020016200054f565b50506000910152565b6000602082840312156200058557600080fd5b81516001600160401b03808211156200059d57600080fd5b818401915084601f830112620005b257600080fd5b815181811115620005c757620005c7620003db565b604051601f8201601f19908116603f01168101908382118183101715620005f257620005f2620003db565b816040528281528760208487010111156200060c57600080fd5b6200061f8360208301602088016200054c565b979650505050505050565b7f455243343632362d577261707065642045756c65722000000000000000000000815260008251620006648160168501602087016200054c565b9190910160160192915050565b61776560f01b815260008251620006908160028501602087016200054c565b9190910160020192915050565b6000808354620006ad81620003f1565b60018281168015620006c85760018114620006de576200070f565b60ff19841687528215158302870194506200070f565b8760005260208060002060005b85811015620007065781548a820152908401908201620006eb565b50505082870194505b50929695505050505050565b60805160a05160c05160e051610100516101205161014051612e7e620008096000396000818161045b0152611e2601526000818161059401528181610738015281816107d10152818161089401528181611eb201528181611fee0152818161237401528181612423015281816124fb015281816125db01526129860152600081816106810152818161172301528181611c84015261231901526000818161040f01528181610fff0152818161116a015281816114c80152818161169f0152818161175001528181611cb101526122f701526000610e1c01526000610de7015260006103ce0152612e7e6000f3fe608060405234801561001057600080fd5b50600436106102d35760003560e01c80637c6967dc11610186578063ba087652116100e3578063d505accf11610097578063dd62ed3e11610071578063dd62ed3e146106a3578063e0bd6775146106ce578063ef8b30f7146106e157600080fd5b8063d505accf14610656578063d905777e14610669578063db661b711461067c57600080fd5b8063c6e6f592116100c8578063c6e6f5921461061d578063ce96cb7714610630578063d279c1911461064357600080fd5b8063ba0876521461060a578063c63d75b61461047d57600080fd5b806395d89b411161013a578063a9059cbb1161011f578063a9059cbb146105d1578063b3d7f6b9146105e4578063b460af94146105f757600080fd5b806395d89b41146105b6578063a694fc3a146105be57600080fd5b80638da5cb5b1161016b5780638da5cb5b1461055c57806394bf804d1461057c578063953d9cf11461058f57600080fd5b80637c6967dc146105295780637ecebe001461053c57600080fd5b8063313ce56711610234578063497f285d116101e857806364b87a70116101cd57806364b87a70146104d65780636e553f65146104f657806370a082311461050957600080fd5b8063497f285d146104b05780634cdad506146104c357600080fd5b806338d52e0f1161021957806338d52e0f1461040a5780633fc6df6e14610456578063402d267d1461047d57600080fd5b8063313ce567146103c95780633644e5151461040257600080fd5b806313af40351161028b578063228cb73311610270578063228cb7331461036f57806323b872dd146103a35780632e17de78146103b657600080fd5b806313af40351461035157806318160ddd1461036657600080fd5b806307a2d13a116102bc57806307a2d13a14610308578063095ea7b31461031b5780630a28a4771461033e57600080fd5b806301e1d114146102d857806306fdde03146102f3575b600080fd5b6102e06106f4565b6040519081526020015b60405180910390f35b6102fb61091b565b6040516102ea91906129ca565b6102e0610316366004612a36565b6109a9565b61032e610329366004612a74565b6109d6565b60405190151581526020016102ea565b6102e061034c366004612a36565b610a50565b61036461035f366004612aa0565b610a70565b005b6102e060025481565b610377610b67565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016102ea565b61032e6103b1366004612abd565b610b96565b6103646103c4366004612a36565b610cda565b6103f07f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102ea565b6102e0610de3565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102ea565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102e061048b366004612aa0565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6103776104be366004612aa0565b610e3e565b6102e06104d1366004612a36565b610f63565b6007546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e0610504366004612afe565b610f6e565b6102e0610517366004612aa0565b60036020526000908152604090205481565b610364610537366004612aa0565b61108e565b6102e061054a366004612aa0565b60056020526000908152604090205481565b6006546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e061058a366004612afe565b611143565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102fb6111f9565b6103646105cc366004612a36565b611206565b61032e6105df366004612a74565b6112de565b6102e06105f2366004612a36565b611363565b6102e0610605366004612b2e565b611382565b6102e0610618366004612b2e565b6114ef565b6102e061062b366004612a36565b6116c6565b6102e061063e366004612aa0565b6116e6565b610377610651366004612aa0565b611807565b610364610664366004612b70565b611928565b6102e0610677366004612aa0565b611c47565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102e06106b1366004612be7565b600460209081526000928352604080842090915290825290205481565b6103646106dc366004612afe565b611d6a565b6102e06106ef366004612a36565b61203b565b6000806106ff612046565b90508015610866576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190612c15565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663010ad6d16108008385612c5d565b6040518263ffffffff1660e01b815260040161081e91815260200190565b602060405180830381865afa15801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f9190612c15565b9250505090565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633af9e669906024015b602060405180830381865afa1580156108f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109159190612c15565b91505090565b6000805461092890612c70565b80601f016020809104026020016040519081016040528092919081815260200182805461095490612c70565b80156109a15780601f10610976576101008083540402835291602001916109a1565b820191906000526020600020905b81548152906001019060200180831161098457829003601f168201915b505050505081565b60025460009080156109cd576109c86109c06106f4565b8490836120be565b6109cf565b825b9392505050565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a3e9086815260200190565b60405180910390a35060015b92915050565b60025460009080156109cd576109c881610a686106f4565b8591906120dd565b60065473ffffffffffffffffffffffffffffffffffffffff163314610af6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6007546000908190610b8e9073ffffffffffffffffffffffffffffffffffffffff16610e3e565b915091509091565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c2a57610bf88382612cc3565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff851660009081526003602052604081208054859290610c5f908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610cc79087815260200190565b60405180910390a3506001949350505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610d5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d906024015b600060405180830381600087803b158015610dc857600080fd5b505af1158015610ddc573d6000803e3d6000fd5b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610e1957610e1461210b565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b60008073ffffffffffffffffffffffffffffffffffffffff831615610f5e578273ffffffffffffffffffffffffffffffffffffffff1663d1af0c7d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612cd6565b6040517e8cc26200000000000000000000000000000000000000000000000000000000815230600482015290925073ffffffffffffffffffffffffffffffffffffffff841690628cc26290602401602060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5b9190612c15565b90505b915091565b6000610a4a826109a9565b6000610f798361203b565b905080600003610fe5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152606401610aed565b61102773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330866121a5565b6110318282612264565b604080518481526020810183905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a83826122dd565b60065473ffffffffffffffffffffffffffffffffffffffff16331461110f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611118816123ea565b50600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600061114e83611363565b905061119273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846121a5565b61119c8284612264565b604080518281526020810185905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a81846122dd565b6001805461092890612c70565b60065473ffffffffffffffffffffffffffffffffffffffff163314611287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063a694fc3a90602401610dae565b336000908152600360205260408120805483919083906112ff908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610a3e9086815260200190565b60025460009080156109cd576109c861137a6106f4565b8490836120dd565b600061138d84610a50565b90503373ffffffffffffffffffffffffffffffffffffffff8316146114425773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114405761140e8282612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b61144c84826124ca565b6114568282612729565b604080518581526020810183905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684866127b7565b60003373ffffffffffffffffffffffffffffffffffffffff8316146115a45773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146115a2576115708582612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b6115ad84610f63565b905080600003611619576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152606401610aed565b61162381856124ca565b61162d8285612729565b604080518281526020810186905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684836127b7565b60025460009080156109cd576109c8816116de6106f4565b8591906120be565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bb9190612c15565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040812054919250906117ee906109a9565b90508082106117fd57806117ff565b815b949350505050565b600654600090819073ffffffffffffffffffffffffffffffffffffffff16331461188d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611895610b67565b600754604080517f3d18b912000000000000000000000000000000000000000000000000000000008152905193955091935073ffffffffffffffffffffffffffffffffffffffff1691633d18b9129160048082019260009290919082900301818387803b15801561190557600080fd5b505af1158015611919573d6000803e3d6000fd5b50505050610f5e828285612870565b42841015611992576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610aed565b6000600161199e610de3565b73ffffffffffffffffffffffffffffffffffffffff8a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611af0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611b6b57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611bd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610aed565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1c9190612c15565b90506000611d29826116c6565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902054909150808210611d5f5780611d61565b815b95945050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611df4816123ea565b6040517f4487d3df000000000000000000000000000000000000000000000000000000008152600481018390526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690634487d3df906024016040805180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190612cf3565b90506000816000015190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff166372f702f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f569190612cd6565b73ffffffffffffffffffffffffffffffffffffffff1614611fa3576040517f63eea51600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155612035907f000000000000000000000000000000000000000000000000000000000000000016827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612897565b50505050565b6000610a4a826116c6565b60075460009073ffffffffffffffffffffffffffffffffffffffff1680156120ba576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8216906370a08231906024016108d4565b5090565b8282028115158415858304851417166120d657600080fd5b0492915050565b8282028115158415858304851417166120f557600080fd5b6001826001830304018115150290509392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161213d9190612d72565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610ddc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610aed565b80600260008282546122769190612c5d565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a35050565b61233e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000084612897565b6040517fe2bbb15800000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e2bbb158906044015b600060405180830381600087803b1580156123ce57600080fd5b505af11580156123e2573d6000803e3d6000fd5b505050505050565b60075473ffffffffffffffffffffffffffffffffffffffff1680156124c65761244b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016826000612897565b60008061245783610e3e565b915091508273ffffffffffffffffffffffffffffffffffffffff1663e9fad8ee6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156124a357600080fd5b505af11580156124b7573d6000803e3d6000fd5b50505050612035828286612870565b5050565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633af9e66990602401602060405180830381865afa158015612557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257b9190612c15565b90508281101561271a5760006125918285612cc3565b6040517f52eac8af0000000000000000000000000000000000000000000000000000000081526004810182905290915060009073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906352eac8af90602401602060405180830381865afa158015612622573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126469190612c15565b90506000612652612046565b905060006126608383612cc3565b9050600061267182600560646120dd565b61267b9085612c5d565b9050600081841061268c578161268e565b835b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156126fb57600080fd5b505af115801561270f573d6000803e3d6000fd5b505050505050505050505b6127248383612950565b505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805483929061275e908490612cc3565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016122d1565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610aed565b81156127245761272473ffffffffffffffffffffffffffffffffffffffff841682846127b7565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610aed565b6040517f441a3e7000000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063441a3e70906044016123b4565b600060208083528351808285015260005b818110156129f7578581018301518582016040015282016129db565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600060208284031215612a4857600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114612a7157600080fd5b50565b60008060408385031215612a8757600080fd5b8235612a9281612a4f565b946020939093013593505050565b600060208284031215612ab257600080fd5b81356109cf81612a4f565b600080600060608486031215612ad257600080fd5b8335612add81612a4f565b92506020840135612aed81612a4f565b929592945050506040919091013590565b60008060408385031215612b1157600080fd5b823591506020830135612b2381612a4f565b809150509250929050565b600080600060608486031215612b4357600080fd5b833592506020840135612b5581612a4f565b91506040840135612b6581612a4f565b809150509250925092565b600080600080600080600060e0888a031215612b8b57600080fd5b8735612b9681612a4f565b96506020880135612ba681612a4f565b95506040880135945060608801359350608088013560ff81168114612bca57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215612bfa57600080fd5b8235612c0581612a4f565b91506020830135612b2381612a4f565b600060208284031215612c2757600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610a4a57610a4a612c2e565b600181811c90821680612c8457607f821691505b602082108103612cbd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b81810381811115610a4a57610a4a612c2e565b600060208284031215612ce857600080fd5b81516109cf81612a4f565b600060408284031215612d0557600080fd5b6040516040810181811067ffffffffffffffff82111715612d4f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528251612d5d81612a4f565b81526020928301519281019290925250919050565b600080835481600182811c915080831680612d8e57607f831692505b60208084108203612dc6577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b818015612dda5760018114612e0d57612e3a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952841515850289019650612e3a565b60008a81526020902060005b86811015612e325781548b820152908501908301612e19565b505084890196505b50949897505050505050505056fea26469706673582212205b2ec9951b3f843925558c2e058c3dd16626e97babb9bf6e691e03b57940817164736f6c63430008100033a2646970667358221220081ef3243f788f78811b2742967facb5f95f625a0f11b38820bbf1c5bba274c164736f6c6343000810003300000000000000000000000027182842e098f60e3d576794a5bffb0777e025d30000000000000000000000003520d5a913427e6f0d6a83e07ccd4a4da316e4d3000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c43000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000f15760003560e01c806380cfde3c1162000097578063adc9772e116200006e578063adc9772e146200024a578063af44af5b1462000261578063c2a672e01462000278578063db661b71146200028f57600080fd5b806380cfde3c14620001fb5780638da5cb5b1462000212578063abeccaa4146200023357600080fd5b80634953c78211620000cc5780634953c78214620001895780636353586b14620001cd5780637dc353e114620001e457600080fd5b806313af403514620000f65780633ac2a032146200010f5780633fc6df6e1462000161575b600080fd5b6200010d6200010736600462000dc9565b620002b7565b005b620001377f0000000000000000000000003520d5a913427e6f0d6a83e07ccd4a4da316e4d381565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b620001377f000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c4381565b620001a06200019a36600462000df0565b620003ae565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520162000158565b620001a0620001de36600462000dc9565b620004d3565b6200010d620001f536600462000e2e565b62000550565b620001376200020c36600462000dc9565b62000662565b600054620001379073ffffffffffffffffffffffffffffffffffffffff1681565b620001376200024436600462000dc9565b62000842565b6200010d6200025b36600462000e75565b62000a56565b6200010d6200027236600462000df0565b62000b60565b6200010d6200028936600462000e75565b62000c38565b620001377f00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d381565b60005473ffffffffffffffffffffffffffffffffffffffff1633146200033e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331462000434576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517fd279c19100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015285169063d279c1919060240160408051808303816000875af1158015620004a2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c8919062000ea4565b915091509250929050565b6000808273ffffffffffffffffffffffffffffffffffffffff1663228cb7336040518163ffffffff1660e01b81526004016040805180830381865afa15801562000521573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000547919062000ea4565b91509150915091565b60005473ffffffffffffffffffffffffffffffffffffffff163314620005d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517fe0bd67750000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff828116602483015284169063e0bd677590604401600060405180830381600087803b1580156200064457600080fd5b505af115801562000659573d6000803e3d6000fd5b50505050505050565b60006200083c604051806020016200067a9062000d95565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f9091011660408190527f8948874900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015285917f00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d3917f0000000000000000000000003520d5a913427e6f0d6a83e07ccd4a4da316e4d31690638948874990602401602060405180830381865afa1580156200075b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000781919062000ed5565b6040805173ffffffffffffffffffffffffffffffffffffffff948516602082015292841690830152821660608201527f000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c4390911660808201523060a082015260c001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905262000820929160200162000f27565b6040516020818303038152906040528051906020012062000d0f565b92915050565b6040517f8948874900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015260009182917f0000000000000000000000003520d5a913427e6f0d6a83e07ccd4a4da316e4d31690638948874990602401602060405180830381865afa158015620008d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008fa919062000ed5565b905073ffffffffffffffffffffffffffffffffffffffff81166200094a576040517f3cfea2b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000801b837f00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d3837f000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c4330604051620009a19062000d95565b73ffffffffffffffffffffffffffffffffffffffff95861681529385166020850152918416604084015283166060830152909116608082015260a0018190604051809103906000f5905080158015620009fe573d6000803e3d6000fd5b5060405173ffffffffffffffffffffffffffffffffffffffff8083168252919350908416907fcbd4e5d1362721c7fd10daaabb1a046344447d4798be55684b8a6b4fc1765d729060200160405180910390a250919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000ad9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810182905273ffffffffffffffffffffffffffffffffffffffff83169063a694fc3a906024015b600060405180830381600087803b15801562000b4357600080fd5b505af115801562000b58573d6000803e3d6000fd5b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517f7c6967dc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690637c6967dc9060240162000b28565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640162000335565b6040517f2e17de780000000000000000000000000000000000000000000000000000000081526004810182905273ffffffffffffffffffffffffffffffffffffffff831690632e17de789060240162000b28565b6040517fff0000000000000000000000000000000000000000000000000000000000000060208201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b16602182015260006035820181905260558201839052906200083c906075016040516020818303038152906040528051906020012090565b6136878062000f4983390190565b73ffffffffffffffffffffffffffffffffffffffff8116811462000dc657600080fd5b50565b60006020828403121562000ddc57600080fd5b813562000de98162000da3565b9392505050565b6000806040838503121562000e0457600080fd5b823562000e118162000da3565b9150602083013562000e238162000da3565b809150509250929050565b60008060006060848603121562000e4457600080fd5b833562000e518162000da3565b925060208401359150604084013562000e6a8162000da3565b809150509250925092565b6000806040838503121562000e8957600080fd5b823562000e968162000da3565b946020939093013593505050565b6000806040838503121562000eb857600080fd5b825162000ec58162000da3565b6020939093015192949293505050565b60006020828403121562000ee857600080fd5b815162000de98162000da3565b6000815160005b8181101562000f18576020818501810151868301520162000efc565b50600093019283525090919050565b600062000f4062000f39838662000ef5565b8462000ef5565b94935050505056fe6101606040523480156200001257600080fd5b50604051620036873803806200368783398101604081905262000035916200032f565b808585858262000045816200016a565b6200005085620001fd565b8181846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000091573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000b79190620003af565b6000620000c5848262000480565b506001620000d4838262000480565b5060ff81166080524660a052620000ea6200027a565b60c052505050506001600160a01b0391821660e0525091821661010052811661012052600680546001600160a01b03191691841691821790556040519091506000907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350506001600160a01b031661014052506200071b915050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620001ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001d5919081019062000572565b604051602001620001e791906200062a565b6040516020818303038152906040529050919050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200023e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000268919081019062000572565b604051602001620001e7919062000671565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620002ae91906200069d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b03811681146200032c57600080fd5b50565b600080600080600060a086880312156200034857600080fd5b8551620003558162000316565b6020870151909550620003688162000316565b60408701519094506200037b8162000316565b60608701519093506200038e8162000316565b6080870151909250620003a18162000316565b809150509295509295909350565b600060208284031215620003c257600080fd5b815160ff81168114620003d457600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200040657607f821691505b6020821081036200042757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200047b57600081815260208120601f850160051c81016020861015620004565750805b601f850160051c820191505b81811015620004775782815560010162000462565b5050505b505050565b81516001600160401b038111156200049c576200049c620003db565b620004b481620004ad8454620003f1565b846200042d565b602080601f831160018114620004ec5760008415620004d35750858301515b600019600386901b1c1916600185901b17855562000477565b600085815260208120601f198616915b828110156200051d57888601518255948401946001909101908401620004fc565b50858210156200053c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60005b83811015620005695781810151838201526020016200054f565b50506000910152565b6000602082840312156200058557600080fd5b81516001600160401b03808211156200059d57600080fd5b818401915084601f830112620005b257600080fd5b815181811115620005c757620005c7620003db565b604051601f8201601f19908116603f01168101908382118183101715620005f257620005f2620003db565b816040528281528760208487010111156200060c57600080fd5b6200061f8360208301602088016200054c565b979650505050505050565b7f455243343632362d577261707065642045756c65722000000000000000000000815260008251620006648160168501602087016200054c565b9190910160160192915050565b61776560f01b815260008251620006908160028501602087016200054c565b9190910160020192915050565b6000808354620006ad81620003f1565b60018281168015620006c85760018114620006de576200070f565b60ff19841687528215158302870194506200070f565b8760005260208060002060005b85811015620007065781548a820152908401908201620006eb565b50505082870194505b50929695505050505050565b60805160a05160c05160e051610100516101205161014051612e7e620008096000396000818161045b0152611e2601526000818161059401528181610738015281816107d10152818161089401528181611eb201528181611fee0152818161237401528181612423015281816124fb015281816125db01526129860152600081816106810152818161172301528181611c84015261231901526000818161040f01528181610fff0152818161116a015281816114c80152818161169f0152818161175001528181611cb101526122f701526000610e1c01526000610de7015260006103ce0152612e7e6000f3fe608060405234801561001057600080fd5b50600436106102d35760003560e01c80637c6967dc11610186578063ba087652116100e3578063d505accf11610097578063dd62ed3e11610071578063dd62ed3e146106a3578063e0bd6775146106ce578063ef8b30f7146106e157600080fd5b8063d505accf14610656578063d905777e14610669578063db661b711461067c57600080fd5b8063c6e6f592116100c8578063c6e6f5921461061d578063ce96cb7714610630578063d279c1911461064357600080fd5b8063ba0876521461060a578063c63d75b61461047d57600080fd5b806395d89b411161013a578063a9059cbb1161011f578063a9059cbb146105d1578063b3d7f6b9146105e4578063b460af94146105f757600080fd5b806395d89b41146105b6578063a694fc3a146105be57600080fd5b80638da5cb5b1161016b5780638da5cb5b1461055c57806394bf804d1461057c578063953d9cf11461058f57600080fd5b80637c6967dc146105295780637ecebe001461053c57600080fd5b8063313ce56711610234578063497f285d116101e857806364b87a70116101cd57806364b87a70146104d65780636e553f65146104f657806370a082311461050957600080fd5b8063497f285d146104b05780634cdad506146104c357600080fd5b806338d52e0f1161021957806338d52e0f1461040a5780633fc6df6e14610456578063402d267d1461047d57600080fd5b8063313ce567146103c95780633644e5151461040257600080fd5b806313af40351161028b578063228cb73311610270578063228cb7331461036f57806323b872dd146103a35780632e17de78146103b657600080fd5b806313af40351461035157806318160ddd1461036657600080fd5b806307a2d13a116102bc57806307a2d13a14610308578063095ea7b31461031b5780630a28a4771461033e57600080fd5b806301e1d114146102d857806306fdde03146102f3575b600080fd5b6102e06106f4565b6040519081526020015b60405180910390f35b6102fb61091b565b6040516102ea91906129ca565b6102e0610316366004612a36565b6109a9565b61032e610329366004612a74565b6109d6565b60405190151581526020016102ea565b6102e061034c366004612a36565b610a50565b61036461035f366004612aa0565b610a70565b005b6102e060025481565b610377610b67565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016102ea565b61032e6103b1366004612abd565b610b96565b6103646103c4366004612a36565b610cda565b6103f07f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102ea565b6102e0610de3565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102ea565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102e061048b366004612aa0565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6103776104be366004612aa0565b610e3e565b6102e06104d1366004612a36565b610f63565b6007546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e0610504366004612afe565b610f6e565b6102e0610517366004612aa0565b60036020526000908152604090205481565b610364610537366004612aa0565b61108e565b6102e061054a366004612aa0565b60056020526000908152604090205481565b6006546104319073ffffffffffffffffffffffffffffffffffffffff1681565b6102e061058a366004612afe565b611143565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102fb6111f9565b6103646105cc366004612a36565b611206565b61032e6105df366004612a74565b6112de565b6102e06105f2366004612a36565b611363565b6102e0610605366004612b2e565b611382565b6102e0610618366004612b2e565b6114ef565b6102e061062b366004612a36565b6116c6565b6102e061063e366004612aa0565b6116e6565b610377610651366004612aa0565b611807565b610364610664366004612b70565b611928565b6102e0610677366004612aa0565b611c47565b6104317f000000000000000000000000000000000000000000000000000000000000000081565b6102e06106b1366004612be7565b600460209081526000928352604080842090915290825290205481565b6103646106dc366004612afe565b611d6a565b6102e06106ef366004612a36565b61203b565b6000806106ff612046565b90508015610866576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190612c15565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663010ad6d16108008385612c5d565b6040518263ffffffff1660e01b815260040161081e91815260200190565b602060405180830381865afa15801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f9190612c15565b9250505090565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633af9e669906024015b602060405180830381865afa1580156108f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109159190612c15565b91505090565b6000805461092890612c70565b80601f016020809104026020016040519081016040528092919081815260200182805461095490612c70565b80156109a15780601f10610976576101008083540402835291602001916109a1565b820191906000526020600020905b81548152906001019060200180831161098457829003601f168201915b505050505081565b60025460009080156109cd576109c86109c06106f4565b8490836120be565b6109cf565b825b9392505050565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a3e9086815260200190565b60405180910390a35060015b92915050565b60025460009080156109cd576109c881610a686106f4565b8591906120dd565b60065473ffffffffffffffffffffffffffffffffffffffff163314610af6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6007546000908190610b8e9073ffffffffffffffffffffffffffffffffffffffff16610e3e565b915091509091565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c2a57610bf88382612cc3565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff851660009081526003602052604081208054859290610c5f908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610cc79087815260200190565b60405180910390a3506001949350505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610d5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d906024015b600060405180830381600087803b158015610dc857600080fd5b505af1158015610ddc573d6000803e3d6000fd5b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610e1957610e1461210b565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b60008073ffffffffffffffffffffffffffffffffffffffff831615610f5e578273ffffffffffffffffffffffffffffffffffffffff1663d1af0c7d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612cd6565b6040517e8cc26200000000000000000000000000000000000000000000000000000000815230600482015290925073ffffffffffffffffffffffffffffffffffffffff841690628cc26290602401602060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5b9190612c15565b90505b915091565b6000610a4a826109a9565b6000610f798361203b565b905080600003610fe5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152606401610aed565b61102773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330866121a5565b6110318282612264565b604080518481526020810183905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a83826122dd565b60065473ffffffffffffffffffffffffffffffffffffffff16331461110f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611118816123ea565b50600780547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600061114e83611363565b905061119273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846121a5565b61119c8284612264565b604080518281526020810185905273ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3610a4a81846122dd565b6001805461092890612c70565b60065473ffffffffffffffffffffffffffffffffffffffff163314611287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b6007546040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063a694fc3a90602401610dae565b336000908152600360205260408120805483919083906112ff908490612cc3565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610a3e9086815260200190565b60025460009080156109cd576109c861137a6106f4565b8490836120dd565b600061138d84610a50565b90503373ffffffffffffffffffffffffffffffffffffffff8316146114425773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146114405761140e8282612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b61144c84826124ca565b6114568282612729565b604080518581526020810183905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684866127b7565b60003373ffffffffffffffffffffffffffffffffffffffff8316146115a45773ffffffffffffffffffffffffffffffffffffffff821660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146115a2576115708582612cc3565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020555b505b6115ad84610f63565b905080600003611619576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152606401610aed565b61162381856124ca565b61162d8285612729565b604080518281526020810186905273ffffffffffffffffffffffffffffffffffffffff808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a46109cf73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684836127b7565b60025460009080156109cd576109c8816116de6106f4565b8591906120be565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bb9190612c15565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040812054919250906117ee906109a9565b90508082106117fd57806117ff565b815b949350505050565b600654600090819073ffffffffffffffffffffffffffffffffffffffff16331461188d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611895610b67565b600754604080517f3d18b912000000000000000000000000000000000000000000000000000000008152905193955091935073ffffffffffffffffffffffffffffffffffffffff1691633d18b9129160048082019260009290919082900301818387803b15801561190557600080fd5b505af1158015611919573d6000803e3d6000fd5b50505050610f5e828285612870565b42841015611992576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610aed565b6000600161199e610de3565b73ffffffffffffffffffffffffffffffffffffffff8a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611af0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611b6b57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611bd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610aed565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1c9190612c15565b90506000611d29826116c6565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902054909150808210611d5f5780611d61565b815b95945050505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314611deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610aed565b611df4816123ea565b6040517f4487d3df000000000000000000000000000000000000000000000000000000008152600481018390526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690634487d3df906024016040805180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190612cf3565b90506000816000015190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff166372f702f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f569190612cd6565b73ffffffffffffffffffffffffffffffffffffffff1614611fa3576040517f63eea51600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155612035907f000000000000000000000000000000000000000000000000000000000000000016827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612897565b50505050565b6000610a4a826116c6565b60075460009073ffffffffffffffffffffffffffffffffffffffff1680156120ba576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8216906370a08231906024016108d4565b5090565b8282028115158415858304851417166120d657600080fd5b0492915050565b8282028115158415858304851417166120f557600080fd5b6001826001830304018115150290509392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161213d9190612d72565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610ddc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401610aed565b80600260008282546122769190612c5d565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a35050565b61233e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000084612897565b6040517fe2bbb15800000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e2bbb158906044015b600060405180830381600087803b1580156123ce57600080fd5b505af11580156123e2573d6000803e3d6000fd5b505050505050565b60075473ffffffffffffffffffffffffffffffffffffffff1680156124c65761244b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016826000612897565b60008061245783610e3e565b915091508273ffffffffffffffffffffffffffffffffffffffff1663e9fad8ee6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156124a357600080fd5b505af11580156124b7573d6000803e3d6000fd5b50505050612035828286612870565b5050565b6040517f3af9e6690000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633af9e66990602401602060405180830381865afa158015612557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257b9190612c15565b90508281101561271a5760006125918285612cc3565b6040517f52eac8af0000000000000000000000000000000000000000000000000000000081526004810182905290915060009073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906352eac8af90602401602060405180830381865afa158015612622573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126469190612c15565b90506000612652612046565b905060006126608383612cc3565b9050600061267182600560646120dd565b61267b9085612c5d565b9050600081841061268c578161268e565b835b6007546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291925073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156126fb57600080fd5b505af115801561270f573d6000803e3d6000fd5b505050505050505050505b6127248383612950565b505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805483929061275e908490612cc3565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016122d1565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610aed565b81156127245761272473ffffffffffffffffffffffffffffffffffffffff841682846127b7565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612035576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610aed565b6040517f441a3e7000000000000000000000000000000000000000000000000000000000815260006004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063441a3e70906044016123b4565b600060208083528351808285015260005b818110156129f7578581018301518582016040015282016129db565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600060208284031215612a4857600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114612a7157600080fd5b50565b60008060408385031215612a8757600080fd5b8235612a9281612a4f565b946020939093013593505050565b600060208284031215612ab257600080fd5b81356109cf81612a4f565b600080600060608486031215612ad257600080fd5b8335612add81612a4f565b92506020840135612aed81612a4f565b929592945050506040919091013590565b60008060408385031215612b1157600080fd5b823591506020830135612b2381612a4f565b809150509250929050565b600080600060608486031215612b4357600080fd5b833592506020840135612b5581612a4f565b91506040840135612b6581612a4f565b809150509250925092565b600080600080600080600060e0888a031215612b8b57600080fd5b8735612b9681612a4f565b96506020880135612ba681612a4f565b95506040880135945060608801359350608088013560ff81168114612bca57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215612bfa57600080fd5b8235612c0581612a4f565b91506020830135612b2381612a4f565b600060208284031215612c2757600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610a4a57610a4a612c2e565b600181811c90821680612c8457607f821691505b602082108103612cbd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b81810381811115610a4a57610a4a612c2e565b600060208284031215612ce857600080fd5b81516109cf81612a4f565b600060408284031215612d0557600080fd5b6040516040810181811067ffffffffffffffff82111715612d4f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528251612d5d81612a4f565b81526020928301519281019290925250919050565b600080835481600182811c915080831680612d8e57607f831692505b60208084108203612dc6577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b818015612dda5760018114612e0d57612e3a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952841515850289019650612e3a565b60008a81526020902060005b86811015612e325781548b820152908501908301612e19565b505084890196505b50949897505050505050505056fea26469706673582212205b2ec9951b3f843925558c2e058c3dd16626e97babb9bf6e691e03b57940817164736f6c63430008100033a2646970667358221220081ef3243f788f78811b2742967facb5f95f625a0f11b38820bbf1c5bba274c164736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d30000000000000000000000003520d5a913427e6f0d6a83e07ccd4a4da316e4d3000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c43000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
-----Decoded View---------------
Arg [0] : euler_ (address): 0x27182842E098f60e3D576794A5bFFb0777E025d3
Arg [1] : markets_ (address): 0x3520d5a913427E6F0D6A83E07ccD4A4da316e4d3
Arg [2] : rewardsDistribution_ (address): 0xA9839D52E964d0ed0d6D546c27D2248Fac610c43
Arg [3] : owner_ (address): 0xEC864BE26084ba3bbF3cAAcF8F6961A9263319C4
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d3
Arg [1] : 0000000000000000000000003520d5a913427e6f0d6a83e07ccd4a4da316e4d3
Arg [2] : 000000000000000000000000a9839d52e964d0ed0d6d546c27d2248fac610c43
Arg [3] : 000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
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.