Source Code
Overview
CELO Balance
0 CELO
More Info
ContractCreator
Multichain Info
N/A
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 26258201 | 77 days ago | IN | 0 CELO | 0.00129084 |
Latest 24 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
29303234 | 35 days ago | 0 CELO | ||||
29303234 | 35 days ago | 0 CELO | ||||
29303234 | 35 days ago | 0 CELO | ||||
29303234 | 35 days ago | 0 CELO | ||||
29303234 | 35 days ago | 0 CELO | ||||
29303131 | 35 days ago | 0 CELO | ||||
29303131 | 35 days ago | 0 CELO | ||||
29303131 | 35 days ago | 0 CELO | ||||
29303131 | 35 days ago | 0 CELO | ||||
29303131 | 35 days ago | 0 CELO | ||||
29303131 | 35 days ago | 0 CELO | ||||
29303131 | 35 days ago | 0 CELO | ||||
29301614 | 36 days ago | 0 CELO | ||||
29301614 | 36 days ago | 0 CELO | ||||
29301614 | 36 days ago | 0 CELO | ||||
29301614 | 36 days ago | 0 CELO | ||||
29301614 | 36 days ago | 0 CELO | ||||
29301614 | 36 days ago | 0 CELO | ||||
29301614 | 36 days ago | 0 CELO | ||||
26939104 | 63 days ago | 0 CELO | ||||
26764892 | 65 days ago | 0 CELO | ||||
26259197 | 77 days ago | 0 CELO | ||||
26259196 | 77 days ago | 0 CELO | ||||
26259062 | 77 days ago | 0 CELO |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
BurnMintTokenPool
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 26000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol"; import {TokenPool} from "./TokenPool.sol"; /// @notice This pool mints and burns a 3rd-party token. /// @dev Pool whitelisting mode is set in the constructor and cannot be modified later. /// It either accepts any address as originalSender, or only accepts whitelisted originalSender. /// The only way to change whitelisting mode is to deploy a new pool. /// If that is expected, please make sure the token's burner/minter roles are adjustable. /// @dev This contract is a variant of BurnMintTokenPool that uses `burn(amount)`. contract BurnMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersion { string public constant override typeAndVersion = "BurnMintTokenPool 1.5.0"; constructor( IBurnMintERC20 token, address[] memory allowlist, address rmnProxy, address router ) TokenPool(token, allowlist, rmnProxy, router) {} /// @inheritdoc BurnMintTokenPoolAbstract function _burn(uint256 amount) internal virtual override { IBurnMintERC20(address(i_token)).burn(amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ITypeAndVersion { function typeAndVersion() external pure returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; interface IBurnMintERC20 is IERC20 { /// @notice Mints new tokens for a given address. /// @param account The address to mint the new tokens to. /// @param amount The number of tokens to be minted. /// @dev this function increases the total supply. function mint(address account, uint256 amount) external; /// @notice Burns tokens from the sender. /// @param amount The number of tokens to be burned. /// @dev this function decreases the total supply. function burn(uint256 amount) external; /// @notice Burns tokens from a given address.. /// @param account The address to burn tokens from. /// @param amount The number of tokens to be burned. /// @dev this function decreases the total supply. function burn(address account, uint256 amount) external; /// @notice Burns tokens from a given address.. /// @param account The address to burn tokens from. /// @param amount The number of tokens to be burned. /// @dev this function decreases the total supply. function burnFrom(address account, uint256 amount) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; import {Pool} from "../libraries/Pool.sol"; import {TokenPool} from "./TokenPool.sol"; abstract contract BurnMintTokenPoolAbstract is TokenPool { /// @notice Contains the specific burn call for a pool. /// @dev overriding this method allows us to create pools with different burn signatures /// without duplicating the underlying logic. function _burn(uint256 amount) internal virtual; /// @notice Burn the token in the pool /// @dev The _validateLockOrBurn check is an essential security check function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn) external virtual override returns (Pool.LockOrBurnOutV1 memory) { _validateLockOrBurn(lockOrBurnIn); _burn(lockOrBurnIn.amount); emit Burned(msg.sender, lockOrBurnIn.amount); return Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""}); } /// @notice Mint tokens from the pool to the recipient /// @dev The _validateReleaseOrMint check is an essential security check function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn) external virtual override returns (Pool.ReleaseOrMintOutV1 memory) { _validateReleaseOrMint(releaseOrMintIn); // Mint to the receiver IBurnMintERC20(address(i_token)).mint(releaseOrMintIn.receiver, releaseOrMintIn.amount); emit Minted(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount); return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount}); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {IPoolV1} from "../interfaces/IPool.sol"; import {IRMN} from "../interfaces/IRMN.sol"; import {IRouter} from "../interfaces/IRouter.sol"; import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol"; import {Pool} from "../libraries/Pool.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol"; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableSet.sol"; /// @notice Base abstract class with common functions for all token pools. /// A token pool serves as isolated place for holding tokens and token specific logic /// that may execute as tokens move across the bridge. abstract contract TokenPool is IPoolV1, OwnerIsCreator { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; using RateLimiter for RateLimiter.TokenBucket; error CallerIsNotARampOnRouter(address caller); error ZeroAddressNotAllowed(); error SenderNotAllowed(address sender); error AllowListNotEnabled(); error NonExistentChain(uint64 remoteChainSelector); error ChainNotAllowed(uint64 remoteChainSelector); error CursedByRMN(); error ChainAlreadyExists(uint64 chainSelector); error InvalidSourcePoolAddress(bytes sourcePoolAddress); error InvalidToken(address token); error Unauthorized(address caller); event Locked(address indexed sender, uint256 amount); event Burned(address indexed sender, uint256 amount); event Released(address indexed sender, address indexed recipient, uint256 amount); event Minted(address indexed sender, address indexed recipient, uint256 amount); event ChainAdded( uint64 remoteChainSelector, bytes remoteToken, RateLimiter.Config outboundRateLimiterConfig, RateLimiter.Config inboundRateLimiterConfig ); event ChainConfigured( uint64 remoteChainSelector, RateLimiter.Config outboundRateLimiterConfig, RateLimiter.Config inboundRateLimiterConfig ); event ChainRemoved(uint64 remoteChainSelector); event RemotePoolSet(uint64 indexed remoteChainSelector, bytes previousPoolAddress, bytes remotePoolAddress); event AllowListAdd(address sender); event AllowListRemove(address sender); event RouterUpdated(address oldRouter, address newRouter); struct ChainUpdate { uint64 remoteChainSelector; // ──╮ Remote chain selector bool allowed; // ────────────────╯ Whether the chain should be enabled bytes remotePoolAddress; // Address of the remote pool, ABI encoded in the case of a remove EVM chain. bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain. RateLimiter.Config outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain RateLimiter.Config inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain } struct RemoteChainConfig { RateLimiter.TokenBucket outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain RateLimiter.TokenBucket inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain bytes remotePoolAddress; // Address of the remote pool, ABI encoded in the case of a remote EVM chain. bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain. } /// @dev The bridgeable token that is managed by this pool. IERC20 internal immutable i_token; /// @dev The address of the RMN proxy address internal immutable i_rmnProxy; /// @dev The immutable flag that indicates if the pool is access-controlled. bool internal immutable i_allowlistEnabled; /// @dev A set of addresses allowed to trigger lockOrBurn as original senders. /// Only takes effect if i_allowlistEnabled is true. /// This can be used to ensure only token-issuer specified addresses can /// move tokens. EnumerableSet.AddressSet internal s_allowList; /// @dev The address of the router IRouter internal s_router; /// @dev A set of allowed chain selectors. We want the allowlist to be enumerable to /// be able to quickly determine (without parsing logs) who can access the pool. /// @dev The chain selectors are in uint256 format because of the EnumerableSet implementation. EnumerableSet.UintSet internal s_remoteChainSelectors; mapping(uint64 remoteChainSelector => RemoteChainConfig) internal s_remoteChainConfigs; /// @notice The address of the rate limiter admin. /// @dev Can be address(0) if none is configured. address internal s_rateLimitAdmin; constructor(IERC20 token, address[] memory allowlist, address rmnProxy, address router) { if (address(token) == address(0) || router == address(0) || rmnProxy == address(0)) revert ZeroAddressNotAllowed(); i_token = token; i_rmnProxy = rmnProxy; s_router = IRouter(router); // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas. i_allowlistEnabled = allowlist.length > 0; if (i_allowlistEnabled) { _applyAllowListUpdates(new address[](0), allowlist); } } /// @notice Get RMN proxy address /// @return rmnProxy Address of RMN proxy function getRmnProxy() public view returns (address rmnProxy) { return i_rmnProxy; } /// @inheritdoc IPoolV1 function isSupportedToken(address token) public view virtual returns (bool) { return token == address(i_token); } /// @notice Gets the IERC20 token that this pool can lock or burn. /// @return token The IERC20 token representation. function getToken() public view returns (IERC20 token) { return i_token; } /// @notice Gets the pool's Router /// @return router The pool's Router function getRouter() public view returns (address router) { return address(s_router); } /// @notice Sets the pool's Router /// @param newRouter The new Router function setRouter(address newRouter) public onlyOwner { if (newRouter == address(0)) revert ZeroAddressNotAllowed(); address oldRouter = address(s_router); s_router = IRouter(newRouter); emit RouterUpdated(oldRouter, newRouter); } /// @notice Signals which version of the pool interface is supported function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { return interfaceId == Pool.CCIP_POOL_V1 || interfaceId == type(IPoolV1).interfaceId || interfaceId == type(IERC165).interfaceId; } // ================================================================ // │ Validation │ // ================================================================ /// @notice Validates the lock or burn input for correctness on /// - token to be locked or burned /// - RMN curse status /// - allowlist status /// - if the sender is a valid onRamp /// - rate limit status /// @param lockOrBurnIn The input to validate. /// @dev This function should always be called before executing a lock or burn. Not doing so would allow /// for various exploits. function _validateLockOrBurn(Pool.LockOrBurnInV1 memory lockOrBurnIn) internal { if (!isSupportedToken(lockOrBurnIn.localToken)) revert InvalidToken(lockOrBurnIn.localToken); if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(lockOrBurnIn.remoteChainSelector)))) revert CursedByRMN(); _checkAllowList(lockOrBurnIn.originalSender); _onlyOnRamp(lockOrBurnIn.remoteChainSelector); _consumeOutboundRateLimit(lockOrBurnIn.remoteChainSelector, lockOrBurnIn.amount); } /// @notice Validates the release or mint input for correctness on /// - token to be released or minted /// - RMN curse status /// - if the sender is a valid offRamp /// - if the source pool is valid /// - rate limit status /// @param releaseOrMintIn The input to validate. /// @dev This function should always be called before executing a release or mint. Not doing so would allow /// for various exploits. function _validateReleaseOrMint(Pool.ReleaseOrMintInV1 memory releaseOrMintIn) internal { if (!isSupportedToken(releaseOrMintIn.localToken)) revert InvalidToken(releaseOrMintIn.localToken); if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(releaseOrMintIn.remoteChainSelector)))) revert CursedByRMN(); _onlyOffRamp(releaseOrMintIn.remoteChainSelector); // Validates that the source pool address is configured on this pool. bytes memory configuredRemotePool = getRemotePool(releaseOrMintIn.remoteChainSelector); if ( configuredRemotePool.length == 0 || keccak256(releaseOrMintIn.sourcePoolAddress) != keccak256(configuredRemotePool) ) { revert InvalidSourcePoolAddress(releaseOrMintIn.sourcePoolAddress); } _consumeInboundRateLimit(releaseOrMintIn.remoteChainSelector, releaseOrMintIn.amount); } // ================================================================ // │ Chain permissions │ // ================================================================ /// @notice Gets the pool address on the remote chain. /// @param remoteChainSelector Remote chain selector. /// @dev To support non-evm chains, this value is encoded into bytes function getRemotePool(uint64 remoteChainSelector) public view returns (bytes memory) { return s_remoteChainConfigs[remoteChainSelector].remotePoolAddress; } /// @notice Gets the token address on the remote chain. /// @param remoteChainSelector Remote chain selector. /// @dev To support non-evm chains, this value is encoded into bytes function getRemoteToken(uint64 remoteChainSelector) public view returns (bytes memory) { return s_remoteChainConfigs[remoteChainSelector].remoteTokenAddress; } /// @notice Sets the remote pool address for a given chain selector. /// @param remoteChainSelector The remote chain selector for which the remote pool address is being set. /// @param remotePoolAddress The address of the remote pool. function setRemotePool(uint64 remoteChainSelector, bytes calldata remotePoolAddress) external onlyOwner { if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector); bytes memory prevAddress = s_remoteChainConfigs[remoteChainSelector].remotePoolAddress; s_remoteChainConfigs[remoteChainSelector].remotePoolAddress = remotePoolAddress; emit RemotePoolSet(remoteChainSelector, prevAddress, remotePoolAddress); } /// @inheritdoc IPoolV1 function isSupportedChain(uint64 remoteChainSelector) public view returns (bool) { return s_remoteChainSelectors.contains(remoteChainSelector); } /// @notice Get list of allowed chains /// @return list of chains. function getSupportedChains() public view returns (uint64[] memory) { uint256[] memory uint256ChainSelectors = s_remoteChainSelectors.values(); uint64[] memory chainSelectors = new uint64[](uint256ChainSelectors.length); for (uint256 i = 0; i < uint256ChainSelectors.length; ++i) { chainSelectors[i] = uint64(uint256ChainSelectors[i]); } return chainSelectors; } /// @notice Sets the permissions for a list of chains selectors. Actual senders for these chains /// need to be allowed on the Router to interact with this pool. /// @dev Only callable by the owner /// @param chains A list of chains and their new permission status & rate limits. Rate limits /// are only used when the chain is being added through `allowed` being true. function applyChainUpdates(ChainUpdate[] calldata chains) external virtual onlyOwner { for (uint256 i = 0; i < chains.length; ++i) { ChainUpdate memory update = chains[i]; RateLimiter._validateTokenBucketConfig(update.outboundRateLimiterConfig, !update.allowed); RateLimiter._validateTokenBucketConfig(update.inboundRateLimiterConfig, !update.allowed); if (update.allowed) { // If the chain already exists, revert if (!s_remoteChainSelectors.add(update.remoteChainSelector)) { revert ChainAlreadyExists(update.remoteChainSelector); } if (update.remotePoolAddress.length == 0 || update.remoteTokenAddress.length == 0) { revert ZeroAddressNotAllowed(); } s_remoteChainConfigs[update.remoteChainSelector] = RemoteChainConfig({ outboundRateLimiterConfig: RateLimiter.TokenBucket({ rate: update.outboundRateLimiterConfig.rate, capacity: update.outboundRateLimiterConfig.capacity, tokens: update.outboundRateLimiterConfig.capacity, lastUpdated: uint32(block.timestamp), isEnabled: update.outboundRateLimiterConfig.isEnabled }), inboundRateLimiterConfig: RateLimiter.TokenBucket({ rate: update.inboundRateLimiterConfig.rate, capacity: update.inboundRateLimiterConfig.capacity, tokens: update.inboundRateLimiterConfig.capacity, lastUpdated: uint32(block.timestamp), isEnabled: update.inboundRateLimiterConfig.isEnabled }), remotePoolAddress: update.remotePoolAddress, remoteTokenAddress: update.remoteTokenAddress }); emit ChainAdded( update.remoteChainSelector, update.remoteTokenAddress, update.outboundRateLimiterConfig, update.inboundRateLimiterConfig ); } else { // If the chain doesn't exist, revert if (!s_remoteChainSelectors.remove(update.remoteChainSelector)) { revert NonExistentChain(update.remoteChainSelector); } delete s_remoteChainConfigs[update.remoteChainSelector]; emit ChainRemoved(update.remoteChainSelector); } } } // ================================================================ // │ Rate limiting │ // ================================================================ /// @notice Sets the rate limiter admin address. /// @dev Only callable by the owner. /// @param rateLimitAdmin The new rate limiter admin address. function setRateLimitAdmin(address rateLimitAdmin) external onlyOwner { s_rateLimitAdmin = rateLimitAdmin; } /// @notice Gets the rate limiter admin address. function getRateLimitAdmin() external view returns (address) { return s_rateLimitAdmin; } /// @notice Consumes outbound rate limiting capacity in this pool function _consumeOutboundRateLimit(uint64 remoteChainSelector, uint256 amount) internal { s_remoteChainConfigs[remoteChainSelector].outboundRateLimiterConfig._consume(amount, address(i_token)); } /// @notice Consumes inbound rate limiting capacity in this pool function _consumeInboundRateLimit(uint64 remoteChainSelector, uint256 amount) internal { s_remoteChainConfigs[remoteChainSelector].inboundRateLimiterConfig._consume(amount, address(i_token)); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function getCurrentOutboundRateLimiterState(uint64 remoteChainSelector) external view returns (RateLimiter.TokenBucket memory) { return s_remoteChainConfigs[remoteChainSelector].outboundRateLimiterConfig._currentTokenBucketState(); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function getCurrentInboundRateLimiterState(uint64 remoteChainSelector) external view returns (RateLimiter.TokenBucket memory) { return s_remoteChainConfigs[remoteChainSelector].inboundRateLimiterConfig._currentTokenBucketState(); } /// @notice Sets the chain rate limiter config. /// @param remoteChainSelector The remote chain selector for which the rate limits apply. /// @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain. /// @param inboundConfig The new inbound rate limiter config, meaning the offRamp rate limits for the given chain. function setChainRateLimiterConfig( uint64 remoteChainSelector, RateLimiter.Config memory outboundConfig, RateLimiter.Config memory inboundConfig ) external { if (msg.sender != s_rateLimitAdmin && msg.sender != owner()) revert Unauthorized(msg.sender); _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig); } function _setRateLimitConfig( uint64 remoteChainSelector, RateLimiter.Config memory outboundConfig, RateLimiter.Config memory inboundConfig ) internal { if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector); RateLimiter._validateTokenBucketConfig(outboundConfig, false); s_remoteChainConfigs[remoteChainSelector].outboundRateLimiterConfig._setTokenBucketConfig(outboundConfig); RateLimiter._validateTokenBucketConfig(inboundConfig, false); s_remoteChainConfigs[remoteChainSelector].inboundRateLimiterConfig._setTokenBucketConfig(inboundConfig); emit ChainConfigured(remoteChainSelector, outboundConfig, inboundConfig); } // ================================================================ // │ Access │ // ================================================================ /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender /// is a permissioned onRamp for the given chain on the Router. function _onlyOnRamp(uint64 remoteChainSelector) internal view { if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector); if (!(msg.sender == s_router.getOnRamp(remoteChainSelector))) revert CallerIsNotARampOnRouter(msg.sender); } /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender /// is a permissioned offRamp for the given chain on the Router. function _onlyOffRamp(uint64 remoteChainSelector) internal view { if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector); if (!s_router.isOffRamp(remoteChainSelector, msg.sender)) revert CallerIsNotARampOnRouter(msg.sender); } // ================================================================ // │ Allowlist │ // ================================================================ function _checkAllowList(address sender) internal view { if (i_allowlistEnabled) { if (!s_allowList.contains(sender)) { revert SenderNotAllowed(sender); } } } /// @notice Gets whether the allowList functionality is enabled. /// @return true is enabled, false if not. function getAllowListEnabled() external view returns (bool) { return i_allowlistEnabled; } /// @notice Gets the allowed addresses. /// @return The allowed addresses. function getAllowList() external view returns (address[] memory) { return s_allowList.values(); } /// @notice Apply updates to the allow list. /// @param removes The addresses to be removed. /// @param adds The addresses to be added. function applyAllowListUpdates(address[] calldata removes, address[] calldata adds) external onlyOwner { _applyAllowListUpdates(removes, adds); } /// @notice Internal version of applyAllowListUpdates to allow for reuse in the constructor. function _applyAllowListUpdates(address[] memory removes, address[] memory adds) internal { if (!i_allowlistEnabled) revert AllowListNotEnabled(); for (uint256 i = 0; i < removes.length; ++i) { address toRemove = removes[i]; if (s_allowList.remove(toRemove)) { emit AllowListRemove(toRemove); } } for (uint256 i = 0; i < adds.length; ++i) { address toAdd = adds[i]; if (toAdd == address(0)) { continue; } if (s_allowList.add(toAdd)) { emit AllowListAdd(toAdd); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice This library contains various token pool functions to aid constructing the return data. library Pool { // The tag used to signal support for the pool v1 standard // bytes4(keccak256("CCIP_POOL_V1")) bytes4 public constant CCIP_POOL_V1 = 0xaff2afbf; // The number of bytes in the return data for a pool v1 releaseOrMint call. // This should match the size of the ReleaseOrMintOutV1 struct. uint16 public constant CCIP_POOL_V1_RET_BYTES = 32; // The default max number of bytes in the return data for a pool v1 lockOrBurn call. // This data can be used to send information to the destination chain token pool. Can be overwritten // in the TokenTransferFeeConfig.destBytesOverhead if more data is required. uint32 public constant CCIP_LOCK_OR_BURN_V1_RET_BYTES = 32; struct LockOrBurnInV1 { bytes receiver; // The recipient of the tokens on the destination chain, abi encoded uint64 remoteChainSelector; // ─╮ The chain ID of the destination chain address originalSender; // ─────╯ The original sender of the tx on the source chain uint256 amount; // The amount of tokens to lock or burn, denominated in the source token's decimals address localToken; // The address on this chain of the token to lock or burn } struct LockOrBurnOutV1 { // The address of the destination token, abi encoded in the case of EVM chains // This value is UNTRUSTED as any pool owner can return whatever value they want. bytes destTokenAddress; // Optional pool data to be transferred to the destination chain. Be default this is capped at // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead // has to be set for the specific token. bytes destPoolData; } struct ReleaseOrMintInV1 { bytes originalSender; // The original sender of the tx on the source chain uint64 remoteChainSelector; // ─╮ The chain ID of the source chain address receiver; // ───────────╯ The recipient of the tokens on the destination chain. uint256 amount; // The amount of tokens to release or mint, denominated in the source token's decimals address localToken; // The address on this chain of the token to release or mint /// @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the /// expected pool address for the given remoteChainSelector. bytes sourcePoolAddress; // The address of the source pool, abi encoded in the case of EVM chains bytes sourcePoolData; // The data received from the source pool to process the release or mint /// @dev WARNING: offchainTokenData is untrusted data. bytes offchainTokenData; // The offchain data to process the release or mint } struct ReleaseOrMintOutV1 { // The number of tokens released or minted on the destination chain, denominated in the local token's decimals. // This value is expected to be equal to the ReleaseOrMintInV1.amount in the case where the source and destination // chain have the same number of decimals. uint256 destinationAmount; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Pool} from "../libraries/Pool.sol"; import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol"; /// @notice Shared public interface for multiple V1 pool types. /// Each pool type handles a different child token model (lock/unlock, mint/burn.) interface IPoolV1 is IERC165 { /// @notice Lock tokens into the pool or burn the tokens. /// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain. /// @return lockOrBurnOut Encoded data fields for the processing of tokens on the destination chain. function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn) external returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut); /// @notice Releases or mints tokens to the receiver address. /// @param releaseOrMintIn All data required to release or mint tokens. /// @return releaseOrMintOut The amount of tokens released or minted on the local chain, denominated /// in the local token's decimals. /// @dev The offramp asserts that the balanceOf of the receiver has been incremented by exactly the number /// of tokens that is returned in ReleaseOrMintOutV1.destinationAmount. If the amounts do not match, the tx reverts. function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn) external returns (Pool.ReleaseOrMintOutV1 memory); /// @notice Checks whether a remote chain is supported in the token pool. /// @param remoteChainSelector The selector of the remote chain. /// @return true if the given chain is a permissioned remote chain. function isSupportedChain(uint64 remoteChainSelector) external view returns (bool); /// @notice Returns if the token pool supports the given token. /// @param token The address of the token. /// @return true if the token is supported by the pool. function isSupportedToken(address token) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts. interface IRMN { /// @notice A Merkle root tagged with the address of the commit store contract it is destined for. struct TaggedRoot { address commitStore; bytes32 root; } /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed. function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool); /// @notice Iff there is an active global or legacy curse, this function returns true. function isCursed() external view returns (bool); /// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true. /// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)). function isCursed(bytes16 subject) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Client} from "../libraries/Client.sol"; interface IRouter { error OnlyOffRamp(); /// @notice Route the message to its intended receiver contract. /// @param message Client.Any2EVMMessage struct. /// @param gasForCallExactCheck of params for exec /// @param gasLimit set of params for exec /// @param receiver set of params for exec /// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165. /// the contract is called. If not, only tokens are transferred. /// @return success A boolean value indicating whether the ccip message was received without errors. /// @return retBytes A bytes array containing return data form CCIP receiver. /// @return gasUsed the gas used by the external customer call. Does not include any overhead. function routeMessage( Client.Any2EVMMessage calldata message, uint16 gasForCallExactCheck, uint256 gasLimit, address receiver ) external returns (bool success, bytes memory retBytes, uint256 gasUsed); /// @notice Returns the configured onramp for a specific destination chain. /// @param destChainSelector The destination chain Id to get the onRamp for. /// @return onRampAddress The address of the onRamp. function getOnRamp(uint64 destChainSelector) external view returns (address onRampAddress); /// @notice Return true if the given offRamp is a configured offRamp for the given source chain. /// @param sourceChainSelector The source chain selector to check. /// @param offRamp The address of the offRamp to check. function isOffRamp(uint64 sourceChainSelector, address offRamp) external view returns (bool isOffRamp); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ConfirmedOwner} from "./ConfirmedOwner.sol"; /// @title The OwnerIsCreator contract /// @notice A contract with helpers for basic contract ownership. contract OwnerIsCreator is ConfirmedOwner { constructor() ConfirmedOwner(msg.sender) {} }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// @notice Implements Token Bucket rate limiting. /// @dev uint128 is safe for rate limiter state. /// For USD value rate limiting, it can adequately store USD value in 18 decimals. /// For ERC20 token amount rate limiting, all tokens that will be listed will have at most /// a supply of uint128.max tokens, and it will therefore not overflow the bucket. /// In exceptional scenarios where tokens consumed may be larger than uint128, /// e.g. compromised issuer, an enabled RateLimiter will check and revert. library RateLimiter { error BucketOverfilled(); error OnlyCallableByAdminOrOwner(); error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress); error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress); error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested); error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available); error InvalidRateLimitRate(Config rateLimiterConfig); error DisabledNonZeroRateLimit(Config config); error RateLimitMustBeDisabled(); event TokensConsumed(uint256 tokens); event ConfigChanged(Config config); struct TokenBucket { uint128 tokens; // ──────╮ Current number of tokens that are in the bucket. uint32 lastUpdated; // │ Timestamp in seconds of the last token refill, good for 100+ years. bool isEnabled; // ──────╯ Indication whether the rate limiting is enabled or not uint128 capacity; // ────╮ Maximum number of tokens that can be in the bucket. uint128 rate; // ────────╯ Number of tokens per second that the bucket is refilled. } struct Config { bool isEnabled; // Indication whether the rate limiting should be enabled uint128 capacity; // ────╮ Specifies the capacity of the rate limiter uint128 rate; // ───────╯ Specifies the rate of the rate limiter } /// @notice _consume removes the given tokens from the pool, lowering the /// rate tokens allowed to be consumed for subsequent calls. /// @param requestTokens The total tokens to be consumed from the bucket. /// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity. /// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket /// @dev emits removal of requestTokens if requestTokens is > 0 function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal { // If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage if (!s_bucket.isEnabled || requestTokens == 0) { return; } uint256 tokens = s_bucket.tokens; uint256 capacity = s_bucket.capacity; uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { if (tokens > capacity) revert BucketOverfilled(); // Refill tokens when arriving at a new block time tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate); s_bucket.lastUpdated = uint32(block.timestamp); } if (capacity < requestTokens) { // Token address 0 indicates consuming aggregate value rate limit capacity. if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens); revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress); } if (tokens < requestTokens) { uint256 rate = s_bucket.rate; // Wait required until the bucket is refilled enough to accept this value, round up to next higher second // Consume is not guaranteed to succeed after wait time passes if there is competing traffic. // This acts as a lower bound of wait time. uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate; if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens); revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress); } tokens -= requestTokens; // Downcast is safe here, as tokens is not larger than capacity s_bucket.tokens = uint128(tokens); emit TokensConsumed(requestTokens); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function _currentTokenBucketState(TokenBucket memory bucket) internal view returns (TokenBucket memory) { // We update the bucket to reflect the status at the exact time of the // call. This means we might need to refill a part of the bucket based // on the time that has passed since the last update. bucket.tokens = uint128(_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate)); bucket.lastUpdated = uint32(block.timestamp); return bucket; } /// @notice Sets the rate limited config. /// @param s_bucket The token bucket /// @param config The new config function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal { // First update the bucket to make sure the proper rate is used for all the time // up until the config change. uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate)); s_bucket.lastUpdated = uint32(block.timestamp); } s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens)); s_bucket.isEnabled = config.isEnabled; s_bucket.capacity = config.capacity; s_bucket.rate = config.rate; emit ConfigChanged(config); } /// @notice Validates the token bucket config function _validateTokenBucketConfig(Config memory config, bool mustBeDisabled) internal pure { if (config.isEnabled) { if (config.rate >= config.capacity || config.rate == 0) { revert InvalidRateLimitRate(config); } if (mustBeDisabled) { revert RateLimitMustBeDisabled(); } } else { if (config.rate != 0 || config.capacity != 0) { revert DisabledNonZeroRateLimit(config); } } } /// @notice Calculate refilled tokens /// @param capacity bucket capacity /// @param tokens current bucket tokens /// @param timeDiff block time difference since last refill /// @param rate bucket refill rate /// @return the value of tokens after refill function _calculateRefill( uint256 capacity, uint256 tokens, uint256 timeDiff, uint256 rate ) private pure returns (uint256) { return _min(capacity, tokens + timeDiff * rate); } /// @notice Return the smallest of two integers /// @param a first int /// @param b second int /// @return smallest function _min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // End consumer library. library Client { /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct EVMTokenAmount { address token; // token address on the local chain. uint256 amount; // Amount of tokens. } struct Any2EVMMessage { bytes32 messageId; // MessageId corresponding to ccipSend on source. uint64 sourceChainSelector; // Source chain selector. bytes sender; // abi.decode(sender) if coming from an EVM chain. bytes data; // payload sent in original message. EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation. } // If extraArgs is empty bytes, the default is 200k gas limit. struct EVM2AnyMessage { bytes receiver; // abi.encode(receiver address) for dest EVM chains bytes data; // Data payload EVMTokenAmount[] tokenAmounts; // Token transfers address feeToken; // Address of feeToken. address(0) means you will send msg.value. bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2) } // bytes4(keccak256("CCIP EVMExtraArgsV1")); bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9; struct EVMExtraArgsV1 { uint256 gasLimit; } function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs); } // bytes4(keccak256("CCIP EVMExtraArgsV2")); bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10; /// @param gasLimit: gas limit for the callback on the destination chain. /// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender. /// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value /// is not set, the message request will revert. struct EVMExtraArgsV2 { uint256 gasLimit; bool allowOutOfOrderExecution; } function _argsToBytes(EVMExtraArgsV2 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol"; /// @title The ConfirmedOwner contract /// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwner is ConfirmedOwnerWithProposal { constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IOwnable} from "../interfaces/IOwnable.sol"; /// @title The ConfirmedOwner contract /// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwnerWithProposal is IOwnable { address private s_owner; address private s_pendingOwner; event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); constructor(address newOwner, address pendingOwner) { // solhint-disable-next-line gas-custom-errors require(newOwner != address(0), "Cannot set owner to zero"); s_owner = newOwner; if (pendingOwner != address(0)) { _transferOwnership(pendingOwner); } } /// @notice Allows an owner to begin transferring ownership to a new address. function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } /// @notice Allows an ownership transfer to be completed by the recipient. function acceptOwnership() external override { // solhint-disable-next-line gas-custom-errors require(msg.sender == s_pendingOwner, "Must be proposed owner"); address oldOwner = s_owner; s_owner = msg.sender; s_pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /// @notice Get the current owner function owner() public view override returns (address) { return s_owner; } /// @notice validate, transfer ownership, and emit relevant events function _transferOwnership(address to) private { // solhint-disable-next-line gas-custom-errors require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /// @notice validate access function _validateOwnership() internal view { // solhint-disable-next-line gas-custom-errors require(msg.sender == s_owner, "Only callable by owner"); } /// @notice Reverts if called by anyone other than the contract owner. modifier onlyOwner() { _validateOwnership(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOwnable { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; }
{ "remappings": [ "forge-std/=src/v0.8/vendor/forge-std/src/", "@openzeppelin/=node_modules/@openzeppelin/", "@arbitrum/=node_modules/@arbitrum/", "hardhat/=node_modules/hardhat/", "@eth-optimism/=node_modules/@eth-optimism/", "@scroll-tech/=node_modules/@scroll-tech/" ], "optimizer": { "enabled": true, "runs": 26000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
[{"inputs":[{"internalType":"contract IBurnMintERC20","name":"token","type":"address"},{"internalType":"address[]","name":"allowlist","type":"address[]"},{"internalType":"address","name":"rmnProxy","type":"address"},{"internalType":"address","name":"router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"AggregateValueMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"AggregateValueRateLimitReached","type":"error"},{"inputs":[],"name":"AllowListNotEnabled","type":"error"},{"inputs":[],"name":"BucketOverfilled","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotARampOnRouter","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"ChainAlreadyExists","type":"error"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"ChainNotAllowed","type":"error"},{"inputs":[],"name":"CursedByRMN","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"DisabledNonZeroRateLimit","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"name":"InvalidRateLimitRate","type":"error"},{"inputs":[{"internalType":"bytes","name":"sourcePoolAddress","type":"bytes"}],"name":"InvalidSourcePoolAddress","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"InvalidToken","type":"error"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"NonExistentChain","type":"error"},{"inputs":[],"name":"RateLimitMustBeDisabled","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenRateLimitReached","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"AllowListAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"AllowListRemove","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"remoteToken","type":"bytes"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"outboundRateLimiterConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"inboundRateLimiterConfig","type":"tuple"}],"name":"ChainAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"outboundRateLimiterConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"inboundRateLimiterConfig","type":"tuple"}],"name":"ChainConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"ChainRemoved","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"ConfigChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Released","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"previousPoolAddress","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"RemotePoolSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRouter","type":"address"},{"indexed":false,"internalType":"address","name":"newRouter","type":"address"}],"name":"RouterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"TokensConsumed","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"removes","type":"address[]"},{"internalType":"address[]","name":"adds","type":"address[]"}],"name":"applyAllowListUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"bytes","name":"remotePoolAddress","type":"bytes"},{"internalType":"bytes","name":"remoteTokenAddress","type":"bytes"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"outboundRateLimiterConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"inboundRateLimiterConfig","type":"tuple"}],"internalType":"struct TokenPool.ChainUpdate[]","name":"chains","type":"tuple[]"}],"name":"applyChainUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllowList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowListEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getCurrentInboundRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getCurrentOutboundRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRateLimitAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getRemotePool","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getRemoteToken","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRmnProxy","outputs":[{"internalType":"address","name":"rmnProxy","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouter","outputs":[{"internalType":"address","name":"router","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedChains","outputs":[{"internalType":"uint64[]","name":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getToken","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"isSupportedChain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isSupportedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"receiver","type":"bytes"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"originalSender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"localToken","type":"address"}],"internalType":"struct Pool.LockOrBurnInV1","name":"lockOrBurnIn","type":"tuple"}],"name":"lockOrBurn","outputs":[{"components":[{"internalType":"bytes","name":"destTokenAddress","type":"bytes"},{"internalType":"bytes","name":"destPoolData","type":"bytes"}],"internalType":"struct Pool.LockOrBurnOutV1","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"originalSender","type":"bytes"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"localToken","type":"address"},{"internalType":"bytes","name":"sourcePoolAddress","type":"bytes"},{"internalType":"bytes","name":"sourcePoolData","type":"bytes"},{"internalType":"bytes","name":"offchainTokenData","type":"bytes"}],"internalType":"struct Pool.ReleaseOrMintInV1","name":"releaseOrMintIn","type":"tuple"}],"name":"releaseOrMint","outputs":[{"components":[{"internalType":"uint256","name":"destinationAmount","type":"uint256"}],"internalType":"struct Pool.ReleaseOrMintOutV1","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"outboundConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"inboundConfig","type":"tuple"}],"name":"setChainRateLimiterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rateLimitAdmin","type":"address"}],"name":"setRateLimitAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"setRemotePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRouter","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b50604051620040b3380380620040b383398101604081905262000034916200054c565b8383838333806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000176565b5050506001600160a01b0384161580620000e357506001600160a01b038116155b80620000f657506001600160a01b038216155b1562000115576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c052620001685760408051600081526020810190915262000168908462000221565b5050505050505050620006aa565b336001600160a01b03821603620001d05760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c05162000242576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002cd5760008382815181106200026657620002666200065c565b60209081029190910101519050620002806002826200037e565b15620002c3576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5060010162000245565b5060005b815181101562000379576000828281518110620002f257620002f26200065c565b6020026020010151905060006001600160a01b0316816001600160a01b0316036200031e575062000370565b6200032b6002826200039e565b156200036e576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101620002d1565b505050565b600062000395836001600160a01b038416620003b5565b90505b92915050565b600062000395836001600160a01b038416620004b9565b60008181526001830160205260408120548015620004ae576000620003dc60018362000672565b8554909150600090620003f29060019062000672565b90508082146200045e5760008660000182815481106200041657620004166200065c565b90600052602060002001549050808760000184815481106200043c576200043c6200065c565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000472576200047262000694565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000398565b600091505062000398565b6000818152600183016020526040812054620005025750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000398565b50600062000398565b6001600160a01b03811681146200052157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b805162000547816200050b565b919050565b600080600080608085870312156200056357600080fd5b845162000570816200050b565b602086810151919550906001600160401b03808211156200059057600080fd5b818801915088601f830112620005a557600080fd5b815181811115620005ba57620005ba62000524565b8060051b604051601f19603f83011681018181108582111715620005e257620005e262000524565b60405291825284820192508381018501918b8311156200060157600080fd5b938501935b828510156200062a576200061a856200053a565b8452938501939285019262000606565b80985050505050505062000641604086016200053a565b915062000651606086016200053a565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b818103818111156200039857634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05161398c62000727600039600081816104dd0152818161177701526121550152600081816104b7015281816115a80152611a2d0152600081816102390152818161028e015281816106e0015281816114c80152818161194d01528181611b3f015281816120eb0152612340015261398c6000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639a4575b9116100ee578063c4bffe2b11610097578063db6327dc11610071578063db6327dc146104a2578063dc0bd971146104b5578063e0351e13146104db578063f2fde38b1461050157600080fd5b8063c4bffe2b14610467578063c75eea9c1461047c578063cf7401f31461048f57600080fd5b8063b0f479a1116100c8578063b0f479a114610423578063b794658014610441578063c0d786551461045457600080fd5b80639a4575b91461037f578063a7cd63b71461039f578063af58d59f146103b457600080fd5b806354c8a4f31161015b57806379ba50971161013557806379ba5097146103335780637d54534e1461033b5780638926f54f1461034e5780638da5cb5b1461036157600080fd5b806354c8a4f3146102ed5780636d3d1a581461030257806378a010b21461032057600080fd5b806321df0da71161018c57806321df0da714610237578063240028e81461027e57806339077537146102cb57600080fd5b806301ffc9a7146101b35780630a2fd493146101db578063181f5a77146101fb575b600080fd5b6101c66101c1366004612ae3565b610514565b60405190151581526020015b60405180910390f35b6101ee6101e9366004612b42565b6105f9565b6040516101d29190612bc1565b6101ee6040518060400160405280601781526020017f4275726e4d696e74546f6b656e506f6f6c20312e352e3000000000000000000081525081565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b6101c661028c366004612c01565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b6102de6102d9366004612c1e565b6106a9565b604051905181526020016101d2565b6103006102fb366004612ca6565b61082f565b005b60085473ffffffffffffffffffffffffffffffffffffffff16610259565b61030061032e366004612d12565b6108aa565b610300610a1e565b610300610349366004612c01565b610b1b565b6101c661035c366004612b42565b610b6a565b60005473ffffffffffffffffffffffffffffffffffffffff16610259565b61039261038d366004612d95565b610b81565b6040516101d29190612dd0565b6103a7610c28565b6040516101d29190612e30565b6103c76103c2366004612b42565b610c39565b6040516101d2919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610259565b6101ee61044f366004612b42565b610d0e565b610300610462366004612c01565b610d39565b61046f610e14565b6040516101d29190612e8a565b6103c761048a366004612b42565b610ecc565b61030061049d366004612ff2565b610f9e565b6103006104b0366004613037565b611027565b7f0000000000000000000000000000000000000000000000000000000000000000610259565b7f00000000000000000000000000000000000000000000000000000000000000006101c6565b61030061050f366004612c01565b6114ad565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf0000000000000000000000000000000000000000000000000000000014806105a757507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b806105f357507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b67ffffffffffffffff8116600090815260076020526040902060040180546060919061062490613079565b80601f016020809104026020016040519081016040528092919081815260200182805461065090613079565b801561069d5780601f106106725761010080835404028352916020019161069d565b820191906000526020600020905b81548152906001019060200180831161068057829003601f168201915b50505050509050919050565b6040805160208101909152600081526106c96106c483613177565b6114c1565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166340c10f196107156060850160408601612c01565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260608501356024820152604401600060405180830381600087803b15801561078557600080fd5b505af1158015610799573d6000803e3d6000fd5b506107ae925050506060830160408401612c01565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0846060013560405161081091815260200190565b60405180910390a3506040805160208101909152606090910135815290565b6108376116f2565b6108a48484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061177592505050565b50505050565b6108b26116f2565b6108bb83610b6a565b610902576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b67ffffffffffffffff83166000908152600760205260408120600401805461092990613079565b80601f016020809104026020016040519081016040528092919081815260200182805461095590613079565b80156109a25780601f10610977576101008083540402835291602001916109a2565b820191906000526020600020905b81548152906001019060200180831161098557829003601f168201915b5050505067ffffffffffffffff86166000908152600760205260409020919250506004016109d18385836132bc565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf828585604051610a10939291906133d6565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108f9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b236116f2565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006105f3600567ffffffffffffffff841661192b565b6040805180820190915260608082526020820152610ba6610ba18361343a565b611946565b610bb38260600135611b10565b6040516060830135815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a26040518060400160405280610c0d84602001602081019061044f9190612b42565b81526040805160208181019092526000815291015292915050565b6060610c346002611bb3565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260039091015480841660608301529190910490911660808201526105f390611bc0565b67ffffffffffffffff8116600090815260076020526040902060050180546060919061062490613079565b610d416116f2565b73ffffffffffffffffffffffffffffffffffffffff8116610d8e576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b60606000610e226005611bb3565b90506000815167ffffffffffffffff811115610e4057610e40612ecc565b604051908082528060200260200182016040528015610e69578160200160208202803683370190505b50905060005b8251811015610ec557828181518110610e8a57610e8a6134dc565b6020026020010151828281518110610ea457610ea46134dc565b67ffffffffffffffff90921660209283029190910190910152600101610e6f565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526105f390611bc0565b60085473ffffffffffffffffffffffffffffffffffffffff163314801590610fde575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611017576040517f8e4a23d60000000000000000000000000000000000000000000000000000000081523360048201526024016108f9565b611022838383611c72565b505050565b61102f6116f2565b60005b8181101561102257600083838381811061104e5761104e6134dc565b9050602002810190611060919061350b565b61106990613549565b905061107e8160800151826020015115611d5c565b6110918160a00151826020015115611d5c565b80602001511561138d5780516110b39060059067ffffffffffffffff16611e95565b6110f85780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108f9565b604081015151158061110d5750606081015151155b15611144576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c1790911696151502959095179098559081015194015193811693169091029190911760038201559151909190600482019061132590826135fd565b506060820151600582019061133a90826135fd565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c295506113809493929190613717565b60405180910390a16114a4565b80516113a59060059067ffffffffffffffff16611ea1565b6113ea5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108f9565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906114536004830182612a95565b611461600583016000612a95565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b50600101611032565b6114b56116f2565b6114be81611ead565b50565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146115565760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016108f9565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611604573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162891906137b0565b1561165f576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61166c8160200151611fa2565b600061167b82602001516105f9565b905080516000148061169f575080805190602001208260a001518051906020012014155b156116dc578160a001516040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016108f99190612bc1565b6116ee826020015183606001516120c8565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611773576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108f9565b565b7f00000000000000000000000000000000000000000000000000000000000000006117cc576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156118625760008382815181106117ec576117ec6134dc565b6020026020010151905061180a81600261210f90919063ffffffff16565b156118595760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506001016117cf565b5060005b8151811015611022576000828281518110611883576118836134dc565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036118c75750611923565b6118d2600282612131565b156119215760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611866565b600081815260018301602052604081205415155b9392505050565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146119db5760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016108f9565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611a89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aad91906137b0565b15611ae4576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611af18160400151612153565b611afe81602001516121d2565b6114be81602001518260600151612320565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906342966c6890602401600060405180830381600087803b158015611b9857600080fd5b505af1158015611bac573d6000803e3d6000fd5b5050505050565b6060600061193f83612364565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611c4e82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611c3291906137fc565b85608001516fffffffffffffffffffffffffffffffff166123bf565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b611c7b83610b6a565b611cbd576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024016108f9565b611cc8826000611d5c565b67ffffffffffffffff83166000908152600760205260409020611ceb90836123e9565b611cf6816000611d5c565b67ffffffffffffffff83166000908152600760205260409020611d1c90600201826123e9565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051611d4f9392919061380f565b60405180910390a1505050565b815115611e235781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580611db2575060408201516fffffffffffffffffffffffffffffffff16155b15611deb57816040517f8020d1240000000000000000000000000000000000000000000000000000000081526004016108f99190613892565b80156116ee576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff16151580611e5c575060208201516fffffffffffffffffffffffffffffffff1615155b156116ee57816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016108f99190613892565b600061193f838361258b565b600061193f83836125da565b3373ffffffffffffffffffffffffffffffffffffffff821603611f2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108f9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611fab81610b6a565b611fed576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016108f9565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa15801561206c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209091906137b0565b6114be576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016108f9565b67ffffffffffffffff821660009081526007602052604090206116ee90600201827f00000000000000000000000000000000000000000000000000000000000000006126cd565b600061193f8373ffffffffffffffffffffffffffffffffffffffff84166125da565b600061193f8373ffffffffffffffffffffffffffffffffffffffff841661258b565b7f0000000000000000000000000000000000000000000000000000000000000000156114be57612184600282612a50565b6114be576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016108f9565b6121db81610b6a565b61221d576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016108f9565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015612296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ba91906138ce565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146114be576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016108f9565b67ffffffffffffffff821660009081526007602052604090206116ee90827f00000000000000000000000000000000000000000000000000000000000000006126cd565b60608160000180548060200260200160405190810160405280929190818152602001828054801561069d57602002820191906000526020600020905b8154815260200190600101908083116123a05750505050509050919050565b60006123de856123cf84866138eb565b6123d99087613902565b612a7f565b90505b949350505050565b815460009061241290700100000000000000000000000000000000900463ffffffff16426137fc565b905080156124b4576001830154835461245a916fffffffffffffffffffffffffffffffff808216928116918591700100000000000000000000000000000000909104166123bf565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546124da916fffffffffffffffffffffffffffffffff9081169116612a7f565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990611d4f908490613892565b60008181526001830160205260408120546125d2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105f3565b5060006105f3565b600081815260018301602052604081205480156126c35760006125fe6001836137fc565b8554909150600090612612906001906137fc565b9050808214612677576000866000018281548110612632576126326134dc565b9060005260206000200154905080876000018481548110612655576126556134dc565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061268857612688613915565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105f3565b60009150506105f3565b825474010000000000000000000000000000000000000000900460ff1615806126f4575081155b156126fe57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061274490700100000000000000000000000000000000900463ffffffff16426137fc565b905080156128045781831115612786576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546127c09083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166123bf565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156128bb5773ffffffffffffffffffffffffffffffffffffffff8416612863576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016108f9565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016108f9565b848310156129ce5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906128ff90826137fc565b612909878a6137fc565b6129139190613902565b61291d9190613944565b905073ffffffffffffffffffffffffffffffffffffffff8616612976576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016108f9565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016108f9565b6129d885846137fc565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561193f565b6000818310612a8e578161193f565b5090919050565b508054612aa190613079565b6000825580601f10612ab1575050565b601f0160209004906000526020600020908101906114be91905b80821115612adf5760008155600101612acb565b5090565b600060208284031215612af557600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461193f57600080fd5b803567ffffffffffffffff81168114612b3d57600080fd5b919050565b600060208284031215612b5457600080fd5b61193f82612b25565b6000815180845260005b81811015612b8357602081850181015186830182015201612b67565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061193f6020830184612b5d565b73ffffffffffffffffffffffffffffffffffffffff811681146114be57600080fd5b8035612b3d81612bd4565b600060208284031215612c1357600080fd5b813561193f81612bd4565b600060208284031215612c3057600080fd5b813567ffffffffffffffff811115612c4757600080fd5b8201610100818503121561193f57600080fd5b60008083601f840112612c6c57600080fd5b50813567ffffffffffffffff811115612c8457600080fd5b6020830191508360208260051b8501011115612c9f57600080fd5b9250929050565b60008060008060408587031215612cbc57600080fd5b843567ffffffffffffffff80821115612cd457600080fd5b612ce088838901612c5a565b90965094506020870135915080821115612cf957600080fd5b50612d0687828801612c5a565b95989497509550505050565b600080600060408486031215612d2757600080fd5b612d3084612b25565b9250602084013567ffffffffffffffff80821115612d4d57600080fd5b818601915086601f830112612d6157600080fd5b813581811115612d7057600080fd5b876020828501011115612d8257600080fd5b6020830194508093505050509250925092565b600060208284031215612da757600080fd5b813567ffffffffffffffff811115612dbe57600080fd5b820160a0818503121561193f57600080fd5b602081526000825160406020840152612dec6060840182612b5d565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016040850152612e278282612b5d565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015612e7e57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612e4c565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612e7e57835167ffffffffffffffff1683529284019291840191600101612ea6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715612f1f57612f1f612ecc565b60405290565b60405160c0810167ffffffffffffffff81118282101715612f1f57612f1f612ecc565b80151581146114be57600080fd5b8035612b3d81612f48565b80356fffffffffffffffffffffffffffffffff81168114612b3d57600080fd5b600060608284031215612f9357600080fd5b6040516060810181811067ffffffffffffffff82111715612fb657612fb6612ecc565b6040529050808235612fc781612f48565b8152612fd560208401612f61565b6020820152612fe660408401612f61565b60408201525092915050565b600080600060e0848603121561300757600080fd5b61301084612b25565b925061301f8560208601612f81565b915061302e8560808601612f81565b90509250925092565b6000806020838503121561304a57600080fd5b823567ffffffffffffffff81111561306157600080fd5b61306d85828601612c5a565b90969095509350505050565b600181811c9082168061308d57607f821691505b6020821081036130c6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f8301126130dd57600080fd5b813567ffffffffffffffff808211156130f8576130f8612ecc565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561313e5761313e612ecc565b8160405283815286602085880101111561315757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000610100823603121561318a57600080fd5b613192612efb565b823567ffffffffffffffff808211156131aa57600080fd5b6131b6368387016130cc565b83526131c460208601612b25565b60208401526131d560408601612bf6565b6040840152606085013560608401526131f060808601612bf6565b608084015260a085013591508082111561320957600080fd5b613215368387016130cc565b60a084015260c085013591508082111561322e57600080fd5b61323a368387016130cc565b60c084015260e085013591508082111561325357600080fd5b50613260368286016130cc565b60e08301525092915050565b601f821115611022576000816000526020600020601f850160051c810160208610156132955750805b601f850160051c820191505b818110156132b4578281556001016132a1565b505050505050565b67ffffffffffffffff8311156132d4576132d4612ecc565b6132e8836132e28354613079565b8361326c565b6000601f84116001811461333a57600085156133045750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611bac565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156133895786850135825560209485019460019092019101613369565b50868210156133c4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b6040815260006133e96040830186612b5d565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060a0823603121561344c57600080fd5b60405160a0810167ffffffffffffffff828210818311171561347057613470612ecc565b81604052843591508082111561348557600080fd5b50613492368286016130cc565b8252506134a160208401612b25565b602082015260408301356134b481612bd4565b60408201526060838101359082015260808301356134d181612bd4565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec183360301811261353f57600080fd5b9190910192915050565b6000610140823603121561355c57600080fd5b613564612f25565b61356d83612b25565b815261357b60208401612f56565b6020820152604083013567ffffffffffffffff8082111561359b57600080fd5b6135a7368387016130cc565b604084015260608501359150808211156135c057600080fd5b506135cd368286016130cc565b6060830152506135e03660808501612f81565b60808201526135f23660e08501612f81565b60a082015292915050565b815167ffffffffffffffff81111561361757613617612ecc565b61362b816136258454613079565b8461326c565b602080601f83116001811461367e57600084156136485750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556132b4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156136cb578886015182559484019460019091019084016136ac565b508582101561370757878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff8716835280602084015261373b81840187612b5d565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff90811660608701529087015116608085015291506137799050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e0830152612e27565b6000602082840312156137c257600080fd5b815161193f81612f48565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105f3576105f36137cd565b67ffffffffffffffff8416815260e0810161385b60208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c08301526123e1565b606081016105f382848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b6000602082840312156138e057600080fd5b815161193f81612bd4565b80820281158282048414176105f3576105f36137cd565b808201808211156105f3576105f36137cd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008261397a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea164736f6c6343000818000a0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f00000000000000000000000000000000000000000000000000000000000000800000000000000000000000007a394c616a7347dc91c40159929e1c9a435cb83a000000000000000000000000b00e95b773528e2ea724db06b75113f239d15dca0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639a4575b9116100ee578063c4bffe2b11610097578063db6327dc11610071578063db6327dc146104a2578063dc0bd971146104b5578063e0351e13146104db578063f2fde38b1461050157600080fd5b8063c4bffe2b14610467578063c75eea9c1461047c578063cf7401f31461048f57600080fd5b8063b0f479a1116100c8578063b0f479a114610423578063b794658014610441578063c0d786551461045457600080fd5b80639a4575b91461037f578063a7cd63b71461039f578063af58d59f146103b457600080fd5b806354c8a4f31161015b57806379ba50971161013557806379ba5097146103335780637d54534e1461033b5780638926f54f1461034e5780638da5cb5b1461036157600080fd5b806354c8a4f3146102ed5780636d3d1a581461030257806378a010b21461032057600080fd5b806321df0da71161018c57806321df0da714610237578063240028e81461027e57806339077537146102cb57600080fd5b806301ffc9a7146101b35780630a2fd493146101db578063181f5a77146101fb575b600080fd5b6101c66101c1366004612ae3565b610514565b60405190151581526020015b60405180910390f35b6101ee6101e9366004612b42565b6105f9565b6040516101d29190612bc1565b6101ee6040518060400160405280601781526020017f4275726e4d696e74546f6b656e506f6f6c20312e352e3000000000000000000081525081565b7f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f5b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b6101c661028c366004612c01565b7f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f73ffffffffffffffffffffffffffffffffffffffff90811691161490565b6102de6102d9366004612c1e565b6106a9565b604051905181526020016101d2565b6103006102fb366004612ca6565b61082f565b005b60085473ffffffffffffffffffffffffffffffffffffffff16610259565b61030061032e366004612d12565b6108aa565b610300610a1e565b610300610349366004612c01565b610b1b565b6101c661035c366004612b42565b610b6a565b60005473ffffffffffffffffffffffffffffffffffffffff16610259565b61039261038d366004612d95565b610b81565b6040516101d29190612dd0565b6103a7610c28565b6040516101d29190612e30565b6103c76103c2366004612b42565b610c39565b6040516101d2919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610259565b6101ee61044f366004612b42565b610d0e565b610300610462366004612c01565b610d39565b61046f610e14565b6040516101d29190612e8a565b6103c761048a366004612b42565b610ecc565b61030061049d366004612ff2565b610f9e565b6103006104b0366004613037565b611027565b7f0000000000000000000000007a394c616a7347dc91c40159929e1c9a435cb83a610259565b7f00000000000000000000000000000000000000000000000000000000000000006101c6565b61030061050f366004612c01565b6114ad565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf0000000000000000000000000000000000000000000000000000000014806105a757507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b806105f357507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b67ffffffffffffffff8116600090815260076020526040902060040180546060919061062490613079565b80601f016020809104026020016040519081016040528092919081815260200182805461065090613079565b801561069d5780601f106106725761010080835404028352916020019161069d565b820191906000526020600020905b81548152906001019060200180831161068057829003601f168201915b50505050509050919050565b6040805160208101909152600081526106c96106c483613177565b6114c1565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f166340c10f196107156060850160408601612c01565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260608501356024820152604401600060405180830381600087803b15801561078557600080fd5b505af1158015610799573d6000803e3d6000fd5b506107ae925050506060830160408401612c01565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0846060013560405161081091815260200190565b60405180910390a3506040805160208101909152606090910135815290565b6108376116f2565b6108a48484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061177592505050565b50505050565b6108b26116f2565b6108bb83610b6a565b610902576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b67ffffffffffffffff83166000908152600760205260408120600401805461092990613079565b80601f016020809104026020016040519081016040528092919081815260200182805461095590613079565b80156109a25780601f10610977576101008083540402835291602001916109a2565b820191906000526020600020905b81548152906001019060200180831161098557829003601f168201915b5050505067ffffffffffffffff86166000908152600760205260409020919250506004016109d18385836132bc565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf828585604051610a10939291906133d6565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108f9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b236116f2565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006105f3600567ffffffffffffffff841661192b565b6040805180820190915260608082526020820152610ba6610ba18361343a565b611946565b610bb38260600135611b10565b6040516060830135815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a26040518060400160405280610c0d84602001602081019061044f9190612b42565b81526040805160208181019092526000815291015292915050565b6060610c346002611bb3565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260039091015480841660608301529190910490911660808201526105f390611bc0565b67ffffffffffffffff8116600090815260076020526040902060050180546060919061062490613079565b610d416116f2565b73ffffffffffffffffffffffffffffffffffffffff8116610d8e576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b60606000610e226005611bb3565b90506000815167ffffffffffffffff811115610e4057610e40612ecc565b604051908082528060200260200182016040528015610e69578160200160208202803683370190505b50905060005b8251811015610ec557828181518110610e8a57610e8a6134dc565b6020026020010151828281518110610ea457610ea46134dc565b67ffffffffffffffff90921660209283029190910190910152600101610e6f565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526105f390611bc0565b60085473ffffffffffffffffffffffffffffffffffffffff163314801590610fde575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611017576040517f8e4a23d60000000000000000000000000000000000000000000000000000000081523360048201526024016108f9565b611022838383611c72565b505050565b61102f6116f2565b60005b8181101561102257600083838381811061104e5761104e6134dc565b9050602002810190611060919061350b565b61106990613549565b905061107e8160800151826020015115611d5c565b6110918160a00151826020015115611d5c565b80602001511561138d5780516110b39060059067ffffffffffffffff16611e95565b6110f85780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108f9565b604081015151158061110d5750606081015151155b15611144576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c1790911696151502959095179098559081015194015193811693169091029190911760038201559151909190600482019061132590826135fd565b506060820151600582019061133a90826135fd565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c295506113809493929190613717565b60405180910390a16114a4565b80516113a59060059067ffffffffffffffff16611ea1565b6113ea5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108f9565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906114536004830182612a95565b611461600583016000612a95565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b50600101611032565b6114b56116f2565b6114be81611ead565b50565b60808101517f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f73ffffffffffffffffffffffffffffffffffffffff9081169116146115565760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016108f9565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f0000000000000000000000007a394c616a7347dc91c40159929e1c9a435cb83a73ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611604573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162891906137b0565b1561165f576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61166c8160200151611fa2565b600061167b82602001516105f9565b905080516000148061169f575080805190602001208260a001518051906020012014155b156116dc578160a001516040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016108f99190612bc1565b6116ee826020015183606001516120c8565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611773576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108f9565b565b7f00000000000000000000000000000000000000000000000000000000000000006117cc576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156118625760008382815181106117ec576117ec6134dc565b6020026020010151905061180a81600261210f90919063ffffffff16565b156118595760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506001016117cf565b5060005b8151811015611022576000828281518110611883576118836134dc565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036118c75750611923565b6118d2600282612131565b156119215760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611866565b600081815260018301602052604081205415155b9392505050565b60808101517f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f73ffffffffffffffffffffffffffffffffffffffff9081169116146119db5760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016108f9565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f0000000000000000000000007a394c616a7347dc91c40159929e1c9a435cb83a73ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611a89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aad91906137b0565b15611ae4576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611af18160400151612153565b611afe81602001516121d2565b6114be81602001518260600151612320565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f73ffffffffffffffffffffffffffffffffffffffff16906342966c6890602401600060405180830381600087803b158015611b9857600080fd5b505af1158015611bac573d6000803e3d6000fd5b5050505050565b6060600061193f83612364565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611c4e82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611c3291906137fc565b85608001516fffffffffffffffffffffffffffffffff166123bf565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b611c7b83610b6a565b611cbd576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024016108f9565b611cc8826000611d5c565b67ffffffffffffffff83166000908152600760205260409020611ceb90836123e9565b611cf6816000611d5c565b67ffffffffffffffff83166000908152600760205260409020611d1c90600201826123e9565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051611d4f9392919061380f565b60405180910390a1505050565b815115611e235781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580611db2575060408201516fffffffffffffffffffffffffffffffff16155b15611deb57816040517f8020d1240000000000000000000000000000000000000000000000000000000081526004016108f99190613892565b80156116ee576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff16151580611e5c575060208201516fffffffffffffffffffffffffffffffff1615155b156116ee57816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016108f99190613892565b600061193f838361258b565b600061193f83836125da565b3373ffffffffffffffffffffffffffffffffffffffff821603611f2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108f9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611fab81610b6a565b611fed576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016108f9565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa15801561206c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209091906137b0565b6114be576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016108f9565b67ffffffffffffffff821660009081526007602052604090206116ee90600201827f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f6126cd565b600061193f8373ffffffffffffffffffffffffffffffffffffffff84166125da565b600061193f8373ffffffffffffffffffffffffffffffffffffffff841661258b565b7f0000000000000000000000000000000000000000000000000000000000000000156114be57612184600282612a50565b6114be576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016108f9565b6121db81610b6a565b61221d576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016108f9565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015612296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ba91906138ce565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146114be576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016108f9565b67ffffffffffffffff821660009081526007602052604090206116ee90827f0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f6126cd565b60608160000180548060200260200160405190810160405280929190818152602001828054801561069d57602002820191906000526020600020905b8154815260200190600101908083116123a05750505050509050919050565b60006123de856123cf84866138eb565b6123d99087613902565b612a7f565b90505b949350505050565b815460009061241290700100000000000000000000000000000000900463ffffffff16426137fc565b905080156124b4576001830154835461245a916fffffffffffffffffffffffffffffffff808216928116918591700100000000000000000000000000000000909104166123bf565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546124da916fffffffffffffffffffffffffffffffff9081169116612a7f565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990611d4f908490613892565b60008181526001830160205260408120546125d2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105f3565b5060006105f3565b600081815260018301602052604081205480156126c35760006125fe6001836137fc565b8554909150600090612612906001906137fc565b9050808214612677576000866000018281548110612632576126326134dc565b9060005260206000200154905080876000018481548110612655576126556134dc565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061268857612688613915565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105f3565b60009150506105f3565b825474010000000000000000000000000000000000000000900460ff1615806126f4575081155b156126fe57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061274490700100000000000000000000000000000000900463ffffffff16426137fc565b905080156128045781831115612786576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546127c09083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166123bf565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156128bb5773ffffffffffffffffffffffffffffffffffffffff8416612863576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016108f9565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016108f9565b848310156129ce5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906128ff90826137fc565b612909878a6137fc565b6129139190613902565b61291d9190613944565b905073ffffffffffffffffffffffffffffffffffffffff8616612976576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016108f9565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016108f9565b6129d885846137fc565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561193f565b6000818310612a8e578161193f565b5090919050565b508054612aa190613079565b6000825580601f10612ab1575050565b601f0160209004906000526020600020908101906114be91905b80821115612adf5760008155600101612acb565b5090565b600060208284031215612af557600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461193f57600080fd5b803567ffffffffffffffff81168114612b3d57600080fd5b919050565b600060208284031215612b5457600080fd5b61193f82612b25565b6000815180845260005b81811015612b8357602081850181015186830182015201612b67565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061193f6020830184612b5d565b73ffffffffffffffffffffffffffffffffffffffff811681146114be57600080fd5b8035612b3d81612bd4565b600060208284031215612c1357600080fd5b813561193f81612bd4565b600060208284031215612c3057600080fd5b813567ffffffffffffffff811115612c4757600080fd5b8201610100818503121561193f57600080fd5b60008083601f840112612c6c57600080fd5b50813567ffffffffffffffff811115612c8457600080fd5b6020830191508360208260051b8501011115612c9f57600080fd5b9250929050565b60008060008060408587031215612cbc57600080fd5b843567ffffffffffffffff80821115612cd457600080fd5b612ce088838901612c5a565b90965094506020870135915080821115612cf957600080fd5b50612d0687828801612c5a565b95989497509550505050565b600080600060408486031215612d2757600080fd5b612d3084612b25565b9250602084013567ffffffffffffffff80821115612d4d57600080fd5b818601915086601f830112612d6157600080fd5b813581811115612d7057600080fd5b876020828501011115612d8257600080fd5b6020830194508093505050509250925092565b600060208284031215612da757600080fd5b813567ffffffffffffffff811115612dbe57600080fd5b820160a0818503121561193f57600080fd5b602081526000825160406020840152612dec6060840182612b5d565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016040850152612e278282612b5d565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015612e7e57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612e4c565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612e7e57835167ffffffffffffffff1683529284019291840191600101612ea6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715612f1f57612f1f612ecc565b60405290565b60405160c0810167ffffffffffffffff81118282101715612f1f57612f1f612ecc565b80151581146114be57600080fd5b8035612b3d81612f48565b80356fffffffffffffffffffffffffffffffff81168114612b3d57600080fd5b600060608284031215612f9357600080fd5b6040516060810181811067ffffffffffffffff82111715612fb657612fb6612ecc565b6040529050808235612fc781612f48565b8152612fd560208401612f61565b6020820152612fe660408401612f61565b60408201525092915050565b600080600060e0848603121561300757600080fd5b61301084612b25565b925061301f8560208601612f81565b915061302e8560808601612f81565b90509250925092565b6000806020838503121561304a57600080fd5b823567ffffffffffffffff81111561306157600080fd5b61306d85828601612c5a565b90969095509350505050565b600181811c9082168061308d57607f821691505b6020821081036130c6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f8301126130dd57600080fd5b813567ffffffffffffffff808211156130f8576130f8612ecc565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561313e5761313e612ecc565b8160405283815286602085880101111561315757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000610100823603121561318a57600080fd5b613192612efb565b823567ffffffffffffffff808211156131aa57600080fd5b6131b6368387016130cc565b83526131c460208601612b25565b60208401526131d560408601612bf6565b6040840152606085013560608401526131f060808601612bf6565b608084015260a085013591508082111561320957600080fd5b613215368387016130cc565b60a084015260c085013591508082111561322e57600080fd5b61323a368387016130cc565b60c084015260e085013591508082111561325357600080fd5b50613260368286016130cc565b60e08301525092915050565b601f821115611022576000816000526020600020601f850160051c810160208610156132955750805b601f850160051c820191505b818110156132b4578281556001016132a1565b505050505050565b67ffffffffffffffff8311156132d4576132d4612ecc565b6132e8836132e28354613079565b8361326c565b6000601f84116001811461333a57600085156133045750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611bac565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156133895786850135825560209485019460019092019101613369565b50868210156133c4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b6040815260006133e96040830186612b5d565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060a0823603121561344c57600080fd5b60405160a0810167ffffffffffffffff828210818311171561347057613470612ecc565b81604052843591508082111561348557600080fd5b50613492368286016130cc565b8252506134a160208401612b25565b602082015260408301356134b481612bd4565b60408201526060838101359082015260808301356134d181612bd4565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec183360301811261353f57600080fd5b9190910192915050565b6000610140823603121561355c57600080fd5b613564612f25565b61356d83612b25565b815261357b60208401612f56565b6020820152604083013567ffffffffffffffff8082111561359b57600080fd5b6135a7368387016130cc565b604084015260608501359150808211156135c057600080fd5b506135cd368286016130cc565b6060830152506135e03660808501612f81565b60808201526135f23660e08501612f81565b60a082015292915050565b815167ffffffffffffffff81111561361757613617612ecc565b61362b816136258454613079565b8461326c565b602080601f83116001811461367e57600084156136485750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556132b4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156136cb578886015182559484019460019091019084016136ac565b508582101561370757878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff8716835280602084015261373b81840187612b5d565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff90811660608701529087015116608085015291506137799050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e0830152612e27565b6000602082840312156137c257600080fd5b815161193f81612f48565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105f3576105f36137cd565b67ffffffffffffffff8416815260e0810161385b60208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c08301526123e1565b606081016105f382848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b6000602082840312156138e057600080fd5b815161193f81612bd4565b80820281158282048414176105f3576105f36137cd565b808201808211156105f3576105f36137cd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008261397a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea164736f6c6343000818000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f00000000000000000000000000000000000000000000000000000000000000800000000000000000000000007a394c616a7347dc91c40159929e1c9a435cb83a000000000000000000000000b00e95b773528e2ea724db06b75113f239d15dca0000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : token (address): 0x7F4e739D40E58BBd59dAD388171d18e37B26326f
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000007f4e739d40e58bbd59dad388171d18e37b26326f
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 0000000000000000000000007a394c616a7347dc91c40159929e1c9a435cb83a
Arg [3] : 000000000000000000000000b00e95b773528e2ea724db06b75113f239d15dca
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
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.