Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 33 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Nops | 4520187 | 523 days ago | IN | 0 ETH | 0 | ||||
Apply Pool Updat... | 4240935 | 565 days ago | IN | 0 ETH | 0.0038641 | ||||
Apply Pool Updat... | 4240930 | 565 days ago | IN | 0 ETH | 0.0022694 | ||||
Apply Pool Updat... | 4204868 | 571 days ago | IN | 0 ETH | 0.00002585 | ||||
Apply Pool Updat... | 4204542 | 571 days ago | IN | 0 ETH | 0.00001257 | ||||
Apply Pool Updat... | 4204525 | 571 days ago | IN | 0 ETH | 0.0000093 | ||||
Apply Pool Updat... | 4204079 | 571 days ago | IN | 0 ETH | 0.00002222 | ||||
Apply Pool Updat... | 3937221 | 612 days ago | IN | 0 ETH | 0.00000007 | ||||
Set Allow List E... | 3929063 | 614 days ago | IN | 0 ETH | 0 | ||||
Apply Pool Updat... | 3928636 | 614 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3927686 | 614 days ago | IN | 0 ETH | 0 | ||||
Apply Pool Updat... | 3924421 | 614 days ago | IN | 0 ETH | 0 | ||||
Apply Pool Updat... | 3924367 | 614 days ago | IN | 0 ETH | 0 | ||||
Set Fee Token Co... | 3924301 | 614 days ago | IN | 0 ETH | 0 | ||||
Set Fee Token Co... | 3924235 | 615 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3919057 | 615 days ago | IN | 0 ETH | 0 | ||||
Set Rate Limiter... | 3914763 | 616 days ago | IN | 0 ETH | 0 | ||||
Set Rate Limiter... | 3914256 | 616 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3876459 | 622 days ago | IN | 0 ETH | 0 | ||||
Apply Pool Updat... | 3876345 | 622 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3875870 | 622 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3872377 | 622 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3866969 | 623 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3843189 | 627 days ago | IN | 0 ETH | 0 | ||||
Apply Allow List... | 3843114 | 627 days ago | IN | 0 ETH | 0 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
EVM2EVMOnRamp
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 26000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; import {IPool} from "../interfaces/pools/IPool.sol"; import {IARM} from "../interfaces/IARM.sol"; import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol"; import {IEVM2AnyOnRamp} from "../interfaces/IEVM2AnyOnRamp.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 {RateLimiter} from "../libraries/RateLimiter.sol"; import {USDPriceWith18Decimals} from "../libraries/USDPriceWith18Decimals.sol"; import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/utils/SafeERC20.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol"; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/structs/EnumerableSet.sol"; import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/structs/EnumerableMap.sol"; /// @notice The onRamp is a contract that handles fee logic, NOP payments, /// token support and an allowList. It will always be deployed 1:1:1 with a /// commitStore and offRamp contract. These three contracts together form a /// `lane`. A lane is an upgradable set of contracts within the non-upgradable /// routers and are always deployed as complete set, even during upgrades. /// This means an upgrade to an onRamp will require redeployment of the /// commitStore and offRamp as well. contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter, TypeAndVersionInterface { using SafeERC20 for IERC20; using EnumerableMap for EnumerableMap.AddressToUintMap; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; using EnumerableSet for EnumerableSet.AddressSet; using USDPriceWith18Decimals for uint192; error InvalidExtraArgsTag(); 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(IERC20 token); error MustBeCalledByRouter(); error RouterMustSetOriginalSender(); error InvalidTokenPoolConfig(); error PoolAlreadyAdded(); error PoolDoesNotExist(address token); error TokenPoolMismatch(); error SenderNotAllowed(address sender); error InvalidConfig(); error InvalidAddress(bytes encodedAddress); error BadARMSignal(); error LinkBalanceNotSettled(); error InvalidNopAddress(address nop); error NotAFeeToken(address token); event AllowListAdd(address sender); event AllowListRemove(address sender); event AllowListEnabledSet(bool enabled); event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig); event NopPaid(address indexed nop, uint256 amount); event FeeConfigSet(FeeTokenConfigArgs[] feeConfig); event TokenTransferFeeConfigSet(TokenTransferFeeConfigArgs[] transferFeeConfig); event CCIPSendRequested(Internal.EVM2EVMMessage message); event NopsSet(uint256 nopWeightsTotal, NopAndWeight[] nopsAndWeights); event PoolAdded(address token, address pool); event PoolRemoved(address token, address pool); /// @dev Struct that contains the static configuration 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 armProxy; // ---------- Address of ARM proxy } /// @dev Struct to contains the dynamic configuration struct DynamicConfig { address router; // -------- ┐ Router address uint16 maxTokensLength; // ┘ Maximum number of distinct ERC20 tokens that can be sent per message address priceRegistry; // --┐ Price registry address uint32 maxDataSize; // | Maximum payload data size uint64 maxGasLimit; // -----┘ Maximum gas limit for messages targeting EVMs } /// @dev Struct to hold the execution fee configuration for a fee token struct FeeTokenConfig { uint96 networkFeeAmountUSD; // --┐ Flat network fee in 1e18 USD uint64 gasMultiplier; // | Price multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost. uint32 destGasOverhead; // | Extra gas charged on top of the gasLimit uint16 destGasPerPayloadByte; // | Destination chain gas charged per byte of `data` payload 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 uint64 gasMultiplier; // --------┘ Price multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost. uint96 networkFeeAmountUSD; // --┐ Flat network fee in 1e18 USD uint32 destGasOverhead; // | Extra gas charged on top of the gasLimit uint16 destGasPerPayloadByte; // | Destination chain gas charged per byte of `data` payload bool enabled; // ----------------┘ Whether this fee token is enabled } /// @dev Struct to hold the transfer fee configuration for token transfers struct TokenTransferFeeConfig { uint32 minFee; // ---┐ Minimum USD fee to charge, multiples of 1 US cent, or 0.01USD uint32 maxFee; // | Maximum USD fee to charge, multiples of 1 US cent, or 0.01USD uint16 ratio; // ----┘ Ratio of token transfer value to charge as fee, multiples of 0.1bps, or 10e-5 } /// @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 minFee; // | Minimum USD fee to charge, multiples of 1 US cent, or 0.01USD uint32 maxFee; // | Maximum USD fee to charge, multiples of 1 US cent, or 0.01USD uint16 ratio; // ----┘ Ratio of token transfer value to charge as fee, multiples of 0.1bps, or 10e-5 } /// @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 // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "EVM2EVMOnRamp 1.0.0"; /// @dev The metadata hash for this contract 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 address internal immutable i_prevOnRamp; /// @dev The address of the arm proxy address internal immutable i_armProxy; /// @dev the maximum number of nops that can be configured at the same time. 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 source token => token pool EnumerableMapAddresses.AddressToAddressMap private s_poolsBySourceToken; /// @dev A set of addresses which can make ccipSend calls. EnumerableSet.AddressSet private s_allowList; /// @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 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; /// @dev Whether this OnRamp is paused or not bool private s_paused = false; /// @dev This allowListing will be removed before public launch /// @dev Whether s_allowList is enabled or not. bool private s_allowlistEnabled; constructor( StaticConfig memory staticConfig, DynamicConfig memory dynamicConfig, Internal.PoolUpdate[] memory tokensAndPools, address[] memory allowlist, 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.armProxy == 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_armProxy = staticConfig.armProxy; _setDynamicConfig(dynamicConfig); _setFeeTokenConfig(feeTokenConfigs); _setTokenTransferFeeConfig(tokenTransferFeeConfigArgs); _setNops(nopsAndWeights); // Set new tokens and pools _applyPoolUpdates(new Internal.PoolUpdate[](0), tokensAndPools); if (allowlist.length > 0) { s_allowlistEnabled = true; _applyAllowListUpdates(new address[](0), allowlist); } } // ================================================================ // | 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 (senderNonce == 0 && i_prevOnRamp != address(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 IEVM2AnyOnRamp function forwardFromRouter( Client.EVM2AnyMessage calldata message, uint256 feeTokenAmount, address originalSender ) external whenHealthy returns (bytes32) { // EVM destination addresses should be abi encoded and therefore always 32 bytes long if (message.receiver.length != 32) revert InvalidAddress(message.receiver); uint256 decodedReceiver = abi.decode(message.receiver, (uint256)); // We want to disallow sending to address(0) and to precompiles, which exist on address(1) through address(9). if (decodedReceiver > type(uint160).max || decodedReceiver < 10) revert InvalidAddress(message.receiver); Client.EVMExtraArgsV1 memory extraArgs = _fromBytes(message.extraArgs); // Validate the message with various checks _validateMessage(message.data.length, extraArgs.gasLimit, message.tokenAmounts.length, originalSender); // Rate limit on aggregated token value _rateLimitValue(message.tokenAmounts, IPriceRegistry(s_dynamicConfig.priceRegistry)); // 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(); if (s_senderNonce[originalSender] == 0 && i_prevOnRamp != address(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, sequenceNumber: ++s_sequenceNumber, feeTokenAmount: feeTokenAmount, sender: originalSender, nonce: ++s_senderNonce[originalSender], gasLimit: extraArgs.gasLimit, strict: extraArgs.strict, receiver: address(uint160(decodedReceiver)), data: message.data, tokenAmounts: message.tokenAmounts, feeToken: message.feeToken, messageId: "" }); newMessage.messageId = Internal._hash(newMessage, i_metadataHash); // 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 < message.tokenAmounts.length; ++i) { Client.EVMTokenAmount memory tokenAndAmount = message.tokenAmounts[i]; getPoolBySourceToken(IERC20(tokenAndAmount.token)).lockOrBurn( originalSender, message.receiver, tokenAndAmount.amount, i_destChainSelector, bytes("") // any future extraArgs component would be added here ); } // Emit message request 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.EVMExtraArgsV1 memory) { if (extraArgs.length == 0) { return Client.EVMExtraArgsV1({gasLimit: i_defaultTxGasLimit, strict: false}); } if (bytes4(extraArgs) != Client.EVM_EXTRA_ARGS_V1_TAG) revert InvalidExtraArgsTag(); return abi.decode(extraArgs[4:], (Client.EVMExtraArgsV1)); } /// @notice Validate the forwarded message with various checks. /// @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. /// @param originalSender The original sender of the message on the router. function _validateMessage( uint256 dataLength, uint256 gasLimit, uint256 numberOfTokens, address originalSender ) internal view { if (originalSender == address(0)) revert RouterMustSetOriginalSender(); // Router address may be zero intentionally to pause. if (msg.sender != s_dynamicConfig.router) revert MustBeCalledByRouter(); // Check that payload is formed correctly uint256 maxDataSize = uint256(s_dynamicConfig.maxDataSize); if (dataLength > maxDataSize) revert MessageTooLarge(maxDataSize, dataLength); if (gasLimit > uint256(s_dynamicConfig.maxGasLimit)) revert MessageGasLimitTooHigh(); if (numberOfTokens > uint256(s_dynamicConfig.maxTokensLength)) revert UnsupportedNumberOfTokens(); if (s_allowlistEnabled && !s_allowList.contains(originalSender)) revert SenderNotAllowed(originalSender); } // ================================================================ // | Config | // ================================================================ /// @notice Returns the static onRamp config. /// @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, armProxy: i_armProxy }); } /// @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, armProxy: i_armProxy }), dynamicConfig ); } // ================================================================ // | Tokens and pools | // ================================================================ /// @inheritdoc IEVM2AnyOnRamp function getSupportedTokens() external view returns (address[] memory) { address[] memory sourceTokens = new address[](s_poolsBySourceToken.length()); for (uint256 i = 0; i < sourceTokens.length; ++i) { (sourceTokens[i], ) = s_poolsBySourceToken.at(i); } return sourceTokens; } /// @inheritdoc IEVM2AnyOnRamp function getPoolBySourceToken(IERC20 sourceToken) public view returns (IPool) { if (!s_poolsBySourceToken.contains(address(sourceToken))) revert UnsupportedToken(sourceToken); return IPool(s_poolsBySourceToken.get(address(sourceToken))); } /// @inheritdoc IEVM2AnyOnRamp /// @dev This method can only be called by the owner of the contract. function applyPoolUpdates( Internal.PoolUpdate[] memory removes, Internal.PoolUpdate[] memory adds ) external onlyOwner { _applyPoolUpdates(removes, adds); } function _applyPoolUpdates(Internal.PoolUpdate[] memory removes, Internal.PoolUpdate[] memory adds) internal { for (uint256 i = 0; i < removes.length; ++i) { address token = removes[i].token; address pool = removes[i].pool; if (!s_poolsBySourceToken.contains(token)) revert PoolDoesNotExist(token); if (s_poolsBySourceToken.get(token) != pool) revert TokenPoolMismatch(); if (s_poolsBySourceToken.remove(token)) { emit PoolRemoved(token, pool); } } for (uint256 i = 0; i < adds.length; ++i) { address token = adds[i].token; address pool = adds[i].pool; if (token == address(0) || pool == address(0)) revert InvalidTokenPoolConfig(); if (token != address(IPool(pool).getToken())) revert TokenPoolMismatch(); if (s_poolsBySourceToken.set(token, pool)) { emit PoolAdded(token, pool); } else { revert PoolAlreadyAdded(); } } } // ================================================================ // | Fees | // ================================================================ /// @inheritdoc IEVM2AnyOnRamp function getFee(Client.EVM2AnyMessage calldata message) external view returns (uint256) { FeeTokenConfig memory feeTokenConfig = s_feeTokenConfig[message.feeToken]; if (!feeTokenConfig.enabled) revert NotAFeeToken(message.feeToken); (uint192 feeTokenPrice, uint192 gasPrice) = IPriceRegistry(s_dynamicConfig.priceRegistry).getTokenAndGasPrices( message.feeToken, i_destChainSelector ); // Total tx fee in USD with 18 decimals precision, excluding token bps // We add the message gas limit, the overhead gas and the calldata gas together. // We then multiple this destination chain gas total with the gas multiplier and // convert it into USD. uint256 executionFeeUsdValue = (gasPrice * ((_fromBytes(message.extraArgs).gasLimit + feeTokenConfig.destGasOverhead + message.data.length * feeTokenConfig.destGasPerPayloadByte) * feeTokenConfig.gasMultiplier)) / 1 ether + feeTokenConfig.networkFeeAmountUSD; // Transform the execution fee into fee token amount and add the token bps fee // which is already priced in fee token return feeTokenPrice._calcTokenAmountFromUSDValue(executionFeeUsdValue) + _getTokenTransferFee(message.feeToken, feeTokenPrice, message.tokenAmounts); } /// @notice Returns the fee based on the tokens transferred. Will always be 0 if /// no tokens are transferred. The token fee is calculated based on basis points. function _getTokenTransferFee( address feeToken, uint192 feeTokenPrice, Client.EVMTokenAmount[] calldata tokenAmounts ) internal view returns (uint256 feeTokenAmount) { uint256 numberOfTokens = tokenAmounts.length; // short-circuit with 0 transfer fee if no token is being transferred if (numberOfTokens == 0) { return 0; } for (uint256 i = 0; i < numberOfTokens; ++i) { Client.EVMTokenAmount memory tokenAmount = tokenAmounts[i]; TokenTransferFeeConfig memory transferFeeConfig = s_tokenTransferFeeConfig[tokenAmount.token]; uint256 feeValue = 0; // ratio can be 0, only calculate bps fee if ratio is greater than 0 if (transferFeeConfig.ratio > 0) { uint192 tokenPrice = feeTokenPrice; if (tokenAmount.token != feeToken) { tokenPrice = IPriceRegistry(s_dynamicConfig.priceRegistry).getValidatedTokenPrice(tokenAmount.token); } // calculate token transfer value, then apply fee ratio // ratio represents multiples of 0.1bps, or 10e-5 feeValue = (tokenPrice._calcUSDValueFromTokenAmount(tokenAmount.amount) * transferFeeConfig.ratio) / 1e5; } // convert USD values with 2 decimals to 18 decimals uint256 minFeeValue = uint256(transferFeeConfig.minFee) * 1e16; uint256 maxFeeValue = uint256(transferFeeConfig.maxFee) * 1e16; if (feeValue < minFeeValue) { feeValue = minFeeValue; } else if (feeValue > maxFeeValue) { feeValue = maxFeeValue; } feeTokenAmount += feeTokenPrice._calcTokenAmountFromUSDValue(feeValue); } return feeTokenAmount; } /// @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({ networkFeeAmountUSD: configArg.networkFeeAmountUSD, gasMultiplier: configArg.gasMultiplier, destGasOverhead: configArg.destGasOverhead, destGasPerPayloadByte: configArg.destGasPerPayloadByte, 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 ) external onlyOwnerOrAdmin { _setTokenTransferFeeConfig(tokenTransferFeeConfigArgs); } /// @notice internal helper to set the token transfer fee config. function _setTokenTransferFeeConfig(TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs) internal { for (uint256 i = 0; i < tokenTransferFeeConfigArgs.length; ++i) { TokenTransferFeeConfigArgs memory configArg = tokenTransferFeeConfigArgs[i]; s_tokenTransferFeeConfig[configArg.token] = TokenTransferFeeConfig({ minFee: configArg.minFee, maxFee: configArg.maxFee, ratio: configArg.ratio }); } emit TokenTransferFeeConfigSet(tokenTransferFeeConfigArgs); } // ================================================================ // | 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); } /// @dev Clears existing nops, sets new nops and weights /// @param nopsAndWeights New set of nops and weights 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 && 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 onlyOwnerOrAdminOrNop { uint256 weightsTotal = s_nopWeightsTotal; if (weightsTotal == 0) revert NoNopsToPay(); uint96 totalFeesToPay = s_nopFeesJuels; if (totalFeesToPay < weightsTotal) revert NoFeesToPay(); if (_linkLeftAfterNopFees() < 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 that is not the fee token /// @param feeToken The token to withdraw /// @param to The address to send the tokens to function withdrawNonLinkFees(address feeToken, address to) external onlyOwnerOrAdmin { if (feeToken == i_linkToken || to == address(0)) revert InvalidWithdrawParams(); // We require the link balance to be settled before allowing withdrawal // of non-link fees. if (_linkLeftAfterNopFees() < 0) revert LinkBalanceNotSettled(); IERC20(feeToken).safeTransfer(to, IERC20(feeToken).balanceOf(address(this))); } // ================================================================ // | Link monitoring | // ================================================================ /// @notice Calculate remaining LINK balance after paying nops /// @return balance if nops were to be paid function _linkLeftAfterNopFees() private 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)); } /// @notice Allow keeper to monitor funds available for paying nops function linkAvailableForPayment() external view returns (int256) { return _linkLeftAfterNopFees(); } // ================================================================ // | Allowlist | // ================================================================ /// @notice Gets whether the allowList functionality is enabled. /// @return true is enabled, false if not. function getAllowListEnabled() external view returns (bool) { return s_allowlistEnabled; } /// @notice Enables or disabled the allowList functionality. /// @param enabled Signals whether the allowlist should be enabled. function setAllowListEnabled(bool enabled) external onlyOwner { s_allowlistEnabled = enabled; emit AllowListEnabledSet(enabled); } /// @notice Gets the allowed addresses. /// @return The allowed addresses. /// @dev May not work if allow list gets too large. Use events in that case to compute the set. function getAllowList() external view returns (address[] memory) { return s_allowList.values(); } /// @notice Apply updates to the allow list. /// @param removes The addresses to be removed. /// @param adds The addresses to be added. /// @dev allowListing will be removed before public launch function applyAllowListUpdates(address[] memory removes, address[] memory adds) external onlyOwner { _applyAllowListUpdates(removes, adds); } /// @notice Internal version of applyAllowListUpdates to allow for reuse in the constructor. /// @dev allowListing will be removed before public launch function _applyAllowListUpdates(address[] memory removes, address[] memory adds) internal { for (uint256 i = 0; i < removes.length; ++i) { address toRemove = removes[i]; if (s_allowList.remove(toRemove)) { emit AllowListRemove(toRemove); } } for (uint256 i = 0; i < adds.length; ++i) { address toAdd = adds[i]; if (toAdd == address(0)) { continue; } if (s_allowList.add(toAdd)) { emit AllowListAdd(toAdd); } } } // ================================================================ // | Access and ARM | // ================================================================ /// @dev Require that the sender is the owner or the fee admin or a nop modifier onlyOwnerOrAdminOrNop() { if (msg.sender != owner() && msg.sender != s_admin && !s_nops.contains(msg.sender)) revert OnlyCallableByOwnerOrAdminOrNop(); _; } /// @dev Require that the sender is the owner or the fee admin modifier onlyOwnerOrAdmin() { if (msg.sender != owner() && msg.sender != s_admin) revert OnlyCallableByOwnerOrAdmin(); _; } /// @notice Ensure that the ARM has not emitted a bad signal, and that the latest heartbeat is not stale. modifier whenHealthy() { if (IARM(i_armProxy).isCursed()) revert BadARMSignal(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract TypeAndVersionInterface { function typeAndVersion() external pure virtual returns (string memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol"; // Shared public interface for multiple pool types. // Each pool type handles a different child token model (lock/unlock, mint/burn.) interface IPool { /// @notice Lock tokens into the pool or burn the tokens. /// @param originalSender Original sender of the tokens. /// @param receiver Receiver of the tokens on destination chain. /// @param amount Amount to lock or burn. /// @param destChainSelector Destination chain Id. /// @param extraArgs Additional data passed in by sender for lockOrBurn processing /// in custom pools on source chain. /// @return retData Optional field that contains bytes. Unused for now but already /// implemented to allow future upgrades while preserving the interface. function lockOrBurn( address originalSender, bytes calldata receiver, uint256 amount, uint64 destChainSelector, bytes calldata extraArgs ) external returns (bytes memory); /// @notice Releases or mints tokens to the receiver address. /// @param originalSender Original sender of the tokens. /// @param receiver Receiver of the tokens. /// @param amount Amount to release or mint. /// @param sourceChainSelector Source chain Id. /// @param extraData Additional data supplied offchain for releaseOrMint processing in /// custom pools on dest chain. This could be an attestation that was retrieved through a /// third party API. /// @dev offchainData can come from any untrusted source. function releaseOrMint( bytes memory originalSender, address receiver, uint256 amount, uint64 sourceChainSelector, bytes memory extraData ) external; /// @notice Gets the IERC20 token that this pool can lock or burn. /// @return token The IERC20 token representation. function getToken() external view returns (IERC20 token); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// @notice This interface contains the only ARM-related functions that might be used on-chain by other CCIP contracts. interface IARM { /// @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 When the ARM is "cursed", CCIP pauses until the curse is lifted. function isCursed() external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {Internal} from "../libraries/Internal.sol"; interface IPriceRegistry { /// @notice Update the price for given tokens and destination chain. /// @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.TimestampedUint192Value 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 (uint192); /// @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.TimestampedUint192Value[] memory); /// @notice Get the `gasPrice` for a given destination chain ID. /// @param destChainSelector The destination chain to get the price for. /// @return gasPrice The gasPrice for the given destination chain ID. function getDestinationChainGasPrice( uint64 destChainSelector ) external view returns (Internal.TimestampedUint192Value 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 (uint192 tokenPrice, uint192 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); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {IPool} from "./pools/IPool.sol"; import {Client} from "../libraries/Client.sol"; import {Internal} from "../libraries/Internal.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol"; interface IEVM2AnyOnRamp { /// @notice Get the fee for a given ccip message /// @param message The message to calculate the cost for /// @return fee The calculated fee function getFee(Client.EVM2AnyMessage calldata message) external view returns (uint256 fee); /// @notice Get the pool for a specific token /// @param sourceToken The source chain token to get the pool for /// @return pool Token pool function getPoolBySourceToken(IERC20 sourceToken) external view returns (IPool); /// @notice Gets a list of all supported source chain tokens. /// @return tokens The addresses of all tokens that this onRamp supports for sending. function getSupportedTokens() external view returns (address[] memory tokens); /// @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); /// @notice Adds and removed token pools. /// @param removes The tokens and pools to be removed /// @param adds The tokens and pools to be added. function applyPoolUpdates(Internal.PoolUpdate[] memory removes, Internal.PoolUpdate[] memory adds) external; /// @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 message Message struct to send /// @param originalSender The original initiator of the CCIP request function forwardFromRouter( Client.EVM2AnyMessage memory message, uint256 feeTokenAmount, address originalSender ) external returns (bytes32); }
// SPDX-License-Identifier: BUSL-1.1 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.19; 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"; contract AggregateRateLimiter is OwnerIsCreator { using RateLimiter for RateLimiter.TokenBucket; using USDPriceWith18Decimals for uint192; 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 containing the capacity and refill rate /// of the bucket, plus the admin address. 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. First, calculate the prices function _rateLimitValue(Client.EVMTokenAmount[] memory tokenAmounts, IPriceRegistry priceRegistry) internal { uint256 numberOfTokens = tokenAmounts.length; uint256 value = 0; for (uint256 i = 0; i < numberOfTokens; ++i) { // not fetching validated price, as price staleness is not important for value-based rate limiting // we only need to verify price is not 0 uint192 pricePerToken = priceRegistry.getTokenPrice(tokenAmounts[i].token).value; if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmounts[i].token); value += pricePerToken._calcUSDValueFromTokenAmount(tokenAmounts[i].amount); } s_rateLimiter._consume(value, address(0)); } /// @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: BUSL-1.1 pragma solidity ^0.8.0; // End consumer library. library Client { 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 and strict = false. 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(EVMExtraArgsV1) } // extraArgs will evolve to support new features // bytes4(keccak256("CCIP EVMExtraArgsV1")); bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9; struct EVMExtraArgsV1 { uint256 gasLimit; // ATTENTION!!! MAX GAS LIMIT 4M FOR BETA TESTING bool strict; // See strict sequencing details below. } function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {Client} from "./Client.sol"; import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol"; // Library for CCIP internal definitions common to multiple contracts. library Internal { struct PriceUpdates { TokenPriceUpdate[] tokenPriceUpdates; uint64 destChainSelector; // --┐ Destination chain selector uint192 usdPerUnitGas; // -----┘ 1e18 USD per smallest unit (e.g. wei) of destination chain gas } struct TokenPriceUpdate { address sourceToken; // Source token uint192 usdPerToken; // 1e18 USD per smallest unit of token } struct TimestampedUint192Value { uint192 value; // -------┐ The price, in 1e18 USD. uint64 timestamp; // ----┘ Timestamp of the most recent price update. } struct PoolUpdate { address token; // The IERC20 token address address pool; // The token pool address } 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 struct EVM2EVMMessage { uint64 sourceChainSelector; uint64 sequenceNumber; uint256 feeTokenAmount; address sender; uint64 nonce; uint256 gasLimit; bool strict; // User fields address receiver; bytes data; Client.EVMTokenAmount[] tokenAmounts; address feeToken; bytes32 messageId; } function _toAny2EVMMessage( EVM2EVMMessage memory original, Client.EVMTokenAmount[] memory destTokenAmounts ) internal pure returns (Client.Any2EVMMessage memory message) { message = Client.Any2EVMMessage({ messageId: original.messageId, sourceChainSelector: original.sourceChainSelector, sender: abi.encode(original.sender), data: original.data, destTokenAmounts: destTokenAmounts }); } bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageEvent"); function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) { return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, metadataHash, original.sequenceNumber, original.nonce, original.sender, original.receiver, keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)), original.gasLimit, original.strict, original.feeToken, original.feeTokenAmount ) ); } /// @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. enum MessageExecutionState { UNTOUCHED, IN_PROGRESS, SUCCESS, FAILURE } }
// 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); 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 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(uint192 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(uint192 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 pragma solidity ^0.8.0; import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/structs/EnumerableMap.sol"; library EnumerableMapAddresses { using EnumerableMap for EnumerableMap.UintToAddressMap; struct AddressToAddressMap { EnumerableMap.UintToAddressMap _inner; } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) { return map._inner.set(uint256(uint160(key)), value); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function remove(AddressToAddressMap storage map, address key) internal returns (bool) { return map._inner.remove(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function contains(AddressToAddressMap storage map, address key) internal view returns (bool) { return map._inner.contains(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function length(AddressToAddressMap storage map) internal view returns (uint256) { return map._inner.length(); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function at(AddressToAddressMap storage map, uint256 index) internal view returns (address, address) { (uint256 key, address value) = map._inner.at(index); return (address(uint160(key)), value); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool, address) { return map._inner.tryGet(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function get(AddressToAddressMap storage map, address key) internal view returns (address) { return map._inner.get(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function get( AddressToAddressMap storage map, address key, string memory errorMessage ) internal view returns (address) { return map._inner.get(uint256(uint160(key)), errorMessage); } }
// 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 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) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @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. * * ``` * 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 of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @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._indexes[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 read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 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 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[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._indexes[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 // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableMap.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. pragma solidity ^0.8.0; import "./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. * * ``` * 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 Uint256ToAddressMap) are just wrappers around // the underlying Map. // This means that we can only create new EnumerableMaps for types that fit // in bytes32. struct Bytes32ToBytes32Map { // Storage of keys EnumerableSet.Bytes32Set _keys; mapping(bytes32 => 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]; require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); return value; } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( Bytes32ToBytes32Map storage map, bytes32 key, string memory errorMessage ) internal view returns (bytes32) { bytes32 value = map._values[key]; require(value != 0 || contains(map, key), errorMessage); return value; } // 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 set. 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 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(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 Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( UintToUintMap storage map, uint256 key, string memory errorMessage ) internal view returns (uint256) { return uint256(get(map._inner, bytes32(key), errorMessage)); } // 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 set. 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 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(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 Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( UintToAddressMap storage map, uint256 key, string memory errorMessage ) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage)))); } // 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 set. 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 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(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 Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( AddressToUintMap storage map, address key, string memory errorMessage ) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage)); } // 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 set. 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 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(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 Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( Bytes32ToUintMap storage map, bytes32 key, string memory errorMessage ) internal view returns (uint256) { return uint256(get(map._inner, key, errorMessage)); } }
// 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 pragma solidity ^0.8.0; import "./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 "./interfaces/OwnableInterface.sol"; /** * @title The ConfirmedOwner contract * @notice A contract with helpers for basic contract ownership. */ contract ConfirmedOwnerWithProposal is OwnableInterface { 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) { 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, * pending. */ function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } /** * @notice Allows an ownership transfer to be completed by the recipient. */ function acceptOwnership() external override { 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 { require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /** * @notice validate access */ function _validateOwnership() internal view { 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 OwnableInterface { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; }
{ "remappings": [ "@eth-optimism/=node_modules/@eth-optimism/", "@openzeppelin/=node_modules/@openzeppelin/", "ds-test/=foundry-lib/forge-std/lib/ds-test/src/", "erc4626-tests/=foundry-lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=foundry-lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 26000 }, "metadata": { "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract ABI
API[{"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":"armProxy","type":"address"}],"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxTokensLength","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataSize","type":"uint32"},{"internalType":"uint64","name":"maxGasLimit","type":"uint64"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"tokensAndPools","type":"tuple[]"},{"internalType":"address[]","name":"allowlist","type":"address[]"},{"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":"uint64","name":"gasMultiplier","type":"uint64"},{"internalType":"uint96","name":"networkFeeAmountUSD","type":"uint96"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.FeeTokenConfigArgs[]","name":"feeTokenConfigs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFee","type":"uint32"},{"internalType":"uint32","name":"maxFee","type":"uint32"},{"internalType":"uint16","name":"ratio","type":"uint16"}],"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":"BadARMSignal","type":"error"},{"inputs":[],"name":"BucketOverfilled","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"bytes","name":"encodedAddress","type":"bytes"}],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidConfig","type":"error"},{"inputs":[],"name":"InvalidExtraArgsTag","type":"error"},{"inputs":[{"internalType":"address","name":"nop","type":"address"}],"name":"InvalidNopAddress","type":"error"},{"inputs":[],"name":"InvalidTokenPoolConfig","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":[],"name":"PoolAlreadyAdded","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"PoolDoesNotExist","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"PriceNotFoundForToken","type":"error"},{"inputs":[],"name":"RouterMustSetOriginalSender","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenMaxCapacityExceeded","type":"error"},{"inputs":[],"name":"TokenPoolMismatch","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":"contract IERC20","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":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"AllowListAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"AllowListEnabledSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"AllowListRemove","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"strict","type":"bool"},{"internalType":"address","name":"receiver","type":"address"},{"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":"bytes32","name":"messageId","type":"bytes32"}],"indexed":false,"internalType":"struct Internal.EVM2EVMMessage","name":"message","type":"tuple"}],"name":"CCIPSendRequested","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":"armProxy","type":"address"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxTokensLength","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataSize","type":"uint32"},{"internalType":"uint64","name":"maxGasLimit","type":"uint64"}],"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":"uint64","name":"gasMultiplier","type":"uint64"},{"internalType":"uint96","name":"networkFeeAmountUSD","type":"uint96"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"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":"token","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFee","type":"uint32"},{"internalType":"uint32","name":"maxFee","type":"uint32"},{"internalType":"uint16","name":"ratio","type":"uint16"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"transferFeeConfig","type":"tuple[]"}],"name":"TokenTransferFeeConfigSet","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"removes","type":"address[]"},{"internalType":"address[]","name":"adds","type":"address[]"}],"name":"applyAllowListUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"removes","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"adds","type":"tuple[]"}],"name":"applyPoolUpdates","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":[{"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":"getAllowList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowListEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDynamicConfig","outputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxTokensLength","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataSize","type":"uint32"},{"internalType":"uint64","name":"maxGasLimit","type":"uint64"}],"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":[{"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":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getFeeTokenConfig","outputs":[{"components":[{"internalType":"uint96","name":"networkFeeAmountUSD","type":"uint96"},{"internalType":"uint64","name":"gasMultiplier","type":"uint64"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"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":"contract IERC20","name":"sourceToken","type":"address"}],"name":"getPoolBySourceToken","outputs":[{"internalType":"contract IPool","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":"armProxy","type":"address"}],"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","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":"minFee","type":"uint32"},{"internalType":"uint32","name":"maxFee","type":"uint32"},{"internalType":"uint16","name":"ratio","type":"uint16"}],"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":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setAllowListEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxTokensLength","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataSize","type":"uint32"},{"internalType":"uint64","name":"maxGasLimit","type":"uint64"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"setDynamicConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"gasMultiplier","type":"uint64"},{"internalType":"uint96","name":"networkFeeAmountUSD","type":"uint96"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"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":"minFee","type":"uint32"},{"internalType":"uint32","name":"maxFee","type":"uint32"},{"internalType":"uint16","name":"ratio","type":"uint16"}],"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"tokenTransferFeeConfigArgs","type":"tuple[]"}],"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
6101806040526012805460ff60c01b191690553480156200001f57600080fd5b50604051620081c1380380620081c1833981016040819052620000429162001eb3565b8333806000816200009a5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cd57620000cd8162000369565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080909301839052600380546001600160a01b031916909417600160801b9283021760ff60a01b1916600160a01b90910217909255029091176004555087516001600160a01b0316158062000176575060208801516001600160401b0316155b806200018d575060408801516001600160401b0316155b80620001a4575060608801516001600160401b0316155b80620001bb575060c08801516001600160a01b0316155b15620001da576040516306b7c75960e31b815260040160405180910390fd5b6020808901516040808b015181517fbdd59ac4dd1d82276c9a9c5d2656546346b9dcdb1f9b4204aed4ec15c23d7d3a948101949094526001600160401b039283169184019190915216606082015230608082015260a00160408051601f19818403018152918152815160209283012060809081528a516001600160a01b0390811660e052928b01516001600160401b0390811661010052918b015182166101205260608b015190911660a0908152908a01516001600160601b031660c0908152908a01518216610140528901511661016052620002b78762000414565b620002c28362000566565b620002cd82620006d8565b620002d881620007e5565b6040805160008082526020820190925262000323916200031b565b6040805180820190915260008082526020820152815260200190600190039081620002f35790505b508762000a0f565b8451156200035b576012805460ff60c81b1916600160c81b179055604080516000808252602082019092526200035b91508662000d12565b505050505050505062002405565b336001600160a01b03821603620003c35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000091565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60408101516001600160a01b031662000440576040516306b7c75960e31b815260040160405180910390fd5b8051600580546020808501516001600160a01b039485166001600160b01b031990931692909217600160a01b61ffff909316830217909255604080850151600680546060808901516080808b0151958a166001600160c01b03199094169390931763ffffffff909116909602959095176001600160c01b0316600160c01b6001600160401b039485160217909155825160e080820185525187168152610100518316958101959095526101205182168584015260a080519092169385019390935260c080516001600160601b03169385019390935261014051851690840152610160519093169082015290517fdd226617d8d287f40a64c54741bbcdc492b3e096ef16bc5273a18cb6ab85f124916200055b91849062001fd6565b60405180910390a150565b60005b8151811015620006a65760008282815181106200058a576200058a62002086565b6020908102919091018101516040805160a08082018352828401516001600160601b039081168352848601516001600160401b0390811684880190815260608088015163ffffffff9081168789019081526080808b015161ffff908116948a01948552978b0151151590890190815299516001600160a01b03166000908152600f909b52979099209551865492519751915198511515600160d01b0260ff60d01b1999909616600160c01b0261ffff60c01b1992909a16600160a01b029190911665ffffffffffff60a01b19979093166c01000000000000000000000000026001600160a01b03199092169316929092179190911793909316929092179390931791909116179055506200069e81620020b2565b905062000569565b507ffba339fca97870ffdfaedbae3745db5e6de1a6909dfd0e0dbb56917469ffe236816040516200055b9190620020ce565b60005b8151811015620007b3576000828281518110620006fc57620006fc62002086565b60209081029190910181015160408051606080820183528385015163ffffffff90811683528385015181168387019081529185015161ffff90811684860190815295516001600160a01b031660009081526010909752939095209151825491519451909316680100000000000000000261ffff60401b19948616640100000000026001600160401b03199092169390951692909217919091179190911691909117905550620007ab81620020b2565b9050620006db565b507fcb0c5f472d325cf0c56953fc81870ddd80d0d3c9a3fbfe777002d75f380dfb81816040516200055b91906200216f565b805160408111156200080a57604051635ad0867d60e11b815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff161580159062000854575060125463ffffffff6c010000000000000000000000008204166001600160601b0390911610155b1562000864576200086462000e5d565b60006200087260076200105d565b90505b8015620008be576000620008986200088f600184620021de565b60079062001070565b509050620008a86007826200108e565b505080620008b690620021f4565b905062000875565b506000805b82811015620009a6576000848281518110620008e357620008e362002086565b6020026020010151600001519050600085838151811062000908576200090862002086565b602002602001015160200151905060e0516001600160a01b0316826001600160a01b031614806200094057506001600160a01b038216155b156200096b57604051634de938d160e01b81526001600160a01b038316600482015260240162000091565b6200097d60078361ffff8416620010ac565b506200098e61ffff8216856200220e565b93505050806200099e90620020b2565b9050620008c3565b506012805463ffffffff60601b19166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd249062000a0290839086906200222e565b60405180910390a1505050565b60005b825181101562000b4b57600083828151811062000a335762000a3362002086565b6020026020010151600001519050600084838151811062000a585762000a5862002086565b6020908102919091018101510151905062000a75600a83620010cc565b62000a9f576040516373913ebd60e01b81526001600160a01b038316600482015260240162000091565b6001600160a01b03811662000ab6600a84620010e3565b6001600160a01b03161462000ade57604051630d98f73360e31b815260040160405180910390fd5b62000aeb600a83620010fa565b1562000b3557604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b50508062000b4390620020b2565b905062000a12565b5060005b815181101562000d0d57600082828151811062000b705762000b7062002086565b6020026020010151600001519050600083838151811062000b955762000b9562002086565b602002602001015160200151905060006001600160a01b0316826001600160a01b0316148062000bcc57506001600160a01b038116155b1562000bea5760405162d8548360e71b815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c29573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c4f91906200229b565b6001600160a01b0316826001600160a01b03161462000c8157604051630d98f73360e31b815260040160405180910390fd5b62000c8f600a838362001111565b1562000cde57604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a162000cf7565b604051633caf458560e01b815260040160405180910390fd5b50508062000d0590620020b2565b905062000b4f565b505050565b60005b825181101562000da757600083828151811062000d365762000d3662002086565b6020908102919091010151905062000d50600d8262001129565b1562000d93576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5062000d9f81620020b2565b905062000d15565b5060005b815181101562000d0d57600082828151811062000dcc5762000dcc62002086565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000df8575062000e4a565b62000e05600d8262001140565b1562000e48576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b62000e5581620020b2565b905062000dab565b6000546001600160a01b0316331480159062000e8457506002546001600160a01b03163314155b801562000e9b575062000e9960073362001157565b155b1562000eba5760405163032bb72b60e31b815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff16600081900362000ef65760405163990e30bf60e01b815260040160405180910390fd5b6012546001600160601b03168181101562000f24576040516311a1ee3b60e31b815260040160405180910390fd5b600062000f306200116e565b121562000f5057604051631e9acf1760e31b815260040160405180910390fd5b80600062000f5f60076200105d565b905060005b81811015620010375760008062000f7d60078462001070565b909250905060008762000f9a836001600160601b038a16620022bb565b62000fa69190620022d5565b905062000fb48187620022f8565b60e05190965062000fd9906001600160a01b0316846001600160601b038416620011fc565b6040516001600160601b03821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a2505050806200102f90620020b2565b905062000f64565b5050601280546001600160601b0319166001600160601b03929092169190911790555050565b60006200106a8262001254565b92915050565b600080808062001081868662001261565b9097909650945050505050565b6000620010a5836001600160a01b0384166200128e565b9392505050565b6000620010c4846001600160a01b03851684620012ad565b949350505050565b6000620010a5836001600160a01b038416620012cc565b6000620010a5836001600160a01b038416620012da565b6000620010a5836001600160a01b038416620012e8565b6000620010c4846001600160a01b03851684620012f6565b6000620010a5836001600160a01b0384166200130e565b6000620010a5836001600160a01b03841662001419565b6000620010a5836001600160a01b0384166200146b565b60125460e0516040516370a0823160e01b81523060048201526000926001600160601b0316916001600160a01b0316906370a0823190602401602060405180830381865afa158015620011c5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011eb91906200231b565b620011f7919062002335565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663a9059cbb60e01b1790915262000d0d9185916200147916565b60006200106a826200154a565b6000808062001271858562001555565b600081815260029690960160205260409095205494959350505050565b60008181526002830160205260408120819055620010a5838362001563565b60008281526002840160205260408120829055620010c4848462001571565b6000620010a583836200146b565b6000620010a583836200157f565b6000620010a583836200128e565b6000620010c484846001600160a01b038516620012ad565b600081815260018301602052604081205480156200140757600062001335600183620021de565b85549091506000906200134b90600190620021de565b9050818114620013b75760008660000182815481106200136f576200136f62002086565b906000526020600020015490508087600001848154811062001395576200139562002086565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620013cb57620013cb62002358565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506200106a565b60009150506200106a565b5092915050565b600081815260018301602052604081205462001462575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200106a565b5060006200106a565b6000620010a58383620015f4565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490820152600090620014c8906001600160a01b0385169084906200160d565b80519091501562000d0d5780806020019051810190620014e991906200236e565b62000d0d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000091565b60006200106a825490565b6000620010a583836200161e565b6000620010a583836200130e565b6000620010a5838362001419565b600081815260028301602052604081205480151580620015a65750620015a684846200146b565b620010a55760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000604482015260640162000091565b60008181526001830160205260408120541515620010a5565b6060620010c484846000856200164b565b600082600001828154811062001638576200163862002086565b9060005260206000200154905092915050565b606082471015620016ae5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000091565b600080866001600160a01b03168587604051620016cc9190620023b2565b60006040518083038185875af1925050503d80600081146200170b576040519150601f19603f3d011682016040523d82523d6000602084013e62001710565b606091505b50909250905062001724878383876200172f565b979650505050505050565b60608315620017a35782516000036200179b576001600160a01b0385163b6200179b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000091565b5081620010c4565b620010c48383815115620017ba5781518083602001fd5b8060405162461bcd60e51b8152600401620000919190620023d0565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715620018115762001811620017d6565b60405290565b60405160c081016001600160401b0381118282101715620018115762001811620017d6565b604051608081016001600160401b0381118282101715620018115762001811620017d6565b604051601f8201601f191681016001600160401b03811182821017156200188c576200188c620017d6565b604052919050565b6001600160a01b0381168114620018aa57600080fd5b50565b80516001600160401b0381168114620018c557600080fd5b919050565b80516001600160601b0381168114620018c557600080fd5b600060e08284031215620018f557600080fd5b60405160e081016001600160401b03811182821017156200191a576200191a620017d6565b806040525080915082516200192f8162001894565b81526200193f60208401620018ad565b60208201526200195260408401620018ad565b60408201526200196560608401620018ad565b60608201526200197860808401620018ca565b608082015260a08301516200198d8162001894565b60a082015260c0830151620019a28162001894565b60c0919091015292915050565b805161ffff81168114620018c557600080fd5b805163ffffffff81168114620018c557600080fd5b600060a08284031215620019ea57600080fd5b60405160a081016001600160401b038111828210171562001a0f5762001a0f620017d6565b8060405250809150825162001a248162001894565b815262001a3460208401620019af565b6020820152604083015162001a498162001894565b604082015262001a5c60608401620019c2565b606082015262001a6f60808401620018ad565b60808201525092915050565b60006001600160401b0382111562001a975762001a97620017d6565b5060051b60200190565b600082601f83011262001ab357600080fd5b8151602062001acc62001ac68362001a7b565b62001861565b82815260069290921b8401810191818101908684111562001aec57600080fd5b8286015b8481101562001b46576040818903121562001b0b5760008081fd5b62001b15620017ec565b815162001b228162001894565b81528185015162001b338162001894565b8186015283529183019160400162001af0565b509695505050505050565b600082601f83011262001b6357600080fd5b8151602062001b7662001ac68362001a7b565b82815260059290921b8401810191818101908684111562001b9657600080fd5b8286015b8481101562001b4657805162001bb08162001894565b835291830191830162001b9a565b80518015158114620018c557600080fd5b80516001600160801b0381168114620018c557600080fd5b60006060828403121562001bfa57600080fd5b604051606081016001600160401b038111828210171562001c1f5762001c1f620017d6565b60405290508062001c308362001bbe565b815262001c406020840162001bcf565b602082015262001c536040840162001bcf565b60408201525092915050565b600082601f83011262001c7157600080fd5b8151602062001c8462001ac68362001a7b565b82815260c0928302850182019282820191908785111562001ca457600080fd5b8387015b8581101562001d465781818a03121562001cc25760008081fd5b62001ccc62001817565b815162001cd98162001894565b815262001ce8828701620018ad565b86820152604062001cfb818401620018ca565b90820152606062001d0e838201620019c2565b90820152608062001d21838201620019af565b9082015260a062001d3483820162001bbe565b90820152845292840192810162001ca8565b5090979650505050505050565b600082601f83011262001d6557600080fd5b8151602062001d7862001ac68362001a7b565b82815260079290921b8401810191818101908684111562001d9857600080fd5b8286015b8481101562001b46576080818903121562001db75760008081fd5b62001dc16200183c565b815162001dce8162001894565b815262001ddd828601620019c2565b85820152604062001df0818401620019c2565b90820152606062001e03838201620019af565b9082015283529183019160800162001d9c565b600082601f83011262001e2857600080fd5b8151602062001e3b62001ac68362001a7b565b82815260069290921b8401810191818101908684111562001e5b57600080fd5b8286015b8481101562001b46576040818903121562001e7a5760008081fd5b62001e84620017ec565b815162001e918162001894565b815262001ea0828601620019af565b8186015283529183019160400162001e5f565b600080600080600080600080610280898b03121562001ed157600080fd5b62001edd8a8a620018e2565b975062001eee8a60e08b01620019d7565b6101808a01519097506001600160401b038082111562001f0d57600080fd5b62001f1b8c838d0162001aa1565b97506101a08b015191508082111562001f3357600080fd5b62001f418c838d0162001b51565b965062001f538c6101c08d0162001be7565b95506102208b015191508082111562001f6b57600080fd5b62001f798c838d0162001c5f565b94506102408b015191508082111562001f9157600080fd5b62001f9f8c838d0162001d53565b93506102608b015191508082111562001fb757600080fd5b5062001fc68b828c0162001e16565b9150509295985092959890939650565b82516001600160a01b0390811682526020808501516001600160401b03908116828501526040808701518216818601526060808801518316818701526080808901516001600160601b03168188015260a0808a015187169088015260c0808a01518716908801528751861660e08801529387015161ffff16610100870152908601519093166101208501529184015163ffffffff16610140840152830151166101608201526101808101620010a5565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620020c757620020c76200209c565b5060010190565b602080825282518282018190526000919060409081850190868401855b828110156200216257815180516001600160a01b03168552868101516001600160401b031687860152858101516001600160601b03168686015260608082015163ffffffff169086015260808082015161ffff169086015260a09081015115159085015260c09093019290850190600101620020eb565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b828110156200216257815180516001600160a01b031685528681015163ffffffff9081168887015286820151168686015260609081015161ffff1690850152608090930192908501906001016200218c565b818103818111156200106a576200106a6200209c565b6000816200220657620022066200209c565b506000190190565b63ffffffff8181168382160190808211156200141257620014126200209c565b6000604080830163ffffffff8616845260208281860152818651808452606087019150828801935060005b818110156200228d57845180516001600160a01b0316845284015161ffff1684840152938301939185019160010162002259565b509098975050505050505050565b600060208284031215620022ae57600080fd5b8151620010a58162001894565b80820281158282048414176200106a576200106a6200209c565b600082620022f357634e487b7160e01b600052601260045260246000fd5b500490565b6001600160601b038281168282160390808211156200141257620014126200209c565b6000602082840312156200232e57600080fd5b5051919050565b81810360008312801583831316838312821617156200141257620014126200209c565b634e487b7160e01b600052603160045260246000fd5b6000602082840312156200238157600080fd5b620010a58262001bbe565b60005b83811015620023a95781810151838201526020016200238f565b50506000910152565b60008251620023c68184602087016200238c565b9190910192915050565b6020815260008251806020840152620023f18160408501602087016200238c565b601f01601f19169190910160400192915050565b60805160a05160c05160e05161010051610120516101405161016051615cb56200250c600039600081816103600152818161140a0152612c2e01526000818161033101528181611320015281816113880152818161185a015281816118c20152612c0601526000818161029d01528181610af901528181611c550152612b7e01526000818161026d0152818161198d0152612b5401526000818161023e01528181610dfa0152818161160d01528181611706015281816121a801528181612b2f01528181612d79015261324a0152600081816102fd015281816117d20152612bd00152600081816102cd015281816122c40152612ba501526000611b6f0152615cb56000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806376f6ae761161010f578063b06d41bc116100a2578063e0351e1311610071578063e0351e13146108ee578063efeadb6d14610921578063eff7cc4814610934578063f2fde38b1461093c57600080fd5b8063b06d41bc146108b5578063c92b2832146108cb578063d09dc339146108de578063d3c7c2c7146108e657600080fd5b80638da5cb5b116100de5780638da5cb5b146107105780639a113c3614610721578063a7cd63b71461088d578063a7d3e02f146108a257600080fd5b806376f6ae76146106cf578063799c3a67146106e257806379ba5097146106f5578063856c8247146106fd57600080fd5b8063549e946f116101875780635d86f141116101565780635d86f141146105d45780635ebbd9f8146105e7578063704b6c02146105fa5780637437ff9f1461060d57600080fd5b8063549e946f1461056957806354b714681461057c57806354c8a4f31461059c578063599f6431146105af57600080fd5b80633a87ac53116101c35780633a87ac53146104bc5780633a9bf949146104d15780634120fccd146104e4578063546719cd1461050557600080fd5b806306285c69146101f55780631772047e146103a6578063181f5a771461045257806338724a951461049b575b600080fd5b6103906040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b60405161039d9190614830565b60405180910390f35b6104216103b43660046148c1565b6040805160608082018352600080835260208084018290529284018190526001600160a01b039490941684526010825292829020825193840183525463ffffffff80821685526401000000008204169184019190915268010000000000000000900461ffff169082015290565b60408051825163ffffffff9081168252602080850151909116908201529181015161ffff169082015260600161039d565b61048e6040518060400160405280601381526020017f45564d3245564d4f6e52616d7020312e302e300000000000000000000000000081525081565b60405161039d919061494c565b6104ae6104a9366004614971565b61094f565b60405190815260200161039d565b6104cf6104ca366004614b58565b610c8d565b005b6104cf6104df366004614bfd565b610ca3565b6104ec610cb7565b60405167ffffffffffffffff909116815260200161039d565b61050d610ceb565b60405161039d919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6104cf610577366004614c91565b610d9b565b6012546040516bffffffffffffffffffffffff909116815260200161039d565b6104cf6105aa366004614d2e565b610f50565b6002546001600160a01b03165b6040516001600160a01b03909116815260200161039d565b6105bc6105e23660046148c1565b610f62565b6104cf6105f5366004614d88565b610fc1565b6104cf6106083660046148c1565b611027565b6106c26040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a0810182526005546001600160a01b038082168352740100000000000000000000000000000000000000009182900461ffff16602084015260065490811693830193909352820463ffffffff166060820152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16608082015290565b60405161039d9190614e66565b6104cf6106dd366004614ec0565b6110f1565b6104cf6106f0366004614f4e565b6111a9565b6104cf61120f565b6104ec61070b3660046148c1565b6112f2565b6000546001600160a01b03166105bc565b61082761072f3660046148c1565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506001600160a01b03166000908152600f6020908152604091829020825160a08101845290546bffffffffffffffffffffffff811682526c01000000000000000000000000810467ffffffffffffffff169282019290925274010000000000000000000000000000000000000000820463ffffffff16928101929092527801000000000000000000000000000000000000000000000000810461ffff1660608301527a010000000000000000000000000000000000000000000000000000900460ff161515608082015290565b60405161039d9190600060a0820190506bffffffffffffffffffffffff835116825267ffffffffffffffff602084015116602083015263ffffffff604084015116604083015261ffff606084015116606083015260808301511515608083015292915050565b6108956113fa565b60405161039d919061506c565b6104ae6108b03660046150b9565b611406565b6108bd611d3c565b60405161039d929190615167565b6104cf6108d93660046151a9565b611e40565b6104ae611ea8565b610895611eb2565b601254790100000000000000000000000000000000000000000000000000900460ff16604051901515815260200161039d565b6104cf61092f366004615217565b611f63565b6104cf611fe9565b6104cf61094a3660046148c1565b612280565b600080600f8161096560808601606087016148c1565b6001600160a01b031681526020808201929092526040908101600020815160a08101835290546bffffffffffffffffffffffff811682526c01000000000000000000000000810467ffffffffffffffff169382019390935274010000000000000000000000000000000000000000830463ffffffff16918101919091527801000000000000000000000000000000000000000000000000820461ffff1660608201527a01000000000000000000000000000000000000000000000000000090910460ff16151560808201819052909150610a8c57610a4960808401606085016148c1565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b60065460009081906001600160a01b031663ffdb4b37610ab260808801606089016148c1565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044016040805180830381865afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b61919061525c565b91509150600083600001516bffffffffffffffffffffffff16670de0b6b3a7640000856020015167ffffffffffffffff16866060015161ffff16898060200190610bab919061528f565b610bb6929150615323565b604088015163ffffffff16610bd6610bd160808d018d61528f565b612291565b51610be1919061533a565b610beb919061533a565b610bf59190615323565b610c199077ffffffffffffffffffffffffffffffffffffffffffffffff8616615323565b610c23919061534d565b610c2d919061533a565b9050610c55610c4260808801606089016148c1565b84610c5060408a018a615388565b612390565b610c7977ffffffffffffffffffffffffffffffffffffffffffffffff8516836125dc565b610c83919061533a565b9695505050505050565b610c95612615565b610c9f828261268b565b5050565b610cab612615565b610cb4816129eb565b50565b601254600090610ce690700100000000000000000000000000000000900467ffffffffffffffff1660016153f0565b905090565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610ce690612c84565b6000546001600160a01b03163314801590610dc157506002546001600160a01b03163314155b15610df8576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480610e3f57506001600160a01b038116155b15610e76576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e80612d36565b1215610eb8576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610c9f9082906001600160a01b038516906370a0823190602401602060405180830381865afa158015610f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3f9190615411565b6001600160a01b0385169190612df6565b610f58612615565b610c9f8282612e76565b6000610f6f600a83612fb1565b610fb0576040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b610fbb600a83612fc6565b92915050565b6000546001600160a01b03163314801590610fe757506002546001600160a01b03163314155b1561101e576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb481612fdb565b6000546001600160a01b0316331480159061104d57506002546001600160a01b03163314155b15611084576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b6000546001600160a01b0316331480159061111757506002546001600160a01b03163314155b1561114e576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c9f8282808060200260200160405190810160405280939291908181526020016000905b8282101561119f576111906040830286013681900381019061542a565b81526020019060010190611173565b5050505050613111565b6000546001600160a01b031633148015906111cf57506002546001600160a01b03163314155b15611206576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb481613384565b6001546001600160a01b03163314611283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610a83565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b03811660009081526011602052604081205467ffffffffffffffff168015801561134b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b15610fbb576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa1580156113cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f39190615469565b9392505050565b6060610ce6600d613593565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148a9190615486565b156114c1576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114cb848061528f565b9050602014611512576114de848061528f565b6040517f370d875f000000000000000000000000000000000000000000000000000000008152600401610a839291906154ec565b600061151e858061528f565b81019061152b9190615500565b90506001600160a01b038111806115425750600a81105b15611551576114de858061528f565b6000611563610bd1608088018861528f565b905061158f611575602088018861528f565b835190915061158760408a018a615388565b9050876135a0565b61160361159f6040880188615388565b808060200260200160405190810160405280939291908181526020016000905b828210156115eb576115dc60408302860136819003810190615519565b815260200190600101906115bf565b50506006546001600160a01b031692506137c3915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661163d60808801606089016148c1565b6001600160a01b0316036116a1576012805486919060009061166e9084906bffffffffffffffffffffffff16615553565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506117c0565b6006546001600160a01b03166241e5be6116c16080890160608a016148c1565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018990527f00000000000000000000000000000000000000000000000000000000000000009091166044820152606401602060405180830381865afa15801561174d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117719190615411565b601280546000906117919084906bffffffffffffffffffffffff16615553565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b6012546bffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116111561182d576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526011602052604090205467ffffffffffffffff1615801561188557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b1561197d576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192d9190615469565b6001600160a01b038516600090815260116020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b60006040518061018001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020016012601081819054906101000a900467ffffffffffffffff166119dd90615578565b825467ffffffffffffffff9182166101009390930a8381029083021990911617909255825260208083018a90526001600160a01b03891660408085018290526000918252601190925290812080546060909401939092611a3d9116615578565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff16815260200183600001518152602001836020015115158152602001846001600160a01b03168152602001888060200190611aa6919061528f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611aed60408a018a615388565b808060200260200160405190810160405280939291908181526020016000905b82821015611b3957611b2a60408302860136819003810190615519565b81526020019060010190611b0d565b5050509183525050602001611b5460808a0160608b016148c1565b6001600160a01b0316815260006020909101529050611b93817f000000000000000000000000000000000000000000000000000000000000000061397c565b61016082015260005b611ba96040890189615388565b9050811015611cf5576000611bc160408a018a615388565b83818110611bd157611bd161559f565b905060400201803603810190611be79190615519565b9050611bf68160000151610f62565b6001600160a01b0316639687544588611c0f8c8061528f565b60208087015160408051928301815260008352517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b168152611c7d959493927f0000000000000000000000000000000000000000000000000000000000000000916004016155ce565b6000604051808303816000875af1158015611c9c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611ce29190810190615626565b505080611cee906156d8565b9050611b9c565b507faffc45517195d6499808c643bd4a7b0ffeedf95bea5852840d7bfcf63f59e82181604051611d259190615754565b60405180910390a161016001519695505050505050565b6060600080611d4b6007613a86565b90508067ffffffffffffffff811115611d6657611d666149a6565b604051908082528060200260200182016040528015611dab57816020015b6040805180820190915260008082526020820152815260200190600190039081611d845790505b50925060005b81811015611e1d57600080611dc7600784613a91565b915091506040518060400160405280836001600160a01b031681526020018261ffff16815250868481518110611dff57611dff61559f565b6020026020010181905250505080611e16906156d8565b9050611db1565b505060125491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b03163314801590611e6657506002546001600160a01b03163314155b15611e9d576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb4600382613aaf565b6000610ce6612d36565b60606000611ec0600a613c87565b67ffffffffffffffff811115611ed857611ed86149a6565b604051908082528060200260200182016040528015611f01578160200160208202803683370190505b50905060005b8151811015611f5d57611f1b600a82613c92565b50828281518110611f2e57611f2e61559f565b60200260200101816001600160a01b03166001600160a01b03168152505080611f56906156d8565b9050611f07565b50919050565b611f6b612615565b60128054821515790100000000000000000000000000000000000000000000000000027fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517fccf4daf6ab6430389f26b970595dab82a5881ad454770907e415ede27c8df032906110e690831515815260200190565b6000546001600160a01b0316331480159061200f57506002546001600160a01b03163314155b80156120235750612021600733613ca1565b155b1561205a576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff1660008190036120ae576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546bffffffffffffffffffffffff16818110156120f9576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612103612d36565b121561213b576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060006121486007613a86565b905060005b8181101561223d57600080612163600784613a91565b9092509050600087612183836bffffffffffffffffffffffff8a16615323565b61218d919061534d565b90506121998187615891565b95506121dd6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016846bffffffffffffffffffffffff8416612df6565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a250505080612236906156d8565b905061214d565b5050601280547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b612288612615565b610cb481613cb6565b604080518082019091526000808252602082015260008290036122f257506040805180820190915267ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016815260006020820152610fbb565b7f97a657c90000000000000000000000000000000000000000000000000000000061231d83856158b6565b7fffffffff000000000000000000000000000000000000000000000000000000001614612376576040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61238382600481866158fe565b8101906113f39190615928565b6000818082036123a45760009150506125d4565b60005b818110156125d15760008585838181106123c3576123c361559f565b9050604002018036038101906123d99190615519565b80516001600160a01b031660009081526010602090815260408083208151606081018352905463ffffffff8082168352640100000000820416938201939093526801000000000000000090920461ffff16908201819052929350911561253057825189906001600160a01b038c81169116146124da5760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152911690634ab35b0b90602401602060405180830381865afa1580156124b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d79190615954565b90505b620186a0836040015161ffff1661251886602001518477ffffffffffffffffffffffffffffffffffffffffffffffff16613d9190919063ffffffff16565b6125229190615323565b61252c919061534d565b9150505b815160009061254c9063ffffffff16662386f26fc10000615323565b90506000836020015163ffffffff16662386f26fc1000061256d9190615323565b90508183101561257f5781925061258b565b8083111561258b578092505b6125af77ffffffffffffffffffffffffffffffffffffffffffffffff8c16846125dc565b6125b9908961533a565b97505050505050806125ca906156d8565b90506123a7565b50505b949350505050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff831661260b83670de0b6b3a7640000615323565b6113f3919061534d565b6000546001600160a01b03163314612689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610a83565b565b60005b82518110156127ec5760008382815181106126ab576126ab61559f565b602002602001015160000151905060008483815181106126cd576126cd61559f565b60200260200101516020015190506126ef82600a612fb190919063ffffffff16565b612730576040517f73913ebd0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b6001600160a01b038116612745600a84612fc6565b6001600160a01b031614612785576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612790600a83613dc0565b156127d957604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b5050806127e5906156d8565b905061268e565b5060005b81518110156129e657600082828151811061280d5761280d61559f565b6020026020010151600001519050600083838151811061282f5761282f61559f565b602002602001015160200151905060006001600160a01b0316826001600160a01b0316148061286557506001600160a01b038116155b1561289c576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fe919061596f565b6001600160a01b0316826001600160a01b031614612948576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612954600a8383613dd5565b156129a157604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a16129d3565b6040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050806129df906156d8565b90506127f0565b505050565b60408101516001600160a01b0316612a2f576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600580546020808501516001600160a01b039485167fffffffffffffffffffff00000000000000000000000000000000000000000000909316929092177401000000000000000000000000000000000000000061ffff909316830217909255604080850151600680546060808901516080808b0151958a167fffffffffffffffff0000000000000000000000000000000000000000000000009094169390931763ffffffff9091169096029590951777ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff9485160217909155825160e0810184527f0000000000000000000000000000000000000000000000000000000000000000871681527f00000000000000000000000000000000000000000000000000000000000000008316958101959095527f00000000000000000000000000000000000000000000000000000000000000008216858401527f0000000000000000000000000000000000000000000000000000000000000000909116928401929092527f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff16918301919091527f0000000000000000000000000000000000000000000000000000000000000000831660a08301527f000000000000000000000000000000000000000000000000000000000000000090921660c082015290517fdd226617d8d287f40a64c54741bbcdc492b3e096ef16bc5273a18cb6ab85f124916110e691849061598c565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152612d1282606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642612cf69190615a61565b85608001516fffffffffffffffffffffffffffffffff16613deb565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6012546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dec9190615411565b610ce69190615a74565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526129e6908490613e13565b60005b8251811015612f07576000838281518110612e9657612e9661559f565b60200260200101519050612eb481600d613f1290919063ffffffff16565b15612ef6576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50612f00816156d8565b9050612e79565b5060005b81518110156129e6576000828281518110612f2857612f2861559f565b6020026020010151905060006001600160a01b0316816001600160a01b031603612f525750612fa1565b612f5d600d82613f27565b15612f9f576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b612faa816156d8565b9050612f0b565b60006113f3836001600160a01b038416613f3c565b60006113f3836001600160a01b038416613f48565b60005b81518110156130e1576000828281518110612ffb57612ffb61559f565b60209081029190910181015160408051606080820183528385015163ffffffff90811683528385015181168387019081529185015161ffff90811684860190815295516001600160a01b03166000908152601090975293909520915182549151945190931668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff948616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921693909516929092179190911791909116919091179055506130da816156d8565b9050612fde565b507fcb0c5f472d325cf0c56953fc81870ddd80d0d3c9a3fbfe777002d75f380dfb81816040516110e69190615a94565b8051604081111561314e576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff161580159061319c575060125463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff90911610155b156131a9576131a9611fe9565b60006131b56007613a86565b90505b80156131f75760006131d66131ce600184615a61565b600790613a91565b5090506131e4600782613f54565b5050806131f090615b0e565b90506131b8565b506000805b828110156133055760008482815181106132185761321861559f565b6020026020010151600001519050600085838151811061323a5761323a61559f565b60200260200101516020015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148061328f57506001600160a01b038216155b156132d1576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b6132e160078361ffff8416613f69565b506132f061ffff821685615b43565b93505050806132fe906156d8565b90506131fc565b50601280547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24906133779083908690615b60565b60405180910390a1505050565b60005b81518110156135635760008282815181106133a4576133a461559f565b6020908102919091018101516040805160a08082018352828401516bffffffffffffffffffffffff90811683528486015167ffffffffffffffff90811684880190815260608088015163ffffffff9081168789019081526080808b015161ffff908116948a01948552978b0151151590890190815299516001600160a01b03166000908152600f909b529790992095518654925197519151985115157a010000000000000000000000000000000000000000000000000000027fffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff999096167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff92909a167401000000000000000000000000000000000000000002919091167fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff979093166c01000000000000000000000000027fffffffffffffffffffffffff000000000000000000000000000000000000000090921693169290921791909117939093169290921793909317919091161790555061355c816156d8565b9050613387565b507ffba339fca97870ffdfaedbae3745db5e6de1a6909dfd0e0dbb56917469ffe236816040516110e69190615b7f565b606060006113f383613f7f565b6001600160a01b0381166135e0576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b03163314613624576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065474010000000000000000000000000000000000000000900463ffffffff1680851115613689576040517f869337890000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610a83565b6006547801000000000000000000000000000000000000000000000000900467ffffffffffffffff168411156136eb576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055474010000000000000000000000000000000000000000900461ffff16831115613743576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254790100000000000000000000000000000000000000000000000000900460ff16801561377a5750613778600d83613fdb565b155b156137bc576040517fd0d259760000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b5050505050565b81516000805b82811015613968576000846001600160a01b031663d02641a08784815181106137f4576137f461559f565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0390911660048201526024016040805180830381865afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f9190615c17565b51905077ffffffffffffffffffffffffffffffffffffffffffffffff8116600003613900578582815181106138b6576138b661559f565b6020908102919091010151516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610a83565b61394a8683815181106139155761391561559f565b6020026020010151602001518277ffffffffffffffffffffffffffffffffffffffffffffffff16613d9190919063ffffffff16565b613954908461533a565b92505080613961906156d8565b90506137c9565b506139766003826000613ffd565b50505050565b60008060001b828460200151856080015186606001518760e00151886101000151805190602001208961012001516040516020016139ba9190615c4a565b604051602081830303815290604052805190602001208a60a001518b60c001518c61014001518d60400151604051602001613a689c9b9a999897969594939291909b8c5260208c019a909a5267ffffffffffffffff98891660408c01529690971660608a01526001600160a01b0394851660808a015292841660a089015260c088019190915260e0870152610100860152911515610120850152166101408301526101608201526101800190565b60405160208183030381529060405280519060200120905092915050565b6000610fbb8261434c565b6000808080613aa08686614357565b909450925050505b9250929050565b8154600090613ad890700100000000000000000000000000000000900463ffffffff1642615a61565b90508015613b7a5760018301548354613b20916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416613deb565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354613ba0916fffffffffffffffffffffffffffffffff9081169116614382565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906133779084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b6000610fbb82613a86565b6000808080613aa08686613a91565b60006113f3836001600160a01b038416614398565b336001600160a01b03821603613d28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610a83565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000670de0b6b3a764000061260b8377ffffffffffffffffffffffffffffffffffffffffffffffff8616615323565b60006113f3836001600160a01b0384166143a4565b60006125d4846001600160a01b038516846143b0565b6000613e0a85613dfb8486615323565b613e05908761533a565b614382565b95945050505050565b6000613e68826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143c69092919063ffffffff16565b8051909150156129e65780806020019051810190613e869190615486565b6129e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a83565b60006113f3836001600160a01b0384166143d5565b60006113f3836001600160a01b0384166144cf565b60006113f38383614398565b60006113f3838361451e565b60006113f3836001600160a01b0384166145a8565b60006125d4846001600160a01b038516846145c5565b606081600001805480602002602001604051908101604052809291908181526020018280548015613fcf57602002820191906000526020600020905b815481526020019060010190808311613fbb575b50505050509050919050565b6001600160a01b038116600090815260018301602052604081205415156113f3565b825474010000000000000000000000000000000000000000900460ff161580614024575081155b1561402e57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061407490700100000000000000000000000000000000900463ffffffff1642615a61565b9050801561413457818311156140b6576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546140f09083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613deb565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156141d1576001600160a01b038416614186576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610a83565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610a83565b848310156142ca5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906142159082615a61565b61421f878a615a61565b614229919061533a565b614233919061534d565b90506001600160a01b03861661427f576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610a83565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610a83565b6142d48584615a61565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610fbb826145e2565b6000808061436585856145ec565b600081815260029690960160205260409095205494959350505050565b600081831061439157816113f3565b5090919050565b60006113f383836145f8565b60006113f383836145a8565b60006125d484846001600160a01b0385166145c5565b60606125d48484600085614610565b600081815260018301602052604081205480156144be5760006143f9600183615a61565b855490915060009061440d90600190615a61565b905081811461447257600086600001828154811061442d5761442d61559f565b90600052602060002001549050808760000184815481106144505761445061559f565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061448357614483615c5d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610fbb565b6000915050610fbb565b5092915050565b600081815260018301602052604081205461451657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610fbb565b506000610fbb565b60008181526002830160205260408120548015158061454257506145428484614398565b6113f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610a83565b600081815260028301602052604081208190556113f3838361471c565b600082815260028401602052604081208290556125d48484614728565b6000610fbb825490565b60006113f38383614734565b600081815260018301602052604081205415156113f3565b6060824710156146a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a83565b600080866001600160a01b031685876040516146be9190615c8c565b60006040518083038185875af1925050503d80600081146146fb576040519150601f19603f3d011682016040523d82523d6000602084013e614700565b606091505b50915091506147118783838761475e565b979650505050505050565b60006113f383836143d5565b60006113f383836144cf565b600082600001828154811061474b5761474b61559f565b9060005260206000200154905092915050565b606083156147e75782516000036147e0576001600160a01b0385163b6147e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a83565b50816125d4565b6125d483838151156147fc5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a83919061494c565b60e08101610fbb82846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b6001600160a01b0381168114610cb457600080fd5b6000602082840312156148d357600080fd5b81356113f3816148ac565b60005b838110156148f95781810151838201526020016148e1565b50506000910152565b6000815180845261491a8160208601602086016148de565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113f36020830184614902565b600060a08284031215611f5d57600080fd5b60006020828403121561498357600080fd5b813567ffffffffffffffff81111561499a57600080fd5b6125d48482850161495f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156149f8576149f86149a6565b60405290565b6040516080810167ffffffffffffffff811182821017156149f8576149f86149a6565b60405160c0810167ffffffffffffffff811182821017156149f8576149f86149a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614a8b57614a8b6149a6565b604052919050565b600067ffffffffffffffff821115614aad57614aad6149a6565b5060051b60200190565b600082601f830112614ac857600080fd5b81356020614add614ad883614a93565b614a44565b82815260069290921b84018101918181019086841115614afc57600080fd5b8286015b84811015614b4d5760408189031215614b195760008081fd5b614b216149d5565b8135614b2c816148ac565b815281850135614b3b816148ac565b81860152835291830191604001614b00565b509695505050505050565b60008060408385031215614b6b57600080fd5b823567ffffffffffffffff80821115614b8357600080fd5b614b8f86838701614ab7565b93506020850135915080821115614ba557600080fd5b50614bb285828601614ab7565b9150509250929050565b803561ffff81168114614bce57600080fd5b919050565b803563ffffffff81168114614bce57600080fd5b67ffffffffffffffff81168114610cb457600080fd5b600060a08284031215614c0f57600080fd5b60405160a0810181811067ffffffffffffffff82111715614c3257614c326149a6565b6040528235614c40816148ac565b8152614c4e60208401614bbc565b60208201526040830135614c61816148ac565b6040820152614c7260608401614bd3565b60608201526080830135614c8581614be7565b60808201529392505050565b60008060408385031215614ca457600080fd5b8235614caf816148ac565b91506020830135614cbf816148ac565b809150509250929050565b600082601f830112614cdb57600080fd5b81356020614ceb614ad883614a93565b82815260059290921b84018101918181019086841115614d0a57600080fd5b8286015b84811015614b4d578035614d21816148ac565b8352918301918301614d0e565b60008060408385031215614d4157600080fd5b823567ffffffffffffffff80821115614d5957600080fd5b614d6586838701614cca565b93506020850135915080821115614d7b57600080fd5b50614bb285828601614cca565b60006020808385031215614d9b57600080fd5b823567ffffffffffffffff811115614db257600080fd5b8301601f81018513614dc357600080fd5b8035614dd1614ad882614a93565b81815260079190911b82018301908381019087831115614df057600080fd5b928401925b828410156147115760808489031215614e0e5760008081fd5b614e166149fe565b8435614e21816148ac565b8152614e2e858701614bd3565b868201526040614e3f818701614bd3565b908201526060614e50868201614bbc565b9082015282526080939093019290840190614df5565b60a08101610fbb82846001600160a01b0380825116835261ffff60208301511660208401528060408301511660408401525063ffffffff606082015116606083015267ffffffffffffffff60808201511660808301525050565b60008060208385031215614ed357600080fd5b823567ffffffffffffffff80821115614eeb57600080fd5b818501915085601f830112614eff57600080fd5b813581811115614f0e57600080fd5b8660208260061b8501011115614f2357600080fd5b60209290920196919550909350505050565b8015158114610cb457600080fd5b8035614bce81614f35565b60006020808385031215614f6157600080fd5b823567ffffffffffffffff811115614f7857600080fd5b8301601f81018513614f8957600080fd5b8035614f97614ad882614a93565b81815260c09182028301840191848201919088841115614fb657600080fd5b938501935b838510156150605780858a031215614fd35760008081fd5b614fdb614a21565b8535614fe6816148ac565b815285870135614ff581614be7565b818801526040868101356bffffffffffffffffffffffff8116811461501a5760008081fd5b90820152606061502b878201614bd3565b90820152608061503c878201614bbc565b9082015260a061504d878201614f43565b9082015283529384019391850191614fbb565b50979650505050505050565b6020808252825182820181905260009190848201906040850190845b818110156150ad5783516001600160a01b031683529284019291840191600101615088565b50909695505050505050565b6000806000606084860312156150ce57600080fd5b833567ffffffffffffffff8111156150e557600080fd5b6150f18682870161495f565b935050602084013591506040840135615109816148ac565b809150509250925092565b600081518084526020808501945080840160005b8381101561515c57815180516001600160a01b0316885283015161ffff168388015260409096019590820190600101615128565b509495945050505050565b60408152600061517a6040830185615114565b90508260208301529392505050565b80356fffffffffffffffffffffffffffffffff81168114614bce57600080fd5b6000606082840312156151bb57600080fd5b6040516060810181811067ffffffffffffffff821117156151de576151de6149a6565b60405282356151ec81614f35565b81526151fa60208401615189565b602082015261520b60408401615189565b60408201529392505050565b60006020828403121561522957600080fd5b81356113f381614f35565b805177ffffffffffffffffffffffffffffffffffffffffffffffff81168114614bce57600080fd5b6000806040838503121561526f57600080fd5b61527883615234565b915061528660208401615234565b90509250929050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126152c457600080fd5b83018035915067ffffffffffffffff8211156152df57600080fd5b602001915036819003821315613aa857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610fbb57610fbb6152f4565b80820180821115610fbb57610fbb6152f4565b600082615383577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126153bd57600080fd5b83018035915067ffffffffffffffff8211156153d857600080fd5b6020019150600681901b3603821315613aa857600080fd5b67ffffffffffffffff8181168382160190808211156144c8576144c86152f4565b60006020828403121561542357600080fd5b5051919050565b60006040828403121561543c57600080fd5b6154446149d5565b823561544f816148ac565b815261545d60208401614bbc565b60208201529392505050565b60006020828403121561547b57600080fd5b81516113f381614be7565b60006020828403121561549857600080fd5b81516113f381614f35565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6020815260006125d46020830184866154a3565b60006020828403121561551257600080fd5b5035919050565b60006040828403121561552b57600080fd5b6155336149d5565b823561553e816148ac565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff8181168382160190808211156144c8576144c86152f4565b600067ffffffffffffffff808316818103615595576155956152f4565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6001600160a01b038716815260a0602082015260006155f160a0830187896154a3565b85604084015267ffffffffffffffff8516606084015282810360808401526156198185614902565b9998505050505050505050565b60006020828403121561563857600080fd5b815167ffffffffffffffff8082111561565057600080fd5b818401915084601f83011261566457600080fd5b815181811115615676576156766149a6565b6156a760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a44565b91508082528560208285010111156156be57600080fd5b6156cf8160208401602086016148de565b50949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615709576157096152f4565b5060010190565b600081518084526020808501945080840160005b8381101561515c57815180516001600160a01b031688528301518388015260409096019590820190600101615724565b6020815261576f60208201835167ffffffffffffffff169052565b6000602083015161578c604084018267ffffffffffffffff169052565b506040830151606083015260608301516157b160808401826001600160a01b03169052565b50608083015167ffffffffffffffff811660a08401525060a083015160c083015260c08301516157e560e084018215159052565b5060e0830151610100615802818501836001600160a01b03169052565b8085015191505061018061012081818601526158226101a0860184614902565b92508086015190506101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086850301818701526158608483615710565b935080870151915050610160615880818701836001600160a01b03169052565b959095015193019290925250919050565b6bffffffffffffffffffffffff8281168282160390808211156144c8576144c86152f4565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156158f65780818660040360031b1b83161692505b505092915050565b6000808585111561590e57600080fd5b8386111561591b57600080fd5b5050820193919092039150565b60006040828403121561593a57600080fd5b6159426149d5565b82358152602083013561545d81614f35565b60006020828403121561596657600080fd5b6113f382615234565b60006020828403121561598157600080fd5b81516113f3816148ac565b6101808101615a0982856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b82516001600160a01b0390811660e0840152602084015161ffff16610100840152604084015116610120830152606083015163ffffffff16610140830152608083015167ffffffffffffffff166101608301526113f3565b81810381811115610fbb57610fbb6152f4565b81810360008312801583831316838312821617156144c8576144c86152f4565b602080825282518282018190526000919060409081850190868401855b82811015615b0157815180516001600160a01b031685528681015163ffffffff9081168887015286820151168686015260609081015161ffff169085015260809093019290850190600101615ab1565b5091979650505050505050565b600081615b1d57615b1d6152f4565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff8181168382160190808211156144c8576144c86152f4565b63ffffffff831681526040602082015260006125d46040830184615114565b602080825282518282018190526000919060409081850190868401855b82811015615b0157815180516001600160a01b031685528681015167ffffffffffffffff1687860152858101516bffffffffffffffffffffffff168686015260608082015163ffffffff169086015260808082015161ffff169086015260a09081015115159085015260c09093019290850190600101615b9c565b600060408284031215615c2957600080fd5b615c316149d5565b615c3a83615234565b8152602083015161545d81614be7565b6020815260006113f36020830184615710565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251615c9e8184602087016148de565b919091019291505056fea164736f6c6343000813000a000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789000000000000000000000000000000000000000000000000de41ba4fc9d91ad9000000000000000000000000000000000000000000000000ccf0a31a221f3c9b0000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000052b7d2dcc80cd2e40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba3f6251de62ded61ff98590cb2fdf6871fbb991000000000000000000000000d0daae2231e9cb96b94c8512223533293c3693bf00000000000000000000000000000000000000000000000000000000000000050000000000000000000000008737a1c3d55779d03b7a08188e97af87b4110946000000000000000000000000000000000000000000000000000000000000c35000000000000000000000000000000000000000000000000000000000003d090000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000460000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000152d02c7e14af68000000000000000000000000000000000000000000000000000090d972f32323c00000000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000007000000000000000000000000b3c3977b0ac329a9035889929482a4c635b50573000000000000000000000000ac8cfc3762a979628334a0e4c1026244498e821b000000000000000000000000b7c8bca891143221a34db60a26639785c4839040000000000000000000000000a04c2cbbfa7bf7adcbde911216a0ba7e3f1e36b3000000000000000000000000f92e4b278380f39fadc24483c7bac61b73ee93f2000000000000000000000000919b1d308e4477c88350c336537ec5ac9ee76d9a000000000000000000000000832ba6abcadc68812be372f4ef20aac268ba20b70000000000000000000000000ea0d7b2b78dd3a926fc76d6875a287f0aeb158f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247890000000000000000000000005344b4bf5ae39038a591866d2853b2b1db62291100000000000000000000000092ea346b7a2aab84e6aab03b80e2421eefb046850000000000000000000000006c4cf212a5d074bb4d9055279b1fb2f1f37265db000000000000000000000000784c400d6ff625051d2f587dc0276e3a1ffd9cda0000000000000000000000005f217ce93e206d6f13b342aeef53a084fa95774500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000493e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001000000000000000000000000097d90c9d3e0b50ca60e1ae45f6a81010f9fb5340000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000493e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007000000000000000000000000b3c3977b0ac329a9035889929482a4c635b505730000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000b7c8bca891143221a34db60a26639785c48390400000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000f92e4b278380f39fadc24483c7bac61b73ee93f20000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000832ba6abcadc68812be372f4ef20aac268ba20b70000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247890000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000003200000000000000000000000092ea346b7a2aab84e6aab03b80e2421eefb046850000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000784c400d6ff625051d2f587dc0276e3a1ffd9cda0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806376f6ae761161010f578063b06d41bc116100a2578063e0351e1311610071578063e0351e13146108ee578063efeadb6d14610921578063eff7cc4814610934578063f2fde38b1461093c57600080fd5b8063b06d41bc146108b5578063c92b2832146108cb578063d09dc339146108de578063d3c7c2c7146108e657600080fd5b80638da5cb5b116100de5780638da5cb5b146107105780639a113c3614610721578063a7cd63b71461088d578063a7d3e02f146108a257600080fd5b806376f6ae76146106cf578063799c3a67146106e257806379ba5097146106f5578063856c8247146106fd57600080fd5b8063549e946f116101875780635d86f141116101565780635d86f141146105d45780635ebbd9f8146105e7578063704b6c02146105fa5780637437ff9f1461060d57600080fd5b8063549e946f1461056957806354b714681461057c57806354c8a4f31461059c578063599f6431146105af57600080fd5b80633a87ac53116101c35780633a87ac53146104bc5780633a9bf949146104d15780634120fccd146104e4578063546719cd1461050557600080fd5b806306285c69146101f55780631772047e146103a6578063181f5a771461045257806338724a951461049b575b600080fd5b6103906040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247896001600160a01b031681526020017f000000000000000000000000000000000000000000000000de41ba4fc9d91ad967ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000ccf0a31a221f3c9b67ffffffffffffffff1681526020017f0000000000000000000000000000000000000000000000000000000000030d4067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000052b7d2dcc80cd2e40000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000ba3f6251de62ded61ff98590cb2fdf6871fbb9916001600160a01b0316815250905090565b60405161039d9190614830565b60405180910390f35b6104216103b43660046148c1565b6040805160608082018352600080835260208084018290529284018190526001600160a01b039490941684526010825292829020825193840183525463ffffffff80821685526401000000008204169184019190915268010000000000000000900461ffff169082015290565b60408051825163ffffffff9081168252602080850151909116908201529181015161ffff169082015260600161039d565b61048e6040518060400160405280601381526020017f45564d3245564d4f6e52616d7020312e302e300000000000000000000000000081525081565b60405161039d919061494c565b6104ae6104a9366004614971565b61094f565b60405190815260200161039d565b6104cf6104ca366004614b58565b610c8d565b005b6104cf6104df366004614bfd565b610ca3565b6104ec610cb7565b60405167ffffffffffffffff909116815260200161039d565b61050d610ceb565b60405161039d919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6104cf610577366004614c91565b610d9b565b6012546040516bffffffffffffffffffffffff909116815260200161039d565b6104cf6105aa366004614d2e565b610f50565b6002546001600160a01b03165b6040516001600160a01b03909116815260200161039d565b6105bc6105e23660046148c1565b610f62565b6104cf6105f5366004614d88565b610fc1565b6104cf6106083660046148c1565b611027565b6106c26040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a0810182526005546001600160a01b038082168352740100000000000000000000000000000000000000009182900461ffff16602084015260065490811693830193909352820463ffffffff166060820152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16608082015290565b60405161039d9190614e66565b6104cf6106dd366004614ec0565b6110f1565b6104cf6106f0366004614f4e565b6111a9565b6104cf61120f565b6104ec61070b3660046148c1565b6112f2565b6000546001600160a01b03166105bc565b61082761072f3660046148c1565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506001600160a01b03166000908152600f6020908152604091829020825160a08101845290546bffffffffffffffffffffffff811682526c01000000000000000000000000810467ffffffffffffffff169282019290925274010000000000000000000000000000000000000000820463ffffffff16928101929092527801000000000000000000000000000000000000000000000000810461ffff1660608301527a010000000000000000000000000000000000000000000000000000900460ff161515608082015290565b60405161039d9190600060a0820190506bffffffffffffffffffffffff835116825267ffffffffffffffff602084015116602083015263ffffffff604084015116604083015261ffff606084015116606083015260808301511515608083015292915050565b6108956113fa565b60405161039d919061506c565b6104ae6108b03660046150b9565b611406565b6108bd611d3c565b60405161039d929190615167565b6104cf6108d93660046151a9565b611e40565b6104ae611ea8565b610895611eb2565b601254790100000000000000000000000000000000000000000000000000900460ff16604051901515815260200161039d565b6104cf61092f366004615217565b611f63565b6104cf611fe9565b6104cf61094a3660046148c1565b612280565b600080600f8161096560808601606087016148c1565b6001600160a01b031681526020808201929092526040908101600020815160a08101835290546bffffffffffffffffffffffff811682526c01000000000000000000000000810467ffffffffffffffff169382019390935274010000000000000000000000000000000000000000830463ffffffff16918101919091527801000000000000000000000000000000000000000000000000820461ffff1660608201527a01000000000000000000000000000000000000000000000000000090910460ff16151560808201819052909150610a8c57610a4960808401606085016148c1565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b60065460009081906001600160a01b031663ffdb4b37610ab260808801606089016148c1565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff7f000000000000000000000000000000000000000000000000ccf0a31a221f3c9b1660248201526044016040805180830381865afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b61919061525c565b91509150600083600001516bffffffffffffffffffffffff16670de0b6b3a7640000856020015167ffffffffffffffff16866060015161ffff16898060200190610bab919061528f565b610bb6929150615323565b604088015163ffffffff16610bd6610bd160808d018d61528f565b612291565b51610be1919061533a565b610beb919061533a565b610bf59190615323565b610c199077ffffffffffffffffffffffffffffffffffffffffffffffff8616615323565b610c23919061534d565b610c2d919061533a565b9050610c55610c4260808801606089016148c1565b84610c5060408a018a615388565b612390565b610c7977ffffffffffffffffffffffffffffffffffffffffffffffff8516836125dc565b610c83919061533a565b9695505050505050565b610c95612615565b610c9f828261268b565b5050565b610cab612615565b610cb4816129eb565b50565b601254600090610ce690700100000000000000000000000000000000900467ffffffffffffffff1660016153f0565b905090565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610ce690612c84565b6000546001600160a01b03163314801590610dc157506002546001600160a01b03163314155b15610df8576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247896001600160a01b0316826001600160a01b03161480610e3f57506001600160a01b038116155b15610e76576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e80612d36565b1215610eb8576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610c9f9082906001600160a01b038516906370a0823190602401602060405180830381865afa158015610f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3f9190615411565b6001600160a01b0385169190612df6565b610f58612615565b610c9f8282612e76565b6000610f6f600a83612fb1565b610fb0576040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b610fbb600a83612fc6565b92915050565b6000546001600160a01b03163314801590610fe757506002546001600160a01b03163314155b1561101e576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb481612fdb565b6000546001600160a01b0316331480159061104d57506002546001600160a01b03163314155b15611084576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b6000546001600160a01b0316331480159061111757506002546001600160a01b03163314155b1561114e576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c9f8282808060200260200160405190810160405280939291908181526020016000905b8282101561119f576111906040830286013681900381019061542a565b81526020019060010190611173565b5050505050613111565b6000546001600160a01b031633148015906111cf57506002546001600160a01b03163314155b15611206576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb481613384565b6001546001600160a01b03163314611283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610a83565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b03811660009081526011602052604081205467ffffffffffffffff168015801561134b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b15610fbb576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa1580156113cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f39190615469565b9392505050565b6060610ce6600d613593565b60007f000000000000000000000000ba3f6251de62ded61ff98590cb2fdf6871fbb9916001600160a01b031663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148a9190615486565b156114c1576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114cb848061528f565b9050602014611512576114de848061528f565b6040517f370d875f000000000000000000000000000000000000000000000000000000008152600401610a839291906154ec565b600061151e858061528f565b81019061152b9190615500565b90506001600160a01b038111806115425750600a81105b15611551576114de858061528f565b6000611563610bd1608088018861528f565b905061158f611575602088018861528f565b835190915061158760408a018a615388565b9050876135a0565b61160361159f6040880188615388565b808060200260200160405190810160405280939291908181526020016000905b828210156115eb576115dc60408302860136819003810190615519565b815260200190600101906115bf565b50506006546001600160a01b031692506137c3915050565b6001600160a01b037f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247891661163d60808801606089016148c1565b6001600160a01b0316036116a1576012805486919060009061166e9084906bffffffffffffffffffffffff16615553565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506117c0565b6006546001600160a01b03166241e5be6116c16080890160608a016148c1565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018990527f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247899091166044820152606401602060405180830381865afa15801561174d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117719190615411565b601280546000906117919084906bffffffffffffffffffffffff16615553565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b6012546bffffffffffffffffffffffff7f00000000000000000000000000000000000000000052b7d2dcc80cd2e400000081169116111561182d576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526011602052604090205467ffffffffffffffff1615801561188557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b1561197d576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192d9190615469565b6001600160a01b038516600090815260116020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b60006040518061018001604052807f000000000000000000000000000000000000000000000000de41ba4fc9d91ad967ffffffffffffffff1681526020016012601081819054906101000a900467ffffffffffffffff166119dd90615578565b825467ffffffffffffffff9182166101009390930a8381029083021990911617909255825260208083018a90526001600160a01b03891660408085018290526000918252601190925290812080546060909401939092611a3d9116615578565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff16815260200183600001518152602001836020015115158152602001846001600160a01b03168152602001888060200190611aa6919061528f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611aed60408a018a615388565b808060200260200160405190810160405280939291908181526020016000905b82821015611b3957611b2a60408302860136819003810190615519565b81526020019060010190611b0d565b5050509183525050602001611b5460808a0160608b016148c1565b6001600160a01b0316815260006020909101529050611b93817ff9130196b84010e25f6b1be7ea09c9f442808cfc82f5d13389160bda5cd7edac61397c565b61016082015260005b611ba96040890189615388565b9050811015611cf5576000611bc160408a018a615388565b83818110611bd157611bd161559f565b905060400201803603810190611be79190615519565b9050611bf68160000151610f62565b6001600160a01b0316639687544588611c0f8c8061528f565b60208087015160408051928301815260008352517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b168152611c7d959493927f000000000000000000000000000000000000000000000000ccf0a31a221f3c9b916004016155ce565b6000604051808303816000875af1158015611c9c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611ce29190810190615626565b505080611cee906156d8565b9050611b9c565b507faffc45517195d6499808c643bd4a7b0ffeedf95bea5852840d7bfcf63f59e82181604051611d259190615754565b60405180910390a161016001519695505050505050565b6060600080611d4b6007613a86565b90508067ffffffffffffffff811115611d6657611d666149a6565b604051908082528060200260200182016040528015611dab57816020015b6040805180820190915260008082526020820152815260200190600190039081611d845790505b50925060005b81811015611e1d57600080611dc7600784613a91565b915091506040518060400160405280836001600160a01b031681526020018261ffff16815250868481518110611dff57611dff61559f565b6020026020010181905250505080611e16906156d8565b9050611db1565b505060125491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b03163314801590611e6657506002546001600160a01b03163314155b15611e9d576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb4600382613aaf565b6000610ce6612d36565b60606000611ec0600a613c87565b67ffffffffffffffff811115611ed857611ed86149a6565b604051908082528060200260200182016040528015611f01578160200160208202803683370190505b50905060005b8151811015611f5d57611f1b600a82613c92565b50828281518110611f2e57611f2e61559f565b60200260200101816001600160a01b03166001600160a01b03168152505080611f56906156d8565b9050611f07565b50919050565b611f6b612615565b60128054821515790100000000000000000000000000000000000000000000000000027fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517fccf4daf6ab6430389f26b970595dab82a5881ad454770907e415ede27c8df032906110e690831515815260200190565b6000546001600160a01b0316331480159061200f57506002546001600160a01b03163314155b80156120235750612021600733613ca1565b155b1561205a576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff1660008190036120ae576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546bffffffffffffffffffffffff16818110156120f9576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612103612d36565b121561213b576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060006121486007613a86565b905060005b8181101561223d57600080612163600784613a91565b9092509050600087612183836bffffffffffffffffffffffff8a16615323565b61218d919061534d565b90506121998187615891565b95506121dd6001600160a01b037f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b462478916846bffffffffffffffffffffffff8416612df6565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a250505080612236906156d8565b905061214d565b5050601280547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b612288612615565b610cb481613cb6565b604080518082019091526000808252602082015260008290036122f257506040805180820190915267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000030d4016815260006020820152610fbb565b7f97a657c90000000000000000000000000000000000000000000000000000000061231d83856158b6565b7fffffffff000000000000000000000000000000000000000000000000000000001614612376576040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61238382600481866158fe565b8101906113f39190615928565b6000818082036123a45760009150506125d4565b60005b818110156125d15760008585838181106123c3576123c361559f565b9050604002018036038101906123d99190615519565b80516001600160a01b031660009081526010602090815260408083208151606081018352905463ffffffff8082168352640100000000820416938201939093526801000000000000000090920461ffff16908201819052929350911561253057825189906001600160a01b038c81169116146124da5760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152911690634ab35b0b90602401602060405180830381865afa1580156124b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d79190615954565b90505b620186a0836040015161ffff1661251886602001518477ffffffffffffffffffffffffffffffffffffffffffffffff16613d9190919063ffffffff16565b6125229190615323565b61252c919061534d565b9150505b815160009061254c9063ffffffff16662386f26fc10000615323565b90506000836020015163ffffffff16662386f26fc1000061256d9190615323565b90508183101561257f5781925061258b565b8083111561258b578092505b6125af77ffffffffffffffffffffffffffffffffffffffffffffffff8c16846125dc565b6125b9908961533a565b97505050505050806125ca906156d8565b90506123a7565b50505b949350505050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff831661260b83670de0b6b3a7640000615323565b6113f3919061534d565b6000546001600160a01b03163314612689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610a83565b565b60005b82518110156127ec5760008382815181106126ab576126ab61559f565b602002602001015160000151905060008483815181106126cd576126cd61559f565b60200260200101516020015190506126ef82600a612fb190919063ffffffff16565b612730576040517f73913ebd0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b6001600160a01b038116612745600a84612fc6565b6001600160a01b031614612785576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612790600a83613dc0565b156127d957604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b5050806127e5906156d8565b905061268e565b5060005b81518110156129e657600082828151811061280d5761280d61559f565b6020026020010151600001519050600083838151811061282f5761282f61559f565b602002602001015160200151905060006001600160a01b0316826001600160a01b0316148061286557506001600160a01b038116155b1561289c576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fe919061596f565b6001600160a01b0316826001600160a01b031614612948576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612954600a8383613dd5565b156129a157604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a16129d3565b6040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050806129df906156d8565b90506127f0565b505050565b60408101516001600160a01b0316612a2f576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600580546020808501516001600160a01b039485167fffffffffffffffffffff00000000000000000000000000000000000000000000909316929092177401000000000000000000000000000000000000000061ffff909316830217909255604080850151600680546060808901516080808b0151958a167fffffffffffffffff0000000000000000000000000000000000000000000000009094169390931763ffffffff9091169096029590951777ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff9485160217909155825160e0810184527f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789871681527f000000000000000000000000000000000000000000000000de41ba4fc9d91ad98316958101959095527f000000000000000000000000000000000000000000000000ccf0a31a221f3c9b8216858401527f0000000000000000000000000000000000000000000000000000000000030d40909116928401929092527f00000000000000000000000000000000000000000052b7d2dcc80cd2e40000006bffffffffffffffffffffffff16918301919091527f0000000000000000000000000000000000000000000000000000000000000000831660a08301527f000000000000000000000000ba3f6251de62ded61ff98590cb2fdf6871fbb99190921660c082015290517fdd226617d8d287f40a64c54741bbcdc492b3e096ef16bc5273a18cb6ab85f124916110e691849061598c565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152612d1282606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642612cf69190615a61565b85608001516fffffffffffffffffffffffffffffffff16613deb565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6012546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247896001600160a01b0316906370a0823190602401602060405180830381865afa158015612dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dec9190615411565b610ce69190615a74565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526129e6908490613e13565b60005b8251811015612f07576000838281518110612e9657612e9661559f565b60200260200101519050612eb481600d613f1290919063ffffffff16565b15612ef6576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50612f00816156d8565b9050612e79565b5060005b81518110156129e6576000828281518110612f2857612f2861559f565b6020026020010151905060006001600160a01b0316816001600160a01b031603612f525750612fa1565b612f5d600d82613f27565b15612f9f576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b612faa816156d8565b9050612f0b565b60006113f3836001600160a01b038416613f3c565b60006113f3836001600160a01b038416613f48565b60005b81518110156130e1576000828281518110612ffb57612ffb61559f565b60209081029190910181015160408051606080820183528385015163ffffffff90811683528385015181168387019081529185015161ffff90811684860190815295516001600160a01b03166000908152601090975293909520915182549151945190931668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff948616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921693909516929092179190911791909116919091179055506130da816156d8565b9050612fde565b507fcb0c5f472d325cf0c56953fc81870ddd80d0d3c9a3fbfe777002d75f380dfb81816040516110e69190615a94565b8051604081111561314e576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff161580159061319c575060125463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff90911610155b156131a9576131a9611fe9565b60006131b56007613a86565b90505b80156131f75760006131d66131ce600184615a61565b600790613a91565b5090506131e4600782613f54565b5050806131f090615b0e565b90506131b8565b506000805b828110156133055760008482815181106132185761321861559f565b6020026020010151600001519050600085838151811061323a5761323a61559f565b60200260200101516020015190507f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247896001600160a01b0316826001600160a01b0316148061328f57506001600160a01b038216155b156132d1576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b6132e160078361ffff8416613f69565b506132f061ffff821685615b43565b93505050806132fe906156d8565b90506131fc565b50601280547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24906133779083908690615b60565b60405180910390a1505050565b60005b81518110156135635760008282815181106133a4576133a461559f565b6020908102919091018101516040805160a08082018352828401516bffffffffffffffffffffffff90811683528486015167ffffffffffffffff90811684880190815260608088015163ffffffff9081168789019081526080808b015161ffff908116948a01948552978b0151151590890190815299516001600160a01b03166000908152600f909b529790992095518654925197519151985115157a010000000000000000000000000000000000000000000000000000027fffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff999096167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff92909a167401000000000000000000000000000000000000000002919091167fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff979093166c01000000000000000000000000027fffffffffffffffffffffffff000000000000000000000000000000000000000090921693169290921791909117939093169290921793909317919091161790555061355c816156d8565b9050613387565b507ffba339fca97870ffdfaedbae3745db5e6de1a6909dfd0e0dbb56917469ffe236816040516110e69190615b7f565b606060006113f383613f7f565b6001600160a01b0381166135e0576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b03163314613624576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065474010000000000000000000000000000000000000000900463ffffffff1680851115613689576040517f869337890000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610a83565b6006547801000000000000000000000000000000000000000000000000900467ffffffffffffffff168411156136eb576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055474010000000000000000000000000000000000000000900461ffff16831115613743576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254790100000000000000000000000000000000000000000000000000900460ff16801561377a5750613778600d83613fdb565b155b156137bc576040517fd0d259760000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b5050505050565b81516000805b82811015613968576000846001600160a01b031663d02641a08784815181106137f4576137f461559f565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0390911660048201526024016040805180830381865afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f9190615c17565b51905077ffffffffffffffffffffffffffffffffffffffffffffffff8116600003613900578582815181106138b6576138b661559f565b6020908102919091010151516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610a83565b61394a8683815181106139155761391561559f565b6020026020010151602001518277ffffffffffffffffffffffffffffffffffffffffffffffff16613d9190919063ffffffff16565b613954908461533a565b92505080613961906156d8565b90506137c9565b506139766003826000613ffd565b50505050565b60008060001b828460200151856080015186606001518760e00151886101000151805190602001208961012001516040516020016139ba9190615c4a565b604051602081830303815290604052805190602001208a60a001518b60c001518c61014001518d60400151604051602001613a689c9b9a999897969594939291909b8c5260208c019a909a5267ffffffffffffffff98891660408c01529690971660608a01526001600160a01b0394851660808a015292841660a089015260c088019190915260e0870152610100860152911515610120850152166101408301526101608201526101800190565b60405160208183030381529060405280519060200120905092915050565b6000610fbb8261434c565b6000808080613aa08686614357565b909450925050505b9250929050565b8154600090613ad890700100000000000000000000000000000000900463ffffffff1642615a61565b90508015613b7a5760018301548354613b20916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416613deb565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354613ba0916fffffffffffffffffffffffffffffffff9081169116614382565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906133779084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b6000610fbb82613a86565b6000808080613aa08686613a91565b60006113f3836001600160a01b038416614398565b336001600160a01b03821603613d28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610a83565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000670de0b6b3a764000061260b8377ffffffffffffffffffffffffffffffffffffffffffffffff8616615323565b60006113f3836001600160a01b0384166143a4565b60006125d4846001600160a01b038516846143b0565b6000613e0a85613dfb8486615323565b613e05908761533a565b614382565b95945050505050565b6000613e68826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143c69092919063ffffffff16565b8051909150156129e65780806020019051810190613e869190615486565b6129e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a83565b60006113f3836001600160a01b0384166143d5565b60006113f3836001600160a01b0384166144cf565b60006113f38383614398565b60006113f3838361451e565b60006113f3836001600160a01b0384166145a8565b60006125d4846001600160a01b038516846145c5565b606081600001805480602002602001604051908101604052809291908181526020018280548015613fcf57602002820191906000526020600020905b815481526020019060010190808311613fbb575b50505050509050919050565b6001600160a01b038116600090815260018301602052604081205415156113f3565b825474010000000000000000000000000000000000000000900460ff161580614024575081155b1561402e57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061407490700100000000000000000000000000000000900463ffffffff1642615a61565b9050801561413457818311156140b6576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546140f09083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613deb565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156141d1576001600160a01b038416614186576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610a83565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610a83565b848310156142ca5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906142159082615a61565b61421f878a615a61565b614229919061533a565b614233919061534d565b90506001600160a01b03861661427f576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610a83565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610a83565b6142d48584615a61565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610fbb826145e2565b6000808061436585856145ec565b600081815260029690960160205260409095205494959350505050565b600081831061439157816113f3565b5090919050565b60006113f383836145f8565b60006113f383836145a8565b60006125d484846001600160a01b0385166145c5565b60606125d48484600085614610565b600081815260018301602052604081205480156144be5760006143f9600183615a61565b855490915060009061440d90600190615a61565b905081811461447257600086600001828154811061442d5761442d61559f565b90600052602060002001549050808760000184815481106144505761445061559f565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061448357614483615c5d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610fbb565b6000915050610fbb565b5092915050565b600081815260018301602052604081205461451657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610fbb565b506000610fbb565b60008181526002830160205260408120548015158061454257506145428484614398565b6113f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610a83565b600081815260028301602052604081208190556113f3838361471c565b600082815260028401602052604081208290556125d48484614728565b6000610fbb825490565b60006113f38383614734565b600081815260018301602052604081205415156113f3565b6060824710156146a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a83565b600080866001600160a01b031685876040516146be9190615c8c565b60006040518083038185875af1925050503d80600081146146fb576040519150601f19603f3d011682016040523d82523d6000602084013e614700565b606091505b50915091506147118783838761475e565b979650505050505050565b60006113f383836143d5565b60006113f383836144cf565b600082600001828154811061474b5761474b61559f565b9060005260206000200154905092915050565b606083156147e75782516000036147e0576001600160a01b0385163b6147e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a83565b50816125d4565b6125d483838151156147fc5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a83919061494c565b60e08101610fbb82846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b6001600160a01b0381168114610cb457600080fd5b6000602082840312156148d357600080fd5b81356113f3816148ac565b60005b838110156148f95781810151838201526020016148e1565b50506000910152565b6000815180845261491a8160208601602086016148de565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113f36020830184614902565b600060a08284031215611f5d57600080fd5b60006020828403121561498357600080fd5b813567ffffffffffffffff81111561499a57600080fd5b6125d48482850161495f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156149f8576149f86149a6565b60405290565b6040516080810167ffffffffffffffff811182821017156149f8576149f86149a6565b60405160c0810167ffffffffffffffff811182821017156149f8576149f86149a6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614a8b57614a8b6149a6565b604052919050565b600067ffffffffffffffff821115614aad57614aad6149a6565b5060051b60200190565b600082601f830112614ac857600080fd5b81356020614add614ad883614a93565b614a44565b82815260069290921b84018101918181019086841115614afc57600080fd5b8286015b84811015614b4d5760408189031215614b195760008081fd5b614b216149d5565b8135614b2c816148ac565b815281850135614b3b816148ac565b81860152835291830191604001614b00565b509695505050505050565b60008060408385031215614b6b57600080fd5b823567ffffffffffffffff80821115614b8357600080fd5b614b8f86838701614ab7565b93506020850135915080821115614ba557600080fd5b50614bb285828601614ab7565b9150509250929050565b803561ffff81168114614bce57600080fd5b919050565b803563ffffffff81168114614bce57600080fd5b67ffffffffffffffff81168114610cb457600080fd5b600060a08284031215614c0f57600080fd5b60405160a0810181811067ffffffffffffffff82111715614c3257614c326149a6565b6040528235614c40816148ac565b8152614c4e60208401614bbc565b60208201526040830135614c61816148ac565b6040820152614c7260608401614bd3565b60608201526080830135614c8581614be7565b60808201529392505050565b60008060408385031215614ca457600080fd5b8235614caf816148ac565b91506020830135614cbf816148ac565b809150509250929050565b600082601f830112614cdb57600080fd5b81356020614ceb614ad883614a93565b82815260059290921b84018101918181019086841115614d0a57600080fd5b8286015b84811015614b4d578035614d21816148ac565b8352918301918301614d0e565b60008060408385031215614d4157600080fd5b823567ffffffffffffffff80821115614d5957600080fd5b614d6586838701614cca565b93506020850135915080821115614d7b57600080fd5b50614bb285828601614cca565b60006020808385031215614d9b57600080fd5b823567ffffffffffffffff811115614db257600080fd5b8301601f81018513614dc357600080fd5b8035614dd1614ad882614a93565b81815260079190911b82018301908381019087831115614df057600080fd5b928401925b828410156147115760808489031215614e0e5760008081fd5b614e166149fe565b8435614e21816148ac565b8152614e2e858701614bd3565b868201526040614e3f818701614bd3565b908201526060614e50868201614bbc565b9082015282526080939093019290840190614df5565b60a08101610fbb82846001600160a01b0380825116835261ffff60208301511660208401528060408301511660408401525063ffffffff606082015116606083015267ffffffffffffffff60808201511660808301525050565b60008060208385031215614ed357600080fd5b823567ffffffffffffffff80821115614eeb57600080fd5b818501915085601f830112614eff57600080fd5b813581811115614f0e57600080fd5b8660208260061b8501011115614f2357600080fd5b60209290920196919550909350505050565b8015158114610cb457600080fd5b8035614bce81614f35565b60006020808385031215614f6157600080fd5b823567ffffffffffffffff811115614f7857600080fd5b8301601f81018513614f8957600080fd5b8035614f97614ad882614a93565b81815260c09182028301840191848201919088841115614fb657600080fd5b938501935b838510156150605780858a031215614fd35760008081fd5b614fdb614a21565b8535614fe6816148ac565b815285870135614ff581614be7565b818801526040868101356bffffffffffffffffffffffff8116811461501a5760008081fd5b90820152606061502b878201614bd3565b90820152608061503c878201614bbc565b9082015260a061504d878201614f43565b9082015283529384019391850191614fbb565b50979650505050505050565b6020808252825182820181905260009190848201906040850190845b818110156150ad5783516001600160a01b031683529284019291840191600101615088565b50909695505050505050565b6000806000606084860312156150ce57600080fd5b833567ffffffffffffffff8111156150e557600080fd5b6150f18682870161495f565b935050602084013591506040840135615109816148ac565b809150509250925092565b600081518084526020808501945080840160005b8381101561515c57815180516001600160a01b0316885283015161ffff168388015260409096019590820190600101615128565b509495945050505050565b60408152600061517a6040830185615114565b90508260208301529392505050565b80356fffffffffffffffffffffffffffffffff81168114614bce57600080fd5b6000606082840312156151bb57600080fd5b6040516060810181811067ffffffffffffffff821117156151de576151de6149a6565b60405282356151ec81614f35565b81526151fa60208401615189565b602082015261520b60408401615189565b60408201529392505050565b60006020828403121561522957600080fd5b81356113f381614f35565b805177ffffffffffffffffffffffffffffffffffffffffffffffff81168114614bce57600080fd5b6000806040838503121561526f57600080fd5b61527883615234565b915061528660208401615234565b90509250929050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126152c457600080fd5b83018035915067ffffffffffffffff8211156152df57600080fd5b602001915036819003821315613aa857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610fbb57610fbb6152f4565b80820180821115610fbb57610fbb6152f4565b600082615383577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126153bd57600080fd5b83018035915067ffffffffffffffff8211156153d857600080fd5b6020019150600681901b3603821315613aa857600080fd5b67ffffffffffffffff8181168382160190808211156144c8576144c86152f4565b60006020828403121561542357600080fd5b5051919050565b60006040828403121561543c57600080fd5b6154446149d5565b823561544f816148ac565b815261545d60208401614bbc565b60208201529392505050565b60006020828403121561547b57600080fd5b81516113f381614be7565b60006020828403121561549857600080fd5b81516113f381614f35565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6020815260006125d46020830184866154a3565b60006020828403121561551257600080fd5b5035919050565b60006040828403121561552b57600080fd5b6155336149d5565b823561553e816148ac565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff8181168382160190808211156144c8576144c86152f4565b600067ffffffffffffffff808316818103615595576155956152f4565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6001600160a01b038716815260a0602082015260006155f160a0830187896154a3565b85604084015267ffffffffffffffff8516606084015282810360808401526156198185614902565b9998505050505050505050565b60006020828403121561563857600080fd5b815167ffffffffffffffff8082111561565057600080fd5b818401915084601f83011261566457600080fd5b815181811115615676576156766149a6565b6156a760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a44565b91508082528560208285010111156156be57600080fd5b6156cf8160208401602086016148de565b50949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615709576157096152f4565b5060010190565b600081518084526020808501945080840160005b8381101561515c57815180516001600160a01b031688528301518388015260409096019590820190600101615724565b6020815261576f60208201835167ffffffffffffffff169052565b6000602083015161578c604084018267ffffffffffffffff169052565b506040830151606083015260608301516157b160808401826001600160a01b03169052565b50608083015167ffffffffffffffff811660a08401525060a083015160c083015260c08301516157e560e084018215159052565b5060e0830151610100615802818501836001600160a01b03169052565b8085015191505061018061012081818601526158226101a0860184614902565b92508086015190506101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086850301818701526158608483615710565b935080870151915050610160615880818701836001600160a01b03169052565b959095015193019290925250919050565b6bffffffffffffffffffffffff8281168282160390808211156144c8576144c86152f4565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156158f65780818660040360031b1b83161692505b505092915050565b6000808585111561590e57600080fd5b8386111561591b57600080fd5b5050820193919092039150565b60006040828403121561593a57600080fd5b6159426149d5565b82358152602083013561545d81614f35565b60006020828403121561596657600080fd5b6113f382615234565b60006020828403121561598157600080fd5b81516113f3816148ac565b6101808101615a0982856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b82516001600160a01b0390811660e0840152602084015161ffff16610100840152604084015116610120830152606083015163ffffffff16610140830152608083015167ffffffffffffffff166101608301526113f3565b81810381811115610fbb57610fbb6152f4565b81810360008312801583831316838312821617156144c8576144c86152f4565b602080825282518282018190526000919060409081850190868401855b82811015615b0157815180516001600160a01b031685528681015163ffffffff9081168887015286820151168686015260609081015161ffff169085015260809093019290850190600101615ab1565b5091979650505050505050565b600081615b1d57615b1d6152f4565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff8181168382160190808211156144c8576144c86152f4565b63ffffffff831681526040602082015260006125d46040830184615114565b602080825282518282018190526000919060409081850190868401855b82811015615b0157815180516001600160a01b031685528681015167ffffffffffffffff1687860152858101516bffffffffffffffffffffffff168686015260608082015163ffffffff169086015260808082015161ffff169086015260a09081015115159085015260c09093019290850190600101615b9c565b600060408284031215615c2957600080fd5b615c316149d5565b615c3a83615234565b8152602083015161545d81614be7565b6020815260006113f36020830184615710565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251615c9e8184602087016148de565b919091019291505056fea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789000000000000000000000000000000000000000000000000de41ba4fc9d91ad9000000000000000000000000000000000000000000000000ccf0a31a221f3c9b0000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000052b7d2dcc80cd2e40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba3f6251de62ded61ff98590cb2fdf6871fbb991000000000000000000000000d0daae2231e9cb96b94c8512223533293c3693bf00000000000000000000000000000000000000000000000000000000000000050000000000000000000000008737a1c3d55779d03b7a08188e97af87b4110946000000000000000000000000000000000000000000000000000000000000c35000000000000000000000000000000000000000000000000000000000003d090000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000460000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000152d02c7e14af68000000000000000000000000000000000000000000000000000090d972f32323c00000000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000007000000000000000000000000b3c3977b0ac329a9035889929482a4c635b50573000000000000000000000000ac8cfc3762a979628334a0e4c1026244498e821b000000000000000000000000b7c8bca891143221a34db60a26639785c4839040000000000000000000000000a04c2cbbfa7bf7adcbde911216a0ba7e3f1e36b3000000000000000000000000f92e4b278380f39fadc24483c7bac61b73ee93f2000000000000000000000000919b1d308e4477c88350c336537ec5ac9ee76d9a000000000000000000000000832ba6abcadc68812be372f4ef20aac268ba20b70000000000000000000000000ea0d7b2b78dd3a926fc76d6875a287f0aeb158f000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247890000000000000000000000005344b4bf5ae39038a591866d2853b2b1db62291100000000000000000000000092ea346b7a2aab84e6aab03b80e2421eefb046850000000000000000000000006c4cf212a5d074bb4d9055279b1fb2f1f37265db000000000000000000000000784c400d6ff625051d2f587dc0276e3a1ffd9cda0000000000000000000000005f217ce93e206d6f13b342aeef53a084fa95774500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000493e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001000000000000000000000000097d90c9d3e0b50ca60e1ae45f6a81010f9fb5340000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000493e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007000000000000000000000000b3c3977b0ac329a9035889929482a4c635b505730000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000b7c8bca891143221a34db60a26639785c48390400000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000f92e4b278380f39fadc24483c7bac61b73ee93f20000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000832ba6abcadc68812be372f4ef20aac268ba20b70000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000779877a7b0d9e8603169ddbd7836e478b46247890000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000003200000000000000000000000092ea346b7a2aab84e6aab03b80e2421eefb046850000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000784c400d6ff625051d2f587dc0276e3a1ffd9cda0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000
-----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] : tokensAndPools (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
79 Constructor Arguments found :
Arg [0] : 000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789
Arg [1] : 000000000000000000000000000000000000000000000000de41ba4fc9d91ad9
Arg [2] : 000000000000000000000000000000000000000000000000ccf0a31a221f3c9b
Arg [3] : 0000000000000000000000000000000000000000000000000000000000030d40
Arg [4] : 00000000000000000000000000000000000000000052b7d2dcc80cd2e4000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 000000000000000000000000ba3f6251de62ded61ff98590cb2fdf6871fbb991
Arg [7] : 000000000000000000000000d0daae2231e9cb96b94c8512223533293c3693bf
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [9] : 0000000000000000000000008737a1c3d55779d03b7a08188e97af87b4110946
Arg [10] : 000000000000000000000000000000000000000000000000000000000000c350
Arg [11] : 00000000000000000000000000000000000000000000000000000000003d0900
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000460
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [15] : 00000000000000000000000000000000000000000000152d02c7e14af6800000
Arg [16] : 0000000000000000000000000000000000000000000000090d972f32323c0000
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000480
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000620
Arg [19] : 00000000000000000000000000000000000000000000000000000000000009c0
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [21] : 000000000000000000000000b3c3977b0ac329a9035889929482a4c635b50573
Arg [22] : 000000000000000000000000ac8cfc3762a979628334a0e4c1026244498e821b
Arg [23] : 000000000000000000000000b7c8bca891143221a34db60a26639785c4839040
Arg [24] : 000000000000000000000000a04c2cbbfa7bf7adcbde911216a0ba7e3f1e36b3
Arg [25] : 000000000000000000000000f92e4b278380f39fadc24483c7bac61b73ee93f2
Arg [26] : 000000000000000000000000919b1d308e4477c88350c336537ec5ac9ee76d9a
Arg [27] : 000000000000000000000000832ba6abcadc68812be372f4ef20aac268ba20b7
Arg [28] : 0000000000000000000000000ea0d7b2b78dd3a926fc76d6875a287f0aeb158f
Arg [29] : 000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789
Arg [30] : 0000000000000000000000005344b4bf5ae39038a591866d2853b2b1db622911
Arg [31] : 00000000000000000000000092ea346b7a2aab84e6aab03b80e2421eefb04685
Arg [32] : 0000000000000000000000006c4cf212a5d074bb4d9055279b1fb2f1f37265db
Arg [33] : 000000000000000000000000784c400d6ff625051d2f587dc0276e3a1ffd9cda
Arg [34] : 0000000000000000000000005f217ce93e206d6f13b342aeef53a084fa957745
Arg [35] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [36] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [37] : 000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789
Arg [38] : 000000000000000000000000000000000000000000000000016345785d8a0000
Arg [39] : 000000000000000000000000000000000000000000000000002386f26fc10000
Arg [40] : 00000000000000000000000000000000000000000000000000000000000493e0
Arg [41] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [42] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [43] : 000000000000000000000000097d90c9d3e0b50ca60e1ae45f6a81010f9fb534
Arg [44] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [45] : 000000000000000000000000000000000000000000000000002386f26fc10000
Arg [46] : 00000000000000000000000000000000000000000000000000000000000493e0
Arg [47] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [48] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [49] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [50] : 000000000000000000000000b3c3977b0ac329a9035889929482a4c635b50573
Arg [51] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [52] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [53] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [54] : 000000000000000000000000b7c8bca891143221a34db60a26639785c4839040
Arg [55] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [56] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [57] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [58] : 000000000000000000000000f92e4b278380f39fadc24483c7bac61b73ee93f2
Arg [59] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [60] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [61] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [62] : 000000000000000000000000832ba6abcadc68812be372f4ef20aac268ba20b7
Arg [63] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [64] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [65] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [66] : 000000000000000000000000779877a7b0d9e8603169ddbd7836e478b4624789
Arg [67] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [68] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [69] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [70] : 00000000000000000000000092ea346b7a2aab84e6aab03b80e2421eefb04685
Arg [71] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [72] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [73] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [74] : 000000000000000000000000784c400d6ff625051d2f587dc0276e3a1ffd9cda
Arg [75] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [76] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [77] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [78] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.