More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 464743 | 13 days ago | IN | 0 S | 0.00004783 |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
EVM2EVMOnRamp
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 4100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {IEVM2AnyOnRamp} from "../interfaces/IEVM2AnyOnRamp.sol"; import {IEVM2AnyOnRampClient} from "../interfaces/IEVM2AnyOnRampClient.sol"; import {IPoolV1} from "../interfaces/IPool.sol"; import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol"; import {IRMN} from "../interfaces/IRMN.sol"; import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol"; import {ILinkAvailable} from "../interfaces/automation/ILinkAvailable.sol"; import {AggregateRateLimiter} from "../AggregateRateLimiter.sol"; import {Client} from "../libraries/Client.sol"; import {Internal} from "../libraries/Internal.sol"; import {Pool} from "../libraries/Pool.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; import {USDPriceWith18Decimals} from "../libraries/USDPriceWith18Decimals.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableMap.sol"; /// @notice The onRamp is a contract that handles lane-specific fee logic, NOP payments and /// bridgeable token support. /// @dev The EVM2EVMOnRamp, CommitStore and EVM2EVMOffRamp form an xchain upgradeable unit. Any change to one of them /// results an onchain upgrade of all 3. contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter, ITypeAndVersion { using SafeERC20 for IERC20; using EnumerableMap for EnumerableMap.AddressToUintMap; using USDPriceWith18Decimals for uint224; error InvalidExtraArgsTag(); error ExtraArgOutOfOrderExecutionMustBeTrue(); error OnlyCallableByOwnerOrAdmin(); error OnlyCallableByOwnerOrAdminOrNop(); error InvalidWithdrawParams(); error NoFeesToPay(); error NoNopsToPay(); error InsufficientBalance(); error TooManyNops(); error MaxFeeBalanceReached(); error MessageTooLarge(uint256 maxSize, uint256 actualSize); error MessageGasLimitTooHigh(); error UnsupportedNumberOfTokens(); error UnsupportedToken(address token); error MustBeCalledByRouter(); error RouterMustSetOriginalSender(); error InvalidConfig(); error CursedByRMN(); error LinkBalanceNotSettled(); error InvalidNopAddress(address nop); error NotAFeeToken(address token); error CannotSendZeroTokens(); error SourceTokenDataTooLarge(address token); error InvalidChainSelector(uint64 chainSelector); error GetSupportedTokensFunctionalityRemovedCheckAdminRegistry(); error InvalidDestBytesOverhead(address token, uint32 destBytesOverhead); event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig); event NopPaid(address indexed nop, uint256 amount); event FeeConfigSet(FeeTokenConfigArgs[] feeConfig); event TokenTransferFeeConfigSet(TokenTransferFeeConfigArgs[] transferFeeConfig); event TokenTransferFeeConfigDeleted(address[] tokens); /// RMN depends on this event, if changing, please notify the RMN maintainers. event CCIPSendRequested(Internal.EVM2EVMMessage message); event NopsSet(uint256 nopWeightsTotal, NopAndWeight[] nopsAndWeights); /// @dev Struct that contains the static configuration /// RMN depends on this struct, if changing, please notify the RMN maintainers. //solhint-disable gas-struct-packing struct StaticConfig { address linkToken; // ────────╮ Link token address uint64 chainSelector; // ─────╯ Source chainSelector uint64 destChainSelector; // ─╮ Destination chainSelector uint64 defaultTxGasLimit; // │ Default gas limit for a tx uint96 maxNopFeesJuels; // ───╯ Max nop fee balance onramp can have address prevOnRamp; // Address of previous-version OnRamp address rmnProxy; // Address of RMN proxy address tokenAdminRegistry; // Address of the token admin registry } /// @dev Struct to contains the dynamic configuration struct DynamicConfig { address router; // ──────────────────────────╮ Router address uint16 maxNumberOfTokensPerMsg; // │ Maximum number of distinct ERC20 token transferred per message uint32 destGasOverhead; // │ Gas charged on top of the gasLimit to cover destination chain costs uint16 destGasPerPayloadByte; // │ Destination chain gas charged for passing each byte of `data` payload to receiver uint32 destDataAvailabilityOverheadGas; // ──╯ Extra data availability gas charged on top of the message, e.g. for OCR uint16 destGasPerDataAvailabilityByte; // ───╮ Amount of gas to charge per byte of message data that needs availability uint16 destDataAvailabilityMultiplierBps; // │ Multiplier for data availability gas, multiples of bps, or 0.0001 address priceRegistry; // │ Price registry address uint32 maxDataBytes; // │ Maximum payload data size in bytes uint32 maxPerMsgGasLimit; // ────────────────╯ Maximum gas limit for messages targeting EVMs // │ // The following three properties are defaults, they can be overridden by setting the TokenTransferFeeConfig for a token uint16 defaultTokenFeeUSDCents; // ──────────╮ Default token fee charged per token transfer uint32 defaultTokenDestGasOverhead; // │ Default gas charged to execute the token transfer on the destination chain bool enforceOutOfOrder; // ──────────────────╯ Whether to enforce the allowOutOfOrderExecution extraArg value to be true. } /// @dev Struct to hold the execution fee configuration for a fee token struct FeeTokenConfig { uint32 networkFeeUSDCents; // ─────────╮ Flat network fee to charge for messages, multiples of 0.01 USD uint64 gasMultiplierWeiPerEth; // │ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost. uint64 premiumMultiplierWeiPerEth; // │ Multiplier for fee-token-specific premiums bool enabled; // ──────────────────────╯ Whether this fee token is enabled } /// @dev Struct to hold the fee configuration for a fee token, same as the FeeTokenConfig but with /// token included so that an array of these can be passed in to setFeeTokenConfig to set the mapping struct FeeTokenConfigArgs { address token; // ─────────────────────╮ Token address uint32 networkFeeUSDCents; // │ Flat network fee to charge for messages, multiples of 0.01 USD uint64 gasMultiplierWeiPerEth; // ─────╯ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost uint64 premiumMultiplierWeiPerEth; // ─╮ Multiplier for fee-token-specific premiums, 1e18 based bool enabled; // ──────────────────────╯ Whether this fee token is enabled } /// @dev Struct to hold the transfer fee configuration for token transfers struct TokenTransferFeeConfig { uint32 minFeeUSDCents; // ──────────╮ Minimum fee to charge per token transfer, multiples of 0.01 USD uint32 maxFeeUSDCents; // │ Maximum fee to charge per token transfer, multiples of 0.01 USD uint16 deciBps; // │ Basis points charged on token transfers, multiples of 0.1bps, or 1e-5 uint32 destGasOverhead; // │ Gas charged to execute the token transfer on the destination chain // │ Extra data availability bytes that are returned from the source pool and sent uint32 destBytesOverhead; // │ to the destination pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES bool aggregateRateLimitEnabled; // │ Whether this transfer token is to be included in Aggregate Rate Limiting bool isEnabled; // ─────────────────╯ Whether this token has custom transfer fees } /// @dev Same as TokenTransferFeeConfig /// token included so that an array of these can be passed in to setTokenTransferFeeConfig struct TokenTransferFeeConfigArgs { address token; // ──────────────────╮ Token address uint32 minFeeUSDCents; // │ Minimum fee to charge per token transfer, multiples of 0.01 USD uint32 maxFeeUSDCents; // │ Maximum fee to charge per token transfer, multiples of 0.01 USD uint16 deciBps; // ─────────────────╯ Basis points charged on token transfers, multiples of 0.1bps, or 1e-5 uint32 destGasOverhead; // ─────────╮ Gas charged to execute the token transfer on the destination chain // │ Extra data availability bytes that are returned from the source pool and sent uint32 destBytesOverhead; // │ to the destination pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES bool aggregateRateLimitEnabled; // ─╯ Whether this transfer token is to be included in Aggregate Rate Limiting } /// @dev Nop address and weight, used to set the nops and their weights struct NopAndWeight { address nop; // ────╮ Address of the node operator uint16 weight; // ──╯ Weight for nop rewards } // STATIC CONFIG string public constant override typeAndVersion = "EVM2EVMOnRamp 1.5.0"; /// @dev metadataHash is a lane-specific prefix for a message hash preimage which ensures global uniqueness /// Ensures that 2 identical messages sent to 2 different lanes will have a distinct hash. /// Must match the metadataHash used in computing leaf hashes offchain for the root committed in /// the commitStore and i_metadataHash in the offRamp. bytes32 internal immutable i_metadataHash; /// @dev Default gas limit for a transactions that did not specify /// a gas limit in the extraArgs. uint64 internal immutable i_defaultTxGasLimit; /// @dev Maximum nop fee that can accumulate in this onramp uint96 internal immutable i_maxNopFeesJuels; /// @dev The link token address - known to pay nops for their work address internal immutable i_linkToken; /// @dev The chain ID of the source chain that this contract is deployed to uint64 internal immutable i_chainSelector; /// @dev The chain ID of the destination chain uint64 internal immutable i_destChainSelector; /// @dev The address of previous-version OnRamp for this lane /// Used to be able to provide sequencing continuity during a zero downtime upgrade. address internal immutable i_prevOnRamp; /// @dev The address of the RMN proxy address internal immutable i_rmnProxy; /// @dev The address of the token admin registry address internal immutable i_tokenAdminRegistry; /// @dev the maximum number of nops that can be configured at the same time. /// Used to bound gas for loops over nops. uint256 private constant MAX_NUMBER_OF_NOPS = 64; // DYNAMIC CONFIG /// @dev The config for the onRamp DynamicConfig internal s_dynamicConfig; /// @dev (address nop => uint256 weight) EnumerableMap.AddressToUintMap internal s_nops; /// @dev The execution fee token config that can be set by the owner or fee admin mapping(address token => FeeTokenConfig feeTokenConfig) internal s_feeTokenConfig; /// @dev The token transfer fee config that can be set by the owner or fee admin mapping(address token => TokenTransferFeeConfig tranferFeeConfig) internal s_tokenTransferFeeConfig; // STATE /// @dev The current nonce per sender. /// The offramp has a corresponding s_senderNonce mapping to ensure messages /// are executed in the same order they are sent. mapping(address sender => uint64 nonce) internal s_senderNonce; /// @dev The amount of LINK available to pay NOPS uint96 internal s_nopFeesJuels; /// @dev The combined weight of all NOPs weights uint32 internal s_nopWeightsTotal; /// @dev The last used sequence number. This is zero in the case where no /// messages has been sent yet. 0 is not a valid sequence number for any /// real transaction. uint64 internal s_sequenceNumber; constructor( StaticConfig memory staticConfig, DynamicConfig memory dynamicConfig, RateLimiter.Config memory rateLimiterConfig, FeeTokenConfigArgs[] memory feeTokenConfigs, TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs, NopAndWeight[] memory nopsAndWeights ) AggregateRateLimiter(rateLimiterConfig) { if ( staticConfig.linkToken == address(0) || staticConfig.chainSelector == 0 || staticConfig.destChainSelector == 0 || staticConfig.defaultTxGasLimit == 0 || staticConfig.rmnProxy == address(0) || staticConfig.tokenAdminRegistry == address(0) ) revert InvalidConfig(); i_metadataHash = keccak256( abi.encode( Internal.EVM_2_EVM_MESSAGE_HASH, staticConfig.chainSelector, staticConfig.destChainSelector, address(this) ) ); i_linkToken = staticConfig.linkToken; i_chainSelector = staticConfig.chainSelector; i_destChainSelector = staticConfig.destChainSelector; i_defaultTxGasLimit = staticConfig.defaultTxGasLimit; i_maxNopFeesJuels = staticConfig.maxNopFeesJuels; i_prevOnRamp = staticConfig.prevOnRamp; i_rmnProxy = staticConfig.rmnProxy; i_tokenAdminRegistry = staticConfig.tokenAdminRegistry; _setDynamicConfig(dynamicConfig); _setFeeTokenConfig(feeTokenConfigs); _setTokenTransferFeeConfig(tokenTransferFeeConfigArgs, new address[](0)); _setNops(nopsAndWeights); } // ================================================================ // │ Messaging │ // ================================================================ /// @inheritdoc IEVM2AnyOnRamp function getExpectedNextSequenceNumber() external view returns (uint64) { return s_sequenceNumber + 1; } /// @inheritdoc IEVM2AnyOnRamp function getSenderNonce(address sender) external view returns (uint64) { uint256 senderNonce = s_senderNonce[sender]; if (i_prevOnRamp != address(0)) { if (senderNonce == 0) { // If OnRamp was upgraded, check if sender has a nonce from the previous OnRamp. return IEVM2AnyOnRamp(i_prevOnRamp).getSenderNonce(sender); } } return uint64(senderNonce); } /// @inheritdoc IEVM2AnyOnRampClient function forwardFromRouter( uint64 destChainSelector, Client.EVM2AnyMessage calldata message, uint256 feeTokenAmount, address originalSender ) external returns (bytes32) { if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(destChainSelector)))) revert CursedByRMN(); // Validate message sender is set and allowed. Not validated in `getFee` since it is not user-driven. if (originalSender == address(0)) revert RouterMustSetOriginalSender(); // Router address may be zero intentionally to pause. if (msg.sender != s_dynamicConfig.router) revert MustBeCalledByRouter(); if (destChainSelector != i_destChainSelector) revert InvalidChainSelector(destChainSelector); Client.EVMExtraArgsV2 memory extraArgs = _fromBytes(message.extraArgs); // Validate the message with various checks uint256 numberOfTokens = message.tokenAmounts.length; _validateMessage(message.data.length, extraArgs.gasLimit, numberOfTokens, extraArgs.allowOutOfOrderExecution); // Only check token value if there are tokens if (numberOfTokens > 0) { uint256 value; for (uint256 i = 0; i < numberOfTokens; ++i) { if (message.tokenAmounts[i].amount == 0) revert CannotSendZeroTokens(); if (s_tokenTransferFeeConfig[message.tokenAmounts[i].token].aggregateRateLimitEnabled) { value += _getTokenValue(message.tokenAmounts[i], IPriceRegistry(s_dynamicConfig.priceRegistry)); } } // Rate limit on aggregated token value if (value > 0) _rateLimitValue(value); } // Convert feeToken to link if not already in link if (message.feeToken == i_linkToken) { // Since there is only 1b link this is safe s_nopFeesJuels += uint96(feeTokenAmount); } else { // the cast from uint256 to uint96 is considered safe, uint96 can store more than max supply of link token s_nopFeesJuels += uint96( IPriceRegistry(s_dynamicConfig.priceRegistry).convertTokenAmount(message.feeToken, feeTokenAmount, i_linkToken) ); } if (s_nopFeesJuels > i_maxNopFeesJuels) revert MaxFeeBalanceReached(); // Get the current nonce if the message is an ordered message. If it's not ordered, we don't have to make the // external call. if (!extraArgs.allowOutOfOrderExecution) { if (i_prevOnRamp != address(0)) { if (s_senderNonce[originalSender] == 0) { // If this is first time send for a sender in new OnRamp, check if they have a nonce // from the previous OnRamp and start from there instead of zero. s_senderNonce[originalSender] = IEVM2AnyOnRamp(i_prevOnRamp).getSenderNonce(originalSender); } } } // We need the next available sequence number so we increment before we use the value Internal.EVM2EVMMessage memory newMessage = Internal.EVM2EVMMessage({ sourceChainSelector: i_chainSelector, sender: originalSender, // EVM destination addresses should be abi encoded and therefore always 32 bytes long // Not duplicately validated in `getFee`. Invalid address is uncommon, gas cost outweighs UX gain. receiver: Internal._validateEVMAddress(message.receiver), sequenceNumber: ++s_sequenceNumber, gasLimit: extraArgs.gasLimit, strict: false, // Only bump nonce for messages that specify allowOutOfOrderExecution == false. Otherwise, we // may block ordered message nonces, which is not what we want. nonce: extraArgs.allowOutOfOrderExecution ? 0 : ++s_senderNonce[originalSender], feeToken: message.feeToken, feeTokenAmount: feeTokenAmount, data: message.data, tokenAmounts: message.tokenAmounts, sourceTokenData: new bytes[](numberOfTokens), // will be populated below messageId: "" }); // Lock the tokens as last step. TokenPools may not always be trusted. // There should be no state changes after external call to TokenPools. for (uint256 i = 0; i < numberOfTokens; ++i) { Client.EVMTokenAmount memory tokenAndAmount = message.tokenAmounts[i]; IPoolV1 sourcePool = getPoolBySourceToken(destChainSelector, IERC20(tokenAndAmount.token)); // We don't have to check if it supports the pool version in a non-reverting way here because // if we revert here, there is no effect on CCIP. Therefore we directly call the supportsInterface // function and not through the ERC165Checker. if (address(sourcePool) == address(0) || !sourcePool.supportsInterface(Pool.CCIP_POOL_V1)) { revert UnsupportedToken(tokenAndAmount.token); } Pool.LockOrBurnOutV1 memory poolReturnData = sourcePool.lockOrBurn( Pool.LockOrBurnInV1({ receiver: message.receiver, remoteChainSelector: i_destChainSelector, originalSender: originalSender, amount: tokenAndAmount.amount, localToken: tokenAndAmount.token }) ); // Since the DON has to pay for the extraData to be included on the destination chain, we cap the length of the // extraData. This prevents gas bomb attacks on the NOPs. As destBytesOverhead accounts for both // extraData and offchainData, this caps the worst case abuse to the number of bytes reserved for offchainData. if (poolReturnData.destPoolData.length > Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) { // If TokenTransferFeeConfig.enabled is false, there is no config. That means destBytesOverhead is zero and // this check is always true. That ensures that a pool without config cannot send more than // Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes of data. if (poolReturnData.destPoolData.length > s_tokenTransferFeeConfig[tokenAndAmount.token].destBytesOverhead) { revert SourceTokenDataTooLarge(tokenAndAmount.token); } } // We validate the token address to ensure it is a valid EVM address Internal._validateEVMAddress(poolReturnData.destTokenAddress); newMessage.sourceTokenData[i] = abi.encode( Internal.SourceTokenData({ sourcePoolAddress: abi.encode(sourcePool), destTokenAddress: poolReturnData.destTokenAddress, extraData: poolReturnData.destPoolData, // The user will be billed either the default or the override, so we send the exact amount that we billed for // to the destination chain to be used for the token releaseOrMint and transfer. destGasAmount: s_tokenTransferFeeConfig[tokenAndAmount.token].isEnabled ? s_tokenTransferFeeConfig[tokenAndAmount.token].destGasOverhead : s_dynamicConfig.defaultTokenDestGasOverhead }) ); } // Hash only after the sourceTokenData has been set newMessage.messageId = Internal._hash(newMessage, i_metadataHash); // Emit message request // This must happen after any pool events as some tokens (e.g. USDC) emit events that we expect to precede this // event in the offchain code. emit CCIPSendRequested(newMessage); return newMessage.messageId; } /// @dev Convert the extra args bytes into a struct /// @param extraArgs The extra args bytes /// @return The extra args struct function _fromBytes(bytes calldata extraArgs) internal view returns (Client.EVMExtraArgsV2 memory) { if (extraArgs.length == 0) { return Client.EVMExtraArgsV2({gasLimit: i_defaultTxGasLimit, allowOutOfOrderExecution: false}); } bytes4 extraArgsTag = bytes4(extraArgs); if (extraArgsTag == Client.EVM_EXTRA_ARGS_V2_TAG) { return abi.decode(extraArgs[4:], (Client.EVMExtraArgsV2)); } else if (extraArgsTag == Client.EVM_EXTRA_ARGS_V1_TAG) { // EVMExtraArgsV1 originally included a second boolean (strict) field which has been deprecated. // Clients may still include it but it will be ignored. return Client.EVMExtraArgsV2({gasLimit: abi.decode(extraArgs[4:], (uint256)), allowOutOfOrderExecution: false}); } revert InvalidExtraArgsTag(); } /// @notice Validate the forwarded message with various checks. /// @dev This function can be called multiple times during a CCIPSend, /// only common user-driven mistakes are validated here to minimize duplicate validation cost. /// @param dataLength The length of the data field of the message. /// @param gasLimit The gasLimit set in message for destination execution. /// @param numberOfTokens The number of tokens to be sent. function _validateMessage( uint256 dataLength, uint256 gasLimit, uint256 numberOfTokens, bool allowOutOfOrderExecution ) internal view { uint256 maxDataBytes = uint256(s_dynamicConfig.maxDataBytes); if (dataLength > maxDataBytes) revert MessageTooLarge(maxDataBytes, dataLength); if (gasLimit > uint256(s_dynamicConfig.maxPerMsgGasLimit)) revert MessageGasLimitTooHigh(); if (numberOfTokens > uint256(s_dynamicConfig.maxNumberOfTokensPerMsg)) revert UnsupportedNumberOfTokens(); if (!allowOutOfOrderExecution) { if (s_dynamicConfig.enforceOutOfOrder) { revert ExtraArgOutOfOrderExecutionMustBeTrue(); } } } // ================================================================ // │ Config │ // ================================================================ /// @notice Returns the static onRamp config. /// @dev RMN depends on this function, if changing, please notify the RMN maintainers. /// @return the configuration. function getStaticConfig() external view returns (StaticConfig memory) { return StaticConfig({ linkToken: i_linkToken, chainSelector: i_chainSelector, destChainSelector: i_destChainSelector, defaultTxGasLimit: i_defaultTxGasLimit, maxNopFeesJuels: i_maxNopFeesJuels, prevOnRamp: i_prevOnRamp, rmnProxy: i_rmnProxy, tokenAdminRegistry: i_tokenAdminRegistry }); } /// @notice Returns the dynamic onRamp config. /// @return dynamicConfig the configuration. function getDynamicConfig() external view returns (DynamicConfig memory dynamicConfig) { return s_dynamicConfig; } /// @notice Sets the dynamic configuration. /// @param dynamicConfig The configuration. function setDynamicConfig(DynamicConfig memory dynamicConfig) external onlyOwner { _setDynamicConfig(dynamicConfig); } /// @notice Internal version of setDynamicConfig to allow for reuse in the constructor. function _setDynamicConfig(DynamicConfig memory dynamicConfig) internal { // We permit router to be set to zero as a way to pause the contract. if (dynamicConfig.priceRegistry == address(0)) revert InvalidConfig(); s_dynamicConfig = dynamicConfig; emit ConfigSet( StaticConfig({ linkToken: i_linkToken, chainSelector: i_chainSelector, destChainSelector: i_destChainSelector, defaultTxGasLimit: i_defaultTxGasLimit, maxNopFeesJuels: i_maxNopFeesJuels, prevOnRamp: i_prevOnRamp, rmnProxy: i_rmnProxy, tokenAdminRegistry: i_tokenAdminRegistry }), dynamicConfig ); } // ================================================================ // │ Tokens and pools │ // ================================================================ /// @inheritdoc IEVM2AnyOnRampClient function getPoolBySourceToken(uint64, /*destChainSelector*/ IERC20 sourceToken) public view returns (IPoolV1) { return IPoolV1(ITokenAdminRegistry(i_tokenAdminRegistry).getPool(address(sourceToken))); } /// @inheritdoc IEVM2AnyOnRampClient function getSupportedTokens(uint64) external pure returns (address[] memory) { revert GetSupportedTokensFunctionalityRemovedCheckAdminRegistry(); } // ================================================================ // │ Fees │ // ================================================================ /// @inheritdoc IEVM2AnyOnRampClient /// @dev getFee MUST revert if the feeToken is not listed in the fee token config, as the router assumes it does. /// @param destChainSelector The destination chain selector. /// @param message The message to get quote for. /// @return feeTokenAmount The amount of fee token needed for the fee, in smallest denomination of the fee token. function getFee( uint64 destChainSelector, Client.EVM2AnyMessage calldata message ) external view returns (uint256 feeTokenAmount) { if (destChainSelector != i_destChainSelector) revert InvalidChainSelector(destChainSelector); Client.EVMExtraArgsV2 memory extraArgs = _fromBytes(message.extraArgs); // Validate the message with various checks _validateMessage( message.data.length, extraArgs.gasLimit, message.tokenAmounts.length, extraArgs.allowOutOfOrderExecution ); FeeTokenConfig memory feeTokenConfig = s_feeTokenConfig[message.feeToken]; if (!feeTokenConfig.enabled) revert NotAFeeToken(message.feeToken); (uint224 feeTokenPrice, uint224 packedGasPrice) = IPriceRegistry(s_dynamicConfig.priceRegistry).getTokenAndGasPrices(message.feeToken, destChainSelector); // Calculate premiumFee in USD with 18 decimals precision first. // If message-only and no token transfers, a flat network fee is charged. // If there are token transfers, premiumFee is calculated from token transfer fee. // If there are both token transfers and message, premiumFee is only calculated from token transfer fee. uint256 premiumFee = 0; uint32 tokenTransferGas = 0; uint32 tokenTransferBytesOverhead = 0; if (message.tokenAmounts.length > 0) { (premiumFee, tokenTransferGas, tokenTransferBytesOverhead) = _getTokenTransferCost(message.feeToken, feeTokenPrice, message.tokenAmounts); } else { // Convert USD cents with 2 decimals to 18 decimals. premiumFee = uint256(feeTokenConfig.networkFeeUSDCents) * 1e16; } // Calculate data availability cost in USD with 36 decimals. Data availability cost exists on rollups that need to post // transaction calldata onto another storage layer, e.g. Eth mainnet, incurring additional storage gas costs. uint256 dataAvailabilityCost = 0; // Only calculate data availability cost if data availability multiplier is non-zero. // The multiplier should be set to 0 if destination chain does not charge data availability cost. if (s_dynamicConfig.destDataAvailabilityMultiplierBps > 0) { dataAvailabilityCost = _getDataAvailabilityCost( // Parse the data availability gas price stored in the higher-order 112 bits of the encoded gas price. uint112(packedGasPrice >> Internal.GAS_PRICE_BITS), message.data.length, message.tokenAmounts.length, tokenTransferBytesOverhead ); } // Calculate execution gas fee on destination chain in USD with 36 decimals. // We add the message gas limit, the overhead gas, the gas of passing message data to receiver, and token transfer gas together. // We then multiply this gas total with the gas multiplier and gas price, converting it into USD with 36 decimals. // uint112(packedGasPrice) = executionGasPrice uint256 executionCost = uint112(packedGasPrice) * ( extraArgs.gasLimit + s_dynamicConfig.destGasOverhead + (message.data.length * s_dynamicConfig.destGasPerPayloadByte) + tokenTransferGas ) * feeTokenConfig.gasMultiplierWeiPerEth; // Calculate number of fee tokens to charge. // Total USD fee is in 36 decimals, feeTokenPrice is in 18 decimals USD for 1e18 smallest token denominations. // Result of the division is the number of smallest token denominations. return ((premiumFee * feeTokenConfig.premiumMultiplierWeiPerEth) + executionCost + dataAvailabilityCost) / feeTokenPrice; } /// @notice Returns the estimated data availability cost of the message. /// @dev To save on gas, we use a single destGasPerDataAvailabilityByte value for both zero and non-zero bytes. /// @param dataAvailabilityGasPrice USD per data availability gas in 18 decimals. /// @param messageDataLength length of the data field in the message. /// @param numberOfTokens number of distinct token transfers in the message. /// @param tokenTransferBytesOverhead additional token transfer data passed to destination, e.g. USDC attestation. /// @return dataAvailabilityCostUSD36Decimal total data availability cost in USD with 36 decimals. function _getDataAvailabilityCost( uint112 dataAvailabilityGasPrice, uint256 messageDataLength, uint256 numberOfTokens, uint32 tokenTransferBytesOverhead ) internal view returns (uint256 dataAvailabilityCostUSD36Decimal) { // dataAvailabilityLengthBytes sums up byte lengths of fixed message fields and dynamic message fields. // Fixed message fields do account for the offset and length slot of the dynamic fields. uint256 dataAvailabilityLengthBytes = Internal.MESSAGE_FIXED_BYTES + messageDataLength + (numberOfTokens * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) + tokenTransferBytesOverhead; // destDataAvailabilityOverheadGas is a separate config value for flexibility to be updated independently of message cost. // Its value is determined by CCIP lane implementation, e.g. the overhead data posted for OCR. uint256 dataAvailabilityGas = (dataAvailabilityLengthBytes * s_dynamicConfig.destGasPerDataAvailabilityByte) + s_dynamicConfig.destDataAvailabilityOverheadGas; // dataAvailabilityGasPrice is in 18 decimals, destDataAvailabilityMultiplierBps is in 4 decimals // We pad 14 decimals to bring the result to 36 decimals, in line with token bps and execution fee. return ((dataAvailabilityGas * dataAvailabilityGasPrice) * s_dynamicConfig.destDataAvailabilityMultiplierBps) * 1e14; } /// @notice Returns the token transfer cost parameters. /// A basis point fee is calculated from the USD value of each token transfer. /// For each individual transfer, this fee is between [minFeeUSD, maxFeeUSD]. /// Total transfer fee is the sum of each individual token transfer fee. /// @dev Assumes that tokenAmounts are validated to be listed tokens elsewhere. /// @dev Splitting one token transfer into multiple transfers is discouraged, /// as it will result in a transferFee equal or greater than the same amount aggregated/de-duped. /// @param feeToken address of the feeToken. /// @param feeTokenPrice price of feeToken in USD with 18 decimals. /// @param tokenAmounts token transfers in the message. /// @return tokenTransferFeeUSDWei total token transfer bps fee in USD with 18 decimals. /// @return tokenTransferGas total execution gas of the token transfers. /// @return tokenTransferBytesOverhead additional token transfer data passed to destination, e.g. USDC attestation. function _getTokenTransferCost( address feeToken, uint224 feeTokenPrice, Client.EVMTokenAmount[] calldata tokenAmounts ) internal view returns (uint256 tokenTransferFeeUSDWei, uint32 tokenTransferGas, uint32 tokenTransferBytesOverhead) { uint256 numberOfTokens = tokenAmounts.length; for (uint256 i = 0; i < numberOfTokens; ++i) { Client.EVMTokenAmount memory tokenAmount = tokenAmounts[i]; // Validate if the token is supported, do not calculate fee for unsupported tokens. if (address(getPoolBySourceToken(i_destChainSelector, IERC20(tokenAmount.token))) == address(0)) { revert UnsupportedToken(tokenAmount.token); } TokenTransferFeeConfig memory transferFeeConfig = s_tokenTransferFeeConfig[tokenAmount.token]; // If the token has no specific overrides configured, we use the global defaults. if (!transferFeeConfig.isEnabled) { tokenTransferFeeUSDWei += uint256(s_dynamicConfig.defaultTokenFeeUSDCents) * 1e16; tokenTransferGas += s_dynamicConfig.defaultTokenDestGasOverhead; tokenTransferBytesOverhead += Pool.CCIP_POOL_V1_RET_BYTES; continue; } uint256 bpsFeeUSDWei = 0; // Only calculate bps fee if ratio is greater than 0. Ratio of 0 means no bps fee for a token. // Useful for when the PriceRegistry cannot return a valid price for the token. if (transferFeeConfig.deciBps > 0) { uint224 tokenPrice = 0; if (tokenAmount.token != feeToken) { tokenPrice = IPriceRegistry(s_dynamicConfig.priceRegistry).getValidatedTokenPrice(tokenAmount.token); } else { tokenPrice = feeTokenPrice; } // Calculate token transfer value, then apply fee ratio // ratio represents multiples of 0.1bps, or 1e-5 bpsFeeUSDWei = (tokenPrice._calcUSDValueFromTokenAmount(tokenAmount.amount) * transferFeeConfig.deciBps) / 1e5; } tokenTransferGas += transferFeeConfig.destGasOverhead; tokenTransferBytesOverhead += transferFeeConfig.destBytesOverhead; // Bps fees should be kept within range of [minFeeUSD, maxFeeUSD]. // Convert USD values with 2 decimals to 18 decimals. uint256 minFeeUSDWei = uint256(transferFeeConfig.minFeeUSDCents) * 1e16; if (bpsFeeUSDWei < minFeeUSDWei) { tokenTransferFeeUSDWei += minFeeUSDWei; continue; } uint256 maxFeeUSDWei = uint256(transferFeeConfig.maxFeeUSDCents) * 1e16; if (bpsFeeUSDWei > maxFeeUSDWei) { tokenTransferFeeUSDWei += maxFeeUSDWei; continue; } tokenTransferFeeUSDWei += bpsFeeUSDWei; } return (tokenTransferFeeUSDWei, tokenTransferGas, tokenTransferBytesOverhead); } /// @notice Gets the fee configuration for a token /// @param token The token to get the fee configuration for /// @return feeTokenConfig FeeTokenConfig struct function getFeeTokenConfig(address token) external view returns (FeeTokenConfig memory feeTokenConfig) { return s_feeTokenConfig[token]; } /// @notice Sets the fee configuration for a token /// @param feeTokenConfigArgs Array of FeeTokenConfigArgs structs. function setFeeTokenConfig(FeeTokenConfigArgs[] memory feeTokenConfigArgs) external { _onlyOwnerOrAdmin(); _setFeeTokenConfig(feeTokenConfigArgs); } /// @dev Set the fee config /// @param feeTokenConfigArgs The fee token configs. function _setFeeTokenConfig(FeeTokenConfigArgs[] memory feeTokenConfigArgs) internal { for (uint256 i = 0; i < feeTokenConfigArgs.length; ++i) { FeeTokenConfigArgs memory configArg = feeTokenConfigArgs[i]; s_feeTokenConfig[configArg.token] = FeeTokenConfig({ networkFeeUSDCents: configArg.networkFeeUSDCents, gasMultiplierWeiPerEth: configArg.gasMultiplierWeiPerEth, premiumMultiplierWeiPerEth: configArg.premiumMultiplierWeiPerEth, enabled: configArg.enabled }); } emit FeeConfigSet(feeTokenConfigArgs); } /// @notice Gets the transfer fee config for a given token. function getTokenTransferFeeConfig(address token) external view returns (TokenTransferFeeConfig memory tokenTransferFeeConfig) { return s_tokenTransferFeeConfig[token]; } /// @notice Sets the transfer fee config. /// @dev only callable by the owner or admin. function setTokenTransferFeeConfig( TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs, address[] memory tokensToUseDefaultFeeConfigs ) external { _onlyOwnerOrAdmin(); _setTokenTransferFeeConfig(tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs); } /// @notice internal helper to set the token transfer fee config. function _setTokenTransferFeeConfig( TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs, address[] memory tokensToUseDefaultFeeConfigs ) internal { for (uint256 i = 0; i < tokenTransferFeeConfigArgs.length; ++i) { TokenTransferFeeConfigArgs memory configArg = tokenTransferFeeConfigArgs[i]; if (configArg.destBytesOverhead < Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) { revert InvalidDestBytesOverhead(configArg.token, configArg.destBytesOverhead); } s_tokenTransferFeeConfig[configArg.token] = TokenTransferFeeConfig({ minFeeUSDCents: configArg.minFeeUSDCents, maxFeeUSDCents: configArg.maxFeeUSDCents, deciBps: configArg.deciBps, destGasOverhead: configArg.destGasOverhead, destBytesOverhead: configArg.destBytesOverhead, aggregateRateLimitEnabled: configArg.aggregateRateLimitEnabled, isEnabled: true }); } emit TokenTransferFeeConfigSet(tokenTransferFeeConfigArgs); // Remove the custom fee configs for the tokens that are in the tokensToUseDefaultFeeConfigs array for (uint256 i = 0; i < tokensToUseDefaultFeeConfigs.length; ++i) { delete s_tokenTransferFeeConfig[tokensToUseDefaultFeeConfigs[i]]; } if (tokensToUseDefaultFeeConfigs.length > 0) { emit TokenTransferFeeConfigDeleted(tokensToUseDefaultFeeConfigs); } } // ================================================================ // │ NOP payments │ // ================================================================ /// @notice Get the total amount of fees to be paid to the Nops (in LINK) /// @return totalNopFees function getNopFeesJuels() external view returns (uint96) { return s_nopFeesJuels; } /// @notice Gets the Nops and their weights /// @return nopsAndWeights Array of NopAndWeight structs /// @return weightsTotal The sum weight of all Nops function getNops() external view returns (NopAndWeight[] memory nopsAndWeights, uint256 weightsTotal) { uint256 length = s_nops.length(); nopsAndWeights = new NopAndWeight[](length); for (uint256 i = 0; i < length; ++i) { (address nopAddress, uint256 nopWeight) = s_nops.at(i); nopsAndWeights[i] = NopAndWeight({nop: nopAddress, weight: uint16(nopWeight)}); } weightsTotal = s_nopWeightsTotal; return (nopsAndWeights, weightsTotal); } /// @notice Sets the Nops and their weights /// @param nopsAndWeights Array of NopAndWeight structs function setNops(NopAndWeight[] calldata nopsAndWeights) external { _onlyOwnerOrAdmin(); _setNops(nopsAndWeights); } /// @param nopsAndWeights New set of nops and weights /// @dev Clears existing nops, sets new nops and weights /// @dev We permit fees to accrue before nops are configured, in which case /// they will go to the first set of configured nops. function _setNops(NopAndWeight[] memory nopsAndWeights) internal { uint256 numberOfNops = nopsAndWeights.length; if (numberOfNops > MAX_NUMBER_OF_NOPS) revert TooManyNops(); // Make sure all nops have been paid before removing nops // We only have to pay when there are nops and there is enough // outstanding NOP balance to trigger a payment. if (s_nopWeightsTotal > 0) { if (s_nopFeesJuels >= s_nopWeightsTotal) { payNops(); } } // Remove all previous nops, move from end to start to avoid shifting for (uint256 i = s_nops.length(); i > 0; --i) { (address nop,) = s_nops.at(i - 1); s_nops.remove(nop); } // Add new uint32 nopWeightsTotal = 0; // nopWeightsTotal is bounded by the MAX_NUMBER_OF_NOPS and the weight of // a single nop being of type uint16. This ensures nopWeightsTotal will // always fit into the uint32 type. for (uint256 i = 0; i < numberOfNops; ++i) { // Make sure the LINK token is not a nop because the link token doesn't allow // self transfers. If set as nop, payNops would always revert. Since setNops // calls payNops, we can never remove the LINK token as a nop. address nop = nopsAndWeights[i].nop; uint16 weight = nopsAndWeights[i].weight; if (nop == i_linkToken || nop == address(0)) revert InvalidNopAddress(nop); s_nops.set(nop, weight); nopWeightsTotal += weight; } s_nopWeightsTotal = nopWeightsTotal; emit NopsSet(nopWeightsTotal, nopsAndWeights); } /// @notice Pays the Node Ops their outstanding balances. /// @dev some balance can remain after payments are done. This is at most the sum /// of the weight of all nops. Since nop weights are uint16s and we can have at /// most MAX_NUMBER_OF_NOPS NOPs, the highest possible value is 2**22 or 0.04 gjuels. function payNops() public { if (msg.sender != owner()) { if (msg.sender != s_admin) { if (!s_nops.contains(msg.sender)) { revert OnlyCallableByOwnerOrAdminOrNop(); } } } uint256 weightsTotal = s_nopWeightsTotal; if (weightsTotal == 0) revert NoNopsToPay(); uint96 totalFeesToPay = s_nopFeesJuels; if (totalFeesToPay < weightsTotal) revert NoFeesToPay(); if (linkAvailableForPayment() < 0) revert InsufficientBalance(); uint96 fundsLeft = totalFeesToPay; uint256 numberOfNops = s_nops.length(); for (uint256 i = 0; i < numberOfNops; ++i) { (address nop, uint256 weight) = s_nops.at(i); // amount can never be higher than totalFeesToPay so the cast to uint96 is safe uint96 amount = uint96((totalFeesToPay * weight) / weightsTotal); fundsLeft -= amount; IERC20(i_linkToken).safeTransfer(nop, amount); emit NopPaid(nop, amount); } // Some funds can remain, since this is an incredibly small // amount we consider this OK. s_nopFeesJuels = fundsLeft; } /// @notice Allows the owner to withdraw any ERC20 token from the contract. /// The NOP link balance is not withdrawable. /// @param feeToken The token to withdraw /// @param to The address to send the tokens to function withdrawNonLinkFees(address feeToken, address to) external { _onlyOwnerOrAdmin(); if (to == address(0)) revert InvalidWithdrawParams(); // We require the link balance to be settled before allowing withdrawal of non-link fees. int256 linkAfterNopFees = linkAvailableForPayment(); if (linkAfterNopFees < 0) revert LinkBalanceNotSettled(); if (feeToken == i_linkToken) { // Withdraw only the left over link balance IERC20(feeToken).safeTransfer(to, uint256(linkAfterNopFees)); } else { // Withdrawal all non-link tokens in the contract IERC20(feeToken).safeTransfer(to, IERC20(feeToken).balanceOf(address(this))); } } // ================================================================ // │ Link monitoring │ // ================================================================ /// @notice Calculate remaining LINK balance after paying nops /// @dev Allow keeper to monitor funds available for paying nops /// @return balance if nops were to be paid function linkAvailableForPayment() public view returns (int256) { // Since LINK caps at uint96, casting to int256 is safe return int256(IERC20(i_linkToken).balanceOf(address(this))) - int256(uint256(s_nopFeesJuels)); } // ================================================================ // │ Access │ // ================================================================ /// @dev Require that the sender is the owner or the fee admin /// Not a modifier to save on contract size function _onlyOwnerOrAdmin() internal view { if (msg.sender != owner()) { if (msg.sender != s_admin) { revert OnlyCallableByOwnerOrAdmin(); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ITypeAndVersion { function typeAndVersion() external pure returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IEVM2AnyOnRampClient} from "./IEVM2AnyOnRampClient.sol"; interface IEVM2AnyOnRamp is IEVM2AnyOnRampClient { /// @notice Gets the next sequence number to be used in the onRamp /// @return the next sequence number to be used function getExpectedNextSequenceNumber() external view returns (uint64); /// @notice Get the next nonce for a given sender /// @param sender The sender to get the nonce for /// @return nonce The next nonce for the sender function getSenderNonce(address sender) external view returns (uint64 nonce); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IPoolV1} from "./IPool.sol"; import {Client} from "../libraries/Client.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; interface IEVM2AnyOnRampClient { /// @notice Get the fee for a given ccip message /// @param destChainSelector The destination chain selector /// @param message The message to calculate the cost for /// @return fee The calculated fee function getFee(uint64 destChainSelector, Client.EVM2AnyMessage calldata message) external view returns (uint256 fee); /// @notice Get the pool for a specific token /// @param destChainSelector The destination chain selector /// @param sourceToken The source chain token to get the pool for /// @return pool Token pool function getPoolBySourceToken(uint64 destChainSelector, IERC20 sourceToken) external view returns (IPoolV1); /// @notice Gets a list of all supported source chain tokens. /// @param destChainSelector The destination chain selector /// @return tokens The addresses of all tokens that this onRamp supports the given destination chain function getSupportedTokens(uint64 destChainSelector) external view returns (address[] memory tokens); /// @notice Send a message to the remote chain /// @dev only callable by the Router /// @dev approve() must have already been called on the token using the this ramp address as the spender. /// @dev if the contract is paused, this function will revert. /// @param destChainSelector The destination chain selector /// @param message Message struct to send /// @param feeTokenAmount Amount of fee tokens for payment /// @param originalSender The original initiator of the CCIP request function forwardFromRouter( uint64 destChainSelector, Client.EVM2AnyMessage memory message, uint256 feeTokenAmount, address originalSender ) external returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Pool} from "../libraries/Pool.sol"; import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol"; /// @notice Shared public interface for multiple V1 pool types. /// Each pool type handles a different child token model (lock/unlock, mint/burn.) interface IPoolV1 is IERC165 { /// @notice Lock tokens into the pool or burn the tokens. /// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain. /// @return lockOrBurnOut Encoded data fields for the processing of tokens on the destination chain. function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn) external returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut); /// @notice Releases or mints tokens to the receiver address. /// @param releaseOrMintIn All data required to release or mint tokens. /// @return releaseOrMintOut The amount of tokens released or minted on the local chain, denominated /// in the local token's decimals. /// @dev The offramp asserts that the balanceOf of the receiver has been incremented by exactly the number /// of tokens that is returned in ReleaseOrMintOutV1.destinationAmount. If the amounts do not match, the tx reverts. function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn) external returns (Pool.ReleaseOrMintOutV1 memory); /// @notice Checks whether a remote chain is supported in the token pool. /// @param remoteChainSelector The selector of the remote chain. /// @return true if the given chain is a permissioned remote chain. function isSupportedChain(uint64 remoteChainSelector) external view returns (bool); /// @notice Returns if the token pool supports the given token. /// @param token The address of the token. /// @return true if the token is supported by the pool. function isSupportedToken(address token) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Client} from "../libraries/Client.sol"; import {Internal} from "../libraries/Internal.sol"; interface IPriceRegistry { /// @notice Token price data feed configuration struct TokenPriceFeedConfig { address dataFeedAddress; // ──╮ AggregatorV3Interface contract (0 - feed is unset) uint8 tokenDecimals; // ──────╯ Decimals of the token that the feed represents } /// @notice Update the price for given tokens and gas prices for given chains. /// @param priceUpdates The price updates to apply. function updatePrices(Internal.PriceUpdates memory priceUpdates) external; /// @notice Get the `tokenPrice` for a given token. /// @param token The token to get the price for. /// @return tokenPrice The tokenPrice for the given token. function getTokenPrice(address token) external view returns (Internal.TimestampedPackedUint224 memory); /// @notice Get the `tokenPrice` for a given token, checks if the price is valid. /// @param token The token to get the price for. /// @return tokenPrice The tokenPrice for the given token if it exists and is valid. function getValidatedTokenPrice(address token) external view returns (uint224); /// @notice Get the `tokenPrice` for an array of tokens. /// @param tokens The tokens to get prices for. /// @return tokenPrices The tokenPrices for the given tokens. function getTokenPrices(address[] calldata tokens) external view returns (Internal.TimestampedPackedUint224[] memory); /// @notice Returns the token price data feed configuration /// @param token The token to retrieve the feed config for /// @return dataFeedAddress The token price data feed config (if feed address is 0, the feed config is disabled) function getTokenPriceFeedConfig(address token) external view returns (TokenPriceFeedConfig memory); /// @notice Get an encoded `gasPrice` for a given destination chain ID. /// The 224-bit result encodes necessary gas price components. /// On L1 chains like Ethereum or Avax, the only component is the gas price. /// On Optimistic Rollups, there are two components - the L2 gas price, and L1 base fee for data availability. /// On future chains, there could be more or differing price components. /// PriceRegistry does not contain chain-specific logic to parse destination chain price components. /// @param destChainSelector The destination chain to get the price for. /// @return gasPrice The encoded gasPrice for the given destination chain ID. function getDestinationChainGasPrice(uint64 destChainSelector) external view returns (Internal.TimestampedPackedUint224 memory); /// @notice Gets the fee token price and the gas price, both denominated in dollars. /// @param token The source token to get the price for. /// @param destChainSelector The destination chain to get the gas price for. /// @return tokenPrice The price of the feeToken in 1e18 dollars per base unit. /// @return gasPrice The price of gas in 1e18 dollars per base unit. function getTokenAndGasPrices( address token, uint64 destChainSelector ) external view returns (uint224 tokenPrice, uint224 gasPrice); /// @notice Convert a given token amount to target token amount. /// @param fromToken The given token address. /// @param fromTokenAmount The given token amount. /// @param toToken The target token address. /// @return toTokenAmount The target token amount. function convertTokenAmount( address fromToken, uint256 fromTokenAmount, address toToken ) external view returns (uint256 toTokenAmount); /// @notice Get the list of fee tokens. /// @return The tokens set as fee tokens. function getFeeTokens() external view returns (address[] memory); /// @notice Validates the ccip message & returns the fee /// @param destChainSelector The destination chain selector. /// @param message The message to get quote for. /// @return feeTokenAmount The amount of fee token needed for the fee, in smallest denomination of the fee token. function getValidatedFee( uint64 destChainSelector, Client.EVM2AnyMessage calldata message ) external view returns (uint256 feeTokenAmount); /// @notice Converts the extraArgs to the latest version and returns the converted message fee in juels /// @param destChainSelector destination chain selector to process /// @param feeToken Fee token address used to pay for message fees /// @param feeTokenAmount Fee token amount /// @param extraArgs Message extra args that were passed in by the client /// @return msgFeeJuels message fee in juels /// @return isOutOfOrderExecution true if the message should be executed out of order /// @return convertedExtraArgs extra args converted to the latest family-specific args version function processMessageArgs( uint64 destChainSelector, address feeToken, uint256 feeTokenAmount, bytes memory extraArgs ) external view returns (uint256 msgFeeJuels, bool isOutOfOrderExecution, bytes memory convertedExtraArgs); /// @notice Validates pool return data /// @param destChainSelector Destination chain selector to which the token amounts are sent to /// @param rampTokenAmounts Token amounts with populated pool return data /// @param sourceTokenAmounts Token amounts originally sent in a Client.EVM2AnyMessage message function validatePoolReturnData( uint64 destChainSelector, Internal.RampTokenAmount[] calldata rampTokenAmounts, Client.EVMTokenAmount[] calldata sourceTokenAmounts ) external view; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts. interface IRMN { /// @notice A Merkle root tagged with the address of the commit store contract it is destined for. struct TaggedRoot { address commitStore; bytes32 root; } /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed. function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool); /// @notice Iff there is an active global or legacy curse, this function returns true. function isCursed() external view returns (bool); /// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true. /// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)). function isCursed(bytes16 subject) external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface ITokenAdminRegistry { /// @notice Returns the pool for the given token. function getPool(address token) external view returns (address); /// @notice Proposes an administrator for the given token as pending administrator. /// @param localToken The token to register the administrator for. /// @param administrator The administrator to register. function proposeAdministrator(address localToken, address administrator) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice Implement this contract so that a keeper-compatible contract can monitor /// and fund the implementation contract with LINK if it falls below a defined threshold. interface ILinkAvailable { function linkAvailableForPayment() external view returns (int256 availableBalance); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol"; import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol"; import {Client} from "./libraries/Client.sol"; import {RateLimiter} from "./libraries/RateLimiter.sol"; import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol"; /// @notice The aggregate rate limiter is a wrapper of the token bucket rate limiter /// which permits rate limiting based on the aggregate value of a group of /// token transfers, using a price registry to convert to a numeraire asset (e.g. USD). contract AggregateRateLimiter is OwnerIsCreator { using RateLimiter for RateLimiter.TokenBucket; using USDPriceWith18Decimals for uint224; error PriceNotFoundForToken(address token); event AdminSet(address newAdmin); // The address of the token limit admin that has the same permissions as the owner. address internal s_admin; // The token bucket object that contains the bucket state. RateLimiter.TokenBucket private s_rateLimiter; /// @param config The RateLimiter.Config constructor(RateLimiter.Config memory config) { s_rateLimiter = RateLimiter.TokenBucket({ rate: config.rate, capacity: config.capacity, tokens: config.capacity, lastUpdated: uint32(block.timestamp), isEnabled: config.isEnabled }); } /// @notice Consumes value from the rate limiter bucket based on the token value given. function _rateLimitValue(uint256 value) internal { s_rateLimiter._consume(value, address(0)); } function _getTokenValue( Client.EVMTokenAmount memory tokenAmount, IPriceRegistry priceRegistry ) internal view returns (uint256) { // not fetching validated price, as price staleness is not important for value-based rate limiting // we only need to verify the price is not 0 uint224 pricePerToken = priceRegistry.getTokenPrice(tokenAmount.token).value; if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmount.token); return pricePerToken._calcUSDValueFromTokenAmount(tokenAmount.amount); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function currentRateLimiterState() external view returns (RateLimiter.TokenBucket memory) { return s_rateLimiter._currentTokenBucketState(); } /// @notice Sets the rate limited config. /// @param config The new rate limiter config. /// @dev should only be callable by the owner or token limit admin. function setRateLimiterConfig(RateLimiter.Config memory config) external onlyAdminOrOwner { s_rateLimiter._setTokenBucketConfig(config); } // ================================================================ // │ Access │ // ================================================================ /// @notice Gets the token limit admin address. /// @return the token limit admin address. function getTokenLimitAdmin() external view returns (address) { return s_admin; } /// @notice Sets the token limit admin address. /// @param newAdmin the address of the new admin. /// @dev setting this to address(0) indicates there is no active admin. function setAdmin(address newAdmin) external onlyAdminOrOwner { s_admin = newAdmin; emit AdminSet(newAdmin); } /// @notice a modifier that allows the owner or the s_tokenLimitAdmin call the functions /// it is applied to. modifier onlyAdminOrOwner() { if (msg.sender != owner() && msg.sender != s_admin) revert RateLimiter.OnlyCallableByAdminOrOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // End consumer library. library Client { /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct EVMTokenAmount { address token; // token address on the local chain. uint256 amount; // Amount of tokens. } struct Any2EVMMessage { bytes32 messageId; // MessageId corresponding to ccipSend on source. uint64 sourceChainSelector; // Source chain selector. bytes sender; // abi.decode(sender) if coming from an EVM chain. bytes data; // payload sent in original message. EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation. } // If extraArgs is empty bytes, the default is 200k gas limit. struct EVM2AnyMessage { bytes receiver; // abi.encode(receiver address) for dest EVM chains bytes data; // Data payload EVMTokenAmount[] tokenAmounts; // Token transfers address feeToken; // Address of feeToken. address(0) means you will send msg.value. bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2) } // bytes4(keccak256("CCIP EVMExtraArgsV1")); bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9; struct EVMExtraArgsV1 { uint256 gasLimit; } function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs); } // bytes4(keccak256("CCIP EVMExtraArgsV2")); bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10; /// @param gasLimit: gas limit for the callback on the destination chain. /// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender. /// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value /// is not set, the message request will revert. struct EVMExtraArgsV2 { uint256 gasLimit; bool allowOutOfOrderExecution; } function _argsToBytes(EVMExtraArgsV2 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol"; import {Client} from "./Client.sol"; // Library for CCIP internal definitions common to multiple contracts. library Internal { error InvalidEVMAddress(bytes encodedAddress); /// @dev The minimum amount of gas to perform the call with exact gas. /// We include this in the offramp so that we can redeploy to adjust it /// should a hardfork change the gas costs of relevant opcodes in callWithExactGas. uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5_000; // @dev We limit return data to a selector plus 4 words. This is to avoid // malicious contracts from returning large amounts of data and causing // repeated out-of-gas scenarios. uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32; /// @dev The expected number of bytes returned by the balanceOf function. uint256 internal constant MAX_BALANCE_OF_RET_BYTES = 32; /// @notice A collection of token price and gas price updates. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct PriceUpdates { TokenPriceUpdate[] tokenPriceUpdates; GasPriceUpdate[] gasPriceUpdates; } /// @notice Token price in USD. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct TokenPriceUpdate { address sourceToken; // Source token uint224 usdPerToken; // 1e18 USD per 1e18 of the smallest token denomination. } /// @notice Gas price for a given chain in USD, its value may contain tightly packed fields. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct GasPriceUpdate { uint64 destChainSelector; // Destination chain selector uint224 usdPerUnitGas; // 1e18 USD per smallest unit (e.g. wei) of destination chain gas } /// @notice A timestamped uint224 value that can contain several tightly packed fields. struct TimestampedPackedUint224 { uint224 value; // ───────╮ Value in uint224, packed. uint32 timestamp; // ────╯ Timestamp of the most recent price update. } /// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices. /// When packing L1 and L2 gas prices, L1 gas price is left-shifted to the higher-order bits. /// Using uint8 type, which cannot be higher than other bit shift operands, to avoid shift operand type warning. uint8 public constant GAS_PRICE_BITS = 112; struct PoolUpdate { address token; // The IERC20 token address address pool; // The token pool address } struct SourceTokenData { // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be // relied upon by the destination pool to validate the source pool. bytes sourcePoolAddress; // 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 extraData; uint32 destGasAmount; // The amount of gas available for the releaseOrMint and balanceOf calls on the offRamp } /// @notice Report that is submitted by the execution DON at the execution phase. (including chain selector data) /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct ExecutionReportSingleChain { uint64 sourceChainSelector; // Source chain selector for which the report is submitted Any2EVMRampMessage[] messages; // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token bytes[][] offchainTokenData; bytes32[] proofs; uint256 proofFlagBits; } /// @notice Report that is submitted by the execution DON at the execution phase. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct ExecutionReport { EVM2EVMMessage[] messages; // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token bytes[][] offchainTokenData; bytes32[] proofs; uint256 proofFlagBits; } /// @notice The cross chain message that gets committed to EVM chains. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct EVM2EVMMessage { uint64 sourceChainSelector; // ────────╮ the chain selector of the source chain, note: not chainId address sender; // ────────────────────╯ sender address on the source chain address receiver; // ──────────────────╮ receiver address on the destination chain uint64 sequenceNumber; // ─────────────╯ sequence number, not unique across lanes uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution bool strict; // ───────────────────────╮ DEPRECATED uint64 nonce; // │ nonce for this lane for this sender, not unique across senders/lanes address feeToken; // ──────────────────╯ fee token uint256 feeTokenAmount; // fee token amount bytes data; // arbitrary data payload supplied by the message sender Client.EVMTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer bytes[] sourceTokenData; // array of token data, one per token bytes32 messageId; // a hash of the message data } /// @dev EVM2EVMMessage struct has 13 fields, including 3 variable arrays. /// Each variable array takes 1 more slot to store its length. /// When abi encoded, excluding array contents, /// EVM2EVMMessage takes up a fixed number of 16 lots, 32 bytes each. /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 17. uint256 public constant MESSAGE_FIXED_BYTES = 32 * 17; /// @dev Each token transfer adds 1 EVMTokenAmount and 3 bytes at 3 slots each and one slot for the destGasAmount. /// When abi encoded, each EVMTokenAmount takes 2 slots, each bytes takes 1 slot for length, one slot of data and one /// slot for the offset. This results in effectively 3*3 slots per SourceTokenData. /// 0x20 /// destGasAmount /// sourcePoolAddress_offset /// destTokenAddress_offset /// extraData_offset /// sourcePoolAddress_length /// sourcePoolAddress_content // assume 1 slot /// destTokenAddress_length /// destTokenAddress_content // assume 1 slot /// extraData_length // contents billed separately uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * ((1 + 3 * 3) + 2); /// @dev Any2EVMRampMessage struct has 10 fields, including 3 variable unnested arrays (data, receiver and tokenAmounts). /// Each variable array takes 1 more slot to store its length. /// When abi encoded, excluding array contents, /// Any2EVMMessage takes up a fixed number of 13 slots, 32 bytes each. /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 14. /// The fixed bytes does not cover struct data (this is represented by ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN) uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES = 32 * 14; /// @dev Each token transfer adds 1 RampTokenAmount /// RampTokenAmount has 4 fields, including 3 bytes. /// Each bytes takes 1 more slot to store its length, and one slot to store the offset. /// When abi encoded, each token transfer takes up 10 slots, excl bytes contents. uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * 10; bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageHashV2"); /// @dev Used to hash messages for single-lane ramps. /// OnRamp hash(EVM2EVMMessage) = OffRamp hash(EVM2EVMMessage) /// The EVM2EVMMessage's messageId is expected to be the output of this hash function /// @param original Message to hash /// @param metadataHash Immutable metadata hash representing a lane with a fixed OnRamp /// @return hashedMessage hashed message as a keccak256 function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) { // Fixed-size message fields are included in nested hash to reduce stack pressure. // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers. return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, metadataHash, keccak256( abi.encode( original.sender, original.receiver, original.sequenceNumber, original.gasLimit, original.strict, original.nonce, original.feeToken, original.feeTokenAmount ) ), keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)), keccak256(abi.encode(original.sourceTokenData)) ) ); } bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256("Any2EVMMessageHashV1"); bytes32 internal constant EVM_2_ANY_MESSAGE_HASH = keccak256("EVM2AnyMessageHashV1"); /// @dev Used to hash messages for multi-lane family-agnostic OffRamps. /// OnRamp hash(EVM2AnyMessage) != Any2EVMRampMessage.messageId /// OnRamp hash(EVM2AnyMessage) != OffRamp hash(Any2EVMRampMessage) /// @param original OffRamp message to hash /// @param onRamp OnRamp to hash the message with - used to compute the metadataHash /// @return hashedMessage hashed message as a keccak256 function _hash(Any2EVMRampMessage memory original, bytes memory onRamp) internal pure returns (bytes32) { // Fixed-size message fields are included in nested hash to reduce stack pressure. // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers. return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, // Implicit metadata hash keccak256( abi.encode( ANY_2_EVM_MESSAGE_HASH, original.header.sourceChainSelector, original.header.destChainSelector, onRamp ) ), keccak256( abi.encode( original.header.messageId, original.sender, original.receiver, original.header.sequenceNumber, original.gasLimit, original.header.nonce ) ), keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)) ) ); } function _hash(EVM2AnyRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) { // Fixed-size message fields are included in nested hash to reduce stack pressure. // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers. return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, metadataHash, keccak256( abi.encode( original.sender, original.receiver, original.header.sequenceNumber, original.header.nonce, original.feeToken, original.feeTokenAmount ) ), keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)), keccak256(original.extraArgs) ) ); } /// @dev We disallow the first 1024 addresses to avoid calling into a range known for hosting precompiles. Calling /// into precompiles probably won't cause any issues, but to be safe we can disallow this range. It is extremely /// unlikely that anyone would ever be able to generate an address in this range. There is no official range of /// precompiles, but EIP-7587 proposes to reserve the range 0x100 to 0x1ff. Our range is more conservative, even /// though it might not be exhaustive for all chains, which is OK. We also disallow the zero address, which is a /// common practice. uint256 public constant PRECOMPILE_SPACE = 1024; /// @notice This methods provides validation for parsing abi encoded addresses by ensuring the /// address is within the EVM address space. If it isn't it will revert with an InvalidEVMAddress error, which /// we can catch and handle more gracefully than a revert from abi.decode. /// @return The address if it is valid, the function will revert otherwise. function _validateEVMAddress(bytes memory encodedAddress) internal pure returns (address) { if (encodedAddress.length != 32) revert InvalidEVMAddress(encodedAddress); uint256 encodedAddressUint = abi.decode(encodedAddress, (uint256)); if (encodedAddressUint > type(uint160).max || encodedAddressUint < PRECOMPILE_SPACE) { revert InvalidEVMAddress(encodedAddress); } return address(uint160(encodedAddressUint)); } /// @notice Enum listing the possible message execution states within /// the offRamp contract. /// UNTOUCHED never executed /// IN_PROGRESS currently being executed, used a replay protection /// SUCCESS successfully executed. End state /// FAILURE unsuccessfully executed, manual execution is now enabled. /// @dev RMN depends on this enum, if changing, please notify the RMN maintainers. enum MessageExecutionState { UNTOUCHED, IN_PROGRESS, SUCCESS, FAILURE } /// @notice CCIP OCR plugin type, used to separate execution & commit transmissions and configs enum OCRPluginType { Commit, Execution } /// @notice Family-agnostic token amounts used for both OnRamp & OffRamp messages struct RampTokenAmount { // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be // relied upon by the destination pool to validate the source pool. bytes sourcePoolAddress; // 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 extraData; uint256 amount; // Amount of tokens. } /// @notice Family-agnostic header for OnRamp & OffRamp messages. /// The messageId is not expected to match hash(message), since it may originate from another ramp family struct RampMessageHeader { bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded) uint64 sourceChainSelector; // ──╮ the chain selector of the source chain, note: not chainId uint64 destChainSelector; // | the chain selector of the destination chain, note: not chainId uint64 sequenceNumber; // │ sequence number, not unique across lanes uint64 nonce; // ────────────────╯ nonce for this lane for this sender, not unique across senders/lanes } /// @notice Family-agnostic message routed to an OffRamp /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage), hash(Any2EVMRampMessage) != messageId /// due to encoding & parameter differences struct Any2EVMRampMessage { RampMessageHeader header; // Message header bytes sender; // sender address on the source chain bytes data; // arbitrary data payload supplied by the message sender address receiver; // receiver address on the destination chain uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution RampTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer } /// @notice Family-agnostic message emitted from the OnRamp /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage) due to encoding & parameter differences /// messageId = hash(EVM2AnyRampMessage) using the source EVM chain's encoding format struct EVM2AnyRampMessage { RampMessageHeader header; // Message header address sender; // sender address on the source chain bytes data; // arbitrary data payload supplied by the message sender bytes receiver; // receiver address on the destination chain bytes extraArgs; // destination-chain specific extra args, such as the gasLimit for EVM chains address feeToken; // fee token uint256 feeTokenAmount; // fee token amount RampTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer } // bytes4(keccak256("CCIP ChainFamilySelector EVM")) bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice This library contains various token pool functions to aid constructing the return data. library Pool { // The tag used to signal support for the pool v1 standard // bytes4(keccak256("CCIP_POOL_V1")) bytes4 public constant CCIP_POOL_V1 = 0xaff2afbf; // The number of bytes in the return data for a pool v1 releaseOrMint call. // This should match the size of the ReleaseOrMintOutV1 struct. uint16 public constant CCIP_POOL_V1_RET_BYTES = 32; // The default max number of bytes in the return data for a pool v1 lockOrBurn call. // This data can be used to send information to the destination chain token pool. Can be overwritten // in the TokenTransferFeeConfig.destBytesOverhead if more data is required. uint32 public constant CCIP_LOCK_OR_BURN_V1_RET_BYTES = 32; struct LockOrBurnInV1 { bytes receiver; // The recipient of the tokens on the destination chain, abi encoded uint64 remoteChainSelector; // ─╮ The chain ID of the destination chain address originalSender; // ─────╯ The original sender of the tx on the source chain uint256 amount; // The amount of tokens to lock or burn, denominated in the source token's decimals address localToken; // The address on this chain of the token to lock or burn } struct LockOrBurnOutV1 { // The address of the destination token, abi encoded in the case of EVM chains // This value is UNTRUSTED as any pool owner can return whatever value they want. bytes destTokenAddress; // Optional pool data to be transferred to the destination chain. Be default this is capped at // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead // has to be set for the specific token. bytes destPoolData; } struct ReleaseOrMintInV1 { bytes originalSender; // The original sender of the tx on the source chain uint64 remoteChainSelector; // ─╮ The chain ID of the source chain address receiver; // ───────────╯ The recipient of the tokens on the destination chain. uint256 amount; // The amount of tokens to release or mint, denominated in the source token's decimals address localToken; // The address on this chain of the token to release or mint /// @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the /// expected pool address for the given remoteChainSelector. bytes sourcePoolAddress; // The address of the source pool, abi encoded in the case of EVM chains bytes sourcePoolData; // The data received from the source pool to process the release or mint /// @dev WARNING: offchainTokenData is untrusted data. bytes offchainTokenData; // The offchain data to process the release or mint } struct ReleaseOrMintOutV1 { // The number of tokens released or minted on the destination chain, denominated in the local token's decimals. // This value is expected to be equal to the ReleaseOrMintInV1.amount in the case where the source and destination // chain have the same number of decimals. uint256 destinationAmount; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// @notice Implements Token Bucket rate limiting. /// @dev uint128 is safe for rate limiter state. /// For USD value rate limiting, it can adequately store USD value in 18 decimals. /// For ERC20 token amount rate limiting, all tokens that will be listed will have at most /// a supply of uint128.max tokens, and it will therefore not overflow the bucket. /// In exceptional scenarios where tokens consumed may be larger than uint128, /// e.g. compromised issuer, an enabled RateLimiter will check and revert. library RateLimiter { error BucketOverfilled(); error OnlyCallableByAdminOrOwner(); error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress); error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress); error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested); error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available); error InvalidRateLimitRate(Config rateLimiterConfig); error DisabledNonZeroRateLimit(Config config); error RateLimitMustBeDisabled(); event TokensConsumed(uint256 tokens); event ConfigChanged(Config config); struct TokenBucket { uint128 tokens; // ──────╮ Current number of tokens that are in the bucket. uint32 lastUpdated; // │ Timestamp in seconds of the last token refill, good for 100+ years. bool isEnabled; // ──────╯ Indication whether the rate limiting is enabled or not uint128 capacity; // ────╮ Maximum number of tokens that can be in the bucket. uint128 rate; // ────────╯ Number of tokens per second that the bucket is refilled. } struct Config { bool isEnabled; // Indication whether the rate limiting should be enabled uint128 capacity; // ────╮ Specifies the capacity of the rate limiter uint128 rate; // ───────╯ Specifies the rate of the rate limiter } /// @notice _consume removes the given tokens from the pool, lowering the /// rate tokens allowed to be consumed for subsequent calls. /// @param requestTokens The total tokens to be consumed from the bucket. /// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity. /// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket /// @dev emits removal of requestTokens if requestTokens is > 0 function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal { // If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage if (!s_bucket.isEnabled || requestTokens == 0) { return; } uint256 tokens = s_bucket.tokens; uint256 capacity = s_bucket.capacity; uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { if (tokens > capacity) revert BucketOverfilled(); // Refill tokens when arriving at a new block time tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate); s_bucket.lastUpdated = uint32(block.timestamp); } if (capacity < requestTokens) { // Token address 0 indicates consuming aggregate value rate limit capacity. if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens); revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress); } if (tokens < requestTokens) { uint256 rate = s_bucket.rate; // Wait required until the bucket is refilled enough to accept this value, round up to next higher second // Consume is not guaranteed to succeed after wait time passes if there is competing traffic. // This acts as a lower bound of wait time. uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate; if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens); revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress); } tokens -= requestTokens; // Downcast is safe here, as tokens is not larger than capacity s_bucket.tokens = uint128(tokens); emit TokensConsumed(requestTokens); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function _currentTokenBucketState(TokenBucket memory bucket) internal view returns (TokenBucket memory) { // We update the bucket to reflect the status at the exact time of the // call. This means we might need to refill a part of the bucket based // on the time that has passed since the last update. bucket.tokens = uint128(_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate)); bucket.lastUpdated = uint32(block.timestamp); return bucket; } /// @notice Sets the rate limited config. /// @param s_bucket The token bucket /// @param config The new config function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal { // First update the bucket to make sure the proper rate is used for all the time // up until the config change. uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate)); s_bucket.lastUpdated = uint32(block.timestamp); } s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens)); s_bucket.isEnabled = config.isEnabled; s_bucket.capacity = config.capacity; s_bucket.rate = config.rate; emit ConfigChanged(config); } /// @notice Validates the token bucket config function _validateTokenBucketConfig(Config memory config, bool mustBeDisabled) internal pure { if (config.isEnabled) { if (config.rate >= config.capacity || config.rate == 0) { revert InvalidRateLimitRate(config); } if (mustBeDisabled) { revert RateLimitMustBeDisabled(); } } else { if (config.rate != 0 || config.capacity != 0) { revert DisabledNonZeroRateLimit(config); } } } /// @notice Calculate refilled tokens /// @param capacity bucket capacity /// @param tokens current bucket tokens /// @param timeDiff block time difference since last refill /// @param rate bucket refill rate /// @return the value of tokens after refill function _calculateRefill( uint256 capacity, uint256 tokens, uint256 timeDiff, uint256 rate ) private pure returns (uint256) { return _min(capacity, tokens + timeDiff * rate); } /// @notice Return the smallest of two integers /// @param a first int /// @param b second int /// @return smallest function _min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; library USDPriceWith18Decimals { /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount, /// and amount of the smallest token denomination, /// calculates the value in USD with 18 decimals. /// @param tokenPrice The USD price of the token. /// @param tokenAmount Amount of the smallest token denomination. /// @return USD value with 18 decimals. /// @dev this function assumes that no more than 1e59 US dollar worth of token is passed in. /// If more is sent, this function will overflow and revert. /// Since there isn't even close to 1e59 dollars, this is ok for all legit tokens. function _calcUSDValueFromTokenAmount(uint224 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) { /// LINK Example: /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals /// tokenAmount: 2e18 -> 2 LINK /// result: 8e18 * 2e18 / 1e18 -> 16e18 with 18 decimals = $16 /// USDC Example: /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals /// tokenAmount: 5e6 -> 5 USDC /// result: 1e30 * 5e6 / 1e18 -> 5e18 with 18 decimals = $5 return (tokenPrice * tokenAmount) / 1e18; } /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount, /// and USD value with 18 decimals, /// calculates amount of the smallest token denomination. /// @param tokenPrice The USD price of the token. /// @param usdValue USD value with 18 decimals. /// @return Amount of the smallest token denomination. function _calcTokenAmountFromUSDValue(uint224 tokenPrice, uint256 usdValue) internal pure returns (uint256) { /// LINK Example: /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals /// usdValue: 16e18 -> $16 /// result: 16e18 * 1e18 / 8e18 -> 2e18 = 2 LINK /// USDC Example: /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals /// usdValue: 5e18 -> $5 /// result: 5e18 * 1e18 / 1e30 -> 5e6 = 5 USDC return (usdValue * 1e18) / tokenPrice; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. pragma solidity ^0.8.20; import {EnumerableSet} from "./EnumerableSet.sol"; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * The following map types are supported: * * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 * * [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 EnumerableMap, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableMap. * ==== */ library EnumerableMap { using EnumerableSet for EnumerableSet.Bytes32Set; // To implement this library for multiple types with as little code repetition as possible, we write it in // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map. // This means that we can only create new EnumerableMaps for types that fit in bytes32. /** * @dev Query for a nonexistent map key. */ error EnumerableMapNonexistentKey(bytes32 key); struct Bytes32ToBytes32Map { // Storage of keys EnumerableSet.Bytes32Set _keys; mapping(bytes32 key => bytes32) _values; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { map._values[key] = value; return map._keys.add(key); } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { delete map._values[key]; return map._keys.remove(key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { return map._keys.contains(key); } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { return map._keys.length(); } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { bytes32 key = map._keys.at(index); return (key, map._values[key]); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { bytes32 value = map._values[key]; if (value == bytes32(0)) { return (contains(map, key), bytes32(0)); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { bytes32 value = map._values[key]; if (value == 0 && !contains(map, key)) { revert EnumerableMapNonexistentKey(key); } return value; } /** * @dev Return the an array containing all the keys * * 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 map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { return map._keys.values(); } // UintToUintMap struct UintToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. 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(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(key))); } /** * @dev Return the an array containing all the keys * * 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 map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintToAddressMap struct UintToAddressMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. 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(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key))))); } /** * @dev Return the an array containing all the keys * * 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 map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressToUintMap struct AddressToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(AddressToUintMap storage map, address key) internal returns (bool) { return remove(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(AddressToUintMap storage map, address key) internal view returns (bool) { return contains(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. O(1). */ function length(AddressToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. 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(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (address(uint160(uint256(key))), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(AddressToUintMap storage map, address key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))))); } /** * @dev Return the an array containing all the keys * * 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 map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(AddressToUintMap storage map) internal view returns (address[] memory) { bytes32[] memory store = keys(map._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // Bytes32ToUintMap struct Bytes32ToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { return set(map._inner, key, bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { return remove(map._inner, key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { return contains(map._inner, key); } /** * @dev Returns the number of elements in the map. O(1). */ function length(Bytes32ToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. 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(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (key, uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, key); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { return uint256(get(map._inner, key)); } /** * @dev Return the an array containing all the keys * * 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 map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { bytes32[] memory store = keys(map._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ConfirmedOwner} from "./ConfirmedOwner.sol"; /// @title The OwnerIsCreator contract /// @notice A contract with helpers for basic contract ownership. contract OwnerIsCreator is ConfirmedOwner { constructor() ConfirmedOwner(msg.sender) {} }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; library MerkleMultiProof { /// @notice Leaf domain separator, should be used as the first 32 bytes of a leaf's preimage. bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000; /// @notice Internal domain separator, should be used as the first 32 bytes of an internal node's preiimage. bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000001; uint256 internal constant MAX_NUM_HASHES = 256; error InvalidProof(); error LeavesCannotBeEmpty(); /// @notice Computes the root based on provided pre-hashed leaf nodes in /// leaves, internal nodes in proofs, and using proofFlagBits' i-th bit to /// determine if an element of proofs or one of the previously computed leafs /// or internal nodes will be used for the i-th hash. /// @param leaves Should be pre-hashed and the first 32 bytes of a leaf's /// preimage should match LEAF_DOMAIN_SEPARATOR. /// @param proofs The hashes to be used instead of a leaf hash when the proofFlagBits /// indicates a proof should be used. /// @param proofFlagBits A single uint256 of which each bit indicates whether a leaf or /// a proof needs to be used in a hash operation. /// @dev the maximum number of hash operations it set to 256. Any input that would require /// more than 256 hashes to get to a root will revert. /// @dev For given input `leaves` = [a,b,c] `proofs` = [D] and `proofFlagBits` = 5 /// totalHashes = 3 + 1 - 1 = 3 /// ** round 1 ** /// proofFlagBits = (5 >> 0) & 1 = true /// hashes[0] = hashPair(a, b) /// (leafPos, hashPos, proofPos) = (2, 0, 0); /// /// ** round 2 ** /// proofFlagBits = (5 >> 1) & 1 = false /// hashes[1] = hashPair(D, c) /// (leafPos, hashPos, proofPos) = (3, 0, 1); /// /// ** round 3 ** /// proofFlagBits = (5 >> 2) & 1 = true /// hashes[2] = hashPair(hashes[0], hashes[1]) /// (leafPos, hashPos, proofPos) = (3, 2, 1); /// /// i = 3 and no longer < totalHashes. The algorithm is done /// return hashes[totalHashes - 1] = hashes[2]; the last hash we computed. // We mark this function as internal to force it to be inlined in contracts // that use it, but semantically it is public. // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function merkleRoot( bytes32[] memory leaves, bytes32[] memory proofs, uint256 proofFlagBits ) internal pure returns (bytes32) { unchecked { uint256 leavesLen = leaves.length; uint256 proofsLen = proofs.length; if (leavesLen == 0) revert LeavesCannotBeEmpty(); if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof(); uint256 totalHashes = leavesLen + proofsLen - 1; if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof(); if (totalHashes == 0) { return leaves[0]; } bytes32[] memory hashes = new bytes32[](totalHashes); (uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0); for (uint256 i = 0; i < totalHashes; ++i) { // Checks if the bit flag signals the use of a supplied proof or a leaf/previous hash. bytes32 a; if (proofFlagBits & (1 << i) == (1 << i)) { // Use a leaf or a previously computed hash. if (leafPos < leavesLen) { a = leaves[leafPos++]; } else { a = hashes[hashPos++]; } } else { // Use a supplied proof. a = proofs[proofPos++]; } // The second part of the hashed pair is never a proof as hashing two proofs would result in a // hash that can already be computed offchain. bytes32 b; if (leafPos < leavesLen) { b = leaves[leafPos++]; } else { b = hashes[hashPos++]; } if (!(hashPos <= i)) revert InvalidProof(); hashes[i] = _hashPair(a, b); } if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof(); // Return the last hash. return hashes[totalHashes - 1]; } } /// @notice Hashes two bytes32 objects in their given order, prepended by the /// INTERNAL_DOMAIN_SEPARATOR. function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) { return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right)); } /// @notice Hashes two bytes32 objects. The order is taken into account, /// using the lower value first. function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol"; /// @title The ConfirmedOwner contract /// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwner is ConfirmedOwnerWithProposal { constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IOwnable} from "../interfaces/IOwnable.sol"; /// @title The ConfirmedOwner contract /// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwnerWithProposal is IOwnable { address private s_owner; address private s_pendingOwner; event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); constructor(address newOwner, address pendingOwner) { // solhint-disable-next-line gas-custom-errors require(newOwner != address(0), "Cannot set owner to zero"); s_owner = newOwner; if (pendingOwner != address(0)) { _transferOwnership(pendingOwner); } } /// @notice Allows an owner to begin transferring ownership to a new address. function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } /// @notice Allows an ownership transfer to be completed by the recipient. function acceptOwnership() external override { // solhint-disable-next-line gas-custom-errors require(msg.sender == s_pendingOwner, "Must be proposed owner"); address oldOwner = s_owner; s_owner = msg.sender; s_pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /// @notice Get the current owner function owner() public view override returns (address) { return s_owner; } /// @notice validate, transfer ownership, and emit relevant events function _transferOwnership(address to) private { // solhint-disable-next-line gas-custom-errors require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /// @notice validate access function _validateOwnership() internal view { // solhint-disable-next-line gas-custom-errors require(msg.sender == s_owner, "Only callable by owner"); } /// @notice Reverts if called by anyone other than the contract owner. modifier onlyOwner() { _validateOwnership(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOwnable { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; }
{ "remappings": [ "forge-std/=src/v0.8/vendor/forge-std/src/", "@openzeppelin/=node_modules/@openzeppelin/", "@arbitrum/=node_modules/@arbitrum/", "hardhat/=node_modules/hardhat/", "@eth-optimism/=node_modules/@eth-optimism/", "@scroll-tech/=node_modules/@scroll-tech/", "@matterlabs/=node_modules/@matterlabs/", "@offchainlabs/=node_modules/@offchainlabs/" ], "optimizer": { "enabled": true, "runs": 4100 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"components":[{"internalType":"address","name":"linkToken","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"defaultTxGasLimit","type":"uint64"},{"internalType":"uint96","name":"maxNopFeesJuels","type":"uint96"},{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"rmnProxy","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"}],"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"},{"internalType":"uint16","name":"defaultTokenFeeUSDCents","type":"uint16"},{"internalType":"uint32","name":"defaultTokenDestGasOverhead","type":"uint32"},{"internalType":"bool","name":"enforceOutOfOrder","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","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":"rateLimiterConfig","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.FeeTokenConfigArgs[]","name":"feeTokenConfigs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"},{"internalType":"bool","name":"aggregateRateLimitEnabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"tokenTransferFeeConfigArgs","type":"tuple[]"},{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"}],"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":"BucketOverfilled","type":"error"},{"inputs":[],"name":"CannotSendZeroTokens","type":"error"},{"inputs":[],"name":"CursedByRMN","type":"error"},{"inputs":[],"name":"ExtraArgOutOfOrderExecutionMustBeTrue","type":"error"},{"inputs":[],"name":"GetSupportedTokensFunctionalityRemovedCheckAdminRegistry","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"InvalidChainSelector","type":"error"},{"inputs":[],"name":"InvalidConfig","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"}],"name":"InvalidDestBytesOverhead","type":"error"},{"inputs":[{"internalType":"bytes","name":"encodedAddress","type":"bytes"}],"name":"InvalidEVMAddress","type":"error"},{"inputs":[],"name":"InvalidExtraArgsTag","type":"error"},{"inputs":[{"internalType":"address","name":"nop","type":"address"}],"name":"InvalidNopAddress","type":"error"},{"inputs":[],"name":"InvalidWithdrawParams","type":"error"},{"inputs":[],"name":"LinkBalanceNotSettled","type":"error"},{"inputs":[],"name":"MaxFeeBalanceReached","type":"error"},{"inputs":[],"name":"MessageGasLimitTooHigh","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxSize","type":"uint256"},{"internalType":"uint256","name":"actualSize","type":"uint256"}],"name":"MessageTooLarge","type":"error"},{"inputs":[],"name":"MustBeCalledByRouter","type":"error"},{"inputs":[],"name":"NoFeesToPay","type":"error"},{"inputs":[],"name":"NoNopsToPay","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"NotAFeeToken","type":"error"},{"inputs":[],"name":"OnlyCallableByAdminOrOwner","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdminOrNop","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"PriceNotFoundForToken","type":"error"},{"inputs":[],"name":"RouterMustSetOriginalSender","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SourceTokenDataTooLarge","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":[],"name":"TooManyNops","type":"error"},{"inputs":[],"name":"UnsupportedNumberOfTokens","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"UnsupportedToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"strict","type":"bool"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"bytes[]","name":"sourceTokenData","type":"bytes[]"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"indexed":false,"internalType":"struct Internal.EVM2EVMMessage","name":"message","type":"tuple"}],"name":"CCIPSendRequested","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":[{"components":[{"internalType":"address","name":"linkToken","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"defaultTxGasLimit","type":"uint64"},{"internalType":"uint96","name":"maxNopFeesJuels","type":"uint96"},{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"rmnProxy","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"},{"internalType":"uint16","name":"defaultTokenFeeUSDCents","type":"uint16"},{"internalType":"uint32","name":"defaultTokenDestGasOverhead","type":"uint32"},{"internalType":"bool","name":"enforceOutOfOrder","type":"bool"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.FeeTokenConfigArgs[]","name":"feeConfig","type":"tuple[]"}],"name":"FeeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nop","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NopPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nopWeightsTotal","type":"uint256"},{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"}],"name":"NopsSet","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":"tokens","type":"address[]"}],"name":"TokenTransferFeeConfigDeleted","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"},{"internalType":"bool","name":"aggregateRateLimitEnabled","type":"bool"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"transferFeeConfig","type":"tuple[]"}],"name":"TokenTransferFeeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"TokensConsumed","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentRateLimiterState","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":"destChainSelector","type":"uint64"},{"components":[{"internalType":"bytes","name":"receiver","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"internalType":"struct Client.EVM2AnyMessage","name":"message","type":"tuple"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"address","name":"originalSender","type":"address"}],"name":"forwardFromRouter","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDynamicConfig","outputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"},{"internalType":"uint16","name":"defaultTokenFeeUSDCents","type":"uint16"},{"internalType":"uint32","name":"defaultTokenDestGasOverhead","type":"uint32"},{"internalType":"bool","name":"enforceOutOfOrder","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedNextSequenceNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"components":[{"internalType":"bytes","name":"receiver","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"internalType":"struct Client.EVM2AnyMessage","name":"message","type":"tuple"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getFeeTokenConfig","outputs":[{"components":[{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.FeeTokenConfig","name":"feeTokenConfig","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNopFeesJuels","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNops","outputs":[{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"},{"internalType":"uint256","name":"weightsTotal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"contract IERC20","name":"sourceToken","type":"address"}],"name":"getPoolBySourceToken","outputs":[{"internalType":"contract IPoolV1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"getSenderNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStaticConfig","outputs":[{"components":[{"internalType":"address","name":"linkToken","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"defaultTxGasLimit","type":"uint64"},{"internalType":"uint96","name":"maxNopFeesJuels","type":"uint96"},{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"rmnProxy","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"}],"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"getSupportedTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTokenLimitAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenTransferFeeConfig","outputs":[{"components":[{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"},{"internalType":"bool","name":"aggregateRateLimitEnabled","type":"bool"},{"internalType":"bool","name":"isEnabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfig","name":"tokenTransferFeeConfig","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payNops","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"},{"internalType":"uint16","name":"defaultTokenFeeUSDCents","type":"uint16"},{"internalType":"uint32","name":"defaultTokenDestGasOverhead","type":"uint32"},{"internalType":"bool","name":"enforceOutOfOrder","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"setDynamicConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.FeeTokenConfigArgs[]","name":"feeTokenConfigArgs","type":"tuple[]"}],"name":"setFeeTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"}],"name":"setNops","outputs":[],"stateMutability":"nonpayable","type":"function"},{"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":"setRateLimiterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"},{"internalType":"bool","name":"aggregateRateLimitEnabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"tokenTransferFeeConfigArgs","type":"tuple[]"},{"internalType":"address[]","name":"tokensToUseDefaultFeeConfigs","type":"address[]"}],"name":"setTokenTransferFeeConfig","outputs":[],"stateMutability":"nonpayable","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"},{"inputs":[{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawNonLinkFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b506040516200822d3803806200822d833981016040819052620000359162001a93565b8333806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c0816200030b565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080909301839052600380546001600160a01b031916909417600160801b9283021760ff60a01b1916600160a01b90910217909255029091176004555085516001600160a01b0316158062000169575060208601516001600160401b0316155b8062000180575060408601516001600160401b0316155b8062000197575060608601516001600160401b0316155b80620001ae575060c08601516001600160a01b0316155b80620001c5575060e08601516001600160a01b0316155b15620001e4576040516306b7c75960e31b815260040160405180910390fd5b60208087015160408089015181517f8acd72527118c8324937b1a42e02cd246697c3b633f1742f3cae11de233722b3948101949094526001600160401b039283169184019190915216606082015230608082015260a00160408051601f198184030181529181528151602092830120608090815288516001600160a01b0390811660e0908152938a01516001600160401b0390811661010052928a015183166101205260608a015190921660a0908152908901516001600160601b031660c090815290890151821661014052880151811661016052908701511661018052620002cd85620003b6565b620002d883620006ad565b604080516000815260208101909152620002f4908390620007dd565b620002ff8162000a83565b5050505050506200218a565b336001600160a01b03821603620003655760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60e08101516001600160a01b0316620003e2576040516306b7c75960e31b815260040160405180910390fd5b80600560008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601a6101000a81548161ffff021916908361ffff160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160006101000a81548161ffff021916908361ffff16021790555060c08201518160010160026101000a81548161ffff021916908361ffff16021790555060e08201518160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160006101000a81548161ffff021916908361ffff1602179055506101608201518160020160026101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160020160066101000a81548160ff0219169083151502179055509050507f45b5ad483aa608464c2c7f278bd413d284d7790cdc836e40652e23a02770822060405180610100016040528060e0516001600160a01b03168152602001610100516001600160401b03168152602001610120516001600160401b0316815260200160a0516001600160401b0316815260200160c0516001600160601b03168152602001610140516001600160a01b03168152602001610160516001600160a01b03168152602001610180516001600160a01b031681525082604051620006a292919062001d1c565b60405180910390a150565b60005b8151811015620007ab576000828281518110620006d157620006d162001de1565b60209081029190910181015160408051608080820183528385015163ffffffff9081168352838501516001600160401b03908116848801908152606080880151831686880190815294880151151590860190815296516001600160a01b03166000908152600b90985294909620925183549451925195511515600160a01b0260ff60a01b199688166c010000000000000000000000000296909616600160601b600160a81b031993909716640100000000026001600160601b031990951691161792909217919091169290921717905550600101620006b0565b507f067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e81604051620006a2919062001df7565b60005b8251811015620009a257600083828151811062000801576200080162001de1565b60200260200101519050602063ffffffff168160a0015163ffffffff1610156200085d57805160a08201516040516312766e0160e11b81526001600160a01b03909216600483015263ffffffff16602482015260440162000084565b6040805160e08101825260208381015163ffffffff908116835284840151811682840190815260608087015161ffff9081168688019081526080808a0151861693880193845260a0808b0151871691890191825260c0808c01511515918a019182526001908a018181529b516001600160a01b03166000908152600c9099529990972097518854955192519451915197519a519087166001600160401b031990961695909517640100000000928716929092029190911765ffffffffffff60401b191668010000000000000000939092169290920263ffffffff60501b1916176a0100000000000000000000918416919091021764ffffffffff60701b1916600160701b939092169290920260ff60901b191617600160901b941515949094029390931760ff60981b1916600160981b931515939093029290921790915501620007e0565b507ff5791bc457b3bb990493cf5f655db46c25ccf5764c9b99b8969b4c72ea7df9d082604051620009d4919062001e86565b60405180910390a160005b815181101562000a3c57600c600083838151811062000a025762000a0262001de1565b6020908102919091018101516001600160a01b0316825281019190915260400160002080546001600160a01b0319169055600101620009df565b5080511562000a7f577ffb95a0042158e60a33e7b5bec100f3d95407b1a71bee6633bd54b8887449750b8160405162000a76919062001f1b565b60405180910390a15b5050565b8051604081111562000aa857604051635ad0867d60e11b815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff161562000afb57600e5463ffffffff6c010000000000000000000000008204166001600160601b039091161062000afb5762000afb62000c9e565b600062000b09600862000e8a565b90505b801562000b5557600062000b2f62000b2660018462001f80565b60089062000e9d565b50905062000b3f60088262000ebb565b50508062000b4d9062001f96565b905062000b0c565b506000805b8281101562000c3557600084828151811062000b7a5762000b7a62001de1565b6020026020010151600001519050600085838151811062000b9f5762000b9f62001de1565b602002602001015160200151905060e0516001600160a01b0316826001600160a01b0316148062000bd757506001600160a01b038216155b1562000c0257604051634de938d160e01b81526001600160a01b038316600482015260240162000084565b62000c1460088361ffff841662000ed9565b5062000c2561ffff82168562001fb0565b9350505080600101905062000b5a565b50600e805463ffffffff60601b19166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd249062000c91908390869062001fd0565b60405180910390a1505050565b6000546001600160a01b0316331462000cef576002546001600160a01b0316331462000cef5762000cd160083362000ef9565b62000cef5760405163032bb72b60e31b815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff16600081900362000d2b5760405163990e30bf60e01b815260040160405180910390fd5b600e546001600160601b03168181101562000d59576040516311a1ee3b60e31b815260040160405180910390fd5b600062000d6562000f10565b121562000d8557604051631e9acf1760e31b815260040160405180910390fd5b80600062000d94600862000e8a565b905060005b8181101562000e645760008062000db260088462000e9d565b909250905060008762000dcf836001600160601b038a1662002040565b62000ddb91906200205a565b905062000de981876200207d565b60e05190965062000e0e906001600160a01b0316846001600160601b03841662000f9e565b6040516001600160601b03821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a250505080600101905062000d99565b5050600e80546001600160601b0319166001600160601b03929092169190911790555050565b600062000e978262000ffb565b92915050565b600080808062000eae868662001008565b9097909650945050505050565b600062000ed2836001600160a01b03841662001035565b9392505050565b600062000ef1846001600160a01b0385168462001054565b949350505050565b600062000ed2836001600160a01b03841662001073565b600e5460e0516040516370a0823160e01b81523060048201526000926001600160601b0316916001600160a01b0316906370a0823190602401602060405180830381865afa15801562000f67573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f8d9190620020a0565b62000f999190620020ba565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663a9059cbb60e01b1790915262000ff69185916200108116565b505050565b600062000e978262001152565b600080806200101885856200115d565b600081815260029690960160205260409095205494959350505050565b6000818152600283016020526040812081905562000ed283836200116b565b6000828152600284016020526040812082905562000ef1848462001179565b600062000ed2838362001187565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490820152600090620010d0906001600160a01b038516908490620011a0565b80519091501562000ff65780806020019051810190620010f19190620020dd565b62000ff65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000084565b600062000e97825490565b600062000ed28383620011b1565b600062000ed28383620011de565b600062000ed28383620012e9565b6000818152600183016020526040812054151562000ed2565b606062000ef184846000856200133b565b6000826000018281548110620011cb57620011cb62001de1565b9060005260206000200154905092915050565b60008181526001830160205260408120548015620012d75760006200120560018362001f80565b85549091506000906200121b9060019062001f80565b9050808214620012875760008660000182815481106200123f576200123f62001de1565b906000526020600020015490508087600001848154811062001265576200126562001de1565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806200129b576200129b620020fb565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000e97565b600091505062000e97565b5092915050565b6000818152600183016020526040812054620013325750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000e97565b50600062000e97565b6060824710156200139e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000084565b600080866001600160a01b03168587604051620013bc919062002137565b60006040518083038185875af1925050503d8060008114620013fb576040519150601f19603f3d011682016040523d82523d6000602084013e62001400565b606091505b50909250905062001414878383876200141f565b979650505050505050565b60608315620014935782516000036200148b576001600160a01b0385163b6200148b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000084565b508162000ef1565b62000ef18383815115620014aa5781518083602001fd5b8060405162461bcd60e51b815260040162000084919062002155565b634e487b7160e01b600052604160045260246000fd5b6040516101a081016001600160401b0381118282101715620015025762001502620014c6565b60405290565b60405160a081016001600160401b0381118282101715620015025762001502620014c6565b60405160e081016001600160401b0381118282101715620015025762001502620014c6565b604080519081016001600160401b0381118282101715620015025762001502620014c6565b60405161010081016001600160401b0381118282101715620015025762001502620014c6565b604051601f8201601f191681016001600160401b0381118282101715620015c857620015c8620014c6565b604052919050565b80516001600160a01b0381168114620015e857600080fd5b919050565b80516001600160401b0381168114620015e857600080fd5b805161ffff81168114620015e857600080fd5b805163ffffffff81168114620015e857600080fd5b80518015158114620015e857600080fd5b60006101a082840312156200165257600080fd5b6200165c620014dc565b90506200166982620015d0565b8152620016796020830162001605565b60208201526200168c6040830162001618565b60408201526200169f6060830162001605565b6060820152620016b26080830162001618565b6080820152620016c560a0830162001605565b60a0820152620016d860c0830162001605565b60c0820152620016eb60e08301620015d0565b60e08201526101006200170081840162001618565b908201526101206200171483820162001618565b908201526101406200172883820162001605565b908201526101606200173c83820162001618565b90820152610180620017508382016200162d565b9082015292915050565b80516001600160801b0381168114620015e857600080fd5b6000606082840312156200178557600080fd5b604051606081016001600160401b0381118282101715620017aa57620017aa620014c6565b604052905080620017bb836200162d565b8152620017cb602084016200175a565b6020820152620017de604084016200175a565b60408201525092915050565b60006001600160401b03821115620018065762001806620014c6565b5060051b60200190565b600082601f8301126200182257600080fd5b815160206200183b6200183583620017ea565b6200159d565b82815260a092830285018201928282019190878511156200185b57600080fd5b8387015b85811015620018e85781818a031215620018795760008081fd5b6200188362001508565b6200188e82620015d0565b81526200189d86830162001618565b868201526040620018b0818401620015ed565b908201526060620018c3838201620015ed565b908201526080620018d68382016200162d565b9082015284529284019281016200185f565b5090979650505050505050565b600082601f8301126200190757600080fd5b815160206200191a6200183583620017ea565b82815260e092830285018201928282019190878511156200193a57600080fd5b8387015b85811015620018e85781818a031215620019585760008081fd5b620019626200152d565b6200196d82620015d0565b81526200197c86830162001618565b8682015260406200198f81840162001618565b908201526060620019a283820162001605565b908201526080620019b583820162001618565b9082015260a0620019c883820162001618565b9082015260c0620019db8382016200162d565b9082015284529284019281016200193e565b600082601f830112620019ff57600080fd5b8151602062001a126200183583620017ea565b82815260069290921b8401810191818101908684111562001a3257600080fd5b8286015b8481101562001a88576040818903121562001a515760008081fd5b62001a5b62001552565b62001a6682620015d0565b815262001a7585830162001605565b8186015283529183019160400162001a36565b509695505050505050565b60008060008060008086880361036081121562001aaf57600080fd5b6101008082121562001ac057600080fd5b62001aca62001577565b915062001ad789620015d0565b825262001ae760208a01620015ed565b602083015262001afa60408a01620015ed565b604083015262001b0d60608a01620015ed565b606083015260808901516001600160601b038116811462001b2d57600080fd5b608083015262001b4060a08a01620015d0565b60a083015262001b5360c08a01620015d0565b60c083015262001b6660e08a01620015d0565b60e083015281975062001b7c8a828b016200163e565b9650505062001b90886102a0890162001772565b6103008801519094506001600160401b038082111562001baf57600080fd5b62001bbd8a838b0162001810565b945061032089015191508082111562001bd557600080fd5b62001be38a838b01620018f5565b935061034089015191508082111562001bfb57600080fd5b5062001c0a89828a01620019ed565b9150509295509295509295565b80516001600160a01b03168252602081015162001c3a602084018261ffff169052565b50604081015162001c53604084018263ffffffff169052565b50606081015162001c6a606084018261ffff169052565b50608081015162001c83608084018263ffffffff169052565b5060a081015162001c9a60a084018261ffff169052565b5060c081015162001cb160c084018261ffff169052565b5060e081015162001ccd60e08401826001600160a01b03169052565b506101008181015163ffffffff90811691840191909152610120808301518216908401526101408083015161ffff16908401526101608083015190911690830152610180908101511515910152565b82516001600160a01b031681526020808401516001600160401b0390811691830191909152604080850151821690830152606080850151918216908301526102a082019050608084015162001d7c60808401826001600160601b03169052565b5060a084015162001d9860a08401826001600160a01b03169052565b5060c084015162001db460c08401826001600160a01b03169052565b5060e084015162001dd060e08401826001600160a01b03169052565b5062000ed261010083018462001c17565b634e487b7160e01b600052603260045260246000fd5b602080825282518282018190526000919060409081850190868401855b8281101562001e7957815180516001600160a01b031685528681015163ffffffff1687860152858101516001600160401b03908116878701526060808301519091169086015260809081015115159085015260a0909301929085019060010162001e14565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b8281101562001e7957815180516001600160a01b031685528681015163ffffffff908116888701528682015181168787015260608083015161ffff169087015260808083015182169087015260a0808301519091169086015260c09081015115159085015260e0909301929085019060010162001ea3565b6020808252825182820181905260009190848201906040850190845b8181101562001f5e5783516001600160a01b03168352928401929184019160010162001f37565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111562000e975762000e9762001f6a565b60008162001fa85762001fa862001f6a565b506000190190565b63ffffffff818116838216019080821115620012e257620012e262001f6a565b6000604080830163ffffffff8616845260206040602086015281865180845260608701915060208801935060005b818110156200203257845180516001600160a01b0316845284015161ffff1684840152938301939185019160010162001ffe565b509098975050505050505050565b808202811582820484141762000e975762000e9762001f6a565b6000826200207857634e487b7160e01b600052601260045260246000fd5b500490565b6001600160601b03828116828216039080821115620012e257620012e262001f6a565b600060208284031215620020b357600080fd5b5051919050565b8181036000831280158383131683831282161715620012e257620012e262001f6a565b600060208284031215620020f057600080fd5b62000ed2826200162d565b634e487b7160e01b600052603160045260246000fd5b60005b838110156200212e57818101518382015260200162002114565b50506000910152565b600082516200214b81846020870162002111565b9190910192915050565b60208152600082518060208401526200217681604085016020870162002111565b601f01601f19169190910160400192915050565b60805160a05160c05160e0516101005161012051610140516101605161018051615f75620022b86000396000818161036101528181610efa0152613786015260008181610332015281816116f80152613757015260008181610303015281816113ae0152818161141301528181611c7401528181611d02015261372801526000818161026f01528181610a30015281816118200152818161222201528181612b42015261369401526000818161023f01528181611dd30152613664015260008181610210015281816110a50152818161162401528181611a4101528181611b42015281816126dd015281816136350152613a240152600081816102cf01528181611c0e01526136f401526000818161029f0152818161283801526136c4015260006124b60152615f756000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80637437ff9f116100f9578063c92b283211610097578063eff7cc4811610071578063eff7cc48146109de578063f25561fd146109e6578063f2fde38b146109f9578063fbca3b7414610a0c57600080fd5b8063c92b2832146109b0578063d09dc339146109c3578063df0aa9e9146109cb57600080fd5b8063856c8247116100d3578063856c8247146108825780638da5cb5b146108955780639a113c36146108a6578063b06d41bc1461099a57600080fd5b80637437ff9f146106c057806376f6ae761461086757806379ba50971461087a57600080fd5b806348a98aa411610166578063549e946f11610140578063549e946f1461066957806354b714681461067c578063599f64311461069c578063704b6c02146106ad57600080fd5b806348a98aa4146105c7578063504bffe0146105f2578063546719cd1461060557600080fd5b806320487ded1161019757806320487ded146105705780634120fccd146105915780634816f4f7146105b257600080fd5b806306285c69146101be5780631772047e146103a7578063181f5a7714610527575b600080fd5b6103916040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101919091526040518061010001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b60405161039e9190614b86565b60405180910390f35b6104bb6103b5366004614bba565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152506001600160a01b03166000908152600c6020908152604091829020825160e081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e0100000000000000000000000000008304909116608082015260ff720100000000000000000000000000000000000083048116151560a0830152730100000000000000000000000000000000000000909204909116151560c082015290565b60405161039e9190600060e08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015260c0830151151560c083015292915050565b6105636040518060400160405280601381526020017f45564d3245564d4f6e52616d7020312e352e300000000000000000000000000081525081565b60405161039e9190614c27565b61058361057e366004614c68565b610a2c565b60405190815260200161039e565b610599610e82565b60405167ffffffffffffffff909116815260200161039e565b6105c56105c0366004614e76565b610ea9565b005b6105da6105d5366004614fb3565b610ebf565b6040516001600160a01b03909116815260200161039e565b6105c5610600366004614fec565b610f6e565b61060d610f82565b60405161039e919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6105c56106773660046150ea565b611014565b600e546040516bffffffffffffffffffffffff909116815260200161039e565b6002546001600160a01b03166105da565b6105c56106bb366004614bba565b61118d565b61085a604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915250604080516101a0810182526005546001600160a01b038082168352600160a01b820461ffff9081166020850152760100000000000000000000000000000000000000000000830463ffffffff908116958501959095527a0100000000000000000000000000000000000000000000000000008304811660608501527c0100000000000000000000000000000000000000000000000000000000928390048516608085015260065480821660a086015262010000808204831660c0870152640100000000820490931660e08601527801000000000000000000000000000000000000000000000000810486166101008601529290920484166101208401526007549182166101408401528104909216610160820152660100000000000090910460ff16151561018082015290565b60405161039e9190615206565b6105c5610875366004615215565b611257565b6105c56112ba565b610599610890366004614bba565b611383565b6000546001600160a01b03166105da565b6109506108b4366004614bba565b604080516080810182526000808252602082018190529181018290526060810191909152506001600160a01b03166000908152600b60209081526040918290208251608081018452905463ffffffff8116825267ffffffffffffffff64010000000082048116938301939093526c0100000000000000000000000081049092169281019290925260ff600160a01b909104161515606082015290565b60408051825163ffffffff16815260208084015167ffffffffffffffff9081169183019190915283830151169181019190915260609182015115159181019190915260800161039e565b6109a261147e565b60405161039e9291906152de565b6105c56109be366004615320565b611579565b6105836115e1565b6105836109d936600461538e565b6116a1565b6105c561252a565b6105c56109f43660046153fa565b6127af565b6105c5610a07366004614bba565b6127c0565b610a1f610a1a3660046154f9565b6127d1565b60405161039e9190615516565b60007f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168367ffffffffffffffff1614610aac576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b6000610ac3610abe6080850185615563565b612805565b9050610af3610ad56020850185615563565b8351909150610ae760408701876155c8565b90508460200151612992565b6000600b81610b086080870160608801614bba565b6001600160a01b0316815260208082019290925260409081016000208151608081018352905463ffffffff81168252640100000000810467ffffffffffffffff908116948301949094526c01000000000000000000000000810490931691810191909152600160a01b90910460ff16151560608201819052909150610bd557610b976080850160608601614bba565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b600654600090819064010000000090046001600160a01b031663ffdb4b37610c036080890160608a01614bba565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff8a1660248201526044016040805180830381865afa158015610c6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c92919061565c565b90925090506000808080610ca960408b018b6155c8565b90501115610ce357610cd7610cc460808b0160608c01614bba565b86610cd260408d018d6155c8565b612af7565b91945092509050610cff565b8551610cfc9063ffffffff16662386f26fc100006156a5565b92505b60065460009062010000900461ffff1615610d5357610d506dffffffffffffffffffffffffffff607087901c16610d3960208d018d615563565b9050610d4860408e018e6155c8565b905085612ec6565b90505b60208781015160055460009267ffffffffffffffff9092169163ffffffff8716917a010000000000000000000000000000000000000000000000000000900461ffff1690610da3908f018f615563565b610dae9291506156a5565b6005548c51610ddd91760100000000000000000000000000000000000000000000900463ffffffff16906156bc565b610de791906156bc565b610df191906156bc565b610e0b906dffffffffffffffffffffffffffff89166156a5565b610e1591906156a5565b9050867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1682828a6040015167ffffffffffffffff1688610e5291906156a5565b610e5c91906156bc565b610e6691906156bc565b610e7091906156cf565b99505050505050505050505b92915050565b600e54600090610ea490600160801b900467ffffffffffffffff1660016156f1565b905090565b610eb1612f97565b610ebb8282612fef565b5050565b6040517fbbe4f6db0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063bbe4f6db90602401602060405180830381865afa158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190615712565b9392505050565b610f76613371565b610f7f816133cb565b50565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff8082168352600160801b80830463ffffffff166020850152600160a01b90920460ff161515938301939093526004548084166060840152049091166080820152610ea4906137c0565b61101c612f97565b6001600160a01b03811661105c576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006110666115e1565b905060008112156110a3576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316036110f5576110f06001600160a01b0384168383613872565b505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526110f09083906001600160a01b038616906370a0823190602401602060405180830381865afa158015611158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117c919061572f565b6001600160a01b0386169190613872565b6000546001600160a01b031633148015906111b357506002546001600160a01b03163314155b156111ea576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b61125f612f97565b610ebb8282808060200260200160405190810160405280939291908181526020016000905b828210156112b0576112a160408302860136819003810190615748565b81526020019060010190611284565b50505050506138f2565b6001546001600160a01b031633146113145760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610aa3565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b038082166000908152600d6020526040812054909167ffffffffffffffff909116907f00000000000000000000000000000000000000000000000000000000000000001615610e7c5780600003610e7c576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa15801561145a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190615787565b606060008061148d6008613b58565b90508067ffffffffffffffff8111156114a8576114a8614cb8565b6040519080825280602002602001820160405280156114ed57816020015b60408051808201909152600080825260208201528152602001906001900390816114c65790505b50925060005b8181101561155657600080611509600884613b63565b915091506040518060400160405280836001600160a01b031681526020018261ffff16815250868481518110611541576115416157a4565b602090810291909101015250506001016114f3565b5050600e5491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b0316331480159061159f57506002546001600160a01b03163314155b156115d6576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f7f600382613b81565b600e546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611673573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611697919061572f565b610ea491906157ba565b6040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815277ffffffffffffffff00000000000000000000000000000000608086901b1660048201526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632cbc26bb90602401602060405180830381865afa15801561173f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176391906157da565b1561179a576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166117da576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b0316331461181e576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168567ffffffffffffffff1614611897576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff86166004820152602401610aa3565b60006118a9610abe6080870187615563565b905060006118ba60408701876155c8565b91506118e090506118ce6020880188615563565b90508360000151838560200151612992565b8015611a37576000805b82811015611a25576118ff60408901896155c8565b8281811061190f5761190f6157a4565b90506040020160200135600003611952576040517f5cf0444900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c600061196360408b018b6155c8565b84818110611973576119736157a4565b6119899260206040909202019081019150614bba565b6001600160a01b031681526020810191909152604001600020547201000000000000000000000000000000000000900460ff1615611a1d57611a106119d160408a018a6155c8565b838181106119e1576119e16157a4565b9050604002018036038101906119f791906157f7565b60065464010000000090046001600160a01b0316613d14565b611a1a90836156bc565b91505b6001016118ea565b508015611a3557611a3581613e35565b505b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611a716080880160608901614bba565b6001600160a01b031603611ad557600e8054869190600090611aa29084906bffffffffffffffffffffffff16615831565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550611bfc565b60065464010000000090046001600160a01b03166241e5be611afd6080890160608a01614bba565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018990527f00000000000000000000000000000000000000000000000000000000000000009091166044820152606401602060405180830381865afa158015611b89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bad919061572f565b600e8054600090611bcd9084906bffffffffffffffffffffffff16615831565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b600e546bffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691161115611c69576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160200151611dbd577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611dbd576001600160a01b0384166000908152600d602052604081205467ffffffffffffffff169003611dbd576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190615787565b6001600160a01b0385166000908152600d6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b604080516101a08101825267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526001600160a01b03861660208201526000918101611e50611e168a80615563565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613e4292505050565b6001600160a01b03168152602001600e601081819054906101000a900467ffffffffffffffff16611e8090615856565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff168152602001846000015181526020016000151581526020018460200151611f2a576001600160a01b0387166000908152600d602052604081208054909190611f009067ffffffffffffffff16615856565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055611f2d565b60005b67ffffffffffffffff168152602001611f4c60808a0160608b01614bba565b6001600160a01b03168152602001878152602001888060200190611f709190615563565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611fb760408a018a6155c8565b808060200260200160405190810160405280939291908181526020016000905b8282101561200357611ff4604083028601368190038101906157f7565b81526020019060010190611fd7565b505050505081526020018367ffffffffffffffff81111561202657612026614cb8565b60405190808252806020026020018201604052801561205957816020015b60608152602001906001900390816120445790505b508152600060209091018190529091505b828110156124af57600061208160408a018a6155c8565b83818110612091576120916157a4565b9050604002018036038101906120a791906157f7565b905060006120b98b8360000151610ebf565b90506001600160a01b038116158061216f57506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527faff2afbf0000000000000000000000000000000000000000000000000000000060048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015612149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216d91906157da565b155b156121b45781516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b6000816001600160a01b0316639a4575b96040518060a001604052808e80600001906121e09190615563565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525067ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166020808301919091526001600160a01b03808f16604080850191909152918901516060840152885116608090920191909152517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526122ab919060040161587d565b6000604051808303816000875af11580156122ca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122f2919081019061594a565b9050602063ffffffff1681602001515111156123895782516001600160a01b03166000908152600c602090815260409091205490820151516e01000000000000000000000000000090910463ffffffff1610156123895782516040517f36f536ca0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b805161239490613e42565b5060408051608081019091526001600160a01b03831660a08201528060c0810160408051808303601f190181529181529082528351602080840191909152808501518383015286516001600160a01b03166000908152600c9091522054606090910190730100000000000000000000000000000000000000900460ff166124295760075462010000900463ffffffff16612458565b84516001600160a01b03166000908152600c60205260409020546a0100000000000000000000900463ffffffff165b63ffffffff16905260405161247091906020016159db565b6040516020818303038152906040528561016001518581518110612496576124966157a4565b602002602001018190525050505080600101905061206a565b506124da817f0000000000000000000000000000000000000000000000000000000000000000613ee8565b6101808201526040517fd0c3c799bf9e2639de44391e7f524d229b2b55f5b1ea94b2bf7da42f7243dddd90612510908390615aef565b60405180910390a16101800151925050505b949350505050565b6000546001600160a01b0316331461258f576002546001600160a01b0316331461258f57612559600833614043565b61258f576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff1660008190036125e3576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546bffffffffffffffffffffffff168181101561262e576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006126386115e1565b1215612670576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600061267d6008613b58565b905060005b8181101561276c57600080612698600884613b63565b90925090506000876126b8836bffffffffffffffffffffffff8a166156a5565b6126c291906156cf565b90506126ce8187615c24565b95506127126001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016846bffffffffffffffffffffffff8416613872565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a2505050806001019050612682565b5050600e80547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b6127b7612f97565b610f7f81614058565b6127c8613371565b610f7f816141ca565b60606040517f9e7177c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260008082526020820152600082900361286657506040805180820190915267ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016815260006020820152610e7c565b60006128728385615c49565b90507fe7e230f0000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016128df576128ca8360048187615c91565b8101906128d79190615cbb565b915050610e7c565b7f6859a837000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016129605760408051808201909152806129408560048189615c91565b81019061294d9190615ce7565b815260006020909101529150610e7c9050565b6040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006547801000000000000000000000000000000000000000000000000900463ffffffff16808511156129fb576040517f869337890000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610aa3565b6006547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16841115612a5d576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554600160a01b900461ffff16831115612aa4576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81612af0576007546601000000000000900460ff1615612af0576040517fee433e9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6000808083815b81811015612eba576000878783818110612b1a57612b1a6157a4565b905060400201803603810190612b3091906157f7565b905060006001600160a01b0316612b6b7f00000000000000000000000000000000000000000000000000000000000000008360000151610ebf565b6001600160a01b031603612bb95780516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b80516001600160a01b03166000908152600c6020908152604091829020825160e081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e0100000000000000000000000000008304909116608082015260ff720100000000000000000000000000000000000083048116151560a0830152730100000000000000000000000000000000000000909204909116151560c08201819052612cde57600754612ca29061ffff16662386f26fc100006156a5565b612cac90886156bc565b600754909750612cc89062010000900463ffffffff1687615d00565b9550612cd5602086615d00565b94505050612eb2565b604081015160009061ffff1615612e025760008c6001600160a01b031684600001516001600160a01b031614612da55760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526401000000009092041690634ab35b0b90602401602060405180830381865afa158015612d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d9e9190615d1d565b9050612da8565b508a5b620186a0836040015161ffff16612dea8660200151847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661428b90919063ffffffff16565b612df491906156a5565b612dfe91906156cf565b9150505b6060820151612e119088615d00565b9650816080015186612e239190615d00565b8251909650600090612e429063ffffffff16662386f26fc100006156a5565b905080821015612e6157612e56818a6156bc565b985050505050612eb2565b6000836020015163ffffffff16662386f26fc10000612e8091906156a5565b905080831115612ea057612e94818b6156bc565b99505050505050612eb2565b612eaa838b6156bc565b995050505050505b600101612afe565b50509450945094915050565b60008063ffffffff8316612edc610180866156a5565b612ee8876102206156bc565b612ef291906156bc565b612efc91906156bc565b6005546006549192506000917c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690612f3e9061ffff16846156a5565b612f4891906156bc565b60065490915062010000900461ffff16612f726dffffffffffffffffffffffffffff8916836156a5565b612f7c91906156a5565b612f8c90655af3107a40006156a5565b979650505050505050565b6000546001600160a01b03163314612fed576002546001600160a01b03163314612fed576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60005b825181101561328357600083828151811061300f5761300f6157a4565b60200260200101519050602063ffffffff168160a0015163ffffffff16101561308257805160a08201516040517f24ecdc020000000000000000000000000000000000000000000000000000000081526001600160a01b03909216600483015263ffffffff166024820152604401610aa3565b6040805160e08101825260208381015163ffffffff908116835284840151811682840190815260608087015161ffff9081168688019081526080808a0151861693880193845260a0808b0151871691890191825260c0808c01511515918a019182526001908a018181529b516001600160a01b03166000908152600c9099529990972097518854955192519451915197519a519087167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009096169590951764010000000092871692909202919091177fffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffff166801000000000000000093909216929092027fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff16176a010000000000000000000091841691909102177fffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffff166e01000000000000000000000000000093909216929092027fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff1617720100000000000000000000000000000000000094151594909402939093177fffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff16730100000000000000000000000000000000000000931515939093029290921790915501612ff2565b507ff5791bc457b3bb990493cf5f655db46c25ccf5764c9b99b8969b4c72ea7df9d0826040516132b39190615d38565b60405180910390a160005b815181101561332e57600c60008383815181106132dd576132dd6157a4565b6020908102919091018101516001600160a01b0316825281019190915260400160002080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001016132be565b50805115610ebb577ffb95a0042158e60a33e7b5bec100f3d95407b1a71bee6633bd54b8887449750b816040516133659190615516565b60405180910390a15050565b6000546001600160a01b03163314612fed5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610aa3565b60e08101516001600160a01b031661340f576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600560008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601a6101000a81548161ffff021916908361ffff160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160006101000a81548161ffff021916908361ffff16021790555060c08201518160010160026101000a81548161ffff021916908361ffff16021790555060e08201518160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160006101000a81548161ffff021916908361ffff1602179055506101608201518160020160026101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160020160066101000a81548160ff0219169083151502179055509050507f45b5ad483aa608464c2c7f278bd413d284d7790cdc836e40652e23a0277082206040518061010001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152508260405161124c929190615dd8565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261384e82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426138329190615df5565b85608001516fffffffffffffffffffffffffffffffff166142c8565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526110f09084906142f0565b8051604081111561392f576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff161561398357600e5463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff909116106139835761398361252a565b600061398f6008613b58565b90505b80156139d15760006139b06139a8600184615df5565b600890613b63565b5090506139be6008826143d5565b5050806139ca90615e08565b9050613992565b506000805b82811015613ad95760008482815181106139f2576139f26157a4565b60200260200101516000015190506000858381518110613a1457613a146157a4565b60200260200101516020015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480613a6957506001600160a01b038216155b15613aab576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610aa3565b613abb60088361ffff84166143ea565b50613aca61ffff821685615d00565b935050508060010190506139d6565b50600e80547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd2490613b4b9083908690615e3d565b60405180910390a1505050565b6000610e7c82614400565b6000808080613b72868661440b565b909450925050505b9250929050565b8154600090613b9d90600160801b900463ffffffff1642615df5565b90508015613c255760018301548354613bd8916fffffffffffffffffffffffffffffffff808216928116918591600160801b909104166142c8565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff000000000000000000000000000000000000000090911617600160801b4263ffffffff16021783555b60208201518354613c4b916fffffffffffffffffffffffffffffffff9081169116614436565b835483511515600160a01b027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff9283161717845560208301516040808501518316600160801b0291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990613b4b9084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b81516040517fd02641a00000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260009182919084169063d02641a0906024016040805180830381865afa158015613d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d9e9190615e5c565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116600003613e075783516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b6020840151612522907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83169061428b565b610f7f600382600061444c565b60008151602014613e8157816040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610aa39190614c27565b600082806020019051810190613e97919061572f565b90506001600160a01b03811180613eaf575061040081105b15610e7c57826040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610aa39190614c27565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151604051602001613f7e9897969594939291906001600160a01b039889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b6040516020818303038152906040528051906020012085610120015180519060200120866101400151604051602001613fb79190615e8f565b60405160208183030381529060405280519060200120876101600151604051602001613fe39190615ea2565b60408051601f198184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b6000610f67836001600160a01b038416614756565b60005b815181101561419a576000828281518110614078576140786157a4565b60209081029190910181015160408051608080820183528385015163ffffffff90811683528385015167ffffffffffffffff908116848801908152606080880151831686880190815294880151151590860190815296516001600160a01b03166000908152600b90985294909620925183549451925195511515600160a01b027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9688166c0100000000000000000000000002969096167fffffffffffffffffffffff000000000000000000ffffffffffffffffffffffff93909716640100000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009095169116179290921791909116929092171790555060010161405b565b507f067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e8160405161124c9190615eb5565b336001600160a01b038216036142225760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610aa3565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000670de0b6b3a76400006142be837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff86166156a5565b610f6791906156cf565b60006142e7856142d884866156a5565b6142e290876156bc565b614436565b95945050505050565b6000614345826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166147629092919063ffffffff16565b8051909150156110f0578080602001905181019061436391906157da565b6110f05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610aa3565b6000610f67836001600160a01b038416614771565b6000612522846001600160a01b0385168461478e565b6000610e7c826147ab565b6000808061441985856147b5565b600081815260029690960160205260409095205494959350505050565b60008183106144455781610f67565b5090919050565b8254600160a01b900460ff161580614462575081155b1561446c57505050565b825460018401546fffffffffffffffffffffffffffffffff808316929116906000906144a590600160801b900463ffffffff1642615df5565b9050801561454b57818311156144e7576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461451490839085908490600160801b90046fffffffffffffffffffffffffffffffff166142c8565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff16600160801b4263ffffffff160217875592505b848210156145e8576001600160a01b03841661459d576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610aa3565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610aa3565b848310156146d457600186810154600160801b90046fffffffffffffffffffffffffffffffff1690600090829061461f9082615df5565b614629878a615df5565b61463391906156bc565b61463d91906156cf565b90506001600160a01b038616614689576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610aa3565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610aa3565b6146de8584615df5565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610f6783836147c1565b606061252284846000856147d9565b60008181526002830160205260408120819055610f6783836148c0565b6000828152600284016020526040812082905561252284846148cc565b6000610e7c825490565b6000610f6783836148d8565b60008181526001830160205260408120541515610f67565b6060824710156148515760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610aa3565b600080866001600160a01b0316858760405161486d9190615f36565b60006040518083038185875af1925050503d80600081146148aa576040519150601f19603f3d011682016040523d82523d6000602084013e6148af565b606091505b5091509150612f8c87838387614902565b6000610f67838361497b565b6000610f678383614a75565b60008260000182815481106148ef576148ef6157a4565b9060005260206000200154905092915050565b6060831561497157825160000361496a576001600160a01b0385163b61496a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aa3565b5081612522565b6125228383614ac4565b60008181526001830160205260408120548015614a6457600061499f600183615df5565b85549091506000906149b390600190615df5565b9050808214614a185760008660000182815481106149d3576149d36157a4565b90600052602060002001549050808760000184815481106149f6576149f66157a4565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614a2957614a29615f52565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610e7c565b6000915050610e7c565b5092915050565b6000818152600183016020526040812054614abc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610e7c565b506000610e7c565b815115614ad45781518083602001fd5b8060405162461bcd60e51b8152600401610aa39190614c27565b6001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401525060c0810151614b6b60c08401826001600160a01b03169052565b5060e08101516110f060e08401826001600160a01b03169052565b6101008101610e7c8284614aee565b6001600160a01b0381168114610f7f57600080fd5b8035614bb581614b95565b919050565b600060208284031215614bcc57600080fd5b8135610f6781614b95565b60005b83811015614bf2578181015183820152602001614bda565b50506000910152565b60008151808452614c13816020860160208601614bd7565b601f01601f19169290920160200192915050565b602081526000610f676020830184614bfb565b67ffffffffffffffff81168114610f7f57600080fd5b600060a08284031215614c6257600080fd5b50919050565b60008060408385031215614c7b57600080fd5b8235614c8681614c3a565b9150602083013567ffffffffffffffff811115614ca257600080fd5b614cae85828601614c50565b9150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b60405290565b6040516101a0810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b60405160a0810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b6040805190810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b604051601f8201601f1916810167ffffffffffffffff81118282101715614d8a57614d8a614cb8565b604052919050565b600067ffffffffffffffff821115614dac57614dac614cb8565b5060051b60200190565b63ffffffff81168114610f7f57600080fd5b8035614bb581614db6565b803561ffff81168114614bb557600080fd5b8015158114610f7f57600080fd5b8035614bb581614de5565b600082601f830112614e0f57600080fd5b81356020614e24614e1f83614d92565b614d61565b8083825260208201915060208460051b870101935086841115614e4657600080fd5b602086015b84811015614e6b578035614e5e81614b95565b8352918301918301614e4b565b509695505050505050565b6000806040808486031215614e8a57600080fd5b833567ffffffffffffffff80821115614ea257600080fd5b818601915086601f830112614eb657600080fd5b81356020614ec6614e1f83614d92565b82815260e0928302850182019282820191908b851115614ee557600080fd5b958301955b84871015614f8e5780878d031215614f025760008081fd5b614f0a614cce565b8735614f1581614b95565b815287850135614f2481614db6565b8186015287890135614f3581614db6565b818a01526060614f46898201614dd3565b90820152608088810135614f5981614db6565b9082015260a0614f6a898201614dc8565b9082015260c0614f7b898201614df3565b9082015283529586019591830191614eea565b5097505087013593505080831115614fa557600080fd5b5050614cae85828601614dfe565b60008060408385031215614fc657600080fd5b8235614fd181614c3a565b91506020830135614fe181614b95565b809150509250929050565b60006101a08284031215614fff57600080fd5b615007614cf7565b61501083614baa565b815261501e60208401614dd3565b602082015261502f60408401614dc8565b604082015261504060608401614dd3565b606082015261505160808401614dc8565b608082015261506260a08401614dd3565b60a082015261507360c08401614dd3565b60c082015261508460e08401614baa565b60e0820152610100615097818501614dc8565b908201526101206150a9848201614dc8565b908201526101406150bb848201614dd3565b908201526101606150cd848201614dc8565b908201526101806150df848201614df3565b908201529392505050565b600080604083850312156150fd57600080fd5b8235614fd181614b95565b80516001600160a01b03168252602081015161512a602084018261ffff169052565b506040810151615142604084018263ffffffff169052565b506060810151615158606084018261ffff169052565b506080810151615170608084018263ffffffff169052565b5060a081015161518660a084018261ffff169052565b5060c081015161519c60c084018261ffff169052565b5060e08101516151b760e08401826001600160a01b03169052565b506101008181015163ffffffff90811691840191909152610120808301518216908401526101408083015161ffff16908401526101608083015190911690830152610180908101511515910152565b6101a08101610e7c8284615108565b6000806020838503121561522857600080fd5b823567ffffffffffffffff8082111561524057600080fd5b818501915085601f83011261525457600080fd5b81358181111561526357600080fd5b8660208260061b850101111561527857600080fd5b60209290920196919550909350505050565b60008151808452602080850194506020840160005b838110156152d357815180516001600160a01b0316885283015161ffff16838801526040909601959082019060010161529f565b509495945050505050565b6040815260006152f1604083018561528a565b90508260208301529392505050565b80356fffffffffffffffffffffffffffffffff81168114614bb557600080fd5b60006060828403121561533257600080fd5b6040516060810181811067ffffffffffffffff8211171561535557615355614cb8565b604052823561536381614de5565b815261537160208401615300565b602082015261538260408401615300565b60408201529392505050565b600080600080608085870312156153a457600080fd5b84356153af81614c3a565b9350602085013567ffffffffffffffff8111156153cb57600080fd5b6153d787828801614c50565b9350506040850135915060608501356153ef81614b95565b939692955090935050565b6000602080838503121561540d57600080fd5b823567ffffffffffffffff81111561542457600080fd5b8301601f8101851361543557600080fd5b8035615443614e1f82614d92565b81815260a0918202830184019184820191908884111561546257600080fd5b938501935b838510156154ed5780858a03121561547f5760008081fd5b615487614d1b565b853561549281614b95565b8152858701356154a181614db6565b818801526040868101356154b481614c3a565b908201526060868101356154c781614c3a565b908201526080868101356154da81614de5565b9082015283529384019391850191615467565b50979650505050505050565b60006020828403121561550b57600080fd5b8135610f6781614c3a565b6020808252825182820181905260009190848201906040850190845b818110156155575783516001600160a01b031683529284019291840191600101615532565b50909695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261559857600080fd5b83018035915067ffffffffffffffff8211156155b357600080fd5b602001915036819003821315613b7a57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155fd57600080fd5b83018035915067ffffffffffffffff82111561561857600080fd5b6020019150600681901b3603821315613b7a57600080fd5b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114614bb557600080fd5b6000806040838503121561566f57600080fd5b61567883615630565b915061568660208401615630565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e7c57610e7c61568f565b80820180821115610e7c57610e7c61568f565b6000826156ec57634e487b7160e01b600052601260045260246000fd5b500490565b67ffffffffffffffff818116838216019080821115614a6e57614a6e61568f565b60006020828403121561572457600080fd5b8151610f6781614b95565b60006020828403121561574157600080fd5b5051919050565b60006040828403121561575a57600080fd5b615762614d3e565b823561576d81614b95565b815261577b60208401614dd3565b60208201529392505050565b60006020828403121561579957600080fd5b8151610f6781614c3a565b634e487b7160e01b600052603260045260246000fd5b8181036000831280158383131683831282161715614a6e57614a6e61568f565b6000602082840312156157ec57600080fd5b8151610f6781614de5565b60006040828403121561580957600080fd5b615811614d3e565b823561581c81614b95565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff818116838216019080821115614a6e57614a6e61568f565b600067ffffffffffffffff8083168181036158735761587361568f565b6001019392505050565b602081526000825160a0602084015261589960c0840182614bfb565b905067ffffffffffffffff602085015116604084015260408401516001600160a01b038082166060860152606086015160808601528060808701511660a086015250508091505092915050565b600082601f8301126158f757600080fd5b815167ffffffffffffffff81111561591157615911614cb8565b6159246020601f19601f84011601614d61565b81815284602083860101111561593957600080fd5b612522826020830160208701614bd7565b60006020828403121561595c57600080fd5b815167ffffffffffffffff8082111561597457600080fd5b908301906040828603121561598857600080fd5b615990614d3e565b82518281111561599f57600080fd5b6159ab878286016158e6565b8252506020830151828111156159c057600080fd5b6159cc878286016158e6565b60208301525095945050505050565b6020815260008251608060208401526159f760a0840182614bfb565b90506020840151601f1980858403016040860152615a158383614bfb565b9250604086015191508085840301606086015250615a338282614bfb565b91505063ffffffff60608501511660808401528091505092915050565b60008151808452602080850194506020840160005b838110156152d357815180516001600160a01b031688528301518388015260409096019590820190600101615a65565b60008282518085526020808601955060208260051b8401016020860160005b84811015615ae257601f19868403018952615ad0838351614bfb565b98840198925090830190600101615ab4565b5090979650505050505050565b60208152615b0a60208201835167ffffffffffffffff169052565b60006020830151615b2660408401826001600160a01b03169052565b5060408301516001600160a01b038116606084015250606083015167ffffffffffffffff8116608084015250608083015160a083015260a0830151615b6f60c084018215159052565b5060c083015167ffffffffffffffff811660e08401525060e0830151610100615ba2818501836001600160a01b03169052565b840151610120848101919091528401516101a061014080860182905291925090615bd06101c0860184614bfb565b9250808601519050601f19610160818786030181880152615bf18584615a50565b945080880151925050610180818786030181880152615c108584615a95565b970151959092019490945250929392505050565b6bffffffffffffffffffffffff828116828216039080821115614a6e57614a6e61568f565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015615c895780818660040360031b1b83161692505b505092915050565b60008085851115615ca157600080fd5b83861115615cae57600080fd5b5050820193919092039150565b600060408284031215615ccd57600080fd5b615cd5614d3e565b82358152602083013561577b81614de5565b600060208284031215615cf957600080fd5b5035919050565b63ffffffff818116838216019080821115614a6e57614a6e61568f565b600060208284031215615d2f57600080fd5b610f6782615630565b602080825282518282018190526000919060409081850190868401855b82811015615dcb57815180516001600160a01b031685528681015163ffffffff908116888701528682015181168787015260608083015161ffff169087015260808083015182169087015260a0808301519091169086015260c09081015115159085015260e09093019290850190600101615d55565b5091979650505050505050565b6102a08101615de78285614aee565b610f67610100830184615108565b81810381811115610e7c57610e7c61568f565b600081615e1757615e1761568f565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff83168152604060208201526000612522604083018461528a565b600060408284031215615e6e57600080fd5b615e76614d3e565b615e7f83615630565b8152602083015161577b81614db6565b602081526000610f676020830184615a50565b602081526000610f676020830184615a95565b602080825282518282018190526000919060409081850190868401855b82811015615dcb57815180516001600160a01b031685528681015163ffffffff16878601528581015167ffffffffffffffff908116878701526060808301519091169086015260809081015115159085015260a09093019290850190600101615ed2565b60008251615f48818460208701614bd7565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfea164736f6c6343000818000a00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f000000000000000000000000000000000000000000000000173ac9059db9595100000000000000000000000000000000000000000000000045849994fc9c7b150000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000043c33c1937564800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060536ef486db5e0e1771874e31485c12e3c2844f0000000000000000000000002961cb47b5111f38d75f415c21ceb4120ddd1b69000000000000000000000000224918d5e099f38eb9f706941ba70a99b11e6a92000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000493e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009cc2b3816ab99e5ae9d8850a0365c2ec55157e6f000000000000000000000000000000000000000000000000000000000000753000000000000000000000000000000000000000000000000000000000002dc6c000000000000000000000000000000000000000000000000000000000000001f40000000000000000000000000000000000000000000000000000000000015f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000e92596fd62900000000000000000000000000000000000000000000000000000c7d713b49da00000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3800000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000e92596fd62900000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101b95760003560e01c80637437ff9f116100f9578063c92b283211610097578063eff7cc4811610071578063eff7cc48146109de578063f25561fd146109e6578063f2fde38b146109f9578063fbca3b7414610a0c57600080fd5b8063c92b2832146109b0578063d09dc339146109c3578063df0aa9e9146109cb57600080fd5b8063856c8247116100d3578063856c8247146108825780638da5cb5b146108955780639a113c36146108a6578063b06d41bc1461099a57600080fd5b80637437ff9f146106c057806376f6ae761461086757806379ba50971461087a57600080fd5b806348a98aa411610166578063549e946f11610140578063549e946f1461066957806354b714681461067c578063599f64311461069c578063704b6c02146106ad57600080fd5b806348a98aa4146105c7578063504bffe0146105f2578063546719cd1461060557600080fd5b806320487ded1161019757806320487ded146105705780634120fccd146105915780634816f4f7146105b257600080fd5b806306285c69146101be5780631772047e146103a7578063181f5a7714610527575b600080fd5b6103916040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101919091526040518061010001604052807f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f6001600160a01b031681526020017f000000000000000000000000000000000000000000000000173ac9059db9595167ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000045849994fc9c7b1567ffffffffffffffff1681526020017f0000000000000000000000000000000000000000000000000000000000030d4067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000043c33c19375648000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000060536ef486db5e0e1771874e31485c12e3c2844f6001600160a01b031681526020017f0000000000000000000000002961cb47b5111f38d75f415c21ceb4120ddd1b696001600160a01b0316815250905090565b60405161039e9190614b86565b60405180910390f35b6104bb6103b5366004614bba565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152506001600160a01b03166000908152600c6020908152604091829020825160e081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e0100000000000000000000000000008304909116608082015260ff720100000000000000000000000000000000000083048116151560a0830152730100000000000000000000000000000000000000909204909116151560c082015290565b60405161039e9190600060e08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015260c0830151151560c083015292915050565b6105636040518060400160405280601381526020017f45564d3245564d4f6e52616d7020312e352e300000000000000000000000000081525081565b60405161039e9190614c27565b61058361057e366004614c68565b610a2c565b60405190815260200161039e565b610599610e82565b60405167ffffffffffffffff909116815260200161039e565b6105c56105c0366004614e76565b610ea9565b005b6105da6105d5366004614fb3565b610ebf565b6040516001600160a01b03909116815260200161039e565b6105c5610600366004614fec565b610f6e565b61060d610f82565b60405161039e919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6105c56106773660046150ea565b611014565b600e546040516bffffffffffffffffffffffff909116815260200161039e565b6002546001600160a01b03166105da565b6105c56106bb366004614bba565b61118d565b61085a604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915250604080516101a0810182526005546001600160a01b038082168352600160a01b820461ffff9081166020850152760100000000000000000000000000000000000000000000830463ffffffff908116958501959095527a0100000000000000000000000000000000000000000000000000008304811660608501527c0100000000000000000000000000000000000000000000000000000000928390048516608085015260065480821660a086015262010000808204831660c0870152640100000000820490931660e08601527801000000000000000000000000000000000000000000000000810486166101008601529290920484166101208401526007549182166101408401528104909216610160820152660100000000000090910460ff16151561018082015290565b60405161039e9190615206565b6105c5610875366004615215565b611257565b6105c56112ba565b610599610890366004614bba565b611383565b6000546001600160a01b03166105da565b6109506108b4366004614bba565b604080516080810182526000808252602082018190529181018290526060810191909152506001600160a01b03166000908152600b60209081526040918290208251608081018452905463ffffffff8116825267ffffffffffffffff64010000000082048116938301939093526c0100000000000000000000000081049092169281019290925260ff600160a01b909104161515606082015290565b60408051825163ffffffff16815260208084015167ffffffffffffffff9081169183019190915283830151169181019190915260609182015115159181019190915260800161039e565b6109a261147e565b60405161039e9291906152de565b6105c56109be366004615320565b611579565b6105836115e1565b6105836109d936600461538e565b6116a1565b6105c561252a565b6105c56109f43660046153fa565b6127af565b6105c5610a07366004614bba565b6127c0565b610a1f610a1a3660046154f9565b6127d1565b60405161039e9190615516565b60007f00000000000000000000000000000000000000000000000045849994fc9c7b1567ffffffffffffffff168367ffffffffffffffff1614610aac576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b6000610ac3610abe6080850185615563565b612805565b9050610af3610ad56020850185615563565b8351909150610ae760408701876155c8565b90508460200151612992565b6000600b81610b086080870160608801614bba565b6001600160a01b0316815260208082019290925260409081016000208151608081018352905463ffffffff81168252640100000000810467ffffffffffffffff908116948301949094526c01000000000000000000000000810490931691810191909152600160a01b90910460ff16151560608201819052909150610bd557610b976080850160608601614bba565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b600654600090819064010000000090046001600160a01b031663ffdb4b37610c036080890160608a01614bba565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff8a1660248201526044016040805180830381865afa158015610c6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c92919061565c565b90925090506000808080610ca960408b018b6155c8565b90501115610ce357610cd7610cc460808b0160608c01614bba565b86610cd260408d018d6155c8565b612af7565b91945092509050610cff565b8551610cfc9063ffffffff16662386f26fc100006156a5565b92505b60065460009062010000900461ffff1615610d5357610d506dffffffffffffffffffffffffffff607087901c16610d3960208d018d615563565b9050610d4860408e018e6155c8565b905085612ec6565b90505b60208781015160055460009267ffffffffffffffff9092169163ffffffff8716917a010000000000000000000000000000000000000000000000000000900461ffff1690610da3908f018f615563565b610dae9291506156a5565b6005548c51610ddd91760100000000000000000000000000000000000000000000900463ffffffff16906156bc565b610de791906156bc565b610df191906156bc565b610e0b906dffffffffffffffffffffffffffff89166156a5565b610e1591906156a5565b9050867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1682828a6040015167ffffffffffffffff1688610e5291906156a5565b610e5c91906156bc565b610e6691906156bc565b610e7091906156cf565b99505050505050505050505b92915050565b600e54600090610ea490600160801b900467ffffffffffffffff1660016156f1565b905090565b610eb1612f97565b610ebb8282612fef565b5050565b6040517fbbe4f6db0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f0000000000000000000000002961cb47b5111f38d75f415c21ceb4120ddd1b699091169063bbe4f6db90602401602060405180830381865afa158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190615712565b9392505050565b610f76613371565b610f7f816133cb565b50565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff8082168352600160801b80830463ffffffff166020850152600160a01b90920460ff161515938301939093526004548084166060840152049091166080820152610ea4906137c0565b61101c612f97565b6001600160a01b03811661105c576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006110666115e1565b905060008112156110a3576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f6001600160a01b0316836001600160a01b0316036110f5576110f06001600160a01b0384168383613872565b505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526110f09083906001600160a01b038616906370a0823190602401602060405180830381865afa158015611158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117c919061572f565b6001600160a01b0386169190613872565b6000546001600160a01b031633148015906111b357506002546001600160a01b03163314155b156111ea576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b61125f612f97565b610ebb8282808060200260200160405190810160405280939291908181526020016000905b828210156112b0576112a160408302860136819003810190615748565b81526020019060010190611284565b50505050506138f2565b6001546001600160a01b031633146113145760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610aa3565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b038082166000908152600d6020526040812054909167ffffffffffffffff909116907f00000000000000000000000000000000000000000000000000000000000000001615610e7c5780600003610e7c576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa15801561145a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190615787565b606060008061148d6008613b58565b90508067ffffffffffffffff8111156114a8576114a8614cb8565b6040519080825280602002602001820160405280156114ed57816020015b60408051808201909152600080825260208201528152602001906001900390816114c65790505b50925060005b8181101561155657600080611509600884613b63565b915091506040518060400160405280836001600160a01b031681526020018261ffff16815250868481518110611541576115416157a4565b602090810291909101015250506001016114f3565b5050600e5491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b0316331480159061159f57506002546001600160a01b03163314155b156115d6576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f7f600382613b81565b600e546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f6001600160a01b0316906370a0823190602401602060405180830381865afa158015611673573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611697919061572f565b610ea491906157ba565b6040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815277ffffffffffffffff00000000000000000000000000000000608086901b1660048201526000906001600160a01b037f00000000000000000000000060536ef486db5e0e1771874e31485c12e3c2844f1690632cbc26bb90602401602060405180830381865afa15801561173f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176391906157da565b1561179a576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166117da576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b0316331461181e576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000045849994fc9c7b1567ffffffffffffffff168567ffffffffffffffff1614611897576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff86166004820152602401610aa3565b60006118a9610abe6080870187615563565b905060006118ba60408701876155c8565b91506118e090506118ce6020880188615563565b90508360000151838560200151612992565b8015611a37576000805b82811015611a25576118ff60408901896155c8565b8281811061190f5761190f6157a4565b90506040020160200135600003611952576040517f5cf0444900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c600061196360408b018b6155c8565b84818110611973576119736157a4565b6119899260206040909202019081019150614bba565b6001600160a01b031681526020810191909152604001600020547201000000000000000000000000000000000000900460ff1615611a1d57611a106119d160408a018a6155c8565b838181106119e1576119e16157a4565b9050604002018036038101906119f791906157f7565b60065464010000000090046001600160a01b0316613d14565b611a1a90836156bc565b91505b6001016118ea565b508015611a3557611a3581613e35565b505b6001600160a01b037f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f16611a716080880160608901614bba565b6001600160a01b031603611ad557600e8054869190600090611aa29084906bffffffffffffffffffffffff16615831565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550611bfc565b60065464010000000090046001600160a01b03166241e5be611afd6080890160608a01614bba565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018990527f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f9091166044820152606401602060405180830381865afa158015611b89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bad919061572f565b600e8054600090611bcd9084906bffffffffffffffffffffffff16615831565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b600e546bffffffffffffffffffffffff7f00000000000000000000000000000000000000000000043c33c1937564800000811691161115611c69576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160200151611dbd577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611dbd576001600160a01b0384166000908152600d602052604081205467ffffffffffffffff169003611dbd576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190615787565b6001600160a01b0385166000908152600d6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b604080516101a08101825267ffffffffffffffff7f000000000000000000000000000000000000000000000000173ac9059db959511681526001600160a01b03861660208201526000918101611e50611e168a80615563565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613e4292505050565b6001600160a01b03168152602001600e601081819054906101000a900467ffffffffffffffff16611e8090615856565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff168152602001846000015181526020016000151581526020018460200151611f2a576001600160a01b0387166000908152600d602052604081208054909190611f009067ffffffffffffffff16615856565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055611f2d565b60005b67ffffffffffffffff168152602001611f4c60808a0160608b01614bba565b6001600160a01b03168152602001878152602001888060200190611f709190615563565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611fb760408a018a6155c8565b808060200260200160405190810160405280939291908181526020016000905b8282101561200357611ff4604083028601368190038101906157f7565b81526020019060010190611fd7565b505050505081526020018367ffffffffffffffff81111561202657612026614cb8565b60405190808252806020026020018201604052801561205957816020015b60608152602001906001900390816120445790505b508152600060209091018190529091505b828110156124af57600061208160408a018a6155c8565b83818110612091576120916157a4565b9050604002018036038101906120a791906157f7565b905060006120b98b8360000151610ebf565b90506001600160a01b038116158061216f57506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527faff2afbf0000000000000000000000000000000000000000000000000000000060048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015612149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216d91906157da565b155b156121b45781516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b6000816001600160a01b0316639a4575b96040518060a001604052808e80600001906121e09190615563565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525067ffffffffffffffff7f00000000000000000000000000000000000000000000000045849994fc9c7b15166020808301919091526001600160a01b03808f16604080850191909152918901516060840152885116608090920191909152517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526122ab919060040161587d565b6000604051808303816000875af11580156122ca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122f2919081019061594a565b9050602063ffffffff1681602001515111156123895782516001600160a01b03166000908152600c602090815260409091205490820151516e01000000000000000000000000000090910463ffffffff1610156123895782516040517f36f536ca0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b805161239490613e42565b5060408051608081019091526001600160a01b03831660a08201528060c0810160408051808303601f190181529181529082528351602080840191909152808501518383015286516001600160a01b03166000908152600c9091522054606090910190730100000000000000000000000000000000000000900460ff166124295760075462010000900463ffffffff16612458565b84516001600160a01b03166000908152600c60205260409020546a0100000000000000000000900463ffffffff165b63ffffffff16905260405161247091906020016159db565b6040516020818303038152906040528561016001518581518110612496576124966157a4565b602002602001018190525050505080600101905061206a565b506124da817f5c3e709f37bab9ed06f1dfa270070e5c2ed77ee71507cfed438743c44518aa6b613ee8565b6101808201526040517fd0c3c799bf9e2639de44391e7f524d229b2b55f5b1ea94b2bf7da42f7243dddd90612510908390615aef565b60405180910390a16101800151925050505b949350505050565b6000546001600160a01b0316331461258f576002546001600160a01b0316331461258f57612559600833614043565b61258f576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff1660008190036125e3576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546bffffffffffffffffffffffff168181101561262e576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006126386115e1565b1215612670576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600061267d6008613b58565b905060005b8181101561276c57600080612698600884613b63565b90925090506000876126b8836bffffffffffffffffffffffff8a166156a5565b6126c291906156cf565b90506126ce8187615c24565b95506127126001600160a01b037f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f16846bffffffffffffffffffffffff8416613872565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a2505050806001019050612682565b5050600e80547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b6127b7612f97565b610f7f81614058565b6127c8613371565b610f7f816141ca565b60606040517f9e7177c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260008082526020820152600082900361286657506040805180820190915267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000030d4016815260006020820152610e7c565b60006128728385615c49565b90507fe7e230f0000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016128df576128ca8360048187615c91565b8101906128d79190615cbb565b915050610e7c565b7f6859a837000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016129605760408051808201909152806129408560048189615c91565b81019061294d9190615ce7565b815260006020909101529150610e7c9050565b6040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006547801000000000000000000000000000000000000000000000000900463ffffffff16808511156129fb576040517f869337890000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610aa3565b6006547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16841115612a5d576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554600160a01b900461ffff16831115612aa4576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81612af0576007546601000000000000900460ff1615612af0576040517fee433e9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6000808083815b81811015612eba576000878783818110612b1a57612b1a6157a4565b905060400201803603810190612b3091906157f7565b905060006001600160a01b0316612b6b7f00000000000000000000000000000000000000000000000045849994fc9c7b158360000151610ebf565b6001600160a01b031603612bb95780516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b80516001600160a01b03166000908152600c6020908152604091829020825160e081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e0100000000000000000000000000008304909116608082015260ff720100000000000000000000000000000000000083048116151560a0830152730100000000000000000000000000000000000000909204909116151560c08201819052612cde57600754612ca29061ffff16662386f26fc100006156a5565b612cac90886156bc565b600754909750612cc89062010000900463ffffffff1687615d00565b9550612cd5602086615d00565b94505050612eb2565b604081015160009061ffff1615612e025760008c6001600160a01b031684600001516001600160a01b031614612da55760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526401000000009092041690634ab35b0b90602401602060405180830381865afa158015612d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d9e9190615d1d565b9050612da8565b508a5b620186a0836040015161ffff16612dea8660200151847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661428b90919063ffffffff16565b612df491906156a5565b612dfe91906156cf565b9150505b6060820151612e119088615d00565b9650816080015186612e239190615d00565b8251909650600090612e429063ffffffff16662386f26fc100006156a5565b905080821015612e6157612e56818a6156bc565b985050505050612eb2565b6000836020015163ffffffff16662386f26fc10000612e8091906156a5565b905080831115612ea057612e94818b6156bc565b99505050505050612eb2565b612eaa838b6156bc565b995050505050505b600101612afe565b50509450945094915050565b60008063ffffffff8316612edc610180866156a5565b612ee8876102206156bc565b612ef291906156bc565b612efc91906156bc565b6005546006549192506000917c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690612f3e9061ffff16846156a5565b612f4891906156bc565b60065490915062010000900461ffff16612f726dffffffffffffffffffffffffffff8916836156a5565b612f7c91906156a5565b612f8c90655af3107a40006156a5565b979650505050505050565b6000546001600160a01b03163314612fed576002546001600160a01b03163314612fed576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60005b825181101561328357600083828151811061300f5761300f6157a4565b60200260200101519050602063ffffffff168160a0015163ffffffff16101561308257805160a08201516040517f24ecdc020000000000000000000000000000000000000000000000000000000081526001600160a01b03909216600483015263ffffffff166024820152604401610aa3565b6040805160e08101825260208381015163ffffffff908116835284840151811682840190815260608087015161ffff9081168688019081526080808a0151861693880193845260a0808b0151871691890191825260c0808c01511515918a019182526001908a018181529b516001600160a01b03166000908152600c9099529990972097518854955192519451915197519a519087167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009096169590951764010000000092871692909202919091177fffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffff166801000000000000000093909216929092027fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff16176a010000000000000000000091841691909102177fffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffff166e01000000000000000000000000000093909216929092027fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff1617720100000000000000000000000000000000000094151594909402939093177fffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff16730100000000000000000000000000000000000000931515939093029290921790915501612ff2565b507ff5791bc457b3bb990493cf5f655db46c25ccf5764c9b99b8969b4c72ea7df9d0826040516132b39190615d38565b60405180910390a160005b815181101561332e57600c60008383815181106132dd576132dd6157a4565b6020908102919091018101516001600160a01b0316825281019190915260400160002080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001016132be565b50805115610ebb577ffb95a0042158e60a33e7b5bec100f3d95407b1a71bee6633bd54b8887449750b816040516133659190615516565b60405180910390a15050565b6000546001600160a01b03163314612fed5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610aa3565b60e08101516001600160a01b031661340f576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600560008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601a6101000a81548161ffff021916908361ffff160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160006101000a81548161ffff021916908361ffff16021790555060c08201518160010160026101000a81548161ffff021916908361ffff16021790555060e08201518160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160006101000a81548161ffff021916908361ffff1602179055506101608201518160020160026101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160020160066101000a81548160ff0219169083151502179055509050507f45b5ad483aa608464c2c7f278bd413d284d7790cdc836e40652e23a0277082206040518061010001604052807f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f6001600160a01b031681526020017f000000000000000000000000000000000000000000000000173ac9059db9595167ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000045849994fc9c7b1567ffffffffffffffff1681526020017f0000000000000000000000000000000000000000000000000000000000030d4067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000043c33c19375648000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000060536ef486db5e0e1771874e31485c12e3c2844f6001600160a01b031681526020017f0000000000000000000000002961cb47b5111f38d75f415c21ceb4120ddd1b696001600160a01b03168152508260405161124c929190615dd8565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261384e82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426138329190615df5565b85608001516fffffffffffffffffffffffffffffffff166142c8565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526110f09084906142f0565b8051604081111561392f576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff161561398357600e5463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff909116106139835761398361252a565b600061398f6008613b58565b90505b80156139d15760006139b06139a8600184615df5565b600890613b63565b5090506139be6008826143d5565b5050806139ca90615e08565b9050613992565b506000805b82811015613ad95760008482815181106139f2576139f26157a4565b60200260200101516000015190506000858381518110613a1457613a146157a4565b60200260200101516020015190507f00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f6001600160a01b0316826001600160a01b03161480613a6957506001600160a01b038216155b15613aab576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610aa3565b613abb60088361ffff84166143ea565b50613aca61ffff821685615d00565b935050508060010190506139d6565b50600e80547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd2490613b4b9083908690615e3d565b60405180910390a1505050565b6000610e7c82614400565b6000808080613b72868661440b565b909450925050505b9250929050565b8154600090613b9d90600160801b900463ffffffff1642615df5565b90508015613c255760018301548354613bd8916fffffffffffffffffffffffffffffffff808216928116918591600160801b909104166142c8565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff000000000000000000000000000000000000000090911617600160801b4263ffffffff16021783555b60208201518354613c4b916fffffffffffffffffffffffffffffffff9081169116614436565b835483511515600160a01b027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff9283161717845560208301516040808501518316600160801b0291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990613b4b9084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b81516040517fd02641a00000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260009182919084169063d02641a0906024016040805180830381865afa158015613d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d9e9190615e5c565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116600003613e075783516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610aa3565b6020840151612522907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83169061428b565b610f7f600382600061444c565b60008151602014613e8157816040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610aa39190614c27565b600082806020019051810190613e97919061572f565b90506001600160a01b03811180613eaf575061040081105b15610e7c57826040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610aa39190614c27565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151604051602001613f7e9897969594939291906001600160a01b039889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b6040516020818303038152906040528051906020012085610120015180519060200120866101400151604051602001613fb79190615e8f565b60405160208183030381529060405280519060200120876101600151604051602001613fe39190615ea2565b60408051601f198184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b6000610f67836001600160a01b038416614756565b60005b815181101561419a576000828281518110614078576140786157a4565b60209081029190910181015160408051608080820183528385015163ffffffff90811683528385015167ffffffffffffffff908116848801908152606080880151831686880190815294880151151590860190815296516001600160a01b03166000908152600b90985294909620925183549451925195511515600160a01b027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9688166c0100000000000000000000000002969096167fffffffffffffffffffffff000000000000000000ffffffffffffffffffffffff93909716640100000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009095169116179290921791909116929092171790555060010161405b565b507f067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e8160405161124c9190615eb5565b336001600160a01b038216036142225760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610aa3565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000670de0b6b3a76400006142be837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff86166156a5565b610f6791906156cf565b60006142e7856142d884866156a5565b6142e290876156bc565b614436565b95945050505050565b6000614345826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166147629092919063ffffffff16565b8051909150156110f0578080602001905181019061436391906157da565b6110f05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610aa3565b6000610f67836001600160a01b038416614771565b6000612522846001600160a01b0385168461478e565b6000610e7c826147ab565b6000808061441985856147b5565b600081815260029690960160205260409095205494959350505050565b60008183106144455781610f67565b5090919050565b8254600160a01b900460ff161580614462575081155b1561446c57505050565b825460018401546fffffffffffffffffffffffffffffffff808316929116906000906144a590600160801b900463ffffffff1642615df5565b9050801561454b57818311156144e7576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461451490839085908490600160801b90046fffffffffffffffffffffffffffffffff166142c8565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff16600160801b4263ffffffff160217875592505b848210156145e8576001600160a01b03841661459d576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610aa3565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610aa3565b848310156146d457600186810154600160801b90046fffffffffffffffffffffffffffffffff1690600090829061461f9082615df5565b614629878a615df5565b61463391906156bc565b61463d91906156cf565b90506001600160a01b038616614689576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610aa3565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610aa3565b6146de8584615df5565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610f6783836147c1565b606061252284846000856147d9565b60008181526002830160205260408120819055610f6783836148c0565b6000828152600284016020526040812082905561252284846148cc565b6000610e7c825490565b6000610f6783836148d8565b60008181526001830160205260408120541515610f67565b6060824710156148515760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610aa3565b600080866001600160a01b0316858760405161486d9190615f36565b60006040518083038185875af1925050503d80600081146148aa576040519150601f19603f3d011682016040523d82523d6000602084013e6148af565b606091505b5091509150612f8c87838387614902565b6000610f67838361497b565b6000610f678383614a75565b60008260000182815481106148ef576148ef6157a4565b9060005260206000200154905092915050565b6060831561497157825160000361496a576001600160a01b0385163b61496a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aa3565b5081612522565b6125228383614ac4565b60008181526001830160205260408120548015614a6457600061499f600183615df5565b85549091506000906149b390600190615df5565b9050808214614a185760008660000182815481106149d3576149d36157a4565b90600052602060002001549050808760000184815481106149f6576149f66157a4565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614a2957614a29615f52565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610e7c565b6000915050610e7c565b5092915050565b6000818152600183016020526040812054614abc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610e7c565b506000610e7c565b815115614ad45781518083602001fd5b8060405162461bcd60e51b8152600401610aa39190614c27565b6001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401525060c0810151614b6b60c08401826001600160a01b03169052565b5060e08101516110f060e08401826001600160a01b03169052565b6101008101610e7c8284614aee565b6001600160a01b0381168114610f7f57600080fd5b8035614bb581614b95565b919050565b600060208284031215614bcc57600080fd5b8135610f6781614b95565b60005b83811015614bf2578181015183820152602001614bda565b50506000910152565b60008151808452614c13816020860160208601614bd7565b601f01601f19169290920160200192915050565b602081526000610f676020830184614bfb565b67ffffffffffffffff81168114610f7f57600080fd5b600060a08284031215614c6257600080fd5b50919050565b60008060408385031215614c7b57600080fd5b8235614c8681614c3a565b9150602083013567ffffffffffffffff811115614ca257600080fd5b614cae85828601614c50565b9150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b60405290565b6040516101a0810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b60405160a0810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b6040805190810167ffffffffffffffff81118282101715614cf157614cf1614cb8565b604051601f8201601f1916810167ffffffffffffffff81118282101715614d8a57614d8a614cb8565b604052919050565b600067ffffffffffffffff821115614dac57614dac614cb8565b5060051b60200190565b63ffffffff81168114610f7f57600080fd5b8035614bb581614db6565b803561ffff81168114614bb557600080fd5b8015158114610f7f57600080fd5b8035614bb581614de5565b600082601f830112614e0f57600080fd5b81356020614e24614e1f83614d92565b614d61565b8083825260208201915060208460051b870101935086841115614e4657600080fd5b602086015b84811015614e6b578035614e5e81614b95565b8352918301918301614e4b565b509695505050505050565b6000806040808486031215614e8a57600080fd5b833567ffffffffffffffff80821115614ea257600080fd5b818601915086601f830112614eb657600080fd5b81356020614ec6614e1f83614d92565b82815260e0928302850182019282820191908b851115614ee557600080fd5b958301955b84871015614f8e5780878d031215614f025760008081fd5b614f0a614cce565b8735614f1581614b95565b815287850135614f2481614db6565b8186015287890135614f3581614db6565b818a01526060614f46898201614dd3565b90820152608088810135614f5981614db6565b9082015260a0614f6a898201614dc8565b9082015260c0614f7b898201614df3565b9082015283529586019591830191614eea565b5097505087013593505080831115614fa557600080fd5b5050614cae85828601614dfe565b60008060408385031215614fc657600080fd5b8235614fd181614c3a565b91506020830135614fe181614b95565b809150509250929050565b60006101a08284031215614fff57600080fd5b615007614cf7565b61501083614baa565b815261501e60208401614dd3565b602082015261502f60408401614dc8565b604082015261504060608401614dd3565b606082015261505160808401614dc8565b608082015261506260a08401614dd3565b60a082015261507360c08401614dd3565b60c082015261508460e08401614baa565b60e0820152610100615097818501614dc8565b908201526101206150a9848201614dc8565b908201526101406150bb848201614dd3565b908201526101606150cd848201614dc8565b908201526101806150df848201614df3565b908201529392505050565b600080604083850312156150fd57600080fd5b8235614fd181614b95565b80516001600160a01b03168252602081015161512a602084018261ffff169052565b506040810151615142604084018263ffffffff169052565b506060810151615158606084018261ffff169052565b506080810151615170608084018263ffffffff169052565b5060a081015161518660a084018261ffff169052565b5060c081015161519c60c084018261ffff169052565b5060e08101516151b760e08401826001600160a01b03169052565b506101008181015163ffffffff90811691840191909152610120808301518216908401526101408083015161ffff16908401526101608083015190911690830152610180908101511515910152565b6101a08101610e7c8284615108565b6000806020838503121561522857600080fd5b823567ffffffffffffffff8082111561524057600080fd5b818501915085601f83011261525457600080fd5b81358181111561526357600080fd5b8660208260061b850101111561527857600080fd5b60209290920196919550909350505050565b60008151808452602080850194506020840160005b838110156152d357815180516001600160a01b0316885283015161ffff16838801526040909601959082019060010161529f565b509495945050505050565b6040815260006152f1604083018561528a565b90508260208301529392505050565b80356fffffffffffffffffffffffffffffffff81168114614bb557600080fd5b60006060828403121561533257600080fd5b6040516060810181811067ffffffffffffffff8211171561535557615355614cb8565b604052823561536381614de5565b815261537160208401615300565b602082015261538260408401615300565b60408201529392505050565b600080600080608085870312156153a457600080fd5b84356153af81614c3a565b9350602085013567ffffffffffffffff8111156153cb57600080fd5b6153d787828801614c50565b9350506040850135915060608501356153ef81614b95565b939692955090935050565b6000602080838503121561540d57600080fd5b823567ffffffffffffffff81111561542457600080fd5b8301601f8101851361543557600080fd5b8035615443614e1f82614d92565b81815260a0918202830184019184820191908884111561546257600080fd5b938501935b838510156154ed5780858a03121561547f5760008081fd5b615487614d1b565b853561549281614b95565b8152858701356154a181614db6565b818801526040868101356154b481614c3a565b908201526060868101356154c781614c3a565b908201526080868101356154da81614de5565b9082015283529384019391850191615467565b50979650505050505050565b60006020828403121561550b57600080fd5b8135610f6781614c3a565b6020808252825182820181905260009190848201906040850190845b818110156155575783516001600160a01b031683529284019291840191600101615532565b50909695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261559857600080fd5b83018035915067ffffffffffffffff8211156155b357600080fd5b602001915036819003821315613b7a57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155fd57600080fd5b83018035915067ffffffffffffffff82111561561857600080fd5b6020019150600681901b3603821315613b7a57600080fd5b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114614bb557600080fd5b6000806040838503121561566f57600080fd5b61567883615630565b915061568660208401615630565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e7c57610e7c61568f565b80820180821115610e7c57610e7c61568f565b6000826156ec57634e487b7160e01b600052601260045260246000fd5b500490565b67ffffffffffffffff818116838216019080821115614a6e57614a6e61568f565b60006020828403121561572457600080fd5b8151610f6781614b95565b60006020828403121561574157600080fd5b5051919050565b60006040828403121561575a57600080fd5b615762614d3e565b823561576d81614b95565b815261577b60208401614dd3565b60208201529392505050565b60006020828403121561579957600080fd5b8151610f6781614c3a565b634e487b7160e01b600052603260045260246000fd5b8181036000831280158383131683831282161715614a6e57614a6e61568f565b6000602082840312156157ec57600080fd5b8151610f6781614de5565b60006040828403121561580957600080fd5b615811614d3e565b823561581c81614b95565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff818116838216019080821115614a6e57614a6e61568f565b600067ffffffffffffffff8083168181036158735761587361568f565b6001019392505050565b602081526000825160a0602084015261589960c0840182614bfb565b905067ffffffffffffffff602085015116604084015260408401516001600160a01b038082166060860152606086015160808601528060808701511660a086015250508091505092915050565b600082601f8301126158f757600080fd5b815167ffffffffffffffff81111561591157615911614cb8565b6159246020601f19601f84011601614d61565b81815284602083860101111561593957600080fd5b612522826020830160208701614bd7565b60006020828403121561595c57600080fd5b815167ffffffffffffffff8082111561597457600080fd5b908301906040828603121561598857600080fd5b615990614d3e565b82518281111561599f57600080fd5b6159ab878286016158e6565b8252506020830151828111156159c057600080fd5b6159cc878286016158e6565b60208301525095945050505050565b6020815260008251608060208401526159f760a0840182614bfb565b90506020840151601f1980858403016040860152615a158383614bfb565b9250604086015191508085840301606086015250615a338282614bfb565b91505063ffffffff60608501511660808401528091505092915050565b60008151808452602080850194506020840160005b838110156152d357815180516001600160a01b031688528301518388015260409096019590820190600101615a65565b60008282518085526020808601955060208260051b8401016020860160005b84811015615ae257601f19868403018952615ad0838351614bfb565b98840198925090830190600101615ab4565b5090979650505050505050565b60208152615b0a60208201835167ffffffffffffffff169052565b60006020830151615b2660408401826001600160a01b03169052565b5060408301516001600160a01b038116606084015250606083015167ffffffffffffffff8116608084015250608083015160a083015260a0830151615b6f60c084018215159052565b5060c083015167ffffffffffffffff811660e08401525060e0830151610100615ba2818501836001600160a01b03169052565b840151610120848101919091528401516101a061014080860182905291925090615bd06101c0860184614bfb565b9250808601519050601f19610160818786030181880152615bf18584615a50565b945080880151925050610180818786030181880152615c108584615a95565b970151959092019490945250929392505050565b6bffffffffffffffffffffffff828116828216039080821115614a6e57614a6e61568f565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015615c895780818660040360031b1b83161692505b505092915050565b60008085851115615ca157600080fd5b83861115615cae57600080fd5b5050820193919092039150565b600060408284031215615ccd57600080fd5b615cd5614d3e565b82358152602083013561577b81614de5565b600060208284031215615cf957600080fd5b5035919050565b63ffffffff818116838216019080821115614a6e57614a6e61568f565b600060208284031215615d2f57600080fd5b610f6782615630565b602080825282518282018190526000919060409081850190868401855b82811015615dcb57815180516001600160a01b031685528681015163ffffffff908116888701528682015181168787015260608083015161ffff169087015260808083015182169087015260a0808301519091169086015260c09081015115159085015260e09093019290850190600101615d55565b5091979650505050505050565b6102a08101615de78285614aee565b610f67610100830184615108565b81810381811115610e7c57610e7c61568f565b600081615e1757615e1761568f565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff83168152604060208201526000612522604083018461528a565b600060408284031215615e6e57600080fd5b615e76614d3e565b615e7f83615630565b8152602083015161577b81614db6565b602081526000610f676020830184615a50565b602081526000610f676020830184615a95565b602080825282518282018190526000919060409081850190868401855b82811015615dcb57815180516001600160a01b031685528681015163ffffffff16878601528581015167ffffffffffffffff908116878701526060808301519091169086015260809081015115159085015260a09093019290850190600101615ed2565b60008251615f48818460208701614bd7565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfea164736f6c6343000818000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f000000000000000000000000000000000000000000000000173ac9059db9595100000000000000000000000000000000000000000000000045849994fc9c7b150000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000043c33c1937564800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060536ef486db5e0e1771874e31485c12e3c2844f0000000000000000000000002961cb47b5111f38d75f415c21ceb4120ddd1b69000000000000000000000000224918d5e099f38eb9f706941ba70a99b11e6a92000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000493e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009cc2b3816ab99e5ae9d8850a0365c2ec55157e6f000000000000000000000000000000000000000000000000000000000000753000000000000000000000000000000000000000000000000000000000002dc6c000000000000000000000000000000000000000000000000000000000000001f40000000000000000000000000000000000000000000000000000000000015f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000e92596fd62900000000000000000000000000000000000000000000000000000c7d713b49da00000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3800000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000e92596fd62900000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : staticConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : dynamicConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : rateLimiterConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [3] : feeTokenConfigs (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
40 Constructor Arguments found :
Arg [0] : 00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f
Arg [1] : 000000000000000000000000000000000000000000000000173ac9059db95951
Arg [2] : 00000000000000000000000000000000000000000000000045849994fc9c7b15
Arg [3] : 0000000000000000000000000000000000000000000000000000000000030d40
Arg [4] : 00000000000000000000000000000000000000000000043c33c1937564800000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 00000000000000000000000060536ef486db5e0e1771874e31485c12e3c2844f
Arg [7] : 0000000000000000000000002961cb47b5111f38d75f415c21ceb4120ddd1b69
Arg [8] : 000000000000000000000000224918d5e099f38eb9f706941ba70a99b11e6a92
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [10] : 00000000000000000000000000000000000000000000000000000000000493e0
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [15] : 0000000000000000000000009cc2b3816ab99e5ae9d8850a0365c2ec55157e6f
Arg [16] : 0000000000000000000000000000000000000000000000000000000000007530
Arg [17] : 00000000000000000000000000000000000000000000000000000000002dc6c0
Arg [18] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [19] : 0000000000000000000000000000000000000000000000000000000000015f90
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [24] : 0000000000000000000000000000000000000000000000000000000000000360
Arg [25] : 00000000000000000000000000000000000000000000000000000000000004c0
Arg [26] : 00000000000000000000000000000000000000000000000000000000000004e0
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [28] : 00000000000000000000000071052bae71c25c78e37fd12e5ff1101a71d9018f
Arg [29] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [30] : 0000000000000000000000000000000000000000000000000e92596fd6290000
Arg [31] : 0000000000000000000000000000000000000000000000000c7d713b49da0000
Arg [32] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [33] : 000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38
Arg [34] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [35] : 0000000000000000000000000000000000000000000000000e92596fd6290000
Arg [36] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [37] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [38] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [39] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.