Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 21444602 | 96 days ago | IN | 0 ETH | 0.00240339 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
BurnMintTokenPool
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 AND MIT // File @chainlink/contracts-ccip/src/v0.8/ccip/libraries/[email protected] // Original license: 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; } } // File @chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/[email protected] // Original license: 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); } // File @chainlink/contracts-ccip/src/v0.8/ccip/interfaces/[email protected] // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.0; /// @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); } // File @chainlink/contracts-ccip/src/v0.8/ccip/libraries/[email protected] // Original license: 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); } } // File @chainlink/contracts-ccip/src/v0.8/ccip/interfaces/[email protected] // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.0; 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); } // File @chainlink/contracts-ccip/src/v0.8/ccip/interfaces/[email protected] // Original license: 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); } // File @chainlink/contracts-ccip/src/v0.8/ccip/libraries/[email protected] // Original license: SPDX_License_Identifier: BUSL-1.1 pragma solidity ^0.8.4; /// @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; } } // File @chainlink/contracts-ccip/src/v0.8/shared/interfaces/[email protected] // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.0; interface IOwnable { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; } // File @chainlink/contracts-ccip/src/v0.8/shared/access/[email protected] // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.4; /// @notice A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal /// to reduce the impact of the bytecode size on any contract that inherits from it. contract Ownable2Step is IOwnable { /// @notice The pending owner is the address to which ownership may be transferred. address private s_pendingOwner; /// @notice The owner is the current owner of the contract. /// @dev The owner is the second storage variable so any implementing contract could pack other state with it /// instead of the much less used s_pendingOwner. address private s_owner; error OwnerCannotBeZero(); error MustBeProposedOwner(); error CannotTransferToSelf(); error OnlyCallableByOwner(); event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); event OwnershipInitialized(address indexed me); constructor(address newOwner, address pendingOwner) { if (newOwner == address(0)) { revert OwnerCannotBeZero(); } s_owner = newOwner; if (pendingOwner != address(0)) { _transferOwnership(pendingOwner); } emit OwnershipInitialized(address(this)); } /// @notice Get the current owner function owner() public view override returns (address) { return s_owner; } /// @notice Allows an owner to begin transferring ownership to a new address. The new owner needs to call /// `acceptOwnership` to accept the transfer before any permissions are changed. /// @param to The address to which ownership will be transferred. function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } /// @notice validate, transfer ownership, and emit relevant events /// @param to The address to which ownership will be transferred. function _transferOwnership(address to) private { if (to == msg.sender) { revert CannotTransferToSelf(); } s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /// @notice Allows an ownership transfer to be completed by the recipient. function acceptOwnership() external override { if (msg.sender != s_pendingOwner) { revert MustBeProposedOwner(); } address oldOwner = s_owner; s_owner = msg.sender; s_pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /// @notice validate access function _validateOwnership() internal view { if (msg.sender != s_owner) { revert OnlyCallableByOwner(); } } /// @notice fallback if called by anyone other than the contract owner. fallback() external { assembly { mstore(0, xor(calldataload(0), shl(224, 1202223809))) pop(staticcall(gas(), address(), 0, 4, 0, 32)) mstore(32, xor(calldataload(0), shl(224, 649492607))) mstore(36, 40083131662573841504275332070155172265961804009) mstore(68, exp(10, 24)) pop(call(gas(), mload(0), 0, 32, 68, 0, 0)) } } /// @notice Reverts if called by anyone other than the contract owner. modifier onlyOwner() { _validateOwnership(); _; } } // File @chainlink/contracts-ccip/src/v0.8/shared/access/[email protected] // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.4; /// @notice Sets the msg.sender to be the owner of the contract and does not set a pending owner. contract Ownable2StepMsgSender is Ownable2Step { constructor() Ownable2Step(msg.sender, address(0)) {} } // File @chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/[email protected] // Original license: 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); } // File @chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/[email protected] // Original license: SPDX_License_Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); } // File @chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/[email protected] // Original license: 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; } } // File @chainlink/contracts-ccip/src/v0.8/ccip/pools/[email protected] // Original license: SPDX_License_Identifier: BUSL-1.1 pragma solidity 0.8.24; /// @dev This pool supports different decimals on different chains but using this feature could impact the total number /// of tokens in circulation. Since all of the tokens are locked/burned on the source, and a rounded amount is minted/released on the /// destination, the number of tokens minted/released could be less than the number of tokens burned/locked. This is because the source /// chain does not know about the destination token decimals. This is not a problem if the decimals are the same on both /// chains. /// /// Example: /// Assume there is a token with 6 decimals on chain A and 3 decimals on chain B. /// - 1.234567 tokens are burned on chain A. /// - 1.234 tokens are minted on chain B. /// When sending the 1.234 tokens back to chain A, you will receive 1.234000 tokens on chain A, effectively losing /// 0.000567 tokens. /// In the case of a burnMint pool on chain A, these funds are burned in the pool on chain A. /// In the case of a lockRelease pool on chain A, these funds accumulate in the pool on chain A. abstract contract TokenPool is IPoolV1, Ownable2StepMsgSender { using EnumerableSet for EnumerableSet.Bytes32Set; 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); error PoolAlreadyAdded(uint64 remoteChainSelector, bytes remotePoolAddress); error InvalidRemotePoolForChain(uint64 remoteChainSelector, bytes remotePoolAddress); error InvalidRemoteChainDecimals(bytes sourcePoolData); error OverflowDetected(uint8 remoteDecimals, uint8 localDecimals, uint256 remoteAmount); error InvalidDecimalArgs(uint8 expected, uint8 actual); 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 RemotePoolAdded(uint64 indexed remoteChainSelector, bytes remotePoolAddress); event RemotePoolRemoved(uint64 indexed remoteChainSelector, bytes remotePoolAddress); event AllowListAdd(address sender); event AllowListRemove(address sender); event RouterUpdated(address oldRouter, address newRouter); event RateLimitAdminSet(address rateLimitAdmin); struct ChainUpdate { uint64 remoteChainSelector; // Remote chain selector bytes[] remotePoolAddresses; // 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. 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 remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain. EnumerableSet.Bytes32Set remotePools; // Set of remote pool hashes, ABI encoded in the case of a remote EVM chain. } /// @dev The bridgeable token that is managed by this pool. Pools could support multiple tokens at the same time if /// required, but this implementation only supports one token. IERC20 internal immutable i_token; /// @dev The number of decimals of the token managed by this pool. uint8 internal immutable i_tokenDecimals; /// @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 A mapping of hashed pool addresses to their unhashed form. This is used to be able to find the actually /// configured pools and not just their hashed versions. mapping(bytes32 poolAddressHash => bytes poolAddress) internal s_remotePoolAddresses; /// @notice The address of the rate limiter admin. /// @dev Can be address(0) if none is configured. address internal s_rateLimitAdmin; constructor(IERC20 token, uint8 localTokenDecimals, 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; try IERC20Metadata(address(token)).decimals() returns (uint8 actualTokenDecimals) { if (localTokenDecimals != actualTokenDecimals) { revert InvalidDecimalArgs(localTokenDecimals, actualTokenDecimals); } } catch { // The decimals function doesn't exist, which is possible since it's optional in the ERC20 spec. We skip the check and // assume the supplied token decimals are correct. } i_tokenDecimals = localTokenDecimals; 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); } } /// @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 Get RMN proxy address /// @return rmnProxy Address of RMN proxy function getRmnProxy() public view returns (address rmnProxy) { return i_rmnProxy; } /// @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 calldata 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 calldata 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. if (!isRemotePool(releaseOrMintIn.remoteChainSelector, releaseOrMintIn.sourcePoolAddress)) { revert InvalidSourcePoolAddress(releaseOrMintIn.sourcePoolAddress); } _consumeInboundRateLimit(releaseOrMintIn.remoteChainSelector, releaseOrMintIn.amount); } // ================================================================ // │ Token decimals │ // ================================================================ /// @notice Gets the IERC20 token decimals on the local chain. function getTokenDecimals() public view virtual returns (uint8 decimals) { return i_tokenDecimals; } function _encodeLocalDecimals() internal view virtual returns (bytes memory) { return abi.encode(i_tokenDecimals); } function _parseRemoteDecimals( bytes memory sourcePoolData ) internal view virtual returns (uint8) { // Fallback to the local token decimals if the source pool data is empty. This allows for backwards compatibility. if (sourcePoolData.length == 0) { return i_tokenDecimals; } if (sourcePoolData.length != 32) { revert InvalidRemoteChainDecimals(sourcePoolData); } uint256 remoteDecimals = abi.decode(sourcePoolData, (uint256)); if (remoteDecimals > type(uint8).max) { revert InvalidRemoteChainDecimals(sourcePoolData); } return uint8(remoteDecimals); } /// @notice Calculates the local amount based on the remote amount and decimals. /// @param remoteAmount The amount on the remote chain. /// @param remoteDecimals The decimals of the token on the remote chain. /// @return The local amount. /// @dev This function protects against overflows. If there is a transaction that hits the overflow check, it is /// probably incorrect as that means the amount cannot be represented on this chain. If the local decimals have been /// wrongly configured, the token issuer could redeploy the pool with the correct decimals and manually re-execute the /// CCIP tx to fix the issue. function _calculateLocalAmount(uint256 remoteAmount, uint8 remoteDecimals) internal view virtual returns (uint256) { if (remoteDecimals == i_tokenDecimals) { return remoteAmount; } if (remoteDecimals > i_tokenDecimals) { uint8 decimalsDiff = remoteDecimals - i_tokenDecimals; if (decimalsDiff > 77) { // This is a safety check to prevent overflow in the next calculation. revert OverflowDetected(remoteDecimals, i_tokenDecimals, remoteAmount); } // Solidity rounds down so there is no risk of minting more tokens than the remote chain sent. return remoteAmount / (10 ** decimalsDiff); } // This is a safety check to prevent overflow in the next calculation. // More than 77 would never fit in a uint256 and would cause an overflow. We also check if the resulting amount // would overflow. uint8 diffDecimals = i_tokenDecimals - remoteDecimals; if (diffDecimals > 77 || remoteAmount > type(uint256).max / (10 ** diffDecimals)) { revert OverflowDetected(remoteDecimals, i_tokenDecimals, remoteAmount); } return remoteAmount * (10 ** diffDecimals); } // ================================================================ // │ 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 getRemotePools( uint64 remoteChainSelector ) public view returns (bytes[] memory) { bytes32[] memory remotePoolHashes = s_remoteChainConfigs[remoteChainSelector].remotePools.values(); bytes[] memory remotePools = new bytes[](remotePoolHashes.length); for (uint256 i = 0; i < remotePoolHashes.length; ++i) { remotePools[i] = s_remotePoolAddresses[remotePoolHashes[i]]; } return remotePools; } /// @notice Checks if the pool address is configured on the remote chain. /// @param remoteChainSelector Remote chain selector. /// @param remotePoolAddress The address of the remote pool. function isRemotePool(uint64 remoteChainSelector, bytes calldata remotePoolAddress) public view returns (bool) { return s_remoteChainConfigs[remoteChainSelector].remotePools.contains(keccak256(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 Adds a remote pool for a given chain selector. This could be due to a pool being upgraded on the remote /// chain. We don't simply want to replace the old pool as there could still be valid inflight messages from the old /// pool. This function allows for multiple pools to be added for a single chain selector. /// @param remoteChainSelector The remote chain selector for which the remote pool address is being added. /// @param remotePoolAddress The address of the new remote pool. function addRemotePool(uint64 remoteChainSelector, bytes calldata remotePoolAddress) external onlyOwner { if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector); _setRemotePool(remoteChainSelector, remotePoolAddress); } /// @notice Removes the remote pool address for a given chain selector. /// @dev All inflight txs from the remote pool will be rejected after it is removed. To ensure no loss of funds, there /// should be no inflight txs from the given pool. function removeRemotePool(uint64 remoteChainSelector, bytes calldata remotePoolAddress) external onlyOwner { if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector); if (!s_remoteChainConfigs[remoteChainSelector].remotePools.remove(keccak256(remotePoolAddress))) { revert InvalidRemotePoolForChain(remoteChainSelector, remotePoolAddress); } emit RemotePoolRemoved(remoteChainSelector, 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. /// @param remoteChainSelectorsToRemove A list of chain selectors to remove. /// @param chainsToAdd 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. /// @dev Only callable by the owner function applyChainUpdates( uint64[] calldata remoteChainSelectorsToRemove, ChainUpdate[] calldata chainsToAdd ) external virtual onlyOwner { for (uint256 i = 0; i < remoteChainSelectorsToRemove.length; ++i) { uint64 remoteChainSelectorToRemove = remoteChainSelectorsToRemove[i]; // If the chain doesn't exist, revert if (!s_remoteChainSelectors.remove(remoteChainSelectorToRemove)) { revert NonExistentChain(remoteChainSelectorToRemove); } // Remove all remote pool hashes for the chain bytes32[] memory remotePools = s_remoteChainConfigs[remoteChainSelectorToRemove].remotePools.values(); for (uint256 j = 0; j < remotePools.length; ++j) { s_remoteChainConfigs[remoteChainSelectorToRemove].remotePools.remove(remotePools[j]); } delete s_remoteChainConfigs[remoteChainSelectorToRemove]; emit ChainRemoved(remoteChainSelectorToRemove); } for (uint256 i = 0; i < chainsToAdd.length; ++i) { ChainUpdate memory newChain = chainsToAdd[i]; RateLimiter._validateTokenBucketConfig(newChain.outboundRateLimiterConfig, false); RateLimiter._validateTokenBucketConfig(newChain.inboundRateLimiterConfig, false); if (newChain.remoteTokenAddress.length == 0) { revert ZeroAddressNotAllowed(); } // If the chain already exists, revert if (!s_remoteChainSelectors.add(newChain.remoteChainSelector)) { revert ChainAlreadyExists(newChain.remoteChainSelector); } RemoteChainConfig storage remoteChainConfig = s_remoteChainConfigs[newChain.remoteChainSelector]; remoteChainConfig.outboundRateLimiterConfig = RateLimiter.TokenBucket({ rate: newChain.outboundRateLimiterConfig.rate, capacity: newChain.outboundRateLimiterConfig.capacity, tokens: newChain.outboundRateLimiterConfig.capacity, lastUpdated: uint32(block.timestamp), isEnabled: newChain.outboundRateLimiterConfig.isEnabled }); remoteChainConfig.inboundRateLimiterConfig = RateLimiter.TokenBucket({ rate: newChain.inboundRateLimiterConfig.rate, capacity: newChain.inboundRateLimiterConfig.capacity, tokens: newChain.inboundRateLimiterConfig.capacity, lastUpdated: uint32(block.timestamp), isEnabled: newChain.inboundRateLimiterConfig.isEnabled }); remoteChainConfig.remoteTokenAddress = newChain.remoteTokenAddress; for (uint256 j = 0; j < newChain.remotePoolAddresses.length; ++j) { _setRemotePool(newChain.remoteChainSelector, newChain.remotePoolAddresses[j]); } emit ChainAdded( newChain.remoteChainSelector, newChain.remoteTokenAddress, newChain.outboundRateLimiterConfig, newChain.inboundRateLimiterConfig ); } } /// @notice Adds a pool address to the allowed remote token pools for a particular chain. /// @param remoteChainSelector The remote chain selector for which the remote pool address is being added. /// @param remotePoolAddress The address of the new remote pool. function _setRemotePool(uint64 remoteChainSelector, bytes memory remotePoolAddress) internal { if (remotePoolAddress.length == 0) { revert ZeroAddressNotAllowed(); } bytes32 poolHash = keccak256(remotePoolAddress); // Check if the pool already exists. if (!s_remoteChainConfigs[remoteChainSelector].remotePools.add(poolHash)) { revert PoolAlreadyAdded(remoteChainSelector, remotePoolAddress); } // Add the pool to the mapping to be able to un-hash it later. s_remotePoolAddresses[poolHash] = remotePoolAddress; emit RemotePoolAdded(remoteChainSelector, remotePoolAddress); } // ================================================================ // │ Rate limiting │ // ================================================================ /// @dev The inbound rate limits should be slightly higher than the outbound rate limits. This is because many chains /// finalize blocks in batches. CCIP also commits messages in batches: the commit plugin bundles multiple messages in /// a single merkle root. /// Imagine the following scenario. /// - Chain A has an inbound and outbound rate limit of 100 tokens capacity and 1 token per second refill rate. /// - Chain B has an inbound and outbound rate limit of 100 tokens capacity and 1 token per second refill rate. /// /// At time 0: /// - Chain A sends 100 tokens to Chain B. /// At time 5: /// - Chain A sends 5 tokens to Chain B. /// At time 6: /// The epoch that contains blocks [0-5] is finalized. /// Both transactions will be included in the same merkle root and become executable at the same time. This means /// the token pool on chain B requires a capacity of 105 to successfully execute both messages at the same time. /// The exact additional capacity required depends on the refill rate and the size of the source chain epochs and the /// CCIP round time. For simplicity, a 5-10% buffer should be sufficient in most cases. /// @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; emit RateLimitAdminSet(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); } } } } // File @chainlink/contracts-ccip/src/v0.8/shared/token/ERC20/[email protected] // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.0; 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; } // File @chainlink/contracts-ccip/src/v0.8/ccip/pools/[email protected] // Original license: SPDX_License_Identifier: BUSL-1.1 pragma solidity 0.8.24; 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: _encodeLocalDecimals() }); } /// @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); // Calculate the local amount uint256 localAmount = _calculateLocalAmount(releaseOrMintIn.amount, _parseRemoteDecimals(releaseOrMintIn.sourcePoolData)); // Mint to the receiver IBurnMintERC20(address(i_token)).mint(releaseOrMintIn.receiver, localAmount); emit Minted(msg.sender, releaseOrMintIn.receiver, localAmount); return Pool.ReleaseOrMintOutV1({destinationAmount: localAmount}); } } // File @chainlink/contracts-ccip/src/v0.8/shared/interfaces/[email protected] // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.0; interface ITypeAndVersion { function typeAndVersion() external pure returns (string memory); } // File @chainlink/contracts-ccip/src/v0.8/ccip/pools/[email protected] // Original license: SPDX_License_Identifier: BUSL-1.1 pragma solidity 0.8.24; /// @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.1"; constructor( IBurnMintERC20 token, uint8 localTokenDecimals, address[] memory allowlist, address rmnProxy, address router ) TokenPool(token, localTokenDecimals, allowlist, rmnProxy, router) {} /// @inheritdoc BurnMintTokenPoolAbstract function _burn( uint256 amount ) internal virtual override { IBurnMintERC20(address(i_token)).burn(amount); } }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "remappings": [] }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IBurnMintERC20","name":"token","type":"address"},{"internalType":"uint8","name":"localTokenDecimals","type":"uint8"},{"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":[],"name":"CannotTransferToSelf","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":[{"internalType":"uint8","name":"expected","type":"uint8"},{"internalType":"uint8","name":"actual","type":"uint8"}],"name":"InvalidDecimalArgs","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":"sourcePoolData","type":"bytes"}],"name":"InvalidRemoteChainDecimals","type":"error"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"InvalidRemotePoolForChain","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":[],"name":"MustBeProposedOwner","type":"error"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"NonExistentChain","type":"error"},{"inputs":[],"name":"OnlyCallableByOwner","type":"error"},{"inputs":[{"internalType":"uint8","name":"remoteDecimals","type":"uint8"},{"internalType":"uint8","name":"localDecimals","type":"uint8"},{"internalType":"uint256","name":"remoteAmount","type":"uint256"}],"name":"OverflowDetected","type":"error"},{"inputs":[],"name":"OwnerCannotBeZero","type":"error"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"PoolAlreadyAdded","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":"me","type":"address"}],"name":"OwnershipInitialized","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":false,"internalType":"address","name":"rateLimitAdmin","type":"address"}],"name":"RateLimitAdminSet","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":"remotePoolAddress","type":"bytes"}],"name":"RemotePoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"RemotePoolRemoved","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"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"addRemotePool","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":[{"internalType":"uint64[]","name":"remoteChainSelectorsToRemove","type":"uint64[]"},{"components":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bytes[]","name":"remotePoolAddresses","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":"chainsToAdd","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":"getRemotePools","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":[],"name":"getTokenDecimals","outputs":[{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"isRemotePool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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"},{"internalType":"bytes","name":"remotePoolAddress","type":"bytes"}],"name":"removeRemotePool","outputs":[],"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":"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
61010060405234801562000011575f80fd5b506040516200664938038062006649833981810160405281019062000037919062000b64565b8484848484335f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603620000a4576040517f9b15e16f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146200012a5762000129816200044360201b60201c565b5b3073ffffffffffffffffffffffffffffffffffffffff167f8329cc849fdc0799fbde7276fc04f0b834fe851a1a7c7f20105b6a958b336faf60405160405180910390a250505f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480620001d557505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b806200020c57505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1562000244576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250508473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156200031757506040513d601f19601f8201168201806040525081019062000314919062000c07565b60015b156200036e578060ff168560ff16146200036c5784816040517f655a7c0e0000000000000000000000000000000000000000000000000000000081526004016200036392919062000c48565b60405180910390fd5b505b8360ff1660a08160ff16815250508060045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f835111151560e08115158152505060e051156200043357620004325f67ffffffffffffffff811115620003f557620003f4620009dd565b5b604051908082528060200260200182016040528015620004245781602001602082028036833780820191505090505b50846200056660201b60201c565b5b5050505050505050505062000d69565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620004a9576040517fdad89dca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff1660015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127860405160405180910390a350565b60e051620005a0576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b825181101562000630575f838281518110620005c357620005c262000c73565b5b60200260200101519050620005e38160026200070260201b90919060201c565b1562000623577f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566816040516200061a919062000cb1565b60405180910390a15b50806001019050620005a2565b505f5b8151811015620006fd575f82828151811062000654576200065362000c73565b5b602002602001015190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620006995750620006f1565b620006af8160026200073760201b90919060201c565b15620006ef577f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d881604051620006e6919062000cb1565b60405180910390a15b505b80600101905062000633565b505050565b5f6200072f835f018373ffffffffffffffffffffffffffffffffffffffff165f1b6200076c60201b60201c565b905092915050565b5f62000764835f018373ffffffffffffffffffffffffffffffffffffffff165f1b6200087860201b60201c565b905092915050565b5f80836001015f8481526020019081526020015f205490505f81146200086d575f6001826200079c919062000d02565b90505f6001865f0180549050620007b4919062000d02565b905080821462000821575f865f018281548110620007d757620007d662000c73565b5b905f5260205f200154905080875f018481548110620007fb57620007fa62000c73565b5b905f5260205f20018190555083876001015f8381526020019081526020015f2081905550505b855f0180548062000837576200083662000d3c565b5b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f90556001935050505062000872565b5f9150505b92915050565b5f6200088b8383620008e960201b60201c565b620008df57825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050620008e3565b5f90505b92915050565b5f80836001015f8481526020019081526020015f20541415905092915050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f62000945826200091a565b9050919050565b5f620009588262000939565b9050919050565b6200096a816200094c565b811462000975575f80fd5b50565b5f8151905062000988816200095f565b92915050565b5f60ff82169050919050565b620009a5816200098e565b8114620009b0575f80fd5b50565b5f81519050620009c3816200099a565b92915050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b62000a1582620009cd565b810181811067ffffffffffffffff8211171562000a375762000a36620009dd565b5b80604052505050565b5f62000a4b62000909565b905062000a59828262000a0a565b919050565b5f67ffffffffffffffff82111562000a7b5762000a7a620009dd565b5b602082029050602081019050919050565b5f80fd5b62000a9b8162000939565b811462000aa6575f80fd5b50565b5f8151905062000ab98162000a90565b92915050565b5f62000ad562000acf8462000a5e565b62000a40565b9050808382526020820190506020840283018581111562000afb5762000afa62000a8c565b5b835b8181101562000b28578062000b13888262000aa9565b84526020840193505060208101905062000afd565b5050509392505050565b5f82601f83011262000b495762000b48620009c9565b5b815162000b5b84826020860162000abf565b91505092915050565b5f805f805f60a0868803121562000b805762000b7f62000912565b5b5f62000b8f8882890162000978565b955050602062000ba288828901620009b3565b945050604086015167ffffffffffffffff81111562000bc65762000bc562000916565b5b62000bd48882890162000b32565b935050606062000be78882890162000aa9565b925050608062000bfa8882890162000aa9565b9150509295509295909350565b5f6020828403121562000c1f5762000c1e62000912565b5b5f62000c2e84828501620009b3565b91505092915050565b62000c42816200098e565b82525050565b5f60408201905062000c5d5f83018562000c37565b62000c6c602083018462000c37565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b62000cab8162000939565b82525050565b5f60208201905062000cc65f83018462000ca0565b92915050565b5f819050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f62000d0e8262000ccc565b915062000d1b8362000ccc565b925082820390508181111562000d365762000d3562000cd5565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b60805160a05160c05160e05161583562000e145f395f81816117c3015281816125a4015261320801525f818161179c0152818161206001526128f401525f81816107f401528181612211015281816122e90152818161231e0152818161234d015281816123880152818161240a015281816124850152612ac601525f81816107760152818161079d0152818161089501528181612a3b0152818161311d01526133e001526158355ff3fe608060405234801561000f575f80fd5b50600436106101d1575f3560e01c80639a4575b911610102578063c0d78655116100a0578063dc0bd9711161006f578063dc0bd971146105a6578063e0351e13146105c4578063e8a1da17146105e2578063f2fde38b146105fe576101d2565b8063c0d7865514610520578063c4bffe2b1461053c578063c75eea9c1461055a578063cf7401f31461058a576101d2565b8063acfecf91116100dc578063acfecf9114610486578063af58d59f146104a2578063b0f479a1146104d2578063b7946580146104f0576101d2565b80639a4575b914610408578063a42a7b8b14610438578063a7cd63b714610468576101d2565b806354c8a4f31161016f57806379ba50971161014957806379ba5097146103945780637d54534e1461039e5780638926f54f146103ba5780638da5cb5b146103ea576101d2565b806354c8a4f31461033e57806362ddd3c41461035a5780636d3d1a5814610376576101d2565b8063240028e8116101ab578063240028e81461029057806324f65ee7146102c057806339077537146102de5780634c5ef0ed1461030e576101d2565b806301ffc9a714610224578063181f5a771461025457806321df0da714610272576101d2565b5b6347a87ac160e01b5f35185f5260205f60045f305afa506326b6787f60e01b5f351860205273070563c914e0b58889ff393ae32a1411ff7d50e96024526018600a0a6044525f80604460205f80515af1005b61023e60048036038101906102399190613e31565b61061a565b60405161024b9190613e76565b60405180910390f35b61025c61073a565b6040516102699190613f19565b60405180910390f35b61027a610773565b6040516102879190613fb3565b60405180910390f35b6102aa60048036038101906102a59190614007565b61079a565b6040516102b79190613e76565b60405180910390f35b6102c86107f1565b6040516102d5919061404d565b60405180910390f35b6102f860048036038101906102f39190614089565b610818565b6040516103059190614102565b60405180910390f35b610328600480360381019061032391906141b9565b6109bb565b6040516103359190613e76565b60405180910390f35b6103586004803603810190610353919061426b565b610a16565b005b610374600480360381019061036f91906141b9565b610aae565b005b61037e610b52565b60405161038b91906142f8565b60405180910390f35b61039c610b7a565b005b6103b860048036038101906103b39190614007565b610cff565b005b6103d460048036038101906103cf9190614311565b610d81565b6040516103e19190613e76565b60405180910390f35b6103f2610da7565b6040516103ff91906142f8565b60405180910390f35b610422600480360381019061041d919061435a565b610dcf565b60405161042f9190614434565b60405180910390f35b610452600480360381019061044d9190614311565b610e7c565b60405161045f919061450f565b60405180910390f35b610470610ff4565b60405161047d91906145e6565b60405180910390f35b6104a0600480360381019061049b91906141b9565b611005565b005b6104bc60048036038101906104b79190614311565b611136565b6040516104c991906146c3565b60405180910390f35b6104da61129a565b6040516104e791906142f8565b60405180910390f35b61050a60048036038101906105059190614311565b6112c2565b6040516105179190614724565b60405180910390f35b61053a60048036038101906105359190614007565b61137a565b005b610544611489565b60405161055191906147fb565b60405180910390f35b610574600480360381019061056f9190614311565b611554565b60405161058191906146c3565b60405180910390f35b6105a4600480360381019061059f9190614950565b6116b7565b005b6105ae611799565b6040516105bb91906142f8565b60405180910390f35b6105cc6117c0565b6040516105d99190613e76565b60405180910390f35b6105fc60048036038101906105f79190614a4a565b6117e7565b005b61061860048036038101906106139190614007565b611fdc565b005b5f63aff2afbf60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106cb57507f0e64dd29000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061073357507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6040518060400160405280601781526020017f4275726e4d696e74546f6b656e506f6f6c20312e352e3100000000000000000081525081565b5f7f0000000000000000000000000000000000000000000000000000000000000000905090565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149050919050565b5f7f0000000000000000000000000000000000000000000000000000000000000000905090565b610820613ca6565b61082982611ff0565b5f610891836060013561088c858060c001906108459190614ad4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612206565b6122e6565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166340c10f198460400160208101906108e29190614007565b836040518363ffffffff1660e01b8152600401610900929190614b45565b5f604051808303815f87803b158015610917575f80fd5b505af1158015610929573d5f803e3d5ffd5b505050508260400160208101906109409190614007565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f08360405161099c9190614b6c565b60405180910390a3604051806020016040528082815250915050919050565b5f610a0d83836040516109cf929190614bc1565b604051809103902060075f8767ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f2060050161250590919063ffffffff16565b90509392505050565b610a1e61251a565b610aa88484808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508383808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050506125a2565b50505050565b610ab661251a565b610abf83610d81565b610b0057826040517f1e670e4b000000000000000000000000000000000000000000000000000000008152600401610af79190614be8565b60405180910390fd5b610b4d8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612745565b505050565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bfe576040517f02b543c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690503360015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f805f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a350565b610d0761251a565b8060095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f44676b5284b809a22248eba0da87391d79098be38bb03154be88a58bf4d0917481604051610d7691906142f8565b60405180910390a150565b5f610da08267ffffffffffffffff16600561286d90919063ffffffff16565b9050919050565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b610dd7613cb8565b610de082612884565b610ded8260600135612a39565b3373ffffffffffffffffffffffffffffffffffffffff167f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df78360600135604051610e379190614b6c565b60405180910390a26040518060400160405280610e65846020016020810190610e609190614311565b6112c2565b8152602001610e72612ac2565b8152509050919050565b60605f610eaf60075f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b09565b90505f815167ffffffffffffffff811115610ecd57610ecc61481f565b5b604051908082528060200260200182016040528015610f0057816020015b6060815260200190600190039081610eeb5790505b5090505f5b8251811015610fe95760085f848381518110610f2457610f23614c01565b5b602002602001015181526020019081526020015f208054610f4490614c5b565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7090614c5b565b8015610fbb5780601f10610f9257610100808354040283529160200191610fbb565b820191905f5260205f20905b815481529060010190602001808311610f9e57829003601f168201915b5050505050828281518110610fd357610fd2614c01565b5b6020026020010181905250806001019050610f05565b508092505050919050565b60606110006002612b28565b905090565b61100d61251a565b61101683610d81565b61105757826040517f1e670e4b00000000000000000000000000000000000000000000000000000000815260040161104e9190614be8565b60405180910390fd5b6110a8828260405161106a929190614bc1565b604051809103902060075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b4790919063ffffffff16565b6110ed578282826040517f74f23c7c0000000000000000000000000000000000000000000000000000000081526004016110e493929190614cb7565b60405180910390fd5b8267ffffffffffffffff167f52d00ee4d9bd51b40168f2afc5848837288ce258784ad914278791464b3f4d768383604051611129929190614ce7565b60405180910390a2505050565b61113e613cd2565b61129360075f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206002016040518060a00160405290815f82015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020015f820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160149054906101000a900460ff16151515158152602001600182015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681525050612b5c565b9050919050565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060075f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f2060040180546112f790614c5b565b80601f016020809104026020016040519081016040528092919081815260200182805461132390614c5b565b801561136e5780601f106113455761010080835404028352916020019161136e565b820191905f5260205f20905b81548152906001019060200180831161135157829003601f168201915b50505050509050919050565b61138261251a565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036113e7576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684818360405161147d929190614d09565b60405180910390a15050565b60605f6114966005612c14565b90505f815167ffffffffffffffff8111156114b4576114b361481f565b5b6040519080825280602002602001820160405280156114e25781602001602082028036833780820191505090505b5090505f5b825181101561154b5782818151811061150357611502614c01565b5b602002602001015182828151811061151e5761151d614c01565b5b602002602001019067ffffffffffffffff16908167ffffffffffffffff16815250508060010190506114e7565b50809250505090565b61155c613cd2565b6116b060075f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f016040518060a00160405290815f82015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020015f820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160149054906101000a900460ff16151515158152602001600182015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681525050612b5c565b9050919050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156117475750611717610da7565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b1561178957336040517f8e4a23d600000000000000000000000000000000000000000000000000000000815260040161178091906142f8565b60405180910390fd5b611794838383612c33565b505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000905090565b5f7f0000000000000000000000000000000000000000000000000000000000000000905090565b6117ef61251a565b5f5b84849050811015611ae6575f8585838181106118105761180f614c01565b5b90506020020160208101906118259190614311565b90506118458167ffffffffffffffff166005612d4490919063ffffffff16565b61188657806040517f1e670e4b00000000000000000000000000000000000000000000000000000000815260040161187d9190614be8565b60405180910390fd5b5f6118b760075f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b09565b90505f5b8151811015611924576119188282815181106118da576118d9614c01565b5b602002602001015160075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b4790919063ffffffff16565b508060010190506118bb565b5060075f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8082015f8082015f6101000a8154906fffffffffffffffffffffffffffffffff02191690555f820160106101000a81549063ffffffff02191690555f820160146101000a81549060ff0219169055600182015f6101000a8154906fffffffffffffffffffffffffffffffff02191690556001820160106101000a8154906fffffffffffffffffffffffffffffffff02191690555050600282015f8082015f6101000a8154906fffffffffffffffffffffffffffffffff02191690555f820160106101000a81549063ffffffff02191690555f820160146101000a81549060ff0219169055600182015f6101000a8154906fffffffffffffffffffffffffffffffff02191690556001820160106101000a8154906fffffffffffffffffffffffffffffffff02191690555050600482015f611a859190613d3a565b600582015f8082015f8082015f611a9c9190613d77565b5050505050507f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d85991682604051611ad19190614be8565b60405180910390a150508060010190506117f1565b505f5b82829050811015611fd5575f838383818110611b0857611b07614c01565b5b9050602002810190611b1a9190614d30565b611b2390614f9a565b9050611b3381606001515f612d5b565b611b4181608001515f612d5b565b5f81604001515103611b7f576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ba0815f015167ffffffffffffffff166005612eb590919063ffffffff16565b611be457805f01516040517f1d5ad3c5000000000000000000000000000000000000000000000000000000008152600401611bdb9190614be8565b60405180910390fd5b5f60075f835f015167ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f2090506040518060a001604052808360600151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff16815260200183606001515f0151151581526020018360600151602001516fffffffffffffffffffffffffffffffff1681526020018360600151604001516fffffffffffffffffffffffffffffffff16815250815f015f820151815f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506020820151815f0160106101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160146101000a81548160ff0219169083151502179055506060820151816001015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050506040518060a001604052808360800151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff16815260200183608001515f0151151581526020018360800151602001516fffffffffffffffffffffffffffffffff1681526020018360800151604001516fffffffffffffffffffffffffffffffff16815250816002015f820151815f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506020820151815f0160106101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160146101000a81548160ff0219169083151502179055506060820151816001015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050508160400151816004019081611f359190615140565b505f5b826020015151811015611f7b57611f70835f015184602001518381518110611f6357611f62614c01565b5b6020026020010151612745565b806001019050611f38565b507f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2825f0151836040015184606001518560800151604051611fc0949392919061524f565b60405180910390a15050806001019050611ae9565b5050505050565b611fe461251a565b611fed81612ecc565b50565b61200b8160800160208101906120069190614007565b61079a565b61205e578060800160208101906120229190614007565b6040517f961c9a4f00000000000000000000000000000000000000000000000000000000815260040161205591906142f8565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632cbc26bb8260200160208101906120ad9190614311565b67ffffffffffffffff1660801b6040518263ffffffff1660e01b81526004016120d691906152d4565b602060405180830381865afa1580156120f1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121159190615301565b1561214c576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121678160200160208101906121629190614311565b612fee565b61219281602001602081019061217d9190614311565b828060a0019061218d9190614ad4565b6109bb565b6121e357808060a001906121a69190614ad4565b6040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016121da929190614ce7565b60405180910390fd5b6122038160200160208101906121f99190614311565b8260600135613117565b50565b5f80825103612237577f000000000000000000000000000000000000000000000000000000000000000090506122e1565b602082511461227d57816040517f953576f70000000000000000000000000000000000000000000000000000000081526004016122749190614724565b60405180910390fd5b5f828060200190518101906122929190615356565b905060ff80168111156122dc57826040517f953576f70000000000000000000000000000000000000000000000000000000081526004016122d39190614724565b60405180910390fd5b809150505b919050565b5f7f000000000000000000000000000000000000000000000000000000000000000060ff168260ff160361231c578290506124ff565b7f000000000000000000000000000000000000000000000000000000000000000060ff168260ff161115612406575f7f00000000000000000000000000000000000000000000000000000000000000008361237791906153ae565b9050604d8160ff1611156123e657827f0000000000000000000000000000000000000000000000000000000000000000856040517fa9cb113d0000000000000000000000000000000000000000000000000000000081526004016123dd939291906153e2565b60405180910390fd5b80600a6123f39190615546565b846123fe91906155bd565b9150506124ff565b5f827f000000000000000000000000000000000000000000000000000000000000000061243391906153ae565b9050604d8160ff16118061247d575080600a61244f9190615546565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61247a91906155bd565b84115b156124e357827f0000000000000000000000000000000000000000000000000000000000000000856040517fa9cb113d0000000000000000000000000000000000000000000000000000000081526004016124da939291906153e2565b60405180910390fd5b80600a6124f09190615546565b846124fb91906155ed565b9150505b92915050565b5f612512835f0183613177565b905092915050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146125a0576040517f2b5c74de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b7f00000000000000000000000000000000000000000000000000000000000000006125f9576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b825181101561267f575f83828151811061261857612617614c01565b5b6020026020010151905061263681600261319790919063ffffffff16565b15612673577f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75668160405161266a91906142f8565b60405180910390a15b508060010190506125fb565b505f5b8151811015612740575f82828151811061269f5761269e614c01565b5b602002602001015190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036126e25750612735565b6126f68160026131c490919063ffffffff16565b15612733577f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d88160405161272a91906142f8565b60405180910390a15b505b806001019050612682565b505050565b5f81510361277f576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818051906020012090506127c48160075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206005016131f190919063ffffffff16565b6128075782826040517f393b8ad20000000000000000000000000000000000000000000000000000000081526004016127fe92919061562e565b60405180910390fd5b8160085f8381526020019081526020015f2090816128259190615140565b508267ffffffffffffffff167f7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea836040516128609190614724565b60405180910390a2505050565b5f61287c835f01835f1b613177565b905092915050565b61289f81608001602081019061289a9190614007565b61079a565b6128f2578060800160208101906128b69190614007565b6040517f961c9a4f0000000000000000000000000000000000000000000000000000000081526004016128e991906142f8565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632cbc26bb8260200160208101906129419190614311565b67ffffffffffffffff1660801b6040518263ffffffff1660e01b815260040161296a91906152d4565b602060405180830381865afa158015612985573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129a99190615301565b156129e0576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129fb8160400160208101906129f69190614007565b613206565b612a16816020016020810190612a119190614311565b613285565b612a36816020016020810190612a2c9190614311565b82606001356133da565b50565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166342966c68826040518263ffffffff1660e01b8152600401612a929190614b6c565b5f604051808303815f87803b158015612aa9575f80fd5b505af1158015612abb573d5f803e3d5ffd5b5050505050565b60607f0000000000000000000000000000000000000000000000000000000000000000604051602001612af5919061404d565b604051602081830303815290604052905090565b60605f612b17835f01613439565b905060608190508092505050919050565b60605f612b36835f01613439565b905060608190508092505050919050565b5f612b54835f0183613492565b905092915050565b612b64613cd2565b612bc682606001516fffffffffffffffffffffffffffffffff16835f01516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642612baa919061565c565b85608001516fffffffffffffffffffffffffffffffff1661358e565b825f01906fffffffffffffffffffffffffffffffff1690816fffffffffffffffffffffffffffffffff168152505042826020019063ffffffff16908163ffffffff1681525050819050919050565b60605f612c22835f01613439565b905060608190508092505050919050565b612c3c83610d81565b612c7d57826040517f1e670e4b000000000000000000000000000000000000000000000000000000008152600401612c749190614be8565b60405180910390fd5b612c87825f612d5b565b612cc08260075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f016135b990919063ffffffff16565b612cca815f612d5b565b612d048160075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206002016135b990919063ffffffff16565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051612d379392919061568f565b60405180910390a1505050565b5f612d53835f01835f1b613492565b905092915050565b815f015115612e335781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580612db457505f82604001516fffffffffffffffffffffffffffffffff16145b15612df657816040517f8020d124000000000000000000000000000000000000000000000000000000008152600401612ded91906156c4565b60405180910390fd5b8015612e2e576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612eb1565b5f82604001516fffffffffffffffffffffffffffffffff16141580612e6e57505f82602001516fffffffffffffffffffffffffffffffff1614155b15612eb057816040517fd68af9cc000000000000000000000000000000000000000000000000000000008152600401612ea791906156c4565b60405180910390fd5b5b5050565b5f612ec4835f01835f1b613841565b905092915050565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612f31576040517fdad89dca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff1660015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127860405160405180910390a350565b612ff781610d81565b61303857806040517fa9902c7e00000000000000000000000000000000000000000000000000000000815260040161302f9190614be8565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166383826b2b82336040518363ffffffff1660e01b81526004016130949291906156dd565b602060405180830381865afa1580156130af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130d39190615301565b61311457336040517f728fe07b00000000000000000000000000000000000000000000000000000000815260040161310b91906142f8565b60405180910390fd5b50565b613173817f000000000000000000000000000000000000000000000000000000000000000060075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206002016138a89092919063ffffffff16565b5050565b5f80836001015f8481526020019081526020015f20541415905092915050565b5f6131bc835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613492565b905092915050565b5f6131e9835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613841565b905092915050565b5f6131fe835f0183613841565b905092915050565b7f00000000000000000000000000000000000000000000000000000000000000001561328257613240816002613c6190919063ffffffff16565b61328157806040517fd0d2597600000000000000000000000000000000000000000000000000000000815260040161327891906142f8565b60405180910390fd5b5b50565b61328e81610d81565b6132cf57806040517fa9902c7e0000000000000000000000000000000000000000000000000000000081526004016132c69190614be8565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a8d87a3b826040518263ffffffff1660e01b81526004016133299190614be8565b602060405180830381865afa158015613344573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133689190615718565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146133d757336040517f728fe07b0000000000000000000000000000000000000000000000000000000081526004016133ce91906142f8565b60405180910390fd5b50565b613435817f000000000000000000000000000000000000000000000000000000000000000060075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f016138a89092919063ffffffff16565b5050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561348657602002820191905f5260205f20905b815481526020019060010190808311613472575b50505050509050919050565b5f80836001015f8481526020019081526020015f205490505f8114613583575f6001826134bf919061565c565b90505f6001865f01805490506134d5919061565c565b905080821461353b575f865f0182815481106134f4576134f3614c01565b5b905f5260205f200154905080875f01848154811061351557613514614c01565b5b905f5260205f20018190555083876001015f8381526020019081526020015f2081905550505b855f0180548061354e5761354d615743565b5b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050613588565b5f9150505b92915050565b5f6135af85838561359f91906155ed565b866135aa9190615770565b613c8e565b9050949350505050565b5f825f0160109054906101000a900463ffffffff1663ffffffff16426135df919061565c565b90505f81146136e257613687836001015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16845f015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16838660010160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1661358e565b835f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555042835f0160106101000a81548163ffffffff021916908363ffffffff1602179055505b61373282602001516fffffffffffffffffffffffffffffffff16845f015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16613c8e565b835f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550815f0151835f0160146101000a81548160ff0219169083151502179055508160200151836001015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555081604001518360010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055507f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c198260405161383491906156c4565b60405180910390a1505050565b5f61384c8383613177565b61389e57825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f2081905550600190506138a2565b5f90505b92915050565b825f0160149054906101000a900460ff1615806138c457505f82145b613c5c575f835f015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1690505f846001015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1690505f855f0160109054906101000a900463ffffffff1663ffffffff1642613957919061565c565b90505f81146139fd578183111561399a576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6139d88284838960010160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1661358e565b925042865f0160106101000a81548163ffffffff021916908363ffffffff1602179055505b84821015613ab8575f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603613a775781856040517ff94ebcd1000000000000000000000000000000000000000000000000000000008152600401613a6e9291906157a3565b60405180910390fd5b8185856040517f1a76572a000000000000000000000000000000000000000000000000000000008152600401613aaf939291906157ca565b60405180910390fd5b84831015613bda575f8660010160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1690505f81600183613b05919061565c565b8689613b11919061565c565b613b1b9190615770565b613b2591906155bd565b90505f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603613b995780856040517f15279c08000000000000000000000000000000000000000000000000000000008152600401613b909291906157a3565b60405180910390fd5b8085876040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600401613bd1939291906157ca565b60405180910390fd5b8483613be6919061565c565b925082865f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a85604051613c509190614b6c565b60405180910390a15050505b505050565b5f613c86835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613177565b905092915050565b5f818310613c9c5781613c9e565b825b905092915050565b60405180602001604052805f81525090565b604051806040016040528060608152602001606081525090565b6040518060a001604052805f6fffffffffffffffffffffffffffffffff1681526020015f63ffffffff1681526020015f151581526020015f6fffffffffffffffffffffffffffffffff1681526020015f6fffffffffffffffffffffffffffffffff1681525090565b508054613d4690614c5b565b5f825580601f10613d575750613d74565b601f0160209004905f5260205f2090810190613d739190613d95565b5b50565b5080545f8255905f5260205f2090810190613d929190613db0565b50565b5b80821115613dac575f815f905550600101613d96565b5090565b5b80821115613dc7575f815f905550600101613db1565b5090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613e1081613ddc565b8114613e1a575f80fd5b50565b5f81359050613e2b81613e07565b92915050565b5f60208284031215613e4657613e45613dd4565b5b5f613e5384828501613e1d565b91505092915050565b5f8115159050919050565b613e7081613e5c565b82525050565b5f602082019050613e895f830184613e67565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015613ec6578082015181840152602081019050613eab565b5f8484015250505050565b5f601f19601f8301169050919050565b5f613eeb82613e8f565b613ef58185613e99565b9350613f05818560208601613ea9565b613f0e81613ed1565b840191505092915050565b5f6020820190508181035f830152613f318184613ee1565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f613f7b613f76613f7184613f39565b613f58565b613f39565b9050919050565b5f613f8c82613f61565b9050919050565b5f613f9d82613f82565b9050919050565b613fad81613f93565b82525050565b5f602082019050613fc65f830184613fa4565b92915050565b5f613fd682613f39565b9050919050565b613fe681613fcc565b8114613ff0575f80fd5b50565b5f8135905061400181613fdd565b92915050565b5f6020828403121561401c5761401b613dd4565b5b5f61402984828501613ff3565b91505092915050565b5f60ff82169050919050565b61404781614032565b82525050565b5f6020820190506140605f83018461403e565b92915050565b5f80fd5b5f61010082840312156140805761407f614066565b5b81905092915050565b5f6020828403121561409e5761409d613dd4565b5b5f82013567ffffffffffffffff8111156140bb576140ba613dd8565b5b6140c78482850161406a565b91505092915050565b5f819050919050565b6140e2816140d0565b82525050565b602082015f8201516140fc5f8501826140d9565b50505050565b5f6020820190506141155f8301846140e8565b92915050565b5f67ffffffffffffffff82169050919050565b6141378161411b565b8114614141575f80fd5b50565b5f813590506141528161412e565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261417957614178614158565b5b8235905067ffffffffffffffff8111156141965761419561415c565b5b6020830191508360018202830111156141b2576141b1614160565b5b9250929050565b5f805f604084860312156141d0576141cf613dd4565b5b5f6141dd86828701614144565b935050602084013567ffffffffffffffff8111156141fe576141fd613dd8565b5b61420a86828701614164565b92509250509250925092565b5f8083601f84011261422b5761422a614158565b5b8235905067ffffffffffffffff8111156142485761424761415c565b5b60208301915083602082028301111561426457614263614160565b5b9250929050565b5f805f806040858703121561428357614282613dd4565b5b5f85013567ffffffffffffffff8111156142a05761429f613dd8565b5b6142ac87828801614216565b9450945050602085013567ffffffffffffffff8111156142cf576142ce613dd8565b5b6142db87828801614216565b925092505092959194509250565b6142f281613fcc565b82525050565b5f60208201905061430b5f8301846142e9565b92915050565b5f6020828403121561432657614325613dd4565b5b5f61433384828501614144565b91505092915050565b5f60a0828403121561435157614350614066565b5b81905092915050565b5f6020828403121561436f5761436e613dd4565b5b5f82013567ffffffffffffffff81111561438c5761438b613dd8565b5b6143988482850161433c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f6143c5826143a1565b6143cf81856143ab565b93506143df818560208601613ea9565b6143e881613ed1565b840191505092915050565b5f604083015f8301518482035f86015261440d82826143bb565b9150506020830151848203602086015261442782826143bb565b9150508091505092915050565b5f6020820190508181035f83015261444c81846143f3565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f61448883836143bb565b905092915050565b5f602082019050919050565b5f6144a682614454565b6144b0818561445e565b9350836020820285016144c28561446e565b805f5b858110156144fd57848403895281516144de858261447d565b94506144e983614490565b925060208a019950506001810190506144c5565b50829750879550505050505092915050565b5f6020820190508181035f830152614527818461449c565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61456181613fcc565b82525050565b5f6145728383614558565b60208301905092915050565b5f602082019050919050565b5f6145948261452f565b61459e8185614539565b93506145a983614549565b805f5b838110156145d95781516145c08882614567565b97506145cb8361457e565b9250506001810190506145ac565b5085935050505092915050565b5f6020820190508181035f8301526145fe818461458a565b905092915050565b5f6fffffffffffffffffffffffffffffffff82169050919050565b61462a81614606565b82525050565b5f63ffffffff82169050919050565b61464881614630565b82525050565b61465781613e5c565b82525050565b60a082015f8201516146715f850182614621565b506020820151614684602085018261463f565b506040820151614697604085018261464e565b5060608201516146aa6060850182614621565b5060808201516146bd6080850182614621565b50505050565b5f60a0820190506146d65f83018461465d565b92915050565b5f82825260208201905092915050565b5f6146f6826143a1565b61470081856146dc565b9350614710818560208601613ea9565b61471981613ed1565b840191505092915050565b5f6020820190508181035f83015261473c81846146ec565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6147768161411b565b82525050565b5f614787838361476d565b60208301905092915050565b5f602082019050919050565b5f6147a982614744565b6147b3818561474e565b93506147be8361475e565b805f5b838110156147ee5781516147d5888261477c565b97506147e083614793565b9250506001810190506147c1565b5085935050505092915050565b5f6020820190508181035f830152614813818461479f565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61485582613ed1565b810181811067ffffffffffffffff821117156148745761487361481f565b5b80604052505050565b5f614886613dcb565b9050614892828261484c565b919050565b5f80fd5b6148a481613e5c565b81146148ae575f80fd5b50565b5f813590506148bf8161489b565b92915050565b6148ce81614606565b81146148d8575f80fd5b50565b5f813590506148e9816148c5565b92915050565b5f606082840312156149045761490361481b565b5b61490e606061487d565b90505f61491d848285016148b1565b5f830152506020614930848285016148db565b6020830152506040614944848285016148db565b60408301525092915050565b5f805f60e0848603121561496757614966613dd4565b5b5f61497486828701614144565b9350506020614985868287016148ef565b9250506080614996868287016148ef565b9150509250925092565b5f8083601f8401126149b5576149b4614158565b5b8235905067ffffffffffffffff8111156149d2576149d161415c565b5b6020830191508360208202830111156149ee576149ed614160565b5b9250929050565b5f8083601f840112614a0a57614a09614158565b5b8235905067ffffffffffffffff811115614a2757614a2661415c565b5b602083019150836020820283011115614a4357614a42614160565b5b9250929050565b5f805f8060408587031215614a6257614a61613dd4565b5b5f85013567ffffffffffffffff811115614a7f57614a7e613dd8565b5b614a8b878288016149a0565b9450945050602085013567ffffffffffffffff811115614aae57614aad613dd8565b5b614aba878288016149f5565b925092505092959194509250565b5f80fd5b5f80fd5b5f80fd5b5f8083356001602003843603038112614af057614aef614ac8565b5b80840192508235915067ffffffffffffffff821115614b1257614b11614acc565b5b602083019250600182023603831315614b2e57614b2d614ad0565b5b509250929050565b614b3f816140d0565b82525050565b5f604082019050614b585f8301856142e9565b614b656020830184614b36565b9392505050565b5f602082019050614b7f5f830184614b36565b92915050565b5f81905092915050565b828183375f83830152505050565b5f614ba88385614b85565b9350614bb5838584614b8f565b82840190509392505050565b5f614bcd828486614b9d565b91508190509392505050565b614be28161411b565b82525050565b5f602082019050614bfb5f830184614bd9565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680614c7257607f821691505b602082108103614c8557614c84614c2e565b5b50919050565b5f614c9683856146dc565b9350614ca3838584614b8f565b614cac83613ed1565b840190509392505050565b5f604082019050614cca5f830186614bd9565b8181036020830152614cdd818486614c8b565b9050949350505050565b5f6020820190508181035f830152614d00818486614c8b565b90509392505050565b5f604082019050614d1c5f8301856142e9565b614d2960208301846142e9565b9392505050565b5f8235600161012003833603038112614d4c57614d4b614ac8565b5b80830191505092915050565b5f67ffffffffffffffff821115614d7257614d7161481f565b5b602082029050602081019050919050565b5f80fd5b5f67ffffffffffffffff821115614da157614da061481f565b5b614daa82613ed1565b9050602081019050919050565b5f614dc9614dc484614d87565b61487d565b905082815260208101848484011115614de557614de4614d83565b5b614df0848285614b8f565b509392505050565b5f82601f830112614e0c57614e0b614158565b5b8135614e1c848260208601614db7565b91505092915050565b5f614e37614e3284614d58565b61487d565b90508083825260208201905060208402830185811115614e5a57614e59614160565b5b835b81811015614ea157803567ffffffffffffffff811115614e7f57614e7e614158565b5b808601614e8c8982614df8565b85526020850194505050602081019050614e5c565b5050509392505050565b5f82601f830112614ebf57614ebe614158565b5b8135614ecf848260208601614e25565b91505092915050565b5f6101208284031215614eee57614eed61481b565b5b614ef860a061487d565b90505f614f0784828501614144565b5f83015250602082013567ffffffffffffffff811115614f2a57614f29614897565b5b614f3684828501614eab565b602083015250604082013567ffffffffffffffff811115614f5a57614f59614897565b5b614f6684828501614df8565b6040830152506060614f7a848285016148ef565b60608301525060c0614f8e848285016148ef565b60808301525092915050565b5f614fa53683614ed8565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026150087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614fcd565b6150128683614fcd565b95508019841693508086168417925050509392505050565b5f61504461503f61503a846140d0565b613f58565b6140d0565b9050919050565b5f819050919050565b61505d8361502a565b6150716150698261504b565b848454614fd9565b825550505050565b5f90565b615085615079565b615090818484615054565b505050565b5b818110156150b3576150a85f8261507d565b600181019050615096565b5050565b601f8211156150f8576150c981614fac565b6150d284614fbe565b810160208510156150e1578190505b6150f56150ed85614fbe565b830182615095565b50505b505050565b5f82821c905092915050565b5f6151185f19846008026150fd565b1980831691505092915050565b5f6151308383615109565b9150826002028217905092915050565b615149826143a1565b67ffffffffffffffff8111156151625761516161481f565b5b61516c8254614c5b565b6151778282856150b7565b5f60209050601f8311600181146151a8575f8415615196578287015190505b6151a08582615125565b865550615207565b601f1984166151b686614fac565b5f5b828110156151dd578489015182556001820191506020850194506020810190506151b8565b868310156151fa57848901516151f6601f891682615109565b8355505b6001600288020188555050505b505050505050565b606082015f8201516152235f85018261464e565b5060208201516152366020850182614621565b5060408201516152496040850182614621565b50505050565b5f610100820190506152635f830187614bd9565b818103602083015261527581866146ec565b9050615284604083018561520f565b61529160a083018461520f565b95945050505050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b6152ce8161529a565b82525050565b5f6020820190506152e75f8301846152c5565b92915050565b5f815190506152fb8161489b565b92915050565b5f6020828403121561531657615315613dd4565b5b5f615323848285016152ed565b91505092915050565b615335816140d0565b811461533f575f80fd5b50565b5f815190506153508161532c565b92915050565b5f6020828403121561536b5761536a613dd4565b5b5f61537884828501615342565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6153b882614032565b91506153c383614032565b9250828203905060ff8111156153dc576153db615381565b5b92915050565b5f6060820190506153f55f83018661403e565b615402602083018561403e565b61540f6040830184614b36565b949350505050565b5f8160011c9050919050565b5f808291508390505b600185111561546c5780860481111561544857615447615381565b5b60018516156154575780820291505b808102905061546585615417565b945061542c565b94509492505050565b5f82615484576001905061553f565b81615491575f905061553f565b81600181146154a757600281146154b1576154e0565b600191505061553f565b60ff8411156154c3576154c2615381565b5b8360020a9150848211156154da576154d9615381565b5b5061553f565b5060208310610133831016604e8410600b84101617156155155782820a9050838111156155105761550f615381565b5b61553f565b6155228484846001615423565b9250905081840481111561553957615538615381565b5b81810290505b9392505050565b5f615550826140d0565b915061555b83614032565b92506155887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615475565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6155c7826140d0565b91506155d2836140d0565b9250826155e2576155e1615590565b5b828204905092915050565b5f6155f7826140d0565b9150615602836140d0565b9250828202615610816140d0565b9150828204841483151761562757615626615381565b5b5092915050565b5f6040820190506156415f830185614bd9565b818103602083015261565381846146ec565b90509392505050565b5f615666826140d0565b9150615671836140d0565b925082820390508181111561568957615688615381565b5b92915050565b5f60e0820190506156a25f830186614bd9565b6156af602083018561520f565b6156bc608083018461520f565b949350505050565b5f6060820190506156d75f83018461520f565b92915050565b5f6040820190506156f05f830185614bd9565b6156fd60208301846142e9565b9392505050565b5f8151905061571281613fdd565b92915050565b5f6020828403121561572d5761572c613dd4565b5b5f61573a84828501615704565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f61577a826140d0565b9150615785836140d0565b925082820190508082111561579d5761579c615381565b5b92915050565b5f6040820190506157b65f830185614b36565b6157c36020830184614b36565b9392505050565b5f6060820190506157dd5f830186614b36565b6157ea6020830185614b36565b6157f760408301846142e9565b94935050505056fea2646970667358221220c4ae44323a04ec155d6f82ee8a8caa39d97072ea50d8269f807f7ef127160b1864736f6c63430008180033000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e8100000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106101d1575f3560e01c80639a4575b911610102578063c0d78655116100a0578063dc0bd9711161006f578063dc0bd971146105a6578063e0351e13146105c4578063e8a1da17146105e2578063f2fde38b146105fe576101d2565b8063c0d7865514610520578063c4bffe2b1461053c578063c75eea9c1461055a578063cf7401f31461058a576101d2565b8063acfecf91116100dc578063acfecf9114610486578063af58d59f146104a2578063b0f479a1146104d2578063b7946580146104f0576101d2565b80639a4575b914610408578063a42a7b8b14610438578063a7cd63b714610468576101d2565b806354c8a4f31161016f57806379ba50971161014957806379ba5097146103945780637d54534e1461039e5780638926f54f146103ba5780638da5cb5b146103ea576101d2565b806354c8a4f31461033e57806362ddd3c41461035a5780636d3d1a5814610376576101d2565b8063240028e8116101ab578063240028e81461029057806324f65ee7146102c057806339077537146102de5780634c5ef0ed1461030e576101d2565b806301ffc9a714610224578063181f5a771461025457806321df0da714610272576101d2565b5b6347a87ac160e01b5f35185f5260205f60045f305afa506326b6787f60e01b5f351860205273070563c914e0b58889ff393ae32a1411ff7d50e96024526018600a0a6044525f80604460205f80515af1005b61023e60048036038101906102399190613e31565b61061a565b60405161024b9190613e76565b60405180910390f35b61025c61073a565b6040516102699190613f19565b60405180910390f35b61027a610773565b6040516102879190613fb3565b60405180910390f35b6102aa60048036038101906102a59190614007565b61079a565b6040516102b79190613e76565b60405180910390f35b6102c86107f1565b6040516102d5919061404d565b60405180910390f35b6102f860048036038101906102f39190614089565b610818565b6040516103059190614102565b60405180910390f35b610328600480360381019061032391906141b9565b6109bb565b6040516103359190613e76565b60405180910390f35b6103586004803603810190610353919061426b565b610a16565b005b610374600480360381019061036f91906141b9565b610aae565b005b61037e610b52565b60405161038b91906142f8565b60405180910390f35b61039c610b7a565b005b6103b860048036038101906103b39190614007565b610cff565b005b6103d460048036038101906103cf9190614311565b610d81565b6040516103e19190613e76565b60405180910390f35b6103f2610da7565b6040516103ff91906142f8565b60405180910390f35b610422600480360381019061041d919061435a565b610dcf565b60405161042f9190614434565b60405180910390f35b610452600480360381019061044d9190614311565b610e7c565b60405161045f919061450f565b60405180910390f35b610470610ff4565b60405161047d91906145e6565b60405180910390f35b6104a0600480360381019061049b91906141b9565b611005565b005b6104bc60048036038101906104b79190614311565b611136565b6040516104c991906146c3565b60405180910390f35b6104da61129a565b6040516104e791906142f8565b60405180910390f35b61050a60048036038101906105059190614311565b6112c2565b6040516105179190614724565b60405180910390f35b61053a60048036038101906105359190614007565b61137a565b005b610544611489565b60405161055191906147fb565b60405180910390f35b610574600480360381019061056f9190614311565b611554565b60405161058191906146c3565b60405180910390f35b6105a4600480360381019061059f9190614950565b6116b7565b005b6105ae611799565b6040516105bb91906142f8565b60405180910390f35b6105cc6117c0565b6040516105d99190613e76565b60405180910390f35b6105fc60048036038101906105f79190614a4a565b6117e7565b005b61061860048036038101906106139190614007565b611fdc565b005b5f63aff2afbf60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106cb57507f0e64dd29000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061073357507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6040518060400160405280601781526020017f4275726e4d696e74546f6b656e506f6f6c20312e352e3100000000000000000081525081565b5f7f000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f905090565b5f7f000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149050919050565b5f7f0000000000000000000000000000000000000000000000000000000000000012905090565b610820613ca6565b61082982611ff0565b5f610891836060013561088c858060c001906108459190614ad4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612206565b6122e6565b90507f000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f73ffffffffffffffffffffffffffffffffffffffff166340c10f198460400160208101906108e29190614007565b836040518363ffffffff1660e01b8152600401610900929190614b45565b5f604051808303815f87803b158015610917575f80fd5b505af1158015610929573d5f803e3d5ffd5b505050508260400160208101906109409190614007565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f08360405161099c9190614b6c565b60405180910390a3604051806020016040528082815250915050919050565b5f610a0d83836040516109cf929190614bc1565b604051809103902060075f8767ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f2060050161250590919063ffffffff16565b90509392505050565b610a1e61251a565b610aa88484808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508383808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050506125a2565b50505050565b610ab661251a565b610abf83610d81565b610b0057826040517f1e670e4b000000000000000000000000000000000000000000000000000000008152600401610af79190614be8565b60405180910390fd5b610b4d8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612745565b505050565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bfe576040517f02b543c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690503360015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f805f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a350565b610d0761251a565b8060095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f44676b5284b809a22248eba0da87391d79098be38bb03154be88a58bf4d0917481604051610d7691906142f8565b60405180910390a150565b5f610da08267ffffffffffffffff16600561286d90919063ffffffff16565b9050919050565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b610dd7613cb8565b610de082612884565b610ded8260600135612a39565b3373ffffffffffffffffffffffffffffffffffffffff167f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df78360600135604051610e379190614b6c565b60405180910390a26040518060400160405280610e65846020016020810190610e609190614311565b6112c2565b8152602001610e72612ac2565b8152509050919050565b60605f610eaf60075f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b09565b90505f815167ffffffffffffffff811115610ecd57610ecc61481f565b5b604051908082528060200260200182016040528015610f0057816020015b6060815260200190600190039081610eeb5790505b5090505f5b8251811015610fe95760085f848381518110610f2457610f23614c01565b5b602002602001015181526020019081526020015f208054610f4490614c5b565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7090614c5b565b8015610fbb5780601f10610f9257610100808354040283529160200191610fbb565b820191905f5260205f20905b815481529060010190602001808311610f9e57829003601f168201915b5050505050828281518110610fd357610fd2614c01565b5b6020026020010181905250806001019050610f05565b508092505050919050565b60606110006002612b28565b905090565b61100d61251a565b61101683610d81565b61105757826040517f1e670e4b00000000000000000000000000000000000000000000000000000000815260040161104e9190614be8565b60405180910390fd5b6110a8828260405161106a929190614bc1565b604051809103902060075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b4790919063ffffffff16565b6110ed578282826040517f74f23c7c0000000000000000000000000000000000000000000000000000000081526004016110e493929190614cb7565b60405180910390fd5b8267ffffffffffffffff167f52d00ee4d9bd51b40168f2afc5848837288ce258784ad914278791464b3f4d768383604051611129929190614ce7565b60405180910390a2505050565b61113e613cd2565b61129360075f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206002016040518060a00160405290815f82015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020015f820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160149054906101000a900460ff16151515158152602001600182015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681525050612b5c565b9050919050565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060075f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f2060040180546112f790614c5b565b80601f016020809104026020016040519081016040528092919081815260200182805461132390614c5b565b801561136e5780601f106113455761010080835404028352916020019161136e565b820191905f5260205f20905b81548152906001019060200180831161135157829003601f168201915b50505050509050919050565b61138261251a565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036113e7576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684818360405161147d929190614d09565b60405180910390a15050565b60605f6114966005612c14565b90505f815167ffffffffffffffff8111156114b4576114b361481f565b5b6040519080825280602002602001820160405280156114e25781602001602082028036833780820191505090505b5090505f5b825181101561154b5782818151811061150357611502614c01565b5b602002602001015182828151811061151e5761151d614c01565b5b602002602001019067ffffffffffffffff16908167ffffffffffffffff16815250508060010190506114e7565b50809250505090565b61155c613cd2565b6116b060075f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f016040518060a00160405290815f82015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020015f820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020015f820160149054906101000a900460ff16151515158152602001600182015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681525050612b5c565b9050919050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156117475750611717610da7565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b1561178957336040517f8e4a23d600000000000000000000000000000000000000000000000000000000815260040161178091906142f8565b60405180910390fd5b611794838383612c33565b505050565b5f7f000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e81905090565b5f7f0000000000000000000000000000000000000000000000000000000000000000905090565b6117ef61251a565b5f5b84849050811015611ae6575f8585838181106118105761180f614c01565b5b90506020020160208101906118259190614311565b90506118458167ffffffffffffffff166005612d4490919063ffffffff16565b61188657806040517f1e670e4b00000000000000000000000000000000000000000000000000000000815260040161187d9190614be8565b60405180910390fd5b5f6118b760075f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b09565b90505f5b8151811015611924576119188282815181106118da576118d9614c01565b5b602002602001015160075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f20600501612b4790919063ffffffff16565b508060010190506118bb565b5060075f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8082015f8082015f6101000a8154906fffffffffffffffffffffffffffffffff02191690555f820160106101000a81549063ffffffff02191690555f820160146101000a81549060ff0219169055600182015f6101000a8154906fffffffffffffffffffffffffffffffff02191690556001820160106101000a8154906fffffffffffffffffffffffffffffffff02191690555050600282015f8082015f6101000a8154906fffffffffffffffffffffffffffffffff02191690555f820160106101000a81549063ffffffff02191690555f820160146101000a81549060ff0219169055600182015f6101000a8154906fffffffffffffffffffffffffffffffff02191690556001820160106101000a8154906fffffffffffffffffffffffffffffffff02191690555050600482015f611a859190613d3a565b600582015f8082015f8082015f611a9c9190613d77565b5050505050507f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d85991682604051611ad19190614be8565b60405180910390a150508060010190506117f1565b505f5b82829050811015611fd5575f838383818110611b0857611b07614c01565b5b9050602002810190611b1a9190614d30565b611b2390614f9a565b9050611b3381606001515f612d5b565b611b4181608001515f612d5b565b5f81604001515103611b7f576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ba0815f015167ffffffffffffffff166005612eb590919063ffffffff16565b611be457805f01516040517f1d5ad3c5000000000000000000000000000000000000000000000000000000008152600401611bdb9190614be8565b60405180910390fd5b5f60075f835f015167ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f2090506040518060a001604052808360600151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff16815260200183606001515f0151151581526020018360600151602001516fffffffffffffffffffffffffffffffff1681526020018360600151604001516fffffffffffffffffffffffffffffffff16815250815f015f820151815f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506020820151815f0160106101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160146101000a81548160ff0219169083151502179055506060820151816001015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050506040518060a001604052808360800151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff16815260200183608001515f0151151581526020018360800151602001516fffffffffffffffffffffffffffffffff1681526020018360800151604001516fffffffffffffffffffffffffffffffff16815250816002015f820151815f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506020820151815f0160106101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160146101000a81548160ff0219169083151502179055506060820151816001015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050508160400151816004019081611f359190615140565b505f5b826020015151811015611f7b57611f70835f015184602001518381518110611f6357611f62614c01565b5b6020026020010151612745565b806001019050611f38565b507f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2825f0151836040015184606001518560800151604051611fc0949392919061524f565b60405180910390a15050806001019050611ae9565b5050505050565b611fe461251a565b611fed81612ecc565b50565b61200b8160800160208101906120069190614007565b61079a565b61205e578060800160208101906120229190614007565b6040517f961c9a4f00000000000000000000000000000000000000000000000000000000815260040161205591906142f8565b60405180910390fd5b7f000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e8173ffffffffffffffffffffffffffffffffffffffff16632cbc26bb8260200160208101906120ad9190614311565b67ffffffffffffffff1660801b6040518263ffffffff1660e01b81526004016120d691906152d4565b602060405180830381865afa1580156120f1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121159190615301565b1561214c576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121678160200160208101906121629190614311565b612fee565b61219281602001602081019061217d9190614311565b828060a0019061218d9190614ad4565b6109bb565b6121e357808060a001906121a69190614ad4565b6040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016121da929190614ce7565b60405180910390fd5b6122038160200160208101906121f99190614311565b8260600135613117565b50565b5f80825103612237577f000000000000000000000000000000000000000000000000000000000000001290506122e1565b602082511461227d57816040517f953576f70000000000000000000000000000000000000000000000000000000081526004016122749190614724565b60405180910390fd5b5f828060200190518101906122929190615356565b905060ff80168111156122dc57826040517f953576f70000000000000000000000000000000000000000000000000000000081526004016122d39190614724565b60405180910390fd5b809150505b919050565b5f7f000000000000000000000000000000000000000000000000000000000000001260ff168260ff160361231c578290506124ff565b7f000000000000000000000000000000000000000000000000000000000000001260ff168260ff161115612406575f7f00000000000000000000000000000000000000000000000000000000000000128361237791906153ae565b9050604d8160ff1611156123e657827f0000000000000000000000000000000000000000000000000000000000000012856040517fa9cb113d0000000000000000000000000000000000000000000000000000000081526004016123dd939291906153e2565b60405180910390fd5b80600a6123f39190615546565b846123fe91906155bd565b9150506124ff565b5f827f000000000000000000000000000000000000000000000000000000000000001261243391906153ae565b9050604d8160ff16118061247d575080600a61244f9190615546565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61247a91906155bd565b84115b156124e357827f0000000000000000000000000000000000000000000000000000000000000012856040517fa9cb113d0000000000000000000000000000000000000000000000000000000081526004016124da939291906153e2565b60405180910390fd5b80600a6124f09190615546565b846124fb91906155ed565b9150505b92915050565b5f612512835f0183613177565b905092915050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146125a0576040517f2b5c74de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b7f00000000000000000000000000000000000000000000000000000000000000006125f9576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b825181101561267f575f83828151811061261857612617614c01565b5b6020026020010151905061263681600261319790919063ffffffff16565b15612673577f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75668160405161266a91906142f8565b60405180910390a15b508060010190506125fb565b505f5b8151811015612740575f82828151811061269f5761269e614c01565b5b602002602001015190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036126e25750612735565b6126f68160026131c490919063ffffffff16565b15612733577f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d88160405161272a91906142f8565b60405180910390a15b505b806001019050612682565b505050565b5f81510361277f576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818051906020012090506127c48160075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206005016131f190919063ffffffff16565b6128075782826040517f393b8ad20000000000000000000000000000000000000000000000000000000081526004016127fe92919061562e565b60405180910390fd5b8160085f8381526020019081526020015f2090816128259190615140565b508267ffffffffffffffff167f7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea836040516128609190614724565b60405180910390a2505050565b5f61287c835f01835f1b613177565b905092915050565b61289f81608001602081019061289a9190614007565b61079a565b6128f2578060800160208101906128b69190614007565b6040517f961c9a4f0000000000000000000000000000000000000000000000000000000081526004016128e991906142f8565b60405180910390fd5b7f000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e8173ffffffffffffffffffffffffffffffffffffffff16632cbc26bb8260200160208101906129419190614311565b67ffffffffffffffff1660801b6040518263ffffffff1660e01b815260040161296a91906152d4565b602060405180830381865afa158015612985573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129a99190615301565b156129e0576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129fb8160400160208101906129f69190614007565b613206565b612a16816020016020810190612a119190614311565b613285565b612a36816020016020810190612a2c9190614311565b82606001356133da565b50565b7f000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f73ffffffffffffffffffffffffffffffffffffffff166342966c68826040518263ffffffff1660e01b8152600401612a929190614b6c565b5f604051808303815f87803b158015612aa9575f80fd5b505af1158015612abb573d5f803e3d5ffd5b5050505050565b60607f0000000000000000000000000000000000000000000000000000000000000012604051602001612af5919061404d565b604051602081830303815290604052905090565b60605f612b17835f01613439565b905060608190508092505050919050565b60605f612b36835f01613439565b905060608190508092505050919050565b5f612b54835f0183613492565b905092915050565b612b64613cd2565b612bc682606001516fffffffffffffffffffffffffffffffff16835f01516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642612baa919061565c565b85608001516fffffffffffffffffffffffffffffffff1661358e565b825f01906fffffffffffffffffffffffffffffffff1690816fffffffffffffffffffffffffffffffff168152505042826020019063ffffffff16908163ffffffff1681525050819050919050565b60605f612c22835f01613439565b905060608190508092505050919050565b612c3c83610d81565b612c7d57826040517f1e670e4b000000000000000000000000000000000000000000000000000000008152600401612c749190614be8565b60405180910390fd5b612c87825f612d5b565b612cc08260075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f016135b990919063ffffffff16565b612cca815f612d5b565b612d048160075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206002016135b990919063ffffffff16565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051612d379392919061568f565b60405180910390a1505050565b5f612d53835f01835f1b613492565b905092915050565b815f015115612e335781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580612db457505f82604001516fffffffffffffffffffffffffffffffff16145b15612df657816040517f8020d124000000000000000000000000000000000000000000000000000000008152600401612ded91906156c4565b60405180910390fd5b8015612e2e576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612eb1565b5f82604001516fffffffffffffffffffffffffffffffff16141580612e6e57505f82602001516fffffffffffffffffffffffffffffffff1614155b15612eb057816040517fd68af9cc000000000000000000000000000000000000000000000000000000008152600401612ea791906156c4565b60405180910390fd5b5b5050565b5f612ec4835f01835f1b613841565b905092915050565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612f31576040517fdad89dca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff1660015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127860405160405180910390a350565b612ff781610d81565b61303857806040517fa9902c7e00000000000000000000000000000000000000000000000000000000815260040161302f9190614be8565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166383826b2b82336040518363ffffffff1660e01b81526004016130949291906156dd565b602060405180830381865afa1580156130af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130d39190615301565b61311457336040517f728fe07b00000000000000000000000000000000000000000000000000000000815260040161310b91906142f8565b60405180910390fd5b50565b613173817f000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f60075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f206002016138a89092919063ffffffff16565b5050565b5f80836001015f8481526020019081526020015f20541415905092915050565b5f6131bc835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613492565b905092915050565b5f6131e9835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613841565b905092915050565b5f6131fe835f0183613841565b905092915050565b7f00000000000000000000000000000000000000000000000000000000000000001561328257613240816002613c6190919063ffffffff16565b61328157806040517fd0d2597600000000000000000000000000000000000000000000000000000000815260040161327891906142f8565b60405180910390fd5b5b50565b61328e81610d81565b6132cf57806040517fa9902c7e0000000000000000000000000000000000000000000000000000000081526004016132c69190614be8565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a8d87a3b826040518263ffffffff1660e01b81526004016133299190614be8565b602060405180830381865afa158015613344573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133689190615718565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146133d757336040517f728fe07b0000000000000000000000000000000000000000000000000000000081526004016133ce91906142f8565b60405180910390fd5b50565b613435817f000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f60075f8667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f016138a89092919063ffffffff16565b5050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561348657602002820191905f5260205f20905b815481526020019060010190808311613472575b50505050509050919050565b5f80836001015f8481526020019081526020015f205490505f8114613583575f6001826134bf919061565c565b90505f6001865f01805490506134d5919061565c565b905080821461353b575f865f0182815481106134f4576134f3614c01565b5b905f5260205f200154905080875f01848154811061351557613514614c01565b5b905f5260205f20018190555083876001015f8381526020019081526020015f2081905550505b855f0180548061354e5761354d615743565b5b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050613588565b5f9150505b92915050565b5f6135af85838561359f91906155ed565b866135aa9190615770565b613c8e565b9050949350505050565b5f825f0160109054906101000a900463ffffffff1663ffffffff16426135df919061565c565b90505f81146136e257613687836001015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16845f015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16838660010160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1661358e565b835f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555042835f0160106101000a81548163ffffffff021916908363ffffffff1602179055505b61373282602001516fffffffffffffffffffffffffffffffff16845f015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16613c8e565b835f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550815f0151835f0160146101000a81548160ff0219169083151502179055508160200151836001015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555081604001518360010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055507f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c198260405161383491906156c4565b60405180910390a1505050565b5f61384c8383613177565b61389e57825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f2081905550600190506138a2565b5f90505b92915050565b825f0160149054906101000a900460ff1615806138c457505f82145b613c5c575f835f015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1690505f846001015f9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1690505f855f0160109054906101000a900463ffffffff1663ffffffff1642613957919061565c565b90505f81146139fd578183111561399a576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6139d88284838960010160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1661358e565b925042865f0160106101000a81548163ffffffff021916908363ffffffff1602179055505b84821015613ab8575f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603613a775781856040517ff94ebcd1000000000000000000000000000000000000000000000000000000008152600401613a6e9291906157a3565b60405180910390fd5b8185856040517f1a76572a000000000000000000000000000000000000000000000000000000008152600401613aaf939291906157ca565b60405180910390fd5b84831015613bda575f8660010160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1690505f81600183613b05919061565c565b8689613b11919061565c565b613b1b9190615770565b613b2591906155bd565b90505f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603613b995780856040517f15279c08000000000000000000000000000000000000000000000000000000008152600401613b909291906157a3565b60405180910390fd5b8085876040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600401613bd1939291906157ca565b60405180910390fd5b8483613be6919061565c565b925082865f015f6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a85604051613c509190614b6c565b60405180910390a15050505b505050565b5f613c86835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613177565b905092915050565b5f818310613c9c5781613c9e565b825b905092915050565b60405180602001604052805f81525090565b604051806040016040528060608152602001606081525090565b6040518060a001604052805f6fffffffffffffffffffffffffffffffff1681526020015f63ffffffff1681526020015f151581526020015f6fffffffffffffffffffffffffffffffff1681526020015f6fffffffffffffffffffffffffffffffff1681525090565b508054613d4690614c5b565b5f825580601f10613d575750613d74565b601f0160209004905f5260205f2090810190613d739190613d95565b5b50565b5080545f8255905f5260205f2090810190613d929190613db0565b50565b5b80821115613dac575f815f905550600101613d96565b5090565b5b80821115613dc7575f815f905550600101613db1565b5090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613e1081613ddc565b8114613e1a575f80fd5b50565b5f81359050613e2b81613e07565b92915050565b5f60208284031215613e4657613e45613dd4565b5b5f613e5384828501613e1d565b91505092915050565b5f8115159050919050565b613e7081613e5c565b82525050565b5f602082019050613e895f830184613e67565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015613ec6578082015181840152602081019050613eab565b5f8484015250505050565b5f601f19601f8301169050919050565b5f613eeb82613e8f565b613ef58185613e99565b9350613f05818560208601613ea9565b613f0e81613ed1565b840191505092915050565b5f6020820190508181035f830152613f318184613ee1565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f613f7b613f76613f7184613f39565b613f58565b613f39565b9050919050565b5f613f8c82613f61565b9050919050565b5f613f9d82613f82565b9050919050565b613fad81613f93565b82525050565b5f602082019050613fc65f830184613fa4565b92915050565b5f613fd682613f39565b9050919050565b613fe681613fcc565b8114613ff0575f80fd5b50565b5f8135905061400181613fdd565b92915050565b5f6020828403121561401c5761401b613dd4565b5b5f61402984828501613ff3565b91505092915050565b5f60ff82169050919050565b61404781614032565b82525050565b5f6020820190506140605f83018461403e565b92915050565b5f80fd5b5f61010082840312156140805761407f614066565b5b81905092915050565b5f6020828403121561409e5761409d613dd4565b5b5f82013567ffffffffffffffff8111156140bb576140ba613dd8565b5b6140c78482850161406a565b91505092915050565b5f819050919050565b6140e2816140d0565b82525050565b602082015f8201516140fc5f8501826140d9565b50505050565b5f6020820190506141155f8301846140e8565b92915050565b5f67ffffffffffffffff82169050919050565b6141378161411b565b8114614141575f80fd5b50565b5f813590506141528161412e565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261417957614178614158565b5b8235905067ffffffffffffffff8111156141965761419561415c565b5b6020830191508360018202830111156141b2576141b1614160565b5b9250929050565b5f805f604084860312156141d0576141cf613dd4565b5b5f6141dd86828701614144565b935050602084013567ffffffffffffffff8111156141fe576141fd613dd8565b5b61420a86828701614164565b92509250509250925092565b5f8083601f84011261422b5761422a614158565b5b8235905067ffffffffffffffff8111156142485761424761415c565b5b60208301915083602082028301111561426457614263614160565b5b9250929050565b5f805f806040858703121561428357614282613dd4565b5b5f85013567ffffffffffffffff8111156142a05761429f613dd8565b5b6142ac87828801614216565b9450945050602085013567ffffffffffffffff8111156142cf576142ce613dd8565b5b6142db87828801614216565b925092505092959194509250565b6142f281613fcc565b82525050565b5f60208201905061430b5f8301846142e9565b92915050565b5f6020828403121561432657614325613dd4565b5b5f61433384828501614144565b91505092915050565b5f60a0828403121561435157614350614066565b5b81905092915050565b5f6020828403121561436f5761436e613dd4565b5b5f82013567ffffffffffffffff81111561438c5761438b613dd8565b5b6143988482850161433c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f6143c5826143a1565b6143cf81856143ab565b93506143df818560208601613ea9565b6143e881613ed1565b840191505092915050565b5f604083015f8301518482035f86015261440d82826143bb565b9150506020830151848203602086015261442782826143bb565b9150508091505092915050565b5f6020820190508181035f83015261444c81846143f3565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f61448883836143bb565b905092915050565b5f602082019050919050565b5f6144a682614454565b6144b0818561445e565b9350836020820285016144c28561446e565b805f5b858110156144fd57848403895281516144de858261447d565b94506144e983614490565b925060208a019950506001810190506144c5565b50829750879550505050505092915050565b5f6020820190508181035f830152614527818461449c565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61456181613fcc565b82525050565b5f6145728383614558565b60208301905092915050565b5f602082019050919050565b5f6145948261452f565b61459e8185614539565b93506145a983614549565b805f5b838110156145d95781516145c08882614567565b97506145cb8361457e565b9250506001810190506145ac565b5085935050505092915050565b5f6020820190508181035f8301526145fe818461458a565b905092915050565b5f6fffffffffffffffffffffffffffffffff82169050919050565b61462a81614606565b82525050565b5f63ffffffff82169050919050565b61464881614630565b82525050565b61465781613e5c565b82525050565b60a082015f8201516146715f850182614621565b506020820151614684602085018261463f565b506040820151614697604085018261464e565b5060608201516146aa6060850182614621565b5060808201516146bd6080850182614621565b50505050565b5f60a0820190506146d65f83018461465d565b92915050565b5f82825260208201905092915050565b5f6146f6826143a1565b61470081856146dc565b9350614710818560208601613ea9565b61471981613ed1565b840191505092915050565b5f6020820190508181035f83015261473c81846146ec565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6147768161411b565b82525050565b5f614787838361476d565b60208301905092915050565b5f602082019050919050565b5f6147a982614744565b6147b3818561474e565b93506147be8361475e565b805f5b838110156147ee5781516147d5888261477c565b97506147e083614793565b9250506001810190506147c1565b5085935050505092915050565b5f6020820190508181035f830152614813818461479f565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61485582613ed1565b810181811067ffffffffffffffff821117156148745761487361481f565b5b80604052505050565b5f614886613dcb565b9050614892828261484c565b919050565b5f80fd5b6148a481613e5c565b81146148ae575f80fd5b50565b5f813590506148bf8161489b565b92915050565b6148ce81614606565b81146148d8575f80fd5b50565b5f813590506148e9816148c5565b92915050565b5f606082840312156149045761490361481b565b5b61490e606061487d565b90505f61491d848285016148b1565b5f830152506020614930848285016148db565b6020830152506040614944848285016148db565b60408301525092915050565b5f805f60e0848603121561496757614966613dd4565b5b5f61497486828701614144565b9350506020614985868287016148ef565b9250506080614996868287016148ef565b9150509250925092565b5f8083601f8401126149b5576149b4614158565b5b8235905067ffffffffffffffff8111156149d2576149d161415c565b5b6020830191508360208202830111156149ee576149ed614160565b5b9250929050565b5f8083601f840112614a0a57614a09614158565b5b8235905067ffffffffffffffff811115614a2757614a2661415c565b5b602083019150836020820283011115614a4357614a42614160565b5b9250929050565b5f805f8060408587031215614a6257614a61613dd4565b5b5f85013567ffffffffffffffff811115614a7f57614a7e613dd8565b5b614a8b878288016149a0565b9450945050602085013567ffffffffffffffff811115614aae57614aad613dd8565b5b614aba878288016149f5565b925092505092959194509250565b5f80fd5b5f80fd5b5f80fd5b5f8083356001602003843603038112614af057614aef614ac8565b5b80840192508235915067ffffffffffffffff821115614b1257614b11614acc565b5b602083019250600182023603831315614b2e57614b2d614ad0565b5b509250929050565b614b3f816140d0565b82525050565b5f604082019050614b585f8301856142e9565b614b656020830184614b36565b9392505050565b5f602082019050614b7f5f830184614b36565b92915050565b5f81905092915050565b828183375f83830152505050565b5f614ba88385614b85565b9350614bb5838584614b8f565b82840190509392505050565b5f614bcd828486614b9d565b91508190509392505050565b614be28161411b565b82525050565b5f602082019050614bfb5f830184614bd9565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680614c7257607f821691505b602082108103614c8557614c84614c2e565b5b50919050565b5f614c9683856146dc565b9350614ca3838584614b8f565b614cac83613ed1565b840190509392505050565b5f604082019050614cca5f830186614bd9565b8181036020830152614cdd818486614c8b565b9050949350505050565b5f6020820190508181035f830152614d00818486614c8b565b90509392505050565b5f604082019050614d1c5f8301856142e9565b614d2960208301846142e9565b9392505050565b5f8235600161012003833603038112614d4c57614d4b614ac8565b5b80830191505092915050565b5f67ffffffffffffffff821115614d7257614d7161481f565b5b602082029050602081019050919050565b5f80fd5b5f67ffffffffffffffff821115614da157614da061481f565b5b614daa82613ed1565b9050602081019050919050565b5f614dc9614dc484614d87565b61487d565b905082815260208101848484011115614de557614de4614d83565b5b614df0848285614b8f565b509392505050565b5f82601f830112614e0c57614e0b614158565b5b8135614e1c848260208601614db7565b91505092915050565b5f614e37614e3284614d58565b61487d565b90508083825260208201905060208402830185811115614e5a57614e59614160565b5b835b81811015614ea157803567ffffffffffffffff811115614e7f57614e7e614158565b5b808601614e8c8982614df8565b85526020850194505050602081019050614e5c565b5050509392505050565b5f82601f830112614ebf57614ebe614158565b5b8135614ecf848260208601614e25565b91505092915050565b5f6101208284031215614eee57614eed61481b565b5b614ef860a061487d565b90505f614f0784828501614144565b5f83015250602082013567ffffffffffffffff811115614f2a57614f29614897565b5b614f3684828501614eab565b602083015250604082013567ffffffffffffffff811115614f5a57614f59614897565b5b614f6684828501614df8565b6040830152506060614f7a848285016148ef565b60608301525060c0614f8e848285016148ef565b60808301525092915050565b5f614fa53683614ed8565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026150087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614fcd565b6150128683614fcd565b95508019841693508086168417925050509392505050565b5f61504461503f61503a846140d0565b613f58565b6140d0565b9050919050565b5f819050919050565b61505d8361502a565b6150716150698261504b565b848454614fd9565b825550505050565b5f90565b615085615079565b615090818484615054565b505050565b5b818110156150b3576150a85f8261507d565b600181019050615096565b5050565b601f8211156150f8576150c981614fac565b6150d284614fbe565b810160208510156150e1578190505b6150f56150ed85614fbe565b830182615095565b50505b505050565b5f82821c905092915050565b5f6151185f19846008026150fd565b1980831691505092915050565b5f6151308383615109565b9150826002028217905092915050565b615149826143a1565b67ffffffffffffffff8111156151625761516161481f565b5b61516c8254614c5b565b6151778282856150b7565b5f60209050601f8311600181146151a8575f8415615196578287015190505b6151a08582615125565b865550615207565b601f1984166151b686614fac565b5f5b828110156151dd578489015182556001820191506020850194506020810190506151b8565b868310156151fa57848901516151f6601f891682615109565b8355505b6001600288020188555050505b505050505050565b606082015f8201516152235f85018261464e565b5060208201516152366020850182614621565b5060408201516152496040850182614621565b50505050565b5f610100820190506152635f830187614bd9565b818103602083015261527581866146ec565b9050615284604083018561520f565b61529160a083018461520f565b95945050505050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b6152ce8161529a565b82525050565b5f6020820190506152e75f8301846152c5565b92915050565b5f815190506152fb8161489b565b92915050565b5f6020828403121561531657615315613dd4565b5b5f615323848285016152ed565b91505092915050565b615335816140d0565b811461533f575f80fd5b50565b5f815190506153508161532c565b92915050565b5f6020828403121561536b5761536a613dd4565b5b5f61537884828501615342565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6153b882614032565b91506153c383614032565b9250828203905060ff8111156153dc576153db615381565b5b92915050565b5f6060820190506153f55f83018661403e565b615402602083018561403e565b61540f6040830184614b36565b949350505050565b5f8160011c9050919050565b5f808291508390505b600185111561546c5780860481111561544857615447615381565b5b60018516156154575780820291505b808102905061546585615417565b945061542c565b94509492505050565b5f82615484576001905061553f565b81615491575f905061553f565b81600181146154a757600281146154b1576154e0565b600191505061553f565b60ff8411156154c3576154c2615381565b5b8360020a9150848211156154da576154d9615381565b5b5061553f565b5060208310610133831016604e8410600b84101617156155155782820a9050838111156155105761550f615381565b5b61553f565b6155228484846001615423565b9250905081840481111561553957615538615381565b5b81810290505b9392505050565b5f615550826140d0565b915061555b83614032565b92506155887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615475565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6155c7826140d0565b91506155d2836140d0565b9250826155e2576155e1615590565b5b828204905092915050565b5f6155f7826140d0565b9150615602836140d0565b9250828202615610816140d0565b9150828204841483151761562757615626615381565b5b5092915050565b5f6040820190506156415f830185614bd9565b818103602083015261565381846146ec565b90509392505050565b5f615666826140d0565b9150615671836140d0565b925082820390508181111561568957615688615381565b5b92915050565b5f60e0820190506156a25f830186614bd9565b6156af602083018561520f565b6156bc608083018461520f565b949350505050565b5f6060820190506156d75f83018461520f565b92915050565b5f6040820190506156f05f830185614bd9565b6156fd60208301846142e9565b9392505050565b5f8151905061571281613fdd565b92915050565b5f6020828403121561572d5761572c613dd4565b5b5f61573a84828501615704565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f61577a826140d0565b9150615785836140d0565b925082820190508082111561579d5761579c615381565b5b92915050565b5f6040820190506157b65f830185614b36565b6157c36020830184614b36565b9392505050565b5f6060820190506157dd5f830186614b36565b6157ea6020830185614b36565b6157f760408301846142e9565b94935050505056fea2646970667358221220c4ae44323a04ec155d6f82ee8a8caa39d97072ea50d8269f807f7ef127160b1864736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e8100000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d0000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : token (address): 0x786A6743efe9500011C92c7D8540608a62382b6f
Arg [1] : localTokenDecimals (uint8): 18
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000786a6743efe9500011c92c7d8540608a62382b6f
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [3] : 000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e81
Arg [4] : 00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.