Source Code
Overview
ETH Balance
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 910 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transmit | 8025530 | 12 days ago | IN | 0 ETH | 0.00009474 | ||||
Transmit | 6991161 | 118 days ago | IN | 0 ETH | 0.00035672 | ||||
Transmit | 6945227 | 122 days ago | IN | 0 ETH | 0.0006114 | ||||
Transmit | 6943152 | 123 days ago | IN | 0 ETH | 0.0004684 | ||||
Transmit | 6942958 | 123 days ago | IN | 0 ETH | 0.0005077 | ||||
Manually Execute | 6942765 | 123 days ago | IN | 0 ETH | 0.0004686 | ||||
Transmit | 6942280 | 123 days ago | IN | 0 ETH | 0.0004615 | ||||
Transmit | 6942209 | 123 days ago | IN | 0 ETH | 0.00046844 | ||||
Transmit | 6674212 | 143 days ago | IN | 0 ETH | 0.00009764 | ||||
Transmit | 6674207 | 143 days ago | IN | 0 ETH | 0.00029792 | ||||
Transmit | 6674201 | 143 days ago | IN | 0 ETH | 0.00029789 | ||||
Transmit | 6674197 | 143 days ago | IN | 0 ETH | 0.0002989 | ||||
Transmit | 6674192 | 143 days ago | IN | 0 ETH | 0.00030424 | ||||
Transmit | 6674188 | 143 days ago | IN | 0 ETH | 0.00020164 | ||||
Transmit | 6674186 | 143 days ago | IN | 0 ETH | 0.00020111 | ||||
Transmit | 6674183 | 143 days ago | IN | 0 ETH | 0.00020095 | ||||
Transmit | 6674177 | 143 days ago | IN | 0 ETH | 0.00020128 | ||||
Transmit | 6674173 | 143 days ago | IN | 0 ETH | 0.00020162 | ||||
Transmit | 6674169 | 143 days ago | IN | 0 ETH | 0.00020184 | ||||
Transmit | 6674164 | 143 days ago | IN | 0 ETH | 0.00020203 | ||||
Transmit | 6674161 | 143 days ago | IN | 0 ETH | 0.00020225 | ||||
Transmit | 6674156 | 143 days ago | IN | 0 ETH | 0.0002034 | ||||
Transmit | 6674151 | 143 days ago | IN | 0 ETH | 0.00020288 | ||||
Transmit | 6674147 | 143 days ago | IN | 0 ETH | 0.00020316 | ||||
Transmit | 6674143 | 143 days ago | IN | 0 ETH | 0.00020182 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
8025530 | 12 days ago | 0 ETH | ||||
8025530 | 12 days ago | 0 ETH | ||||
8025530 | 12 days ago | 0 ETH | ||||
6991161 | 118 days ago | 0 ETH | ||||
6991161 | 118 days ago | 0 ETH | ||||
6991161 | 118 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6945227 | 122 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH | ||||
6943152 | 123 days ago | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
EVM2EVMOffRamp
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 18000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol"; import {IAny2EVMOffRamp} from "../interfaces/IAny2EVMOffRamp.sol"; import {ICommitStore} from "../interfaces/ICommitStore.sol"; import {IPoolV1} from "../interfaces/IPool.sol"; import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol"; import {IRMN} from "../interfaces/IRMN.sol"; import {IRouter} from "../interfaces/IRouter.sol"; import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol"; import {CallWithExactGas} from "../../shared/call/CallWithExactGas.sol"; import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol"; import {AggregateRateLimiter} from "../AggregateRateLimiter.sol"; import {Client} from "../libraries/Client.sol"; import {Internal} from "../libraries/Internal.sol"; import {Pool} from "../libraries/Pool.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; import {OCR2BaseNoChecks} from "../ocr/OCR2BaseNoChecks.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {ERC165Checker} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/ERC165Checker.sol"; /// @notice EVM2EVMOffRamp enables OCR networks to execute multiple messages /// in an OffRamp in a single transaction. /// @dev The EVM2EVMOnRamp, CommitStore and EVM2EVMOffRamp form an xchain upgradeable unit. Any change to one of them /// results an onchain upgrade of all 3. /// @dev OCR2BaseNoChecks is used to save gas, signatures are not required as the offramp can only execute /// messages which are committed in the commitStore. We still make use of OCR2 as an executor whitelist /// and turn-taking mechanism. contract EVM2EVMOffRamp is IAny2EVMOffRamp, AggregateRateLimiter, ITypeAndVersion, OCR2BaseNoChecks { using ERC165Checker for address; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; error ZeroAddressNotAllowed(); error CommitStoreAlreadyInUse(); error ExecutionError(bytes err); error InvalidSourceChain(uint64 sourceChainSelector); error MessageTooLarge(uint256 maxSize, uint256 actualSize); error TokenDataMismatch(uint64 sequenceNumber); error UnexpectedTokenData(); error UnsupportedNumberOfTokens(uint64 sequenceNumber); error ManualExecutionNotYetEnabled(); error ManualExecutionGasLimitMismatch(); error DestinationGasAmountCountMismatch(bytes32 messageId, uint64 sequenceNumber); error InvalidManualExecutionGasLimit(bytes32 messageId, uint256 oldLimit, uint256 newLimit); error InvalidTokenGasOverride(bytes32 messageId, uint256 tokenIndex, uint256 oldLimit, uint256 tokenGasOverride); error RootNotCommitted(); error CanOnlySelfCall(); error ReceiverError(bytes err); error TokenHandlingError(bytes err); error ReleaseOrMintBalanceMismatch(uint256 amountReleased, uint256 balancePre, uint256 balancePost); error EmptyReport(); error CursedByRMN(); error InvalidMessageId(); error NotACompatiblePool(address notPool); error InvalidDataLength(uint256 expected, uint256 got); error InvalidNewState(uint64 sequenceNumber, Internal.MessageExecutionState newState); /// @dev Atlas depends on this event, if changing, please notify Atlas. event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig); event SkippedIncorrectNonce(uint64 indexed nonce, address indexed sender); event SkippedSenderWithPreviousRampMessageInflight(uint64 indexed nonce, address indexed sender); /// @dev RMN depends on this event, if changing, please notify the RMN maintainers. event ExecutionStateChanged( uint64 indexed sequenceNumber, bytes32 indexed messageId, Internal.MessageExecutionState state, bytes returnData ); event TokenAggregateRateLimitAdded(address sourceToken, address destToken); event TokenAggregateRateLimitRemoved(address sourceToken, address destToken); event SkippedAlreadyExecutedMessage(uint64 indexed sequenceNumber); event AlreadyAttempted(uint64 sequenceNumber); /// @notice Static offRamp config /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. //solhint-disable gas-struct-packing struct StaticConfig { address commitStore; // ────────╮ CommitStore address on the destination chain uint64 chainSelector; // ───────╯ Destination chainSelector uint64 sourceChainSelector; // ─╮ Source chainSelector address onRamp; // ─────────────╯ OnRamp address on the source chain address prevOffRamp; // Address of previous-version OffRamp address rmnProxy; // RMN proxy address address tokenAdminRegistry; // Token admin registry address } /// @notice Dynamic offRamp config /// @dev since OffRampConfig is part of OffRampConfigChanged event, if changing it, we should update the ABI on Atlas struct DynamicConfig { uint32 permissionLessExecutionThresholdSeconds; // ─╮ Waiting time before manual execution is enabled uint32 maxDataBytes; // │ Maximum payload data size in bytes uint16 maxNumberOfTokensPerMsg; // │ Maximum number of ERC20 token transfers that can be included per message address router; // ─────────────────────────────────╯ Router address address priceRegistry; // Price registry address } /// @notice RateLimitToken struct containing both the source and destination token addresses struct RateLimitToken { address sourceToken; address destToken; } /// @notice Gas overrides for manual exec, the number of token overrides must match the number of tokens in the msg. struct GasLimitOverride { /// @notice Overrides EVM2EVMMessage.gasLimit. A value of zero indicates no override and is valid. uint256 receiverExecutionGasLimit; /// @notice Overrides EVM2EVMMessage.sourceTokenData.destGasAmount. Must be same length as tokenAmounts. A value /// of zero indicates no override and is valid. uint32[] tokenGasOverrides; } // STATIC CONFIG string public constant override typeAndVersion = "EVM2EVMOffRamp 1.5.0"; /// @dev Commit store address on the destination chain address internal immutable i_commitStore; /// @dev ChainSelector of the source chain uint64 internal immutable i_sourceChainSelector; /// @dev ChainSelector of this chain uint64 internal immutable i_chainSelector; /// @dev OnRamp address on the source chain address internal immutable i_onRamp; /// @dev metadataHash is a lane-specific prefix for a message hash preimage which ensures global uniqueness. /// Ensures that 2 identical messages sent to 2 different lanes will have a distinct hash. /// Must match the metadataHash used in computing leaf hashes offchain for the root committed in /// the commitStore and i_metadataHash in the onRamp. bytes32 internal immutable i_metadataHash; /// @dev The address of previous-version OffRamp for this lane. /// Used to be able to provide sequencing continuity during a zero downtime upgrade. address internal immutable i_prevOffRamp; /// @dev The address of the RMN proxy address internal immutable i_rmnProxy; /// @dev The address of the token admin registry address internal immutable i_tokenAdminRegistry; // DYNAMIC CONFIG DynamicConfig internal s_dynamicConfig; /// @dev Tokens that should be included in Aggregate Rate Limiting /// An (address => address) map is used for backwards compatability of offchain code EnumerableMapAddresses.AddressToAddressMap internal s_rateLimitedTokensDestToSource; // STATE /// @dev The expected nonce for a given sender. /// Corresponds to s_senderNonce in the OnRamp, used to enforce that messages are /// executed in the same order they are sent (assuming they are DON). Note that re-execution /// of FAILED messages however, can be out of order. mapping(address sender => uint64 nonce) internal s_senderNonce; /// @dev A mapping of sequence numbers to execution state using a bitmap with each execution /// state only taking up 2 bits of the uint256, packing 128 states into a single slot. /// Message state is tracked to ensure message can only be executed successfully once. mapping(uint64 seqNum => uint256 executionStateBitmap) internal s_executionStates; constructor( StaticConfig memory staticConfig, RateLimiter.Config memory rateLimiterConfig ) OCR2BaseNoChecks() AggregateRateLimiter(rateLimiterConfig) { if ( staticConfig.onRamp == address(0) || staticConfig.commitStore == address(0) || staticConfig.tokenAdminRegistry == address(0) ) revert ZeroAddressNotAllowed(); // Ensures we can never deploy a new offRamp that points to a commitStore that // already has roots committed. if (ICommitStore(staticConfig.commitStore).getExpectedNextSequenceNumber() != 1) revert CommitStoreAlreadyInUse(); i_commitStore = staticConfig.commitStore; i_sourceChainSelector = staticConfig.sourceChainSelector; i_chainSelector = staticConfig.chainSelector; i_onRamp = staticConfig.onRamp; i_prevOffRamp = staticConfig.prevOffRamp; i_rmnProxy = staticConfig.rmnProxy; i_tokenAdminRegistry = staticConfig.tokenAdminRegistry; i_metadataHash = _metadataHash(Internal.EVM_2_EVM_MESSAGE_HASH); } // ================================================================ // │ Messaging │ // ================================================================ // The size of the execution state in bits uint256 private constant MESSAGE_EXECUTION_STATE_BIT_WIDTH = 2; // The mask for the execution state bits uint256 private constant MESSAGE_EXECUTION_STATE_MASK = (1 << MESSAGE_EXECUTION_STATE_BIT_WIDTH) - 1; /// @notice Returns the current execution state of a message based on its sequenceNumber. /// @param sequenceNumber The sequence number of the message to get the execution state for. /// @return The current execution state of the message. /// @dev we use the literal number 128 because using a constant increased gas usage. function getExecutionState(uint64 sequenceNumber) public view returns (Internal.MessageExecutionState) { return Internal.MessageExecutionState( (s_executionStates[sequenceNumber / 128] >> ((sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH)) & MESSAGE_EXECUTION_STATE_MASK ); } /// @notice Sets a new execution state for a given sequence number. It will overwrite any existing state. /// @param sequenceNumber The sequence number for which the state will be saved. /// @param newState The new value the state will be in after this function is called. /// @dev we use the literal number 128 because using a constant increased gas usage. function _setExecutionState(uint64 sequenceNumber, Internal.MessageExecutionState newState) internal { uint256 offset = (sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH; uint256 bitmap = s_executionStates[sequenceNumber / 128]; // to unset any potential existing state we zero the bits of the section the state occupies, // then we do an AND operation to blank out any existing state for the section. bitmap &= ~(MESSAGE_EXECUTION_STATE_MASK << offset); // Set the new state bitmap |= uint256(newState) << offset; s_executionStates[sequenceNumber / 128] = bitmap; } /// @inheritdoc IAny2EVMOffRamp function getSenderNonce(address sender) external view returns (uint64 nonce) { uint256 senderNonce = s_senderNonce[sender]; if (senderNonce == 0) { if (i_prevOffRamp != address(0)) { // If OffRamp was upgraded, check if sender has a nonce from the previous OffRamp. return IAny2EVMOffRamp(i_prevOffRamp).getSenderNonce(sender); } } return uint64(senderNonce); } /// @notice Manually execute a message. /// @param report Internal.ExecutionReport. /// @param gasLimitOverrides New gasLimit for each message in the report. /// @dev We permit gas limit overrides so that users may manually execute messages which failed due to /// insufficient gas provided. function manuallyExecute( Internal.ExecutionReport memory report, GasLimitOverride[] memory gasLimitOverrides ) external { // We do this here because the other _execute path is already covered OCR2BaseXXX. _checkChainForked(); uint256 numMsgs = report.messages.length; if (numMsgs != gasLimitOverrides.length) revert ManualExecutionGasLimitMismatch(); for (uint256 i = 0; i < numMsgs; ++i) { Internal.EVM2EVMMessage memory message = report.messages[i]; GasLimitOverride memory gasLimitOverride = gasLimitOverrides[i]; uint256 newLimit = gasLimitOverride.receiverExecutionGasLimit; // Checks to ensure message cannot be executed with less gas than specified. if (newLimit != 0) { if (newLimit < message.gasLimit) { revert InvalidManualExecutionGasLimit(message.messageId, message.gasLimit, newLimit); } } if (message.tokenAmounts.length != gasLimitOverride.tokenGasOverrides.length) { revert DestinationGasAmountCountMismatch(message.messageId, message.sequenceNumber); } bytes[] memory encodedSourceTokenData = message.sourceTokenData; for (uint256 j = 0; j < message.tokenAmounts.length; ++j) { Internal.SourceTokenData memory sourceTokenData = abi.decode(encodedSourceTokenData[i], (Internal.SourceTokenData)); uint256 tokenGasOverride = gasLimitOverride.tokenGasOverrides[j]; // The gas limit can not be lowered as that could cause the message to fail. If manual execution is done // from an UNTOUCHED state and we would allow lower gas limit, anyone could grief by executing the message with // lower gas limit than the DON would have used. This results in the message being marked FAILURE and the DON // would not attempt it with the correct gas limit. if (tokenGasOverride != 0 && tokenGasOverride < sourceTokenData.destGasAmount) { revert InvalidTokenGasOverride(message.messageId, j, sourceTokenData.destGasAmount, tokenGasOverride); } } } _execute(report, gasLimitOverrides); } /// @notice Entrypoint for execution, called by the OCR network /// @dev Expects an encoded ExecutionReport /// @dev Supplies no GasLimitOverrides as the DON will only execute with the original gas limits. function _report(bytes calldata report) internal override { _execute(abi.decode(report, (Internal.ExecutionReport)), new GasLimitOverride[](0)); } /// @notice Executes a report, executing each message in order. /// @param report The execution report containing the messages and proofs. /// @param manualExecGasOverrides An array of gas limits to use for manual execution. /// @dev If called from the DON, this array is always empty. /// @dev If called from manual execution, this array is always same length as messages. function _execute(Internal.ExecutionReport memory report, GasLimitOverride[] memory manualExecGasOverrides) internal { if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(i_sourceChainSelector)))) revert CursedByRMN(); uint256 numMsgs = report.messages.length; if (numMsgs == 0) revert EmptyReport(); if (numMsgs != report.offchainTokenData.length) revert UnexpectedTokenData(); bytes32[] memory hashedLeaves = new bytes32[](numMsgs); for (uint256 i = 0; i < numMsgs; ++i) { Internal.EVM2EVMMessage memory message = report.messages[i]; // We do this hash here instead of in _verifyMessages to avoid two separate loops // over the same data, which increases gas cost hashedLeaves[i] = Internal._hash(message, i_metadataHash); // For EVM2EVM offramps, the messageID is the leaf hash. // Asserting that this is true ensures we don't accidentally commit and then execute // a message with an unexpected hash. if (hashedLeaves[i] != message.messageId) revert InvalidMessageId(); } bool manualExecution = manualExecGasOverrides.length != 0; // SECURITY CRITICAL CHECK uint256 timestampCommitted = ICommitStore(i_commitStore).verify(hashedLeaves, report.proofs, report.proofFlagBits); if (timestampCommitted == 0) revert RootNotCommitted(); // Execute messages for (uint256 i = 0; i < numMsgs; ++i) { Internal.EVM2EVMMessage memory message = report.messages[i]; Internal.MessageExecutionState originalState = getExecutionState(message.sequenceNumber); // Two valid cases here, we either have never touched this message before, or we tried to execute // and failed. This check protects against reentry and re-execution because the other state is // IN_PROGRESS which should not be allowed to execute. if ( !( originalState == Internal.MessageExecutionState.UNTOUCHED || originalState == Internal.MessageExecutionState.FAILURE ) ) { // If the message has already been executed, we skip it. We want to not revert on race conditions between // executing parties. This will allow us to open up manual exec while also attempting with the DON, without // reverting an entire DON batch when a user manually executes while the tx is inflight. emit SkippedAlreadyExecutedMessage(message.sequenceNumber); continue; } uint32[] memory tokenGasOverrides; if (manualExecution) { tokenGasOverrides = manualExecGasOverrides[i].tokenGasOverrides; bool isOldCommitReport = (block.timestamp - timestampCommitted) > s_dynamicConfig.permissionLessExecutionThresholdSeconds; // Manually execution is fine if we previously failed or if the commit report is just too old // Acceptable state transitions: FAILURE->SUCCESS, UNTOUCHED->SUCCESS, FAILURE->FAILURE if (!(isOldCommitReport || originalState == Internal.MessageExecutionState.FAILURE)) { revert ManualExecutionNotYetEnabled(); } // Manual execution gas limit can override gas limit specified in the message. Value of 0 indicates no override. if (manualExecGasOverrides[i].receiverExecutionGasLimit != 0) { message.gasLimit = manualExecGasOverrides[i].receiverExecutionGasLimit; } } else { // DON can only execute a message once // Acceptable state transitions: UNTOUCHED->SUCCESS, UNTOUCHED->FAILURE if (originalState != Internal.MessageExecutionState.UNTOUCHED) { emit AlreadyAttempted(message.sequenceNumber); continue; } } if (message.nonce != 0) { // In the scenario where we upgrade offRamps, we still want to have sequential nonces. // Referencing the old offRamp to check the expected nonce if none is set for a // given sender allows us to skip the current message if it would not be the next according // to the old offRamp. This preserves sequencing between updates. uint64 prevNonce = s_senderNonce[message.sender]; if (prevNonce == 0) { if (i_prevOffRamp != address(0)) { prevNonce = IAny2EVMOffRamp(i_prevOffRamp).getSenderNonce(message.sender); if (prevNonce + 1 != message.nonce) { // the starting v2 onramp nonce, i.e. the 1st message nonce v2 offramp is expected to receive, // is guaranteed to equal (largest v1 onramp nonce + 1). // if this message's nonce isn't (v1 offramp nonce + 1), then v1 offramp nonce != largest v1 onramp nonce, // it tells us there are still messages inflight for v1 offramp emit SkippedSenderWithPreviousRampMessageInflight(message.nonce, message.sender); continue; } // Otherwise this nonce is indeed the "transitional nonce", that is // all messages sent to v1 ramp have been executed by the DON and the sequence can resume in V2. // Note if first time user in V2, then prevNonce will be 0, and message.nonce = 1, so this will be a no-op. s_senderNonce[message.sender] = prevNonce; } } // UNTOUCHED messages MUST be executed in order always IF message.nonce > 0. if (originalState == Internal.MessageExecutionState.UNTOUCHED) { if (prevNonce + 1 != message.nonce) { // We skip the message if the nonce is incorrect, since message.nonce > 0. emit SkippedIncorrectNonce(message.nonce, message.sender); continue; } } } // Although we expect only valid messages will be committed, we check again // when executing as a defense in depth measure. bytes[] memory offchainTokenData = report.offchainTokenData[i]; _isWellFormed( message.sequenceNumber, message.sourceChainSelector, message.tokenAmounts.length, message.data.length, offchainTokenData.length ); _setExecutionState(message.sequenceNumber, Internal.MessageExecutionState.IN_PROGRESS); (Internal.MessageExecutionState newState, bytes memory returnData) = _trialExecute(message, offchainTokenData, tokenGasOverrides); _setExecutionState(message.sequenceNumber, newState); // Since it's hard to estimate whether manual execution will succeed, we // revert the entire transaction if it fails. This will show the user if // their manual exec will fail before they submit it. if (manualExecution) { if (newState == Internal.MessageExecutionState.FAILURE) { if (originalState != Internal.MessageExecutionState.UNTOUCHED) { // If manual execution fails, we revert the entire transaction, unless the originalState is UNTOUCHED as we // would still be making progress by changing the state from UNTOUCHED to FAILURE. revert ExecutionError(returnData); } } } // The only valid prior states are UNTOUCHED and FAILURE (checked above) // The only valid post states are SUCCESS and FAILURE (checked below) if (newState != Internal.MessageExecutionState.SUCCESS) { if (newState != Internal.MessageExecutionState.FAILURE) { revert InvalidNewState(message.sequenceNumber, newState); } } // Nonce changes per state transition. // These only apply for ordered messages. // UNTOUCHED -> FAILURE nonce bump // UNTOUCHED -> SUCCESS nonce bump // FAILURE -> FAILURE no nonce bump // FAILURE -> SUCCESS no nonce bump if (message.nonce != 0) { if (originalState == Internal.MessageExecutionState.UNTOUCHED) { s_senderNonce[message.sender]++; } } emit ExecutionStateChanged(message.sequenceNumber, message.messageId, newState, returnData); } } /// @notice Does basic message validation. Should never fail. /// @param sequenceNumber Sequence number of the message. /// @param sourceChainSelector SourceChainSelector of the message. /// @param numberOfTokens Length of tokenAmounts array in the message. /// @param dataLength Length of data field in the message. /// @param offchainTokenDataLength Length of offchainTokenData array. /// @dev reverts on validation failures. function _isWellFormed( uint64 sequenceNumber, uint64 sourceChainSelector, uint256 numberOfTokens, uint256 dataLength, uint256 offchainTokenDataLength ) private view { if (sourceChainSelector != i_sourceChainSelector) revert InvalidSourceChain(sourceChainSelector); if (numberOfTokens > uint256(s_dynamicConfig.maxNumberOfTokensPerMsg)) { revert UnsupportedNumberOfTokens(sequenceNumber); } if (numberOfTokens != offchainTokenDataLength) revert TokenDataMismatch(sequenceNumber); if (dataLength > uint256(s_dynamicConfig.maxDataBytes)) { revert MessageTooLarge(uint256(s_dynamicConfig.maxDataBytes), dataLength); } } /// @notice Try executing a message. /// @param message Internal.EVM2EVMMessage memory message. /// @param offchainTokenData Data provided by the DON for token transfers. /// @return the new state of the message, being either SUCCESS or FAILURE. /// @return revert data in bytes if CCIP receiver reverted during execution. function _trialExecute( Internal.EVM2EVMMessage memory message, bytes[] memory offchainTokenData, uint32[] memory tokenGasOverrides ) internal returns (Internal.MessageExecutionState, bytes memory) { try this.executeSingleMessage(message, offchainTokenData, tokenGasOverrides) {} catch (bytes memory err) { // return the message execution state as FAILURE and the revert data // Max length of revert data is Router.MAX_RET_BYTES, max length of err is 4 + Router.MAX_RET_BYTES return (Internal.MessageExecutionState.FAILURE, err); } // If message execution succeeded, no CCIP receiver return data is expected, return with empty bytes. return (Internal.MessageExecutionState.SUCCESS, ""); } /// @notice Execute a single message. /// @param message The message that will be executed. /// @param offchainTokenData Token transfer data to be passed to TokenPool. /// @dev We make this external and callable by the contract itself, in order to try/catch /// its execution and enforce atomicity among successful message processing and token transfer. /// @dev We use ERC-165 to check for the ccipReceive interface to permit sending tokens to contracts /// (for example smart contract wallets) without an associated message. function executeSingleMessage( Internal.EVM2EVMMessage calldata message, bytes[] calldata offchainTokenData, uint32[] memory tokenGasOverrides ) external { if (msg.sender != address(this)) revert CanOnlySelfCall(); Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](0); if (message.tokenAmounts.length > 0) { destTokenAmounts = _releaseOrMintTokens( message.tokenAmounts, abi.encode(message.sender), message.receiver, message.sourceTokenData, offchainTokenData, tokenGasOverrides ); } // There are three cases in which we skip calling the receiver: // 1. If the message data is empty AND the gas limit is 0. // This indicates a message that only transfers tokens. It is valid to only send tokens to a contract // that supports the IAny2EVMMessageReceiver interface, but without this first check we would call the // receiver without any gas, which would revert the transaction. // 2. If the receiver is not a contract. // 3. If the receiver is a contract but it does not support the IAny2EVMMessageReceiver interface. // // The ordering of these checks is important, as the first check is the cheapest to execute. if ( (message.data.length == 0 && message.gasLimit == 0) || message.receiver.code.length == 0 || !message.receiver.supportsInterface(type(IAny2EVMMessageReceiver).interfaceId) ) return; (bool success, bytes memory returnData,) = IRouter(s_dynamicConfig.router).routeMessage( Client.Any2EVMMessage({ messageId: message.messageId, sourceChainSelector: message.sourceChainSelector, sender: abi.encode(message.sender), data: message.data, destTokenAmounts: destTokenAmounts }), Internal.GAS_FOR_CALL_EXACT_CHECK, message.gasLimit, message.receiver ); // If CCIP receiver execution is not successful, revert the call including token transfers if (!success) revert ReceiverError(returnData); } /// @notice creates a unique hash to be used in message hashing. function _metadataHash(bytes32 prefix) internal view returns (bytes32) { return keccak256(abi.encode(prefix, i_sourceChainSelector, i_chainSelector, i_onRamp)); } // ================================================================ // │ Config │ // ================================================================ /// @notice Returns the static config. /// @dev This function will always return the same struct as the contents is static and can never change. /// RMN depends on this function, if changing, please notify the RMN maintainers. function getStaticConfig() external view returns (StaticConfig memory) { return StaticConfig({ commitStore: i_commitStore, chainSelector: i_chainSelector, sourceChainSelector: i_sourceChainSelector, onRamp: i_onRamp, prevOffRamp: i_prevOffRamp, rmnProxy: i_rmnProxy, tokenAdminRegistry: i_tokenAdminRegistry }); } /// @notice Returns the current dynamic config. /// @return The current config. function getDynamicConfig() external view returns (DynamicConfig memory) { return s_dynamicConfig; } /// @notice Sets the dynamic config. This function is called during `setOCR2Config` flow function _beforeSetConfig(bytes memory onchainConfig) internal override { DynamicConfig memory dynamicConfig = abi.decode(onchainConfig, (DynamicConfig)); if (dynamicConfig.router == address(0)) revert ZeroAddressNotAllowed(); s_dynamicConfig = dynamicConfig; emit ConfigSet( StaticConfig({ commitStore: i_commitStore, chainSelector: i_chainSelector, sourceChainSelector: i_sourceChainSelector, onRamp: i_onRamp, prevOffRamp: i_prevOffRamp, rmnProxy: i_rmnProxy, tokenAdminRegistry: i_tokenAdminRegistry }), dynamicConfig ); } /// @notice Get all tokens which are included in Aggregate Rate Limiting. /// @return sourceTokens The source representation of the tokens that are rate limited. /// @return destTokens The destination representation of the tokens that are rate limited. /// @dev the order of IDs in the list is **not guaranteed**, therefore, if ordering matters when /// making successive calls, one should keep the block height constant to ensure a consistent result. function getAllRateLimitTokens() external view returns (address[] memory sourceTokens, address[] memory destTokens) { uint256 numRateLimitedTokens = s_rateLimitedTokensDestToSource.length(); sourceTokens = new address[](numRateLimitedTokens); destTokens = new address[](numRateLimitedTokens); for (uint256 i = 0; i < numRateLimitedTokens; ++i) { (address destToken, address sourceToken) = s_rateLimitedTokensDestToSource.at(i); sourceTokens[i] = sourceToken; destTokens[i] = destToken; } return (sourceTokens, destTokens); } /// @notice Adds or removes tokens from being used in Aggregate Rate Limiting. /// @param removes - A list of one or more tokens to be removed. /// @param adds - A list of one or more tokens to be added. function updateRateLimitTokens(RateLimitToken[] memory removes, RateLimitToken[] memory adds) external onlyOwner { for (uint256 i = 0; i < removes.length; ++i) { if (s_rateLimitedTokensDestToSource.remove(removes[i].destToken)) { emit TokenAggregateRateLimitRemoved(removes[i].sourceToken, removes[i].destToken); } } for (uint256 i = 0; i < adds.length; ++i) { if (s_rateLimitedTokensDestToSource.set(adds[i].destToken, adds[i].sourceToken)) { emit TokenAggregateRateLimitAdded(adds[i].sourceToken, adds[i].destToken); } } } // ================================================================ // │ Tokens and pools │ // ================================================================ /// @notice Uses a pool to release or mint a token to a receiver address, with balance checks before and after the /// transfer. This is done to ensure the exact number of tokens the pool claims to release are actually transferred. /// @dev The local token address is validated through the TokenAdminRegistry. If, due to some misconfiguration, the /// token is unknown to the registry, the offRamp will revert. The tx, and the tokens, can be retrieved by /// registering the token on this chain, and re-trying the msg. /// @param sourceAmount The amount of tokens to be released/minted. /// @param originalSender The message sender on the source chain. /// @param receiver The address that will receive the tokens. /// @param sourceTokenData A struct containing the local token address, the source pool address and optional data /// returned from the source pool. /// @param offchainTokenData Data fetched offchain by the DON. function _releaseOrMintToken( uint256 sourceAmount, bytes memory originalSender, address receiver, Internal.SourceTokenData memory sourceTokenData, bytes memory offchainTokenData ) internal returns (Client.EVMTokenAmount memory destTokenAmount) { // We need to safely decode the token address from the sourceTokenData, as it could be wrong, // in which case it doesn't have to be a valid EVM address. address localToken = Internal._validateEVMAddress(sourceTokenData.destTokenAddress); // We check with the token admin registry if the token has a pool on this chain. address localPoolAddress = ITokenAdminRegistry(i_tokenAdminRegistry).getPool(localToken); // This will call the supportsInterface through the ERC165Checker, and not directly on the pool address. // This is done to prevent a pool from reverting the entire transaction if it doesn't support the interface. // The call gets a max or 30k gas per instance, of which there are three. This means gas estimations should // account for 90k gas overhead due to the interface check. if (localPoolAddress == address(0) || !localPoolAddress.supportsInterface(Pool.CCIP_POOL_V1)) { revert NotACompatiblePool(localPoolAddress); } // We retrieve the local token balance of the receiver before the pool call. (uint256 balancePre, uint256 gasLeft) = _getBalanceOfReceiver(receiver, localToken, sourceTokenData.destGasAmount); // We determined that the pool address is a valid EVM address, but that does not mean the code at this // address is a (compatible) pool contract. _callWithExactGasSafeReturnData will check if the location // contains a contract. If it doesn't it reverts with a known error, which we catch gracefully. // We call the pool with exact gas to increase resistance against malicious tokens or token pools. // We protects against return data bombs by capping the return data size at MAX_RET_BYTES. (bool success, bytes memory returnData, uint256 gasUsedReleaseOrMint) = CallWithExactGas ._callWithExactGasSafeReturnData( abi.encodeCall( IPoolV1.releaseOrMint, Pool.ReleaseOrMintInV1({ originalSender: originalSender, receiver: receiver, amount: sourceAmount, localToken: localToken, remoteChainSelector: i_sourceChainSelector, sourcePoolAddress: sourceTokenData.sourcePoolAddress, sourcePoolData: sourceTokenData.extraData, offchainTokenData: offchainTokenData }) ), localPoolAddress, gasLeft, Internal.GAS_FOR_CALL_EXACT_CHECK, Internal.MAX_RET_BYTES ); // wrap and rethrow the error so we can catch it lower in the stack if (!success) revert TokenHandlingError(returnData); // If the call was successful, the returnData should contain only the local token amount. if (returnData.length != Pool.CCIP_POOL_V1_RET_BYTES) { revert InvalidDataLength(Pool.CCIP_POOL_V1_RET_BYTES, returnData.length); } uint256 localAmount = abi.decode(returnData, (uint256)); // We don't need to do balance checks if the pool is the receiver, as they would always fail in the case // of a lockRelease pool. if (receiver != localPoolAddress) { (uint256 balancePost,) = _getBalanceOfReceiver(receiver, localToken, gasLeft - gasUsedReleaseOrMint); // First we check if the subtraction would result in an underflow to ensure we revert with a clear error if (balancePost < balancePre || balancePost - balancePre != localAmount) { revert ReleaseOrMintBalanceMismatch(localAmount, balancePre, balancePost); } } return Client.EVMTokenAmount({token: localToken, amount: localAmount}); } function _getBalanceOfReceiver( address receiver, address token, uint256 gasLimit ) internal returns (uint256 balance, uint256 gasLeft) { (bool success, bytes memory returnData, uint256 gasUsed) = CallWithExactGas._callWithExactGasSafeReturnData( abi.encodeCall(IERC20.balanceOf, (receiver)), token, gasLimit, Internal.GAS_FOR_CALL_EXACT_CHECK, Internal.MAX_RET_BYTES ); if (!success) revert TokenHandlingError(returnData); // If the call was successful, the returnData should contain only the balance. if (returnData.length != Internal.MAX_BALANCE_OF_RET_BYTES) { revert InvalidDataLength(Internal.MAX_BALANCE_OF_RET_BYTES, returnData.length); } // Return the decoded balance, which cannot fail as we checked the length, and the gas that is left // after this call. return (abi.decode(returnData, (uint256)), gasLimit - gasUsed); } /// @notice Uses pools to release or mint a number of different tokens to a receiver address. /// @param sourceTokenAmounts List of tokens and amount values to be released/minted. /// @param originalSender The message sender. /// @param receiver The address that will receive the tokens. /// @param encodedSourceTokenData Array of token data returned by token pools on the source chain. /// @param offchainTokenData Array of token data fetched offchain by the DON. /// @dev This function wrappes the token pool call in a try catch block to gracefully handle /// any non-rate limiting errors that may occur. If we encounter a rate limiting related error /// we bubble it up. If we encounter a non-rate limiting error we wrap it in a TokenHandlingError. function _releaseOrMintTokens( Client.EVMTokenAmount[] calldata sourceTokenAmounts, bytes memory originalSender, address receiver, bytes[] calldata encodedSourceTokenData, bytes[] calldata offchainTokenData, uint32[] memory tokenGasOverrides ) internal returns (Client.EVMTokenAmount[] memory destTokenAmounts) { // Creating a copy is more gas efficient than initializing a new array. destTokenAmounts = sourceTokenAmounts; uint256 value = 0; for (uint256 i = 0; i < sourceTokenAmounts.length; ++i) { Internal.SourceTokenData memory sourceTokenData = abi.decode(encodedSourceTokenData[i], (Internal.SourceTokenData)); if (tokenGasOverrides.length != 0) { if (tokenGasOverrides[i] != 0) { sourceTokenData.destGasAmount = tokenGasOverrides[i]; } } destTokenAmounts[i] = _releaseOrMintToken( sourceTokenAmounts[i].amount, originalSender, receiver, // This should never revert as the onRamp encodes the sourceTokenData struct. Only the inner components from // this struct come from untrusted sources. sourceTokenData, offchainTokenData[i] ); if (s_rateLimitedTokensDestToSource.contains(destTokenAmounts[i].token)) { value += _getTokenValue(destTokenAmounts[i], IPriceRegistry(s_dynamicConfig.priceRegistry)); } } if (value > 0) _rateLimitValue(value); return destTokenAmounts; } // ================================================================ // │ Access │ // ================================================================ /// @notice Reverts as this contract should not access CCIP messages function ccipReceive(Client.Any2EVMMessage calldata) external pure { // solhint-disable-next-line revert(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ITypeAndVersion { function typeAndVersion() external pure returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Client} from "../libraries/Client.sol"; /// @notice Application contracts that intend to receive messages from /// the router should implement this interface. interface IAny2EVMMessageReceiver { /// @notice Called by the Router to deliver a message. /// If this reverts, any token transfers also revert. The message /// will move to a FAILED state and become available for manual execution. /// @param message CCIP Message /// @dev Note ensure you check the msg.sender is the OffRampRouter function ccipReceive(Client.Any2EVMMessage calldata message) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IAny2EVMOffRamp { /// @notice Returns the the current nonce for a receiver. /// @param sender The sender address /// @return nonce The nonce value belonging to the sender address. function getSenderNonce(address sender) external view returns (uint64 nonce); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ICommitStore { /// @notice Returns timestamp of when root was accepted or 0 if verification fails. /// @dev This method uses a merkle tree within a merkle tree, with the hashedLeaves, /// proofs and proofFlagBits being used to get the root of the inner tree. /// This root is then used as the singular leaf of the outer tree. function verify( bytes32[] calldata hashedLeaves, bytes32[] calldata proofs, uint256 proofFlagBits ) external view returns (uint256 timestamp); /// @notice Returns the expected next sequence number function getExpectedNextSequenceNumber() external view returns (uint64 sequenceNumber); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Pool} from "../libraries/Pool.sol"; import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol"; /// @notice Shared public interface for multiple V1 pool types. /// Each pool type handles a different child token model (lock/unlock, mint/burn.) interface IPoolV1 is IERC165 { /// @notice Lock tokens into the pool or burn the tokens. /// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain. /// @return lockOrBurnOut Encoded data fields for the processing of tokens on the destination chain. function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn) external returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut); /// @notice Releases or mints tokens to the receiver address. /// @param releaseOrMintIn All data required to release or mint tokens. /// @return releaseOrMintOut The amount of tokens released or minted on the local chain, denominated /// in the local token's decimals. /// @dev The offramp asserts that the balanceOf of the receiver has been incremented by exactly the number /// of tokens that is returned in ReleaseOrMintOutV1.destinationAmount. If the amounts do not match, the tx reverts. function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn) external returns (Pool.ReleaseOrMintOutV1 memory); /// @notice Checks whether a remote chain is supported in the token pool. /// @param remoteChainSelector The selector of the remote chain. /// @return true if the given chain is a permissioned remote chain. function isSupportedChain(uint64 remoteChainSelector) external view returns (bool); /// @notice Returns if the token pool supports the given token. /// @param token The address of the token. /// @return true if the token is supported by the pool. function isSupportedToken(address token) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Client} from "../libraries/Client.sol"; import {Internal} from "../libraries/Internal.sol"; interface IPriceRegistry { /// @notice Token price data feed configuration struct TokenPriceFeedConfig { address dataFeedAddress; // ──╮ AggregatorV3Interface contract (0 - feed is unset) uint8 tokenDecimals; // ──────╯ Decimals of the token that the feed represents } /// @notice Update the price for given tokens and gas prices for given chains. /// @param priceUpdates The price updates to apply. function updatePrices(Internal.PriceUpdates memory priceUpdates) external; /// @notice Get the `tokenPrice` for a given token. /// @param token The token to get the price for. /// @return tokenPrice The tokenPrice for the given token. function getTokenPrice(address token) external view returns (Internal.TimestampedPackedUint224 memory); /// @notice Get the `tokenPrice` for a given token, checks if the price is valid. /// @param token The token to get the price for. /// @return tokenPrice The tokenPrice for the given token if it exists and is valid. function getValidatedTokenPrice(address token) external view returns (uint224); /// @notice Get the `tokenPrice` for an array of tokens. /// @param tokens The tokens to get prices for. /// @return tokenPrices The tokenPrices for the given tokens. function getTokenPrices(address[] calldata tokens) external view returns (Internal.TimestampedPackedUint224[] memory); /// @notice Returns the token price data feed configuration /// @param token The token to retrieve the feed config for /// @return dataFeedAddress The token price data feed config (if feed address is 0, the feed config is disabled) function getTokenPriceFeedConfig(address token) external view returns (TokenPriceFeedConfig memory); /// @notice Get an encoded `gasPrice` for a given destination chain ID. /// The 224-bit result encodes necessary gas price components. /// On L1 chains like Ethereum or Avax, the only component is the gas price. /// On Optimistic Rollups, there are two components - the L2 gas price, and L1 base fee for data availability. /// On future chains, there could be more or differing price components. /// PriceRegistry does not contain chain-specific logic to parse destination chain price components. /// @param destChainSelector The destination chain to get the price for. /// @return gasPrice The encoded gasPrice for the given destination chain ID. function getDestinationChainGasPrice(uint64 destChainSelector) external view returns (Internal.TimestampedPackedUint224 memory); /// @notice Gets the fee token price and the gas price, both denominated in dollars. /// @param token The source token to get the price for. /// @param destChainSelector The destination chain to get the gas price for. /// @return tokenPrice The price of the feeToken in 1e18 dollars per base unit. /// @return gasPrice The price of gas in 1e18 dollars per base unit. function getTokenAndGasPrices( address token, uint64 destChainSelector ) external view returns (uint224 tokenPrice, uint224 gasPrice); /// @notice Convert a given token amount to target token amount. /// @param fromToken The given token address. /// @param fromTokenAmount The given token amount. /// @param toToken The target token address. /// @return toTokenAmount The target token amount. function convertTokenAmount( address fromToken, uint256 fromTokenAmount, address toToken ) external view returns (uint256 toTokenAmount); /// @notice Get the list of fee tokens. /// @return The tokens set as fee tokens. function getFeeTokens() external view returns (address[] memory); /// @notice Validates the ccip message & returns the fee /// @param destChainSelector The destination chain selector. /// @param message The message to get quote for. /// @return feeTokenAmount The amount of fee token needed for the fee, in smallest denomination of the fee token. function getValidatedFee( uint64 destChainSelector, Client.EVM2AnyMessage calldata message ) external view returns (uint256 feeTokenAmount); /// @notice Converts the extraArgs to the latest version and returns the converted message fee in juels /// @param destChainSelector destination chain selector to process /// @param feeToken Fee token address used to pay for message fees /// @param feeTokenAmount Fee token amount /// @param extraArgs Message extra args that were passed in by the client /// @return msgFeeJuels message fee in juels /// @return isOutOfOrderExecution true if the message should be executed out of order /// @return convertedExtraArgs extra args converted to the latest family-specific args version function processMessageArgs( uint64 destChainSelector, address feeToken, uint256 feeTokenAmount, bytes memory extraArgs ) external view returns (uint256 msgFeeJuels, bool isOutOfOrderExecution, bytes memory convertedExtraArgs); /// @notice Validates pool return data /// @param destChainSelector Destination chain selector to which the token amounts are sent to /// @param rampTokenAmounts Token amounts with populated pool return data /// @param sourceTokenAmounts Token amounts originally sent in a Client.EVM2AnyMessage message function validatePoolReturnData( uint64 destChainSelector, Internal.RampTokenAmount[] calldata rampTokenAmounts, Client.EVMTokenAmount[] calldata sourceTokenAmounts ) external view; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts. interface IRMN { /// @notice A Merkle root tagged with the address of the commit store contract it is destined for. struct TaggedRoot { address commitStore; bytes32 root; } /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed. function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool); /// @notice Iff there is an active global or legacy curse, this function returns true. function isCursed() external view returns (bool); /// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true. /// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)). function isCursed(bytes16 subject) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Client} from "../libraries/Client.sol"; interface IRouter { error OnlyOffRamp(); /// @notice Route the message to its intended receiver contract. /// @param message Client.Any2EVMMessage struct. /// @param gasForCallExactCheck of params for exec /// @param gasLimit set of params for exec /// @param receiver set of params for exec /// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165. /// the contract is called. If not, only tokens are transferred. /// @return success A boolean value indicating whether the ccip message was received without errors. /// @return retBytes A bytes array containing return data form CCIP receiver. /// @return gasUsed the gas used by the external customer call. Does not include any overhead. function routeMessage( Client.Any2EVMMessage calldata message, uint16 gasForCallExactCheck, uint256 gasLimit, address receiver ) external returns (bool success, bytes memory retBytes, uint256 gasUsed); /// @notice Returns the configured onramp for a specific destination chain. /// @param destChainSelector The destination chain Id to get the onRamp for. /// @return onRampAddress The address of the onRamp. function getOnRamp(uint64 destChainSelector) external view returns (address onRampAddress); /// @notice Return true if the given offRamp is a configured offRamp for the given source chain. /// @param sourceChainSelector The source chain selector to check. /// @param offRamp The address of the offRamp to check. function isOffRamp(uint64 sourceChainSelector, address offRamp) external view returns (bool isOffRamp); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface ITokenAdminRegistry { /// @notice Returns the pool for the given token. function getPool(address token) external view returns (address); /// @notice Proposes an administrator for the given token as pending administrator. /// @param localToken The token to register the administrator for. /// @param administrator The administrator to register. function proposeAdministrator(address localToken, address administrator) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice This library contains various callWithExactGas functions. All of them are /// safe from gas bomb attacks. /// @dev There is code duplication in this library. This is done to not leave the assembly /// the blocks. library CallWithExactGas { error NoContract(); error NoGasForCallExactCheck(); error NotEnoughGasForCall(); bytes4 internal constant NO_CONTRACT_SIG = 0x0c3b563c; bytes4 internal constant NO_GAS_FOR_CALL_EXACT_CHECK_SIG = 0xafa32a2c; bytes4 internal constant NOT_ENOUGH_GAS_FOR_CALL_SIG = 0x37c3be29; /// @notice calls target address with exactly gasAmount gas and payload as calldata. /// Accounts for gasForCallExactCheck gas that will be used by this function. Will revert /// if the target is not a contact. Will revert when there is not enough gas to call the /// target with gasAmount gas. /// @dev Ignores the return data, which makes it immune to gas bomb attacks. /// @return success whether the call succeeded function _callWithExactGas( bytes memory payload, address target, uint256 gasLimit, uint16 gasForCallExactCheck ) internal returns (bool success) { assembly { // solidity calls check that a contract actually exists at the destination, so we do the same // Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion") // doesn't need to account for it. if iszero(extcodesize(target)) { mstore(0x0, NO_CONTRACT_SIG) revert(0x0, 0x4) } let g := gas() // Compute g -= gasForCallExactCheck and check for underflow // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). // We want to ensure that we revert if gasAmount > 63//64*gas available // as we do not want to provide them with less, however that check itself costs // gas. gasForCallExactCheck ensures we have at least enough gas to be able // to revert if gasAmount > 63//64*gas available. if lt(g, gasForCallExactCheck) { mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG) revert(0x0, 0x4) } g := sub(g, gasForCallExactCheck) // if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150 if iszero(gt(sub(g, div(g, 64)), gasLimit)) { mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG) revert(0x0, 0x4) } // call and return whether we succeeded. ignore return data // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0) } return success; } /// @notice calls target address with exactly gasAmount gas and payload as calldata. /// Account for gasForCallExactCheck gas that will be used by this function. Will revert /// if the target is not a contact. Will revert when there is not enough gas to call the /// target with gasAmount gas. /// @dev Caps the return data length, which makes it immune to gas bomb attacks. /// @dev Return data cap logic borrowed from /// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol. /// @return success whether the call succeeded /// @return retData the return data from the call, capped at maxReturnBytes bytes /// @return gasUsed the gas used by the external call. Does not include the overhead of this function. function _callWithExactGasSafeReturnData( bytes memory payload, address target, uint256 gasLimit, uint16 gasForCallExactCheck, uint16 maxReturnBytes ) internal returns (bool success, bytes memory retData, uint256 gasUsed) { // allocate retData memory ahead of time retData = new bytes(maxReturnBytes); assembly { // solidity calls check that a contract actually exists at the destination, so we do the same // Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion") // doesn't need to account for it. if iszero(extcodesize(target)) { mstore(0x0, NO_CONTRACT_SIG) revert(0x0, 0x4) } let g := gas() // Compute g -= gasForCallExactCheck and check for underflow // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). // We want to ensure that we revert if gasAmount > 63//64*gas available // as we do not want to provide them with less, however that check itself costs // gas. gasForCallExactCheck ensures we have at least enough gas to be able // to revert if gasAmount > 63//64*gas available. if lt(g, gasForCallExactCheck) { mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG) revert(0x0, 0x4) } g := sub(g, gasForCallExactCheck) // if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150 if iszero(gt(sub(g, div(g, 64)), gasLimit)) { mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG) revert(0x0, 0x4) } // We save the gas before the call so we can calculate how much gas the call used let gasBeforeCall := gas() // call and return whether we succeeded. ignore return data // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0) gasUsed := sub(gasBeforeCall, gas()) // limit our copy to maxReturnBytes bytes let toCopy := returndatasize() if gt(toCopy, maxReturnBytes) { toCopy := maxReturnBytes } // Store the length of the copied bytes mstore(retData, toCopy) // copy the bytes from retData[0:_toCopy] returndatacopy(add(retData, 0x20), 0x0, toCopy) } return (success, retData, gasUsed); } /// @notice Calls target address with exactly gasAmount gas and payload as calldata /// or reverts if at least gasLimit gas is not available. /// @dev Does not check if target is a contract. If it is not a contract, the low-level /// call will still be made and it will succeed. /// @dev Ignores the return data, which makes it immune to gas bomb attacks. /// @return success whether the call succeeded /// @return sufficientGas Whether there was enough gas to make the call function _callWithExactGasEvenIfTargetIsNoContract( bytes memory payload, address target, uint256 gasLimit, uint16 gasForCallExactCheck ) internal returns (bool success, bool sufficientGas) { assembly { let g := gas() // Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We // need the cushion since the logic following the above call to gas also // costs gas which we cannot account for exactly. So cushion is a // conservative upper bound for the cost of this logic. if iszero(lt(g, gasForCallExactCheck)) { g := sub(g, gasForCallExactCheck) // If g - g//64 <= gasAmount, we don't have enough gas. We subtract g//64 because of EIP-150. if gt(sub(g, div(g, 64)), gasLimit) { // Call and ignore success/return data. Note that we did not check // whether a contract actually exists at the target address. success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0) sufficientGas := true } } } return (success, sufficientGas); } }
// SPDX-License-Identifier: MIT /* solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore */ pragma solidity ^0.8.0; import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; import {EnumerableMapBytes32} from "./EnumerableMapBytes32.sol"; // TODO: the lib can be replaced with OZ v5.1 post-upgrade, which has AddressToAddressMap and AddressToBytes32Map library EnumerableMapAddresses { using EnumerableMap for EnumerableMap.UintToAddressMap; using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map; using EnumerableMapBytes32 for EnumerableMapBytes32.Bytes32ToBytesMap; 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); } struct AddressToBytes32Map { EnumerableMap.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. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function set(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) { return map._inner.set(bytes32(uint256(uint160(key))), value); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function remove(AddressToBytes32Map storage map, address key) internal returns (bool) { return map._inner.remove(bytes32(uint256(uint160(key)))); } /** * @dev Returns true if the key is in the map. O(1). */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function contains(AddressToBytes32Map storage map, address key) internal view returns (bool) { return map._inner.contains(bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. O(1). */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function length(AddressToBytes32Map storage map) internal view returns (uint256) { return map._inner.length(); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function at(AddressToBytes32Map storage map, uint256 index) internal view returns (address, bytes32) { (bytes32 key, bytes32 value) = map._inner.at(index); return (address(uint160(uint256(key))), value); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool, bytes32) { (bool success, bytes32 value) = map._inner.tryGet(bytes32(uint256(uint160(key)))); return (success, value); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) { return map._inner.get(bytes32(uint256(uint160(key)))); } struct AddressToBytesMap { EnumerableMapBytes32.Bytes32ToBytesMap _inner; } /** * @dev Sets the value for `key` in the map. Returns true if the key was added to the map, that is if it was not already present. * @param map The map where the value will be set * @param key The key to set the value for * @param value The value to set for the key * @return bool indicating whether the key was added to the map */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function set(AddressToBytesMap storage map, address key, bytes memory value) internal returns (bool) { return map._inner.set(bytes32(uint256(uint160(key))), value); } /** * @dev Removes the value for `key` in the map. Returns true if the key was removed from the map, that is if it was present. * @param map The map where the value will be removed * @param key The key to remove the value for * @return bool indicating whether the key was removed from the map */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function remove(AddressToBytesMap storage map, address key) internal returns (bool) { return map._inner.remove(bytes32(uint256(uint160(key)))); } /** * @dev Checks if the map contains the `key`. Returns true if the key is in the map. * @param map The map to check for the presence of the key * @param key The key to check for presence in the map * @return bool indicating whether the key is in the map */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function contains(AddressToBytesMap storage map, address key) internal view returns (bool) { return map._inner.contains(bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. * @param map The map to check the length of * @return uint256 indicating the number of elements in the map */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function length(AddressToBytesMap storage map) internal view returns (uint256) { return map._inner.length(); } /** * @dev Returns the element stored at position `index` in the map. 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. * @param map The map to retrieve the element from * @param index The index to retrieve the element at * @return address The key of the element at the specified index * @return bytes The value of the element at the specified index */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function at(AddressToBytesMap storage map, uint256 index) internal view returns (address, bytes memory) { (bytes32 key, bytes memory value) = map._inner.at(index); return (address(uint160(uint256(key))), value); } /** * @dev Tries to return the value associated with `key`. Does not revert if `key` is not in the map. * @param map The map to retrieve the value from * @param key The key to retrieve the value for * @return bool indicating whether the key was in the map * @return bytes The value associated with the key */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function tryGet(AddressToBytesMap storage map, address key) internal view returns (bool, bytes memory) { return map._inner.tryGet(bytes32(uint256(uint160(key)))); } /** * @dev Returns the value associated with `key`. * @param map The map to retrieve the value from * @param key The key to retrieve the value for * @return bytes The value associated with the key */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function get(AddressToBytesMap storage map, address key) internal view returns (bytes memory) { return map._inner.get(bytes32(uint256(uint160(key)))); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol"; import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol"; import {Client} from "./libraries/Client.sol"; import {RateLimiter} from "./libraries/RateLimiter.sol"; import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol"; /// @notice The aggregate rate limiter is a wrapper of the token bucket rate limiter /// which permits rate limiting based on the aggregate value of a group of /// token transfers, using a price registry to convert to a numeraire asset (e.g. USD). contract AggregateRateLimiter is OwnerIsCreator { using RateLimiter for RateLimiter.TokenBucket; using USDPriceWith18Decimals for uint224; error PriceNotFoundForToken(address token); event AdminSet(address newAdmin); // The address of the token limit admin that has the same permissions as the owner. address internal s_admin; // The token bucket object that contains the bucket state. RateLimiter.TokenBucket private s_rateLimiter; /// @param config The RateLimiter.Config constructor(RateLimiter.Config memory config) { s_rateLimiter = RateLimiter.TokenBucket({ rate: config.rate, capacity: config.capacity, tokens: config.capacity, lastUpdated: uint32(block.timestamp), isEnabled: config.isEnabled }); } /// @notice Consumes value from the rate limiter bucket based on the token value given. function _rateLimitValue(uint256 value) internal { s_rateLimiter._consume(value, address(0)); } function _getTokenValue( Client.EVMTokenAmount memory tokenAmount, IPriceRegistry priceRegistry ) internal view returns (uint256) { // not fetching validated price, as price staleness is not important for value-based rate limiting // we only need to verify the price is not 0 uint224 pricePerToken = priceRegistry.getTokenPrice(tokenAmount.token).value; if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmount.token); return pricePerToken._calcUSDValueFromTokenAmount(tokenAmount.amount); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function currentRateLimiterState() external view returns (RateLimiter.TokenBucket memory) { return s_rateLimiter._currentTokenBucketState(); } /// @notice Sets the rate limited config. /// @param config The new rate limiter config. /// @dev should only be callable by the owner or token limit admin. function setRateLimiterConfig(RateLimiter.Config memory config) external onlyAdminOrOwner { s_rateLimiter._setTokenBucketConfig(config); } // ================================================================ // │ Access │ // ================================================================ /// @notice Gets the token limit admin address. /// @return the token limit admin address. function getTokenLimitAdmin() external view returns (address) { return s_admin; } /// @notice Sets the token limit admin address. /// @param newAdmin the address of the new admin. /// @dev setting this to address(0) indicates there is no active admin. function setAdmin(address newAdmin) external onlyAdminOrOwner { s_admin = newAdmin; emit AdminSet(newAdmin); } /// @notice a modifier that allows the owner or the s_tokenLimitAdmin call the functions /// it is applied to. modifier onlyAdminOrOwner() { if (msg.sender != owner() && msg.sender != s_admin) revert RateLimiter.OnlyCallableByAdminOrOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // End consumer library. library Client { /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct EVMTokenAmount { address token; // token address on the local chain. uint256 amount; // Amount of tokens. } struct Any2EVMMessage { bytes32 messageId; // MessageId corresponding to ccipSend on source. uint64 sourceChainSelector; // Source chain selector. bytes sender; // abi.decode(sender) if coming from an EVM chain. bytes data; // payload sent in original message. EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation. } // If extraArgs is empty bytes, the default is 200k gas limit. struct EVM2AnyMessage { bytes receiver; // abi.encode(receiver address) for dest EVM chains bytes data; // Data payload EVMTokenAmount[] tokenAmounts; // Token transfers address feeToken; // Address of feeToken. address(0) means you will send msg.value. bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2) } // bytes4(keccak256("CCIP EVMExtraArgsV1")); bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9; struct EVMExtraArgsV1 { uint256 gasLimit; } function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs); } // bytes4(keccak256("CCIP EVMExtraArgsV2")); bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10; /// @param gasLimit: gas limit for the callback on the destination chain. /// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender. /// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value /// is not set, the message request will revert. struct EVMExtraArgsV2 { uint256 gasLimit; bool allowOutOfOrderExecution; } function _argsToBytes(EVMExtraArgsV2 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol"; import {Client} from "./Client.sol"; // Library for CCIP internal definitions common to multiple contracts. library Internal { error InvalidEVMAddress(bytes encodedAddress); /// @dev The minimum amount of gas to perform the call with exact gas. /// We include this in the offramp so that we can redeploy to adjust it /// should a hardfork change the gas costs of relevant opcodes in callWithExactGas. uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5_000; // @dev We limit return data to a selector plus 4 words. This is to avoid // malicious contracts from returning large amounts of data and causing // repeated out-of-gas scenarios. uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32; /// @dev The expected number of bytes returned by the balanceOf function. uint256 internal constant MAX_BALANCE_OF_RET_BYTES = 32; /// @notice A collection of token price and gas price updates. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct PriceUpdates { TokenPriceUpdate[] tokenPriceUpdates; GasPriceUpdate[] gasPriceUpdates; } /// @notice Token price in USD. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct TokenPriceUpdate { address sourceToken; // Source token uint224 usdPerToken; // 1e18 USD per 1e18 of the smallest token denomination. } /// @notice Gas price for a given chain in USD, its value may contain tightly packed fields. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct GasPriceUpdate { uint64 destChainSelector; // Destination chain selector uint224 usdPerUnitGas; // 1e18 USD per smallest unit (e.g. wei) of destination chain gas } /// @notice A timestamped uint224 value that can contain several tightly packed fields. struct TimestampedPackedUint224 { uint224 value; // ───────╮ Value in uint224, packed. uint32 timestamp; // ────╯ Timestamp of the most recent price update. } /// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices. /// When packing L1 and L2 gas prices, L1 gas price is left-shifted to the higher-order bits. /// Using uint8 type, which cannot be higher than other bit shift operands, to avoid shift operand type warning. uint8 public constant GAS_PRICE_BITS = 112; struct PoolUpdate { address token; // The IERC20 token address address pool; // The token pool address } struct SourceTokenData { // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be // relied upon by the destination pool to validate the source pool. bytes sourcePoolAddress; // The address of the destination token, abi encoded in the case of EVM chains // This value is UNTRUSTED as any pool owner can return whatever value they want. bytes destTokenAddress; // Optional pool data to be transferred to the destination chain. Be default this is capped at // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead // has to be set for the specific token. bytes extraData; uint32 destGasAmount; // The amount of gas available for the releaseOrMint and balanceOf calls on the offRamp } /// @notice Report that is submitted by the execution DON at the execution phase. (including chain selector data) /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct ExecutionReportSingleChain { uint64 sourceChainSelector; // Source chain selector for which the report is submitted Any2EVMRampMessage[] messages; // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token bytes[][] offchainTokenData; bytes32[] proofs; uint256 proofFlagBits; } /// @notice Report that is submitted by the execution DON at the execution phase. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct ExecutionReport { EVM2EVMMessage[] messages; // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token bytes[][] offchainTokenData; bytes32[] proofs; uint256 proofFlagBits; } /// @notice The cross chain message that gets committed to EVM chains. /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers. struct EVM2EVMMessage { uint64 sourceChainSelector; // ────────╮ the chain selector of the source chain, note: not chainId address sender; // ────────────────────╯ sender address on the source chain address receiver; // ──────────────────╮ receiver address on the destination chain uint64 sequenceNumber; // ─────────────╯ sequence number, not unique across lanes uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution bool strict; // ───────────────────────╮ DEPRECATED uint64 nonce; // │ nonce for this lane for this sender, not unique across senders/lanes address feeToken; // ──────────────────╯ fee token uint256 feeTokenAmount; // fee token amount bytes data; // arbitrary data payload supplied by the message sender Client.EVMTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer bytes[] sourceTokenData; // array of token data, one per token bytes32 messageId; // a hash of the message data } /// @dev EVM2EVMMessage struct has 13 fields, including 3 variable arrays. /// Each variable array takes 1 more slot to store its length. /// When abi encoded, excluding array contents, /// EVM2EVMMessage takes up a fixed number of 16 lots, 32 bytes each. /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 17. uint256 public constant MESSAGE_FIXED_BYTES = 32 * 17; /// @dev Each token transfer adds 1 EVMTokenAmount and 3 bytes at 3 slots each and one slot for the destGasAmount. /// When abi encoded, each EVMTokenAmount takes 2 slots, each bytes takes 1 slot for length, one slot of data and one /// slot for the offset. This results in effectively 3*3 slots per SourceTokenData. /// 0x20 /// destGasAmount /// sourcePoolAddress_offset /// destTokenAddress_offset /// extraData_offset /// sourcePoolAddress_length /// sourcePoolAddress_content // assume 1 slot /// destTokenAddress_length /// destTokenAddress_content // assume 1 slot /// extraData_length // contents billed separately uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * ((1 + 3 * 3) + 2); /// @dev Any2EVMRampMessage struct has 10 fields, including 3 variable unnested arrays (data, receiver and tokenAmounts). /// Each variable array takes 1 more slot to store its length. /// When abi encoded, excluding array contents, /// Any2EVMMessage takes up a fixed number of 13 slots, 32 bytes each. /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 14. /// The fixed bytes does not cover struct data (this is represented by ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN) uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES = 32 * 14; /// @dev Each token transfer adds 1 RampTokenAmount /// RampTokenAmount has 4 fields, including 3 bytes. /// Each bytes takes 1 more slot to store its length, and one slot to store the offset. /// When abi encoded, each token transfer takes up 10 slots, excl bytes contents. uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * 10; bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageHashV2"); /// @dev Used to hash messages for single-lane ramps. /// OnRamp hash(EVM2EVMMessage) = OffRamp hash(EVM2EVMMessage) /// The EVM2EVMMessage's messageId is expected to be the output of this hash function /// @param original Message to hash /// @param metadataHash Immutable metadata hash representing a lane with a fixed OnRamp /// @return hashedMessage hashed message as a keccak256 function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) { // Fixed-size message fields are included in nested hash to reduce stack pressure. // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers. return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, metadataHash, keccak256( abi.encode( original.sender, original.receiver, original.sequenceNumber, original.gasLimit, original.strict, original.nonce, original.feeToken, original.feeTokenAmount ) ), keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)), keccak256(abi.encode(original.sourceTokenData)) ) ); } bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256("Any2EVMMessageHashV1"); bytes32 internal constant EVM_2_ANY_MESSAGE_HASH = keccak256("EVM2AnyMessageHashV1"); /// @dev Used to hash messages for multi-lane family-agnostic OffRamps. /// OnRamp hash(EVM2AnyMessage) != Any2EVMRampMessage.messageId /// OnRamp hash(EVM2AnyMessage) != OffRamp hash(Any2EVMRampMessage) /// @param original OffRamp message to hash /// @param onRamp OnRamp to hash the message with - used to compute the metadataHash /// @return hashedMessage hashed message as a keccak256 function _hash(Any2EVMRampMessage memory original, bytes memory onRamp) internal pure returns (bytes32) { // Fixed-size message fields are included in nested hash to reduce stack pressure. // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers. return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, // Implicit metadata hash keccak256( abi.encode( ANY_2_EVM_MESSAGE_HASH, original.header.sourceChainSelector, original.header.destChainSelector, onRamp ) ), keccak256( abi.encode( original.header.messageId, original.sender, original.receiver, original.header.sequenceNumber, original.gasLimit, original.header.nonce ) ), keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)) ) ); } function _hash(EVM2AnyRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) { // Fixed-size message fields are included in nested hash to reduce stack pressure. // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers. return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, metadataHash, keccak256( abi.encode( original.sender, original.receiver, original.header.sequenceNumber, original.header.nonce, original.feeToken, original.feeTokenAmount ) ), keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)), keccak256(original.extraArgs) ) ); } /// @dev We disallow the first 1024 addresses to avoid calling into a range known for hosting precompiles. Calling /// into precompiles probably won't cause any issues, but to be safe we can disallow this range. It is extremely /// unlikely that anyone would ever be able to generate an address in this range. There is no official range of /// precompiles, but EIP-7587 proposes to reserve the range 0x100 to 0x1ff. Our range is more conservative, even /// though it might not be exhaustive for all chains, which is OK. We also disallow the zero address, which is a /// common practice. uint256 public constant PRECOMPILE_SPACE = 1024; /// @notice This methods provides validation for parsing abi encoded addresses by ensuring the /// address is within the EVM address space. If it isn't it will revert with an InvalidEVMAddress error, which /// we can catch and handle more gracefully than a revert from abi.decode. /// @return The address if it is valid, the function will revert otherwise. function _validateEVMAddress(bytes memory encodedAddress) internal pure returns (address) { if (encodedAddress.length != 32) revert InvalidEVMAddress(encodedAddress); uint256 encodedAddressUint = abi.decode(encodedAddress, (uint256)); if (encodedAddressUint > type(uint160).max || encodedAddressUint < PRECOMPILE_SPACE) { revert InvalidEVMAddress(encodedAddress); } return address(uint160(encodedAddressUint)); } /// @notice Enum listing the possible message execution states within /// the offRamp contract. /// UNTOUCHED never executed /// IN_PROGRESS currently being executed, used a replay protection /// SUCCESS successfully executed. End state /// FAILURE unsuccessfully executed, manual execution is now enabled. /// @dev RMN depends on this enum, if changing, please notify the RMN maintainers. enum MessageExecutionState { UNTOUCHED, IN_PROGRESS, SUCCESS, FAILURE } /// @notice CCIP OCR plugin type, used to separate execution & commit transmissions and configs enum OCRPluginType { Commit, Execution } /// @notice Family-agnostic token amounts used for both OnRamp & OffRamp messages struct RampTokenAmount { // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be // relied upon by the destination pool to validate the source pool. bytes sourcePoolAddress; // The address of the destination token, abi encoded in the case of EVM chains // This value is UNTRUSTED as any pool owner can return whatever value they want. bytes destTokenAddress; // Optional pool data to be transferred to the destination chain. Be default this is capped at // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead // has to be set for the specific token. bytes extraData; uint256 amount; // Amount of tokens. } /// @notice Family-agnostic header for OnRamp & OffRamp messages. /// The messageId is not expected to match hash(message), since it may originate from another ramp family struct RampMessageHeader { bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded) uint64 sourceChainSelector; // ──╮ the chain selector of the source chain, note: not chainId uint64 destChainSelector; // | the chain selector of the destination chain, note: not chainId uint64 sequenceNumber; // │ sequence number, not unique across lanes uint64 nonce; // ────────────────╯ nonce for this lane for this sender, not unique across senders/lanes } /// @notice Family-agnostic message routed to an OffRamp /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage), hash(Any2EVMRampMessage) != messageId /// due to encoding & parameter differences struct Any2EVMRampMessage { RampMessageHeader header; // Message header bytes sender; // sender address on the source chain bytes data; // arbitrary data payload supplied by the message sender address receiver; // receiver address on the destination chain uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution RampTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer } /// @notice Family-agnostic message emitted from the OnRamp /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage) due to encoding & parameter differences /// messageId = hash(EVM2AnyRampMessage) using the source EVM chain's encoding format struct EVM2AnyRampMessage { RampMessageHeader header; // Message header address sender; // sender address on the source chain bytes data; // arbitrary data payload supplied by the message sender bytes receiver; // receiver address on the destination chain bytes extraArgs; // destination-chain specific extra args, such as the gasLimit for EVM chains address feeToken; // fee token uint256 feeTokenAmount; // fee token amount RampTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer } // bytes4(keccak256("CCIP ChainFamilySelector EVM")) bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice This library contains various token pool functions to aid constructing the return data. library Pool { // The tag used to signal support for the pool v1 standard // bytes4(keccak256("CCIP_POOL_V1")) bytes4 public constant CCIP_POOL_V1 = 0xaff2afbf; // The number of bytes in the return data for a pool v1 releaseOrMint call. // This should match the size of the ReleaseOrMintOutV1 struct. uint16 public constant CCIP_POOL_V1_RET_BYTES = 32; // The default max number of bytes in the return data for a pool v1 lockOrBurn call. // This data can be used to send information to the destination chain token pool. Can be overwritten // in the TokenTransferFeeConfig.destBytesOverhead if more data is required. uint32 public constant CCIP_LOCK_OR_BURN_V1_RET_BYTES = 32; struct LockOrBurnInV1 { bytes receiver; // The recipient of the tokens on the destination chain, abi encoded uint64 remoteChainSelector; // ─╮ The chain ID of the destination chain address originalSender; // ─────╯ The original sender of the tx on the source chain uint256 amount; // The amount of tokens to lock or burn, denominated in the source token's decimals address localToken; // The address on this chain of the token to lock or burn } struct LockOrBurnOutV1 { // The address of the destination token, abi encoded in the case of EVM chains // This value is UNTRUSTED as any pool owner can return whatever value they want. bytes destTokenAddress; // Optional pool data to be transferred to the destination chain. Be default this is capped at // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead // has to be set for the specific token. bytes destPoolData; } struct ReleaseOrMintInV1 { bytes originalSender; // The original sender of the tx on the source chain uint64 remoteChainSelector; // ─╮ The chain ID of the source chain address receiver; // ───────────╯ The recipient of the tokens on the destination chain. uint256 amount; // The amount of tokens to release or mint, denominated in the source token's decimals address localToken; // The address on this chain of the token to release or mint /// @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the /// expected pool address for the given remoteChainSelector. bytes sourcePoolAddress; // The address of the source pool, abi encoded in the case of EVM chains bytes sourcePoolData; // The data received from the source pool to process the release or mint /// @dev WARNING: offchainTokenData is untrusted data. bytes offchainTokenData; // The offchain data to process the release or mint } struct ReleaseOrMintOutV1 { // The number of tokens released or minted on the destination chain, denominated in the local token's decimals. // This value is expected to be equal to the ReleaseOrMintInV1.amount in the case where the source and destination // chain have the same number of decimals. uint256 destinationAmount; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// @notice Implements Token Bucket rate limiting. /// @dev uint128 is safe for rate limiter state. /// For USD value rate limiting, it can adequately store USD value in 18 decimals. /// For ERC20 token amount rate limiting, all tokens that will be listed will have at most /// a supply of uint128.max tokens, and it will therefore not overflow the bucket. /// In exceptional scenarios where tokens consumed may be larger than uint128, /// e.g. compromised issuer, an enabled RateLimiter will check and revert. library RateLimiter { error BucketOverfilled(); error OnlyCallableByAdminOrOwner(); error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress); error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress); error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested); error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available); error InvalidRateLimitRate(Config rateLimiterConfig); error DisabledNonZeroRateLimit(Config config); error RateLimitMustBeDisabled(); event TokensConsumed(uint256 tokens); event ConfigChanged(Config config); struct TokenBucket { uint128 tokens; // ──────╮ Current number of tokens that are in the bucket. uint32 lastUpdated; // │ Timestamp in seconds of the last token refill, good for 100+ years. bool isEnabled; // ──────╯ Indication whether the rate limiting is enabled or not uint128 capacity; // ────╮ Maximum number of tokens that can be in the bucket. uint128 rate; // ────────╯ Number of tokens per second that the bucket is refilled. } struct Config { bool isEnabled; // Indication whether the rate limiting should be enabled uint128 capacity; // ────╮ Specifies the capacity of the rate limiter uint128 rate; // ───────╯ Specifies the rate of the rate limiter } /// @notice _consume removes the given tokens from the pool, lowering the /// rate tokens allowed to be consumed for subsequent calls. /// @param requestTokens The total tokens to be consumed from the bucket. /// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity. /// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket /// @dev emits removal of requestTokens if requestTokens is > 0 function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal { // If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage if (!s_bucket.isEnabled || requestTokens == 0) { return; } uint256 tokens = s_bucket.tokens; uint256 capacity = s_bucket.capacity; uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { if (tokens > capacity) revert BucketOverfilled(); // Refill tokens when arriving at a new block time tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate); s_bucket.lastUpdated = uint32(block.timestamp); } if (capacity < requestTokens) { // Token address 0 indicates consuming aggregate value rate limit capacity. if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens); revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress); } if (tokens < requestTokens) { uint256 rate = s_bucket.rate; // Wait required until the bucket is refilled enough to accept this value, round up to next higher second // Consume is not guaranteed to succeed after wait time passes if there is competing traffic. // This acts as a lower bound of wait time. uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate; if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens); revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress); } tokens -= requestTokens; // Downcast is safe here, as tokens is not larger than capacity s_bucket.tokens = uint128(tokens); emit TokensConsumed(requestTokens); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function _currentTokenBucketState(TokenBucket memory bucket) internal view returns (TokenBucket memory) { // We update the bucket to reflect the status at the exact time of the // call. This means we might need to refill a part of the bucket based // on the time that has passed since the last update. bucket.tokens = uint128(_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate)); bucket.lastUpdated = uint32(block.timestamp); return bucket; } /// @notice Sets the rate limited config. /// @param s_bucket The token bucket /// @param config The new config function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal { // First update the bucket to make sure the proper rate is used for all the time // up until the config change. uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate)); s_bucket.lastUpdated = uint32(block.timestamp); } s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens)); s_bucket.isEnabled = config.isEnabled; s_bucket.capacity = config.capacity; s_bucket.rate = config.rate; emit ConfigChanged(config); } /// @notice Validates the token bucket config function _validateTokenBucketConfig(Config memory config, bool mustBeDisabled) internal pure { if (config.isEnabled) { if (config.rate >= config.capacity || config.rate == 0) { revert InvalidRateLimitRate(config); } if (mustBeDisabled) { revert RateLimitMustBeDisabled(); } } else { if (config.rate != 0 || config.capacity != 0) { revert DisabledNonZeroRateLimit(config); } } } /// @notice Calculate refilled tokens /// @param capacity bucket capacity /// @param tokens current bucket tokens /// @param timeDiff block time difference since last refill /// @param rate bucket refill rate /// @return the value of tokens after refill function _calculateRefill( uint256 capacity, uint256 tokens, uint256 timeDiff, uint256 rate ) private pure returns (uint256) { return _min(capacity, tokens + timeDiff * rate); } /// @notice Return the smallest of two integers /// @param a first int /// @param b second int /// @return smallest function _min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol"; import {OCR2Abstract} from "./OCR2Abstract.sol"; /// @notice Onchain verification of reports from the offchain reporting protocol /// @dev For details on its operation, see the offchain reporting protocol design /// doc, which refers to this contract as simply the "contract". /// @dev This contract does ***NOT*** check the supplied signatures on `transmit` /// This is intentional. abstract contract OCR2BaseNoChecks is OwnerIsCreator, OCR2Abstract { error InvalidConfig(InvalidConfigErrorType errorType); error WrongMessageLength(uint256 expected, uint256 actual); error ConfigDigestMismatch(bytes32 expected, bytes32 actual); error ForkedChain(uint256 expected, uint256 actual); error UnauthorizedTransmitter(); error OracleCannotBeZeroAddress(); enum InvalidConfigErrorType { F_MUST_BE_POSITIVE, TOO_MANY_TRANSMITTERS, REPEATED_ORACLE_ADDRESS } // Packing these fields used on the hot path in a ConfigInfo variable reduces the // retrieval of all of them to a minimum number of SLOADs. struct ConfigInfo { bytes32 latestConfigDigest; uint8 f; uint8 n; } // Used for s_oracles[a].role, where a is an address, to track the purpose // of the address, or to indicate that the address is unset. enum Role { // No oracle role has been set for address a Unset, // Unused Signer, // Transmission address for the s_oracles[a].index'th oracle. I.e., if a // report is received by OCR2Aggregator.transmit in which msg.sender is // a, it is attributed to the s_oracles[a].index'th oracle. Transmitter } struct Oracle { uint8 index; // Index of oracle in s_transmitters Role role; // Role of the address which mapped to this struct } // The current config ConfigInfo internal s_configInfo; // incremented each time a new config is posted. This count is incorporated // into the config digest, to prevent replay attacks. uint32 internal s_configCount; // makes it easier for offchain systems to extract config from logs. uint32 internal s_latestConfigBlockNumber; // Transmitter address mapping(address transmitter => Oracle oracle) internal s_oracles; // s_transmitters contains the transmission address of each oracle, // i.e. the address the oracle actually sends transactions to the contract from address[] internal s_transmitters; // The constant-length components of the msg.data sent to transmit. // See the "If we wanted to call sam" example on for example reasoning // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = 4 // function selector + 32 * 3 // 3 words containing reportContext + 32 // word containing start location of abiencoded report value + 32 // word containing location start of abiencoded rs value + 32 // word containing start location of abiencoded ss value + 32 // rawVs value + 32 // word containing length of report + 32 // word containing length rs + 32; // word containing length of ss uint256 internal immutable i_chainID; // Reverts transaction if config args are invalid modifier checkConfigValid(uint256 numTransmitters, uint256 f) { if (numTransmitters > MAX_NUM_ORACLES) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_TRANSMITTERS); if (f == 0) revert InvalidConfig(InvalidConfigErrorType.F_MUST_BE_POSITIVE); _; } constructor() { i_chainID = block.chainid; } /// @notice sets offchain reporting protocol configuration incl. participating oracles /// @param signers addresses with which oracles sign the reports /// @param transmitters addresses oracles use to transmit the reports /// @param f number of faulty oracles the system can tolerate /// @param onchainConfig encoded on-chain contract configuration /// @param offchainConfigVersion version number for offchainEncoding schema /// @param offchainConfig encoded off-chain oracle configuration function setOCR2Config( address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) external override checkConfigValid(transmitters.length, f) onlyOwner { _beforeSetConfig(onchainConfig); // Scoped to reduce contract size { uint256 oldTransmitterLength = s_transmitters.length; for (uint256 i = 0; i < oldTransmitterLength; ++i) { delete s_oracles[s_transmitters[i]]; } } uint256 newTransmitterLength = transmitters.length; for (uint256 i = 0; i < newTransmitterLength; ++i) { address transmitter = transmitters[i]; if (s_oracles[transmitter].role != Role.Unset) { revert InvalidConfig(InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS); } if (transmitter == address(0)) revert OracleCannotBeZeroAddress(); s_oracles[transmitter] = Oracle(uint8(i), Role.Transmitter); } s_transmitters = transmitters; s_configInfo.f = f; s_configInfo.n = uint8(newTransmitterLength); s_configInfo.latestConfigDigest = _configDigestFromConfigData( block.chainid, address(this), ++s_configCount, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig ); uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; s_latestConfigBlockNumber = uint32(block.number); emit ConfigSet( previousConfigBlockNumber, s_configInfo.latestConfigDigest, s_configCount, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig ); } /// @dev Hook that is run from setOCR2Config() right after validating configuration. /// Empty by default, please provide an implementation in a child contract if you need additional configuration processing function _beforeSetConfig(bytes memory _onchainConfig) internal virtual; /// @return list of addresses permitted to transmit reports to this contract /// @dev The list will match the order used to specify the transmitter during setConfig function getTransmitters() external view returns (address[] memory) { return s_transmitters; } /// @notice transmit is called to post a new report to the contract /// @param report serialized report, which the signatures are signing. /// @param rs ith element is the R components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly bytes32[3] calldata reportContext, bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 // signatures ) external override { _report(report); // reportContext consists of: // reportContext[0]: ConfigDigest // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round // reportContext[2]: ExtraHash bytes32 configDigest = reportContext[0]; bytes32 latestConfigDigest = s_configInfo.latestConfigDigest; if (latestConfigDigest != configDigest) revert ConfigDigestMismatch(latestConfigDigest, configDigest); _checkChainForked(); emit Transmitted(configDigest, uint32(uint256(reportContext[1]) >> 8)); // Scoping this reduces stack pressure and gas usage { Oracle memory transmitter = s_oracles[msg.sender]; // Check that sender is authorized to report if (!(transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index])) { revert UnauthorizedTransmitter(); } } uint256 expectedDataLength = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) + report.length // one byte pure entry in _report + rs.length * 32 // 32 bytes per entry in _rs + ss.length * 32; // 32 bytes per entry in _ss) if (msg.data.length != expectedDataLength) revert WrongMessageLength(expectedDataLength, msg.data.length); } function _checkChainForked() internal view { // If the cached chainID at time of deployment doesn't match the current chainID, we reject all signed reports. // This avoids a (rare) scenario where chain A forks into chain A and A', A' still has configDigest // calculated from chain A and so OCR reports will be valid on both forks. if (i_chainID != block.chainid) revert ForkedChain(i_chainID, block.chainid); } /// @notice information about current offchain reporting protocol configuration /// @return configCount ordinal number of current config, out of all configs applied to this contract so far /// @return blockNumber block at which this config was set /// @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) function latestConfigDetails() external view override returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) { return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); } /// @inheritdoc OCR2Abstract function latestConfigDigestAndEpoch() external view virtual override returns (bool scanLogs, bytes32 configDigest, uint32 epoch) { return (true, bytes32(0), uint32(0)); } function _report(bytes calldata report) internal virtual; }
// 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 v5.0.0) (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface. */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. */ function getSupportedInterfaces( address account, bytes4[] memory interfaceIds ) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * * Some precompiled contracts will falsely indicate support for a given interface, so caution * should be exercised when using this function. * * Interface identification is specified in ERC-165. */ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { // prepare call bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId)); // perform static call bool success; uint256 returnSize; uint256 returnValue; assembly { success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) returnSize := returndatasize() returnValue := mload(0x00) } return success && returnSize >= 0x20 && returnValue > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated 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 /* solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore */ pragma solidity ^0.8.0; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/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 EnumerableMapBytes32 for EnumerableMapBytes32.Bytes32ToBytesMap; * * // Declare a set state variable * EnumerableMapBytes32.Bytes32ToBytesMap private myMap; * } * ``` * * The following map types are supported: * * - `bytes32 -> bytes` (`Bytes32ToBytes`) * * [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 up an EnumerableMapBytes32, you should remove all elements one by one. * ==== */ library EnumerableMapBytes32 { using EnumerableSet for EnumerableSet.Bytes32Set; error NonexistentKeyError(); struct Bytes32ToBytesMap { EnumerableSet.Bytes32Set _keys; mapping(bytes32 => bytes) _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. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function set(Bytes32ToBytesMap storage map, bytes32 key, bytes memory 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. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function remove(Bytes32ToBytesMap 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). */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function contains(Bytes32ToBytesMap 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). */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function length(Bytes32ToBytesMap 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}. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function at(Bytes32ToBytesMap storage map, uint256 index) internal view returns (bytes32, bytes memory) { 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. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function tryGet(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bool, bytes memory) { bytes memory value = map._values[key]; if (value.length == 0) { return (contains(map, key), bytes("")); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function get(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bytes memory) { bytes memory value = map._values[key]; if (value.length == 0 && !contains(map, key)) { revert NonexistentKeyError(); } return value; } }
// 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 USDPriceWith18Decimals { /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount, /// and amount of the smallest token denomination, /// calculates the value in USD with 18 decimals. /// @param tokenPrice The USD price of the token. /// @param tokenAmount Amount of the smallest token denomination. /// @return USD value with 18 decimals. /// @dev this function assumes that no more than 1e59 US dollar worth of token is passed in. /// If more is sent, this function will overflow and revert. /// Since there isn't even close to 1e59 dollars, this is ok for all legit tokens. function _calcUSDValueFromTokenAmount(uint224 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) { /// LINK Example: /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals /// tokenAmount: 2e18 -> 2 LINK /// result: 8e18 * 2e18 / 1e18 -> 16e18 with 18 decimals = $16 /// USDC Example: /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals /// tokenAmount: 5e6 -> 5 USDC /// result: 1e30 * 5e6 / 1e18 -> 5e18 with 18 decimals = $5 return (tokenPrice * tokenAmount) / 1e18; } /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount, /// and USD value with 18 decimals, /// calculates amount of the smallest token denomination. /// @param tokenPrice The USD price of the token. /// @param usdValue USD value with 18 decimals. /// @return Amount of the smallest token denomination. function _calcTokenAmountFromUSDValue(uint224 tokenPrice, uint256 usdValue) internal pure returns (uint256) { /// LINK Example: /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals /// usdValue: 16e18 -> $16 /// result: 16e18 * 1e18 / 8e18 -> 2e18 = 2 LINK /// USDC Example: /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals /// usdValue: 5e18 -> $5 /// result: 5e18 * 1e18 / 1e30 -> 5e6 = 5 USDC return (usdValue * 1e18) / tokenPrice; } }
// SPDX-License-Identifier: 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: BUSL-1.1 pragma solidity ^0.8.0; import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; abstract contract OCR2Abstract is ITypeAndVersion { // Maximum number of oracles the offchain reporting protocol is designed for uint256 internal constant MAX_NUM_ORACLES = 31; /// @notice triggers a new run of the offchain reporting protocol /// @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis /// @param configDigest configDigest of this configuration /// @param configCount ordinal number of this config setting among all config settings over the life of this contract /// @param signers ith element is address ith oracle uses to sign a report /// @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method /// @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly /// @param onchainConfig serialized configuration used by the contract (and possibly oracles) /// @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter /// @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract event ConfigSet( uint32 previousConfigBlockNumber, bytes32 configDigest, uint64 configCount, address[] signers, address[] transmitters, uint8 f, bytes onchainConfig, uint64 offchainConfigVersion, bytes offchainConfig ); /// @notice sets offchain reporting protocol configuration incl. participating oracles /// @param signers addresses with which oracles sign the reports /// @param transmitters addresses oracles use to transmit the reports /// @param f number of faulty oracles the system can tolerate /// @param onchainConfig serialized configuration used by the contract (and possibly oracles) /// @param offchainConfigVersion version number for offchainEncoding schema /// @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract function setOCR2Config( address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) external virtual; /// @notice information about current offchain reporting protocol configuration /// @return configCount ordinal number of current config, out of all configs applied to this contract so far /// @return blockNumber block at which this config was set /// @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) function latestConfigDetails() external view virtual returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); function _configDigestFromConfigData( uint256 chainId, address contractAddress, uint64 configCount, address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) internal pure returns (bytes32) { uint256 h = uint256( keccak256( abi.encode( chainId, contractAddress, configCount, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig ) ) ); uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 return bytes32((prefix & prefixMask) | (h & ~prefixMask)); } /// @notice optionally emitted to indicate the latest configDigest and epoch for /// which a report was successfully transmitted. Alternatively, the contract may /// use latestConfigDigestAndEpoch with scanLogs set to false. event Transmitted(bytes32 configDigest, uint32 epoch); /// @notice optionally returns the latest configDigest and epoch for which a /// report was successfully transmitted. Alternatively, the contract may return /// scanLogs set to true and use Transmitted events to provide this information /// to offchain watchers. /// @return scanLogs indicates whether to rely on the configDigest and epoch /// returned or whether to scan logs for the Transmitted event instead. /// @return configDigest /// @return epoch function latestConfigDigestAndEpoch() external view virtual returns (bool scanLogs, bytes32 configDigest, uint32 epoch); /// @notice transmit is called to post a new report to the contract /// @param report serialized report, which the signatures are signing. /// @param rs ith element is the R components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries /// @param rawVs ith element is the the V component of the ith signature function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly bytes32[3] calldata reportContext, bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs // signatures ) external virtual; }
// 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 pragma solidity ^0.8.0; import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol"; /// @title The ConfirmedOwner contract /// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwner is ConfirmedOwnerWithProposal { constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IOwnable} from "../interfaces/IOwnable.sol"; /// @title The ConfirmedOwner contract /// @notice A contract with helpers for basic contract ownership. contract ConfirmedOwnerWithProposal is IOwnable { address private s_owner; address private s_pendingOwner; event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); constructor(address newOwner, address pendingOwner) { // solhint-disable-next-line gas-custom-errors require(newOwner != address(0), "Cannot set owner to zero"); s_owner = newOwner; if (pendingOwner != address(0)) { _transferOwnership(pendingOwner); } } /// @notice Allows an owner to begin transferring ownership to a new address. function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } /// @notice Allows an ownership transfer to be completed by the recipient. function acceptOwnership() external override { // solhint-disable-next-line gas-custom-errors require(msg.sender == s_pendingOwner, "Must be proposed owner"); address oldOwner = s_owner; s_owner = msg.sender; s_pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /// @notice Get the current owner function owner() public view override returns (address) { return s_owner; } /// @notice validate, transfer ownership, and emit relevant events function _transferOwnership(address to) private { // solhint-disable-next-line gas-custom-errors require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /// @notice validate access function _validateOwnership() internal view { // solhint-disable-next-line gas-custom-errors require(msg.sender == s_owner, "Only callable by owner"); } /// @notice Reverts if called by anyone other than the contract owner. modifier onlyOwner() { _validateOwnership(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOwnable { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; }
{ "remappings": [ "forge-std/=src/v0.8/vendor/forge-std/src/", "@openzeppelin/=node_modules/@openzeppelin/", "@arbitrum/=node_modules/@arbitrum/", "hardhat/=node_modules/hardhat/", "@eth-optimism/=node_modules/@eth-optimism/", "@scroll-tech/=node_modules/@scroll-tech/", "@offchainlabs/=node_modules/@offchainlabs/" ], "optimizer": { "enabled": true, "runs": 18000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
[{"inputs":[{"components":[{"internalType":"address","name":"commitStore","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"onRamp","type":"address"},{"internalType":"address","name":"prevOffRamp","type":"address"},{"internalType":"address","name":"rmnProxy","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"}],"internalType":"struct EVM2EVMOffRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"AggregateValueMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"AggregateValueRateLimitReached","type":"error"},{"inputs":[],"name":"BucketOverfilled","type":"error"},{"inputs":[],"name":"CanOnlySelfCall","type":"error"},{"inputs":[],"name":"CommitStoreAlreadyInUse","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"CursedByRMN","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"DestinationGasAmountCountMismatch","type":"error"},{"inputs":[],"name":"EmptyReport","type":"error"},{"inputs":[{"internalType":"bytes","name":"err","type":"bytes"}],"name":"ExecutionError","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"ForkedChain","type":"error"},{"inputs":[{"internalType":"enum OCR2BaseNoChecks.InvalidConfigErrorType","name":"errorType","type":"uint8"}],"name":"InvalidConfig","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"got","type":"uint256"}],"name":"InvalidDataLength","type":"error"},{"inputs":[{"internalType":"bytes","name":"encodedAddress","type":"bytes"}],"name":"InvalidEVMAddress","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint256","name":"oldLimit","type":"uint256"},{"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"InvalidManualExecutionGasLimit","type":"error"},{"inputs":[],"name":"InvalidMessageId","type":"error"},{"inputs":[{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"enum Internal.MessageExecutionState","name":"newState","type":"uint8"}],"name":"InvalidNewState","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"InvalidSourceChain","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint256","name":"tokenIndex","type":"uint256"},{"internalType":"uint256","name":"oldLimit","type":"uint256"},{"internalType":"uint256","name":"tokenGasOverride","type":"uint256"}],"name":"InvalidTokenGasOverride","type":"error"},{"inputs":[],"name":"ManualExecutionGasLimitMismatch","type":"error"},{"inputs":[],"name":"ManualExecutionNotYetEnabled","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxSize","type":"uint256"},{"internalType":"uint256","name":"actualSize","type":"uint256"}],"name":"MessageTooLarge","type":"error"},{"inputs":[{"internalType":"address","name":"notPool","type":"address"}],"name":"NotACompatiblePool","type":"error"},{"inputs":[],"name":"OnlyCallableByAdminOrOwner","type":"error"},{"inputs":[],"name":"OracleCannotBeZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"PriceNotFoundForToken","type":"error"},{"inputs":[{"internalType":"bytes","name":"err","type":"bytes"}],"name":"ReceiverError","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountReleased","type":"uint256"},{"internalType":"uint256","name":"balancePre","type":"uint256"},{"internalType":"uint256","name":"balancePost","type":"uint256"}],"name":"ReleaseOrMintBalanceMismatch","type":"error"},{"inputs":[],"name":"RootNotCommitted","type":"error"},{"inputs":[{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"TokenDataMismatch","type":"error"},{"inputs":[{"internalType":"bytes","name":"err","type":"bytes"}],"name":"TokenHandlingError","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenRateLimitReached","type":"error"},{"inputs":[],"name":"UnauthorizedTransmitter","type":"error"},{"inputs":[],"name":"UnexpectedTokenData","type":"error"},{"inputs":[{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"UnsupportedNumberOfTokens","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"WrongMessageLength","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"AlreadyAttempted","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"ConfigChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"commitStore","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"onRamp","type":"address"},{"internalType":"address","name":"prevOffRamp","type":"address"},{"internalType":"address","name":"rmnProxy","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"}],"indexed":false,"internalType":"struct EVM2EVMOffRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"priceRegistry","type":"address"}],"indexed":false,"internalType":"struct EVM2EVMOffRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"enum Internal.MessageExecutionState","name":"state","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"ExecutionStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"SkippedAlreadyExecutedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"SkippedIncorrectNonce","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"SkippedSenderWithPreviousRampMessageInflight","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"}],"name":"TokenAggregateRateLimitAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"}],"name":"TokenAggregateRateLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"TokensConsumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","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":"destTokenAmounts","type":"tuple[]"}],"internalType":"struct Client.Any2EVMMessage","name":"","type":"tuple"}],"name":"ccipReceive","outputs":[],"stateMutability":"pure","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":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"strict","type":"bool"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"bytes[]","name":"sourceTokenData","type":"bytes[]"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"internalType":"struct Internal.EVM2EVMMessage","name":"message","type":"tuple"},{"internalType":"bytes[]","name":"offchainTokenData","type":"bytes[]"},{"internalType":"uint32[]","name":"tokenGasOverrides","type":"uint32[]"}],"name":"executeSingleMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllRateLimitTokens","outputs":[{"internalType":"address[]","name":"sourceTokens","type":"address[]"},{"internalType":"address[]","name":"destTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDynamicConfig","outputs":[{"components":[{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"priceRegistry","type":"address"}],"internalType":"struct EVM2EVMOffRamp.DynamicConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"getExecutionState","outputs":[{"internalType":"enum Internal.MessageExecutionState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"getSenderNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStaticConfig","outputs":[{"components":[{"internalType":"address","name":"commitStore","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"onRamp","type":"address"},{"internalType":"address","name":"prevOffRamp","type":"address"},{"internalType":"address","name":"rmnProxy","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"}],"internalType":"struct EVM2EVMOffRamp.StaticConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenLimitAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmitters","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"strict","type":"bool"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"bytes[]","name":"sourceTokenData","type":"bytes[]"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"internalType":"struct Internal.EVM2EVMMessage[]","name":"messages","type":"tuple[]"},{"internalType":"bytes[][]","name":"offchainTokenData","type":"bytes[][]"},{"internalType":"bytes32[]","name":"proofs","type":"bytes32[]"},{"internalType":"uint256","name":"proofFlagBits","type":"uint256"}],"internalType":"struct Internal.ExecutionReport","name":"report","type":"tuple"},{"components":[{"internalType":"uint256","name":"receiverExecutionGasLimit","type":"uint256"},{"internalType":"uint32[]","name":"tokenGasOverrides","type":"uint32[]"}],"internalType":"struct EVM2EVMOffRamp.GasLimitOverride[]","name":"gasLimitOverrides","type":"tuple[]"}],"name":"manuallyExecute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setOCR2Config","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":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"report","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sourceToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"}],"internalType":"struct EVM2EVMOffRamp.RateLimitToken[]","name":"removes","type":"tuple[]"},{"components":[{"internalType":"address","name":"sourceToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"}],"internalType":"struct EVM2EVMOffRamp.RateLimitToken[]","name":"adds","type":"tuple[]"}],"name":"updateRateLimitTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b506040516200660a3803806200660a8339810160408190526200003591620004ec565b8033806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c081620002ca565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606080870182905298909601519091166080948501819052600380546001600160a01b031916909217600160801b9485021760ff60a01b1916600160a01b90930292909217905502909117600455469052508201516001600160a01b031615806200016f575081516001600160a01b0316155b8062000186575060c08201516001600160a01b0316155b15620001a5576040516342bcdf7f60e11b815260040160405180910390fd5b81600001516001600160a01b0316634120fccd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001e8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020e9190620005b5565b6001600160401b03166001146200023857604051636fc2a20760e11b815260040160405180910390fd5b81516001600160a01b0390811660a090815260408401516001600160401b0390811660c0908152602086015190911660e05260608501518316610100526080850151831661014052908401518216610160528301511661018052620002bd7f8acd72527118c8324937b1a42e02cd246697c3b633f1742f3cae11de233722b362000375565b6101205250620005da9050565b336001600160a01b03821603620003245760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008160c05160e05161010051604051602001620003bf94939291909384526001600160401b039283166020850152911660408301526001600160a01b0316606082015260800190565b604051602081830303815290604052805190602001209050919050565b60405160e081016001600160401b03811182821017156200040d57634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b03811681146200042b57600080fd5b919050565b80516001600160401b03811681146200042b57600080fd5b80516001600160801b03811681146200042b57600080fd5b6000606082840312156200047357600080fd5b604051606081016001600160401b0381118282101715620004a457634e487b7160e01b600052604160045260246000fd5b806040525080915082518015158114620004bd57600080fd5b8152620004cd6020840162000448565b6020820152620004e06040840162000448565b60408201525092915050565b6000808284036101408112156200050257600080fd5b60e08112156200051157600080fd5b506200051c620003dc565b620005278462000413565b8152620005376020850162000430565b60208201526200054a6040850162000430565b60408201526200055d6060850162000413565b6060820152620005706080850162000413565b60808201526200058360a0850162000413565b60a08201526200059660c0850162000413565b60c08201529150620005ac8460e0850162000460565b90509250929050565b600060208284031215620005c857600080fd5b620005d38262000430565b9392505050565b60805160a05160c05160e0516101005161012051610140516101605161018051615f41620006c9600039600081816102ec01528181611c6a01526133920152600081816102bd01528181611c420152611f2701526000818161028e01528181610d8d01528181610df201528181611c18015281816124a4015261250e015260006120c601526000818161025f0152611bee0152600081816101ff0152611b9201526000818161022f01528181611bc601528181611ee40152818161303b01526134bf0152600081816101d001528181611b6d01526121ac015260008181611e3e0152611e8a0152615f416000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c806385572ffb116100d8578063afcb95d71161008c578063c92b283211610066578063c92b2832146105f3578063f077b59214610606578063f2fde38b1461061c57600080fd5b8063afcb95d7146105ad578063b1dc65a4146105cd578063b6113fce146105e057600080fd5b8063873504d7116100bd578063873504d7146105765780638926c4ee146105895780638da5cb5b1461059c57600080fd5b806385572ffb1461053c578063856c82471461054a57600080fd5b8063599f64311161013a5780637437ff9f116101145780637437ff9f1461046157806379ba50971461050457806381ff70481461050c57600080fd5b8063599f643114610414578063666cab8d14610439578063704b6c021461044e57600080fd5b8063181f5a771161016b578063181f5a77146103525780631ef381741461039b578063546719cd146103b057600080fd5b806306285c6914610187578063142a98fc14610332575b600080fd5b61031c6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b6040516103299190614312565b60405180910390f35b6103456103403660046143a8565b61062f565b6040516103299190614408565b61038e6040518060400160405280601481526020017f45564d3245564d4f666652616d7020312e352e3000000000000000000000000081525081565b6040516103299190614466565b6103ae6103a936600461468f565b6106aa565b005b6103b8610a9e565b604051610329919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6002546001600160a01b03165b6040516001600160a01b039091168152602001610329565b610441610b53565b60405161032991906147a1565b6103ae61045c3660046147b4565b610bb5565b6104f76040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a081018252600a5463ffffffff8082168352640100000000820416602083015268010000000000000000810461ffff16928201929092526a01000000000000000000009091046001600160a01b039081166060830152600b5416608082015290565b60405161032991906147d1565b6103ae610c7e565b6007546005546040805163ffffffff80851682526401000000009094049093166020840152820152606001610329565b6103ae610182366004614827565b61055d6105583660046147b4565b610d61565b60405167ffffffffffffffff9091168152602001610329565b6103ae6105843660046148f3565b610e64565b6103ae610597366004614e1e565b611037565b6000546001600160a01b0316610421565b604080516001815260006020820181905291810191909152606001610329565b6103ae6105db366004614f75565b61129c565b6103ae6105ee36600461505a565b6114a7565b6103ae610601366004615111565b6117e7565b61060e611852565b60405161032992919061517f565b6103ae61062a3660046147b4565b611978565b600061063d600160046151d3565b600261064a608085615215565b67ffffffffffffffff1661065e919061523c565b6010600061066d608087615253565b67ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002054901c1660038111156106a4576106a46143c5565b92915050565b84518460ff16601f8211156106f75760016040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016106ee919061527a565b60405180910390fd5b806000036107345760006040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016106ee919061527a565b61073c611989565b610745856119ff565b60095460005b818110156107bc57600860006009838154811061076a5761076a615294565b60009182526020808320909101546001600160a01b03168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560010161074b565b5050865160005b8181101561095f5760008982815181106107df576107df615294565b60200260200101519050600060028111156107fc576107fc6143c5565b6001600160a01b038216600090815260086020526040902054610100900460ff16600281111561082e5761082e6143c5565b146108685760026040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016106ee919061527a565b6001600160a01b0381166108a8576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff8316815260208101600290526001600160a01b03821660009081526008602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561094b5761094b6143c5565b0217905550905050508060010190506107c3565b5087516109739060099060208b0190614280565b506006805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908a1617179055600780546109f99146913091906000906109cb9063ffffffff166152c3565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168c8c8c8c8c8c611cc9565b6005819055600780544363ffffffff9081166401000000009081027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff841681179094556040519083048216947f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0594610a8a9487949293918316921691909117908f908f908f908f908f908f906152e6565b60405180910390a150505050505050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610b4e90611d56565b905090565b60606009805480602002602001604051908101604052809291908181526020018280548015610bab57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610b8d575b5050505050905090565b6000546001600160a01b03163314801590610bdb57506002546001600160a01b03163314155b15610c12576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c9060200160405180910390a150565b6001546001600160a01b03163314610cf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016106ee565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b0381166000908152600f602052604081205467ffffffffffffffff168082036106a4577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316156106a4576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015610e39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5d919061537c565b9392505050565b610e6c611989565b60005b8251811015610f3f57610ea9838281518110610e8d57610e8d615294565b602002602001015160200151600c611e0890919063ffffffff16565b15610f37577fcbf3cbeaed4ac1d605ed30f4af06c35acaeff2379db7f6146c9cceee83d58782838281518110610ee157610ee1615294565b602002602001015160000151848381518110610eff57610eff615294565b602002602001015160200151604051610f2e9291906001600160a01b0392831681529116602082015260400190565b60405180910390a15b600101610e6f565b5060005b815181101561103257610f9c828281518110610f6157610f61615294565b602002602001015160200151838381518110610f7f57610f7f615294565b602002602001015160000151600c611e1d9092919063ffffffff16565b1561102a577ffc23abf7ddbd3c02b1420dafa2355c56c1a06fbb8723862ac14d6bd74177361a828281518110610fd457610fd4615294565b602002602001015160000151838381518110610ff257610ff2615294565b6020026020010151602001516040516110219291906001600160a01b0392831681529116602082015260400190565b60405180910390a15b600101610f43565b505050565b61103f611e3b565b8151518151811461107c576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156112915760008460000151828151811061109f5761109f615294565b6020026020010151905060008483815181106110bd576110bd615294565b60209081029190910101518051909150801561112c57826080015181101561112c5761018083015160808401516040517f9c6db58d00000000000000000000000000000000000000000000000000000000815260048101929092526024820152604481018290526064016106ee565b816020015151836101400151511461118e5761018083015160608401516040517f85d2e5bf000000000000000000000000000000000000000000000000000000008152600481019290925267ffffffffffffffff1660248201526044016106ee565b61016083015160005b846101400151518110156112815760008287815181106111b9576111b9615294565b60200260200101518060200190518101906111d491906153de565b90506000856020015183815181106111ee576111ee615294565b602002602001015163ffffffff169050806000141580156112185750816060015163ffffffff1681105b156112775761018087015160608301516040517fef0c635200000000000000000000000000000000000000000000000000000000815260048101929092526024820185905263ffffffff166044820152606481018290526084016106ee565b5050600101611197565b505050505080600101905061107f565b506110328383611ebc565b6112a6878761290f565b6005548835908082146112ef576040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016106ee565b6112f7611e3b565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a13360009081526008602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561137f5761137f6143c5565b6002811115611390576113906143c5565b90525090506002816020015160028111156113ad576113ad6143c5565b1480156113e757506009816000015160ff16815481106113cf576113cf615294565b6000918252602090912001546001600160a01b031633145b61141d576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600061142b85602061523c565b61143688602061523c565b6114428b6101446154aa565b61144c91906154aa565b61145691906154aa565b905036811461149a576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016106ee565b5050505050505050505050565b3330146114e0576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516000808252602082019092528161151d565b60408051808201909152600080825260208201528152602001906001900390816114f65790505b50905060006115306101408701876154bd565b905011156115a7576115a46115496101408701876154bd565b6115596040890160208a016147b4565b604080516001600160a01b0390921660208301520160408051601f1981840301815291815261158e9060608b01908b016147b4565b61159c6101608b018b615525565b8a8a8a612966565b90505b6115b561012086018661558d565b15905080156115c657506080850135155b806115e857506115dc60608601604087016147b4565b6001600160a01b03163b155b8061163357506116317f85572ffb0000000000000000000000000000000000000000000000000000000061162260608801604089016147b4565b6001600160a01b031690612b8f565b155b1561163e57506117e1565b600a546040805160a08101909152610180870135815260009182916a01000000000000000000009091046001600160a01b031690633cf979839060208082019061168a908c018c6143a8565b67ffffffffffffffff1681526020018a60200160208101906116ac91906147b4565b604080516001600160a01b0390921660208301520160408051601f1981840301815291905281526020016116e46101208c018c61558d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200186905261138860808b013561173960608d0160408e016147b4565b6040518563ffffffff1660e01b81526004016117589493929190615637565b6000604051808303816000875af1158015611777573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261179f91908101906156fc565b5091509150816117dd57806040517f0a8d6e8c0000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b5050505b50505050565b6000546001600160a01b0316331480159061180d57506002546001600160a01b03163314155b15611844576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61184f600382612bab565b50565b6060806000611861600c612d90565b90508067ffffffffffffffff81111561187c5761187c614479565b6040519080825280602002602001820160405280156118a5578160200160208202803683370190505b5092508067ffffffffffffffff8111156118c1576118c1614479565b6040519080825280602002602001820160405280156118ea578160200160208202803683370190505b50915060005b8181101561197257600080611906600c84612d9b565b915091508086848151811061191d5761191d615294565b60200260200101906001600160a01b031690816001600160a01b0316815250508185848151811061195057611950615294565b6001600160a01b039092166020928302919091019091015250506001016118f0565b50509091565b611980611989565b61184f81612db9565b6000546001600160a01b031633146119fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016106ee565b565b600081806020019051810190611a159190615756565b60608101519091506001600160a01b0316611a5c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600a805460208085015160408087015160608089015163ffffffff9889167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909716969096176401000000009890941697909702929092177fffff00000000000000000000000000000000000000000000ffffffffffffffff166801000000000000000061ffff909316929092027fffff0000000000000000000000000000000000000000ffffffffffffffffffff16919091176a01000000000000000000006001600160a01b039485160217909355608080860151600b80547fffffffffffffffffffffffff000000000000000000000000000000000000000016918516919091179055835160e0810185527f0000000000000000000000000000000000000000000000000000000000000000841681527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff908116938201939093527f0000000000000000000000000000000000000000000000000000000000000000909216828501527f00000000000000000000000000000000000000000000000000000000000000008316948201949094527f00000000000000000000000000000000000000000000000000000000000000008216938101939093527f0000000000000000000000000000000000000000000000000000000000000000811660a08401527f00000000000000000000000000000000000000000000000000000000000000001660c0830152517f7879e20bb60a503429de4a2c912b5904f08a39f2af054c10fb46434b5d61126091611cbd9184906157f5565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a604051602001611ced999897969594939291906158b7565b60408051601f1981840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611de482606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611dc891906151d3565b85608001516fffffffffffffffffffffffffffffffff16612e94565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6000610e5d836001600160a01b038416612ebc565b6000611e33846001600160a01b03851684612ec8565b949350505050565b467f0000000000000000000000000000000000000000000000000000000000000000146119fd576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201526044016106ee565b6040517f2cbc26bb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060801b77ffffffffffffffff000000000000000000000000000000001660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632cbc26bb90602401602060405180830381865afa158015611f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9a919061593f565b15611fd1576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815151600081900361200e576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015151811461204c576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561206757612067614479565b604051908082528060200260200182016040528015612090578160200160208202803683370190505b50905060005b82811015612168576000856000015182815181106120b6576120b6615294565b602002602001015190506120ea817f0000000000000000000000000000000000000000000000000000000000000000612ede565b8383815181106120fc576120fc615294565b60200260200101818152505080610180015183838151811061212057612120615294565b60200260200101511461215f576040517f7185cf6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101612096565b508251604080860151606087015191517f32048875000000000000000000000000000000000000000000000000000000008152921515926000926001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016926332048875926121e29288929160040161598d565b602060405180830381865afa1580156121ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222391906159c3565b90508060000361225f576040517fea75680100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b848110156117dd5760008760000151828151811061228257612282615294565b60200260200101519050600061229b826060015161062f565b905060008160038111156122b1576122b16143c5565b14806122ce575060038160038111156122cc576122cc6143c5565b145b61231457816060015167ffffffffffffffff167fe3dd0bec917c965a133ddb2c84874725ee1e2fd8d763c19efa36d6a11cd82b1f60405160405180910390a25050612907565b606085156123fa5788848151811061232e5761232e615294565b6020908102919091018101510151600a5490915060009063ffffffff1661235587426151d3565b119050808061237557506003836003811115612373576123736143c5565b145b6123ab576040517f6358b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8985815181106123bd576123bd615294565b6020026020010151600001516000146123f4578985815181106123e2576123e2615294565b60209081029190910101515160808501525b5061245e565b600082600381111561240e5761240e6143c5565b1461245e57606083015160405167ffffffffffffffff90911681527f67d9ba0f63d427c482c2736300e6d5a34c6691dbcdea8ad35828a1f1ba47e8729060200160405180910390a1505050612907565b60c083015167ffffffffffffffff16156126df576020808401516001600160a01b03166000908152600f909152604081205467ffffffffffffffff1690819003612649577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316156126495760208401516040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063856c824790602401602060405180830381865afa158015612557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257b919061537c565b60c085015190915067ffffffffffffffff166125988260016159dc565b67ffffffffffffffff16146125f95783602001516001600160a01b03168460c0015167ffffffffffffffff167fe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d60405160405180910390a350505050612907565b6020848101516001600160a01b03166000908152600f9091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790555b600083600381111561265d5761265d6143c5565b036126dd5760c084015167ffffffffffffffff1661267c8260016159dc565b67ffffffffffffffff16146126dd5783602001516001600160a01b03168460c0015167ffffffffffffffff167fd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf4123760405160405180910390a350505050612907565b505b60008a6020015185815181106126f7576126f7615294565b602002602001015190506127238460600151856000015186610140015151876101200151518551613039565b612732846060015160016131ba565b600080612740868486613264565b915091506127528660600151836131ba565b88156127be57600382600381111561276c5761276c6143c5565b036127be576000856003811115612785576127856143c5565b146127be57806040517fcf19edfd0000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b60028260038111156127d2576127d26143c5565b1461282a5760038260038111156127eb576127eb6143c5565b1461282a578560600151826040517f9e2616030000000000000000000000000000000000000000000000000000000081526004016106ee9291906159fd565b60c086015167ffffffffffffffff16156128b2576000856003811115612852576128526143c5565b036128b2576020808701516001600160a01b03166000908152600f90915260408120805467ffffffffffffffff169161288a83615a1b565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b856101800151866060015167ffffffffffffffff167fd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef6584846040516128f8929190615a38565b60405180910390a35050505050505b600101612262565b61296261291e82840184615a58565b604080516000808252602082019092529061295c565b6040805180820190915260008152606060208201528152602001906001900390816129345790505b50611ebc565b5050565b60608989808060200260200160405190810160405280939291908181526020016000905b828210156129b6576129a760408302860136819003810190615a8d565b8152602001906001019061298a565b505050505090506000805b8a811015612b715760008888838181106129dd576129dd615294565b90506020028101906129ef919061558d565b8101906129fc9190615aa9565b90508451600014612a5757848281518110612a1957612a19615294565b602002602001015163ffffffff16600014612a5757848281518110612a4057612a40615294565b602090810291909101015163ffffffff1660608201525b612ad78d8d84818110612a6c57612a6c615294565b905060400201602001358c8c848b8b88818110612a8b57612a8b615294565b9050602002810190612a9d919061558d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061333192505050565b848381518110612ae957612ae9615294565b6020026020010181905250612b25848381518110612b0957612b09615294565b602002602001015160000151600c6136fd90919063ffffffff16565b15612b6857612b5b848381518110612b3f57612b3f615294565b6020908102919091010151600b546001600160a01b0316613712565b612b6590846154aa565b92505b506001016129c1565b508015612b8157612b8181613833565b509998505050505050505050565b6000612b9a83613840565b8015610e5d5750610e5d83836138a4565b8154600090612bd490700100000000000000000000000000000000900463ffffffff16426151d3565b90508015612c765760018301548354612c1c916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612e94565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612c9c916fffffffffffffffffffffffffffffffff9081169116613974565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612d839084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60405180910390a1505050565b60006106a48261398a565b6000808080612daa8686613995565b909450925050505b9250929050565b336001600160a01b03821603612e2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016106ee565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000612eb385612ea4848661523c565b612eae90876154aa565b613974565b95945050505050565b6000610e5d83836139a4565b6000611e3384846001600160a01b0385166139c1565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151604051602001612f749897969594939291906001600160a01b039889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b6040516020818303038152906040528051906020012085610120015180519060200120866101400151604051602001612fad9190615b65565b60405160208183030381529060405280519060200120876101600151604051602001612fd99190615bd2565b60408051601f198184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168467ffffffffffffffff16146130b2576040517f1279ec8a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526024016106ee565b600a5468010000000000000000900461ffff1683111561310a576040517f099d3f7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff861660048201526024016106ee565b80831461314f576040517f8808f8e700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff861660048201526024016106ee565b600a54640100000000900463ffffffff168211156131b357600a546040517f8693378900000000000000000000000000000000000000000000000000000000815264010000000090910463ffffffff166004820152602481018390526044016106ee565b5050505050565b600060026131c9608085615215565b67ffffffffffffffff166131dd919061523c565b905060006010816131ef608087615253565b67ffffffffffffffff168152602081019190915260400160002054905081613219600160046151d3565b901b191681836003811115613230576132306143c5565b901b178060106000613243608088615253565b67ffffffffffffffff16815260208101919091526040016000205550505050565b6040517fb6113fce000000000000000000000000000000000000000000000000000000008152600090606090309063b6113fce906132aa90889088908890600401615c1c565b600060405180830381600087803b1580156132c457600080fd5b505af19250505080156132d5575060015b613314573d808015613303576040519150601f19603f3d011682016040523d82523d6000602084013e613308565b606091505b50600392509050613329565b50506040805160208101909152600081526002905b935093915050565b6040805180820190915260008082526020820152600061335484602001516139de565b6040517fbbe4f6db0000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bbe4f6db90602401602060405180830381865afa1580156133d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fd9190615da5565b90506001600160a01b038116158061344557506134436001600160a01b0382167faff2afbf00000000000000000000000000000000000000000000000000000000612b8f565b155b15613487576040517fae9b4ce90000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016106ee565b60008061349f8885896060015163ffffffff16613a84565b91509150600080600061359d6040518061010001604052808e81526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020018d6001600160a01b031681526020018f8152602001896001600160a01b031681526020018c6000015181526020018c6040015181526020018b8152506040516024016135399190615dc2565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f390775370000000000000000000000000000000000000000000000000000000017905287866113886084613bc7565b925092509250826135dc57816040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b81516020146136245781516040517f78ef80240000000000000000000000000000000000000000000000000000000081526020600482015260248101919091526044016106ee565b60008280602001905181019061363a91906159c3565b9050866001600160a01b03168c6001600160a01b0316146136cf57600061366b8d8a613666868a6151d3565b613a84565b5090508681108061368557508161368288836151d3565b14155b156136cd576040517fa966e21f0000000000000000000000000000000000000000000000000000000081526004810183905260248101889052604481018290526064016106ee565b505b604080518082019091526001600160a01b039098168852602088015250949550505050505095945050505050565b6000610e5d836001600160a01b038416613ced565b81516040517fd02641a00000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260009182919084169063d02641a0906024016040805180830381865afa158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c9190615e8f565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81166000036138055783516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106ee565b6020840151611e33907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff831690613cf9565b61184f6003826000613d36565b600061386c827f01ffc9a7000000000000000000000000000000000000000000000000000000006138a4565b80156106a4575061389d827fffffffff000000000000000000000000000000000000000000000000000000006138a4565b1592915050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000082166024820152600090819060440160408051601f19818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561395d575060208210155b80156139695750600081115b979650505050505050565b60008183106139835781610e5d565b5090919050565b60006106a482614085565b6000808080612daa8686614090565b60008181526002830160205260408120819055610e5d83836140bb565b60008281526002840160205260408120829055611e3384846140c7565b60008151602014613a1d57816040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b600082806020019051810190613a3391906159c3565b90506001600160a01b03811180613a4b575061040081105b156106a457826040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b6000806000806000613b1388604051602401613aaf91906001600160a01b0391909116815260200190565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a082310000000000000000000000000000000000000000000000000000000017905288886113886084613bc7565b92509250925082613b5257816040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b6020825114613b9a5781516040517f78ef80240000000000000000000000000000000000000000000000000000000081526020600482015260248101919091526044016106ee565b81806020019051810190613bae91906159c3565b613bb882886151d3565b94509450505050935093915050565b6000606060008361ffff1667ffffffffffffffff811115613bea57613bea614479565b6040519080825280601f01601f191660200182016040528015613c14576020820181803683370190505b509150863b613c47577f0c3b563c0000000000000000000000000000000000000000000000000000000060005260046000fd5b5a85811015613c7a577fafa32a2c0000000000000000000000000000000000000000000000000000000060005260046000fd5b8590036040810481038710613cb3577f37c3be290000000000000000000000000000000000000000000000000000000060005260046000fd5b505a6000808a5160208c0160008c8cf193505a900390503d84811115613cd65750835b808352806000602085013e50955095509592505050565b6000610e5d83836140d3565b6000670de0b6b3a7640000613d2c837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff861661523c565b610e5d9190615ef1565b825474010000000000000000000000000000000000000000900460ff161580613d5d575081155b15613d6757505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090613dad90700100000000000000000000000000000000900463ffffffff16426151d3565b90508015613e6d5781831115613def576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154613e299083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612e94565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b84821015613f0a576001600160a01b038416613ebf576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016106ee565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b03851660448201526064016106ee565b848310156140035760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16906000908290613f4e90826151d3565b613f58878a6151d3565b613f6291906154aa565b613f6c9190615ef1565b90506001600160a01b038616613fb8576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016106ee565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b03871660448201526064016106ee565b61400d85846151d3565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60006106a4826140df565b6000808061409e85856140e9565b600081815260029690960160205260409095205494959350505050565b6000610e5d83836140f5565b6000610e5d83836141ef565b6000610e5d838361423e565b60006106a4825490565b6000610e5d8383614256565b600081815260018301602052604081205480156141de5760006141196001836151d3565b855490915060009061412d906001906151d3565b905081811461419257600086600001828154811061414d5761414d615294565b906000526020600020015490508087600001848154811061417057614170615294565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806141a3576141a3615f05565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106a4565b60009150506106a4565b5092915050565b6000818152600183016020526040812054614236575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106a4565b5060006106a4565b60008181526001830160205260408120541515610e5d565b600082600001828154811061426d5761426d615294565b9060005260206000200154905092915050565b8280548282559060005260206000209081019282156142ed579160200282015b828111156142ed57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039091161782556020909201916001909101906142a0565b506142f99291506142fd565b5090565b5b808211156142f957600081556001016142fe565b60e081016106a482846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b67ffffffffffffffff8116811461184f57600080fd5b80356143a381614382565b919050565b6000602082840312156143ba57600080fd5b8135610e5d81614382565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110614404576144046143c5565b9052565b602081016106a482846143f4565b60005b83811015614431578181015183820152602001614419565b50506000910152565b60008151808452614452816020860160208601614416565b601f01601f19169290920160200192915050565b602081526000610e5d602083018461443a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156144cb576144cb614479565b60405290565b6040516080810167ffffffffffffffff811182821017156144cb576144cb614479565b6040516101a0810167ffffffffffffffff811182821017156144cb576144cb614479565b604051601f8201601f1916810167ffffffffffffffff8111828210171561454157614541614479565b604052919050565b600067ffffffffffffffff82111561456357614563614479565b5060051b60200190565b6001600160a01b038116811461184f57600080fd5b80356143a38161456d565b600082601f83011261459e57600080fd5b813560206145b36145ae83614549565b614518565b8083825260208201915060208460051b8701019350868411156145d557600080fd5b602086015b848110156145fa5780356145ed8161456d565b83529183019183016145da565b509695505050505050565b803560ff811681146143a357600080fd5b600067ffffffffffffffff82111561463057614630614479565b50601f01601f191660200190565b600082601f83011261464f57600080fd5b813561465d6145ae82614616565b81815284602083860101111561467257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156146a857600080fd5b863567ffffffffffffffff808211156146c057600080fd5b6146cc8a838b0161458d565b975060208901359150808211156146e257600080fd5b6146ee8a838b0161458d565b96506146fc60408a01614605565b9550606089013591508082111561471257600080fd5b61471e8a838b0161463e565b945061472c60808a01614398565b935060a089013591508082111561474257600080fd5b5061474f89828a0161463e565b9150509295509295509295565b60008151808452602080850194506020840160005b838110156147965781516001600160a01b031687529582019590820190600101614771565b509495945050505050565b602081526000610e5d602083018461475c565b6000602082840312156147c657600080fd5b8135610e5d8161456d565b60a081016106a4828463ffffffff8082511683528060208301511660208401525061ffff604082015116604083015260608101516001600160a01b03808216606085015280608084015116608085015250505050565b60006020828403121561483957600080fd5b813567ffffffffffffffff81111561485057600080fd5b820160a08185031215610e5d57600080fd5b600082601f83011261487357600080fd5b813560206148836145ae83614549565b82815260069290921b840181019181810190868411156148a257600080fd5b8286015b848110156145fa57604081890312156148bf5760008081fd5b6148c76144a8565b81356148d28161456d565b8152818501356148e18161456d565b818601528352918301916040016148a6565b6000806040838503121561490657600080fd5b823567ffffffffffffffff8082111561491e57600080fd5b61492a86838701614862565b9350602085013591508082111561494057600080fd5b5061494d85828601614862565b9150509250929050565b801515811461184f57600080fd5b80356143a381614957565b60006040828403121561498257600080fd5b61498a6144a8565b905081356149978161456d565b808252506020820135602082015292915050565b600082601f8301126149bc57600080fd5b813560206149cc6145ae83614549565b8083825260208201915060208460061b8701019350868411156149ee57600080fd5b602086015b848110156145fa57614a058882614970565b8352918301916040016149f3565b600082601f830112614a2457600080fd5b81356020614a346145ae83614549565b82815260059290921b84018101918181019086841115614a5357600080fd5b8286015b848110156145fa57803567ffffffffffffffff811115614a775760008081fd5b614a858986838b010161463e565b845250918301918301614a57565b600082601f830112614aa457600080fd5b81356020614ab46145ae83614549565b82815260059290921b84018101918181019086841115614ad357600080fd5b8286015b848110156145fa57803567ffffffffffffffff811115614af75760008081fd5b614b058986838b0101614a13565b845250918301918301614ad7565b600082601f830112614b2457600080fd5b81356020614b346145ae83614549565b8083825260208201915060208460051b870101935086841115614b5657600080fd5b602086015b848110156145fa5780358352918301918301614b5b565b600060808284031215614b8457600080fd5b614b8c6144d1565b9050813567ffffffffffffffff80821115614ba657600080fd5b818401915084601f830112614bba57600080fd5b81356020614bca6145ae83614549565b82815260059290921b84018101918181019088841115614be957600080fd5b8286015b84811015614d4557803586811115614c0457600080fd5b87016101a0818c03601f19011215614c1b57600080fd5b614c236144f4565b614c2e868301614398565b8152614c3c60408301614582565b86820152614c4c60608301614582565b6040820152614c5d60808301614398565b606082015260a08201356080820152614c7860c08301614965565b60a0820152614c8960e08301614398565b60c0820152610100614c9c818401614582565b60e083015261012080840135828401526101409150818401358a811115614cc257600080fd5b614cd08f8a8388010161463e565b828501525050610160808401358a811115614cea57600080fd5b614cf88f8a838801016149ab565b83850152506101809150818401358a811115614d1357600080fd5b614d218f8a83880101614a13565b91840191909152506101a09290920135918101919091528352918301918301614bed565b5086525085810135935082841115614d5c57600080fd5b614d6887858801614a93565b90850152506040840135915080821115614d8157600080fd5b50614d8e84828501614b13565b6040830152506060820135606082015292915050565b63ffffffff8116811461184f57600080fd5b600082601f830112614dc757600080fd5b81356020614dd76145ae83614549565b8083825260208201915060208460051b870101935086841115614df957600080fd5b602086015b848110156145fa578035614e1181614da4565b8352918301918301614dfe565b6000806040808486031215614e3257600080fd5b833567ffffffffffffffff80821115614e4a57600080fd5b614e5687838801614b72565b9450602091508186013581811115614e6d57600080fd5b8601601f81018813614e7e57600080fd5b8035614e8c6145ae82614549565b81815260059190911b8201840190848101908a831115614eab57600080fd5b8584015b83811015614f1e57803586811115614ec75760008081fd5b8501808d03601f1901891315614edd5760008081fd5b614ee56144a8565b8882013581528982013588811115614efd5760008081fd5b614f0b8f8b83860101614db6565b828b015250845250918601918601614eaf565b50809750505050505050509250929050565b60008083601f840112614f4257600080fd5b50813567ffffffffffffffff811115614f5a57600080fd5b6020830191508360208260051b8501011115612db257600080fd5b60008060008060008060008060e0898b031215614f9157600080fd5b606089018a811115614fa257600080fd5b8998503567ffffffffffffffff80821115614fbc57600080fd5b818b0191508b601f830112614fd057600080fd5b813581811115614fdf57600080fd5b8c6020828501011115614ff157600080fd5b6020830199508098505060808b013591508082111561500f57600080fd5b61501b8c838d01614f30565b909750955060a08b013591508082111561503457600080fd5b506150418b828c01614f30565b999c989b50969995989497949560c00135949350505050565b6000806000806060858703121561507057600080fd5b843567ffffffffffffffff8082111561508857600080fd5b908601906101a0828903121561509d57600080fd5b909450602086013590808211156150b357600080fd5b6150bf88838901614f30565b909550935060408701359150808211156150d857600080fd5b506150e587828801614db6565b91505092959194509250565b80356fffffffffffffffffffffffffffffffff811681146143a357600080fd5b60006060828403121561512357600080fd5b6040516060810181811067ffffffffffffffff8211171561514657615146614479565b604052823561515481614957565b8152615162602084016150f1565b6020820152615173604084016150f1565b60408201529392505050565b604081526000615192604083018561475c565b8281036020840152612eb3818561475c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106a4576106a46151a4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff80841680615230576152306151e6565b92169190910692915050565b80820281158282048414176106a4576106a46151a4565b600067ffffffffffffffff8084168061526e5761526e6151e6565b92169190910492915050565b602081016003831061528e5761528e6143c5565b91905290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff8083168181036152dc576152dc6151a4565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526153168184018a61475c565b9050828103608084015261532a818961475c565b905060ff871660a084015282810360c0840152615347818761443a565b905067ffffffffffffffff851660e084015282810361010084015261536c818561443a565b9c9b505050505050505050505050565b60006020828403121561538e57600080fd5b8151610e5d81614382565b600082601f8301126153aa57600080fd5b81516153b86145ae82614616565b8181528460208386010111156153cd57600080fd5b611e33826020830160208701614416565b6000602082840312156153f057600080fd5b815167ffffffffffffffff8082111561540857600080fd5b908301906080828603121561541c57600080fd5b6154246144d1565b82518281111561543357600080fd5b61543f87828601615399565b82525060208301518281111561545457600080fd5b61546087828601615399565b60208301525060408301518281111561547857600080fd5b61548487828601615399565b6040830152506060830151925061549a83614da4565b6060810192909252509392505050565b808201808211156106a4576106a46151a4565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126154f257600080fd5b83018035915067ffffffffffffffff82111561550d57600080fd5b6020019150600681901b3603821315612db257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261555a57600080fd5b83018035915067ffffffffffffffff82111561557557600080fd5b6020019150600581901b3603821315612db257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155c257600080fd5b83018035915067ffffffffffffffff8211156155dd57600080fd5b602001915036819003821315612db257600080fd5b60008151808452602080850194506020840160005b8381101561479657815180516001600160a01b031688528301518388015260409096019590820190600101615607565b608081528451608082015267ffffffffffffffff60208601511660a08201526000604086015160a060c084015261567261012084018261443a565b905060608701517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808584030160e08601526156ae838361443a565b9250608089015191508085840301610100860152506156cd82826155f2565b925050506156e1602083018661ffff169052565b836040830152612eb360608301846001600160a01b03169052565b60008060006060848603121561571157600080fd5b835161571c81614957565b602085015190935067ffffffffffffffff81111561573957600080fd5b61574586828701615399565b925050604084015190509250925092565b600060a0828403121561576857600080fd5b60405160a0810181811067ffffffffffffffff8211171561578b5761578b614479565b604052825161579981614da4565b815260208301516157a981614da4565b6020820152604083015161ffff811681146157c357600080fd5b604082015260608301516157d68161456d565b606082015260808301516157e98161456d565b60808201529392505050565b610180810161586682856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b825163ffffffff90811660e0840152602084015116610100830152604083015161ffff1661012083015260608301516001600160a01b03908116610140840152608084015116610160830152610e5d565b60006101208b83526001600160a01b038b16602084015267ffffffffffffffff808b1660408501528160608501526158f18285018b61475c565b91508382036080850152615905828a61475c565b915060ff881660a085015283820360c0850152615922828861443a565b90861660e0850152838103610100850152905061536c818561443a565b60006020828403121561595157600080fd5b8151610e5d81614957565b60008151808452602080850194506020840160005b8381101561479657815187529582019590820190600101615971565b6060815260006159a0606083018661595c565b82810360208401526159b2818661595c565b915050826040830152949350505050565b6000602082840312156159d557600080fd5b5051919050565b67ffffffffffffffff8181168382160190808211156141e8576141e86151a4565b67ffffffffffffffff8316815260408101610e5d60208301846143f4565b600067ffffffffffffffff8083168181036152dc576152dc6151a4565b615a4281846143f4565b604060208201526000611e33604083018461443a565b600060208284031215615a6a57600080fd5b813567ffffffffffffffff811115615a8157600080fd5b611e3384828501614b72565b600060408284031215615a9f57600080fd5b610e5d8383614970565b600060208284031215615abb57600080fd5b813567ffffffffffffffff80821115615ad357600080fd5b9083019060808286031215615ae757600080fd5b615aef6144d1565b823582811115615afe57600080fd5b615b0a8782860161463e565b825250602083013582811115615b1f57600080fd5b615b2b8782860161463e565b602083015250604083013582811115615b4357600080fd5b615b4f8782860161463e565b6040830152506060830135925061549a83614da4565b602081526000610e5d60208301846155f2565b60008282518085526020808601955060208260051b8401016020860160005b84811015615bc557601f19868403018952615bb383835161443a565b98840198925090830190600101615b97565b5090979650505050505050565b602081526000610e5d6020830184615b78565b60008151808452602080850194506020840160005b8381101561479657815163ffffffff1687529582019590820190600101615bfa565b60608152615c3760608201855167ffffffffffffffff169052565b60006020850151615c5360808401826001600160a01b03169052565b5060408501516001600160a01b03811660a084015250606085015167ffffffffffffffff811660c084015250608085015160e083015260a0850151610100615c9e8185018315159052565b60c08701519150610120615cbd8186018467ffffffffffffffff169052565b60e08801519250610140615cdb818701856001600160a01b03169052565b828901519350610160925083838701528189015193506101a091506101808281880152615d0c61020088018661443a565b9450818a015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0808887030184890152615d4886846155f2565b948b01518886039091016101c0890152939450615d658585615b78565b9450808a01516101e0880152505050508281036020840152615d878186615b78565b90508281036040840152615d9b8185615be5565b9695505050505050565b600060208284031215615db757600080fd5b8151610e5d8161456d565b6020815260008251610100806020850152615de161012085018361443a565b91506020850151615dfe604086018267ffffffffffffffff169052565b5060408501516001600160a01b038116606086015250606085015160808501526080850151615e3860a08601826001600160a01b03169052565b5060a0850151601f19808685030160c0870152615e55848361443a565b935060c08701519150808685030160e0870152615e72848361443a565b935060e0870151915080868503018387015250615d9b838261443a565b600060408284031215615ea157600080fd5b615ea96144a8565b82517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114615ed557600080fd5b81526020830151615ee581614da4565b60208201529392505050565b600082615f0057615f006151e6565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a00000000000000000000000075d23898771cc508234b5be8318a0c5ee8ebae060000000000000000000000000000000000000000000000001fa3b5d5b7cd348b000000000000000000000000000000000000000000000000de41ba4fc9d91ad9000000000000000000000000f2e86c53c3305d37b161d30783869624cfaae69100000000000000000000000000000000000000000000000000000000000000000000000000000000000000008f4413e02265f65ef89fb908dba2915ff9f7f8cb000000000000000000000000f49c561cf56149517c67793a3035d1877ffe2f04000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000152d02c7e14af68000000000000000000000000000000000000000000000000000090d972f32323c0000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101825760003560e01c806385572ffb116100d8578063afcb95d71161008c578063c92b283211610066578063c92b2832146105f3578063f077b59214610606578063f2fde38b1461061c57600080fd5b8063afcb95d7146105ad578063b1dc65a4146105cd578063b6113fce146105e057600080fd5b8063873504d7116100bd578063873504d7146105765780638926c4ee146105895780638da5cb5b1461059c57600080fd5b806385572ffb1461053c578063856c82471461054a57600080fd5b8063599f64311161013a5780637437ff9f116101145780637437ff9f1461046157806379ba50971461050457806381ff70481461050c57600080fd5b8063599f643114610414578063666cab8d14610439578063704b6c021461044e57600080fd5b8063181f5a771161016b578063181f5a77146103525780631ef381741461039b578063546719cd146103b057600080fd5b806306285c6914610187578063142a98fc14610332575b600080fd5b61031c6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f00000000000000000000000075d23898771cc508234b5be8318a0c5ee8ebae066001600160a01b031681526020017f0000000000000000000000000000000000000000000000001fa3b5d5b7cd348b67ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000de41ba4fc9d91ad967ffffffffffffffff1681526020017f000000000000000000000000f2e86c53c3305d37b161d30783869624cfaae6916001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f0000000000000000000000008f4413e02265f65ef89fb908dba2915ff9f7f8cb6001600160a01b031681526020017f000000000000000000000000f49c561cf56149517c67793a3035d1877ffe2f046001600160a01b0316815250905090565b6040516103299190614312565b60405180910390f35b6103456103403660046143a8565b61062f565b6040516103299190614408565b61038e6040518060400160405280601481526020017f45564d3245564d4f666652616d7020312e352e3000000000000000000000000081525081565b6040516103299190614466565b6103ae6103a936600461468f565b6106aa565b005b6103b8610a9e565b604051610329919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6002546001600160a01b03165b6040516001600160a01b039091168152602001610329565b610441610b53565b60405161032991906147a1565b6103ae61045c3660046147b4565b610bb5565b6104f76040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a081018252600a5463ffffffff8082168352640100000000820416602083015268010000000000000000810461ffff16928201929092526a01000000000000000000009091046001600160a01b039081166060830152600b5416608082015290565b60405161032991906147d1565b6103ae610c7e565b6007546005546040805163ffffffff80851682526401000000009094049093166020840152820152606001610329565b6103ae610182366004614827565b61055d6105583660046147b4565b610d61565b60405167ffffffffffffffff9091168152602001610329565b6103ae6105843660046148f3565b610e64565b6103ae610597366004614e1e565b611037565b6000546001600160a01b0316610421565b604080516001815260006020820181905291810191909152606001610329565b6103ae6105db366004614f75565b61129c565b6103ae6105ee36600461505a565b6114a7565b6103ae610601366004615111565b6117e7565b61060e611852565b60405161032992919061517f565b6103ae61062a3660046147b4565b611978565b600061063d600160046151d3565b600261064a608085615215565b67ffffffffffffffff1661065e919061523c565b6010600061066d608087615253565b67ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002054901c1660038111156106a4576106a46143c5565b92915050565b84518460ff16601f8211156106f75760016040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016106ee919061527a565b60405180910390fd5b806000036107345760006040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016106ee919061527a565b61073c611989565b610745856119ff565b60095460005b818110156107bc57600860006009838154811061076a5761076a615294565b60009182526020808320909101546001600160a01b03168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560010161074b565b5050865160005b8181101561095f5760008982815181106107df576107df615294565b60200260200101519050600060028111156107fc576107fc6143c5565b6001600160a01b038216600090815260086020526040902054610100900460ff16600281111561082e5761082e6143c5565b146108685760026040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016106ee919061527a565b6001600160a01b0381166108a8576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff8316815260208101600290526001600160a01b03821660009081526008602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561094b5761094b6143c5565b0217905550905050508060010190506107c3565b5087516109739060099060208b0190614280565b506006805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908a1617179055600780546109f99146913091906000906109cb9063ffffffff166152c3565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168c8c8c8c8c8c611cc9565b6005819055600780544363ffffffff9081166401000000009081027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff841681179094556040519083048216947f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0594610a8a9487949293918316921691909117908f908f908f908f908f908f906152e6565b60405180910390a150505050505050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610b4e90611d56565b905090565b60606009805480602002602001604051908101604052809291908181526020018280548015610bab57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610b8d575b5050505050905090565b6000546001600160a01b03163314801590610bdb57506002546001600160a01b03163314155b15610c12576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c9060200160405180910390a150565b6001546001600160a01b03163314610cf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016106ee565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b0381166000908152600f602052604081205467ffffffffffffffff168082036106a4577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316156106a4576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015610e39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5d919061537c565b9392505050565b610e6c611989565b60005b8251811015610f3f57610ea9838281518110610e8d57610e8d615294565b602002602001015160200151600c611e0890919063ffffffff16565b15610f37577fcbf3cbeaed4ac1d605ed30f4af06c35acaeff2379db7f6146c9cceee83d58782838281518110610ee157610ee1615294565b602002602001015160000151848381518110610eff57610eff615294565b602002602001015160200151604051610f2e9291906001600160a01b0392831681529116602082015260400190565b60405180910390a15b600101610e6f565b5060005b815181101561103257610f9c828281518110610f6157610f61615294565b602002602001015160200151838381518110610f7f57610f7f615294565b602002602001015160000151600c611e1d9092919063ffffffff16565b1561102a577ffc23abf7ddbd3c02b1420dafa2355c56c1a06fbb8723862ac14d6bd74177361a828281518110610fd457610fd4615294565b602002602001015160000151838381518110610ff257610ff2615294565b6020026020010151602001516040516110219291906001600160a01b0392831681529116602082015260400190565b60405180910390a15b600101610f43565b505050565b61103f611e3b565b8151518151811461107c576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156112915760008460000151828151811061109f5761109f615294565b6020026020010151905060008483815181106110bd576110bd615294565b60209081029190910101518051909150801561112c57826080015181101561112c5761018083015160808401516040517f9c6db58d00000000000000000000000000000000000000000000000000000000815260048101929092526024820152604481018290526064016106ee565b816020015151836101400151511461118e5761018083015160608401516040517f85d2e5bf000000000000000000000000000000000000000000000000000000008152600481019290925267ffffffffffffffff1660248201526044016106ee565b61016083015160005b846101400151518110156112815760008287815181106111b9576111b9615294565b60200260200101518060200190518101906111d491906153de565b90506000856020015183815181106111ee576111ee615294565b602002602001015163ffffffff169050806000141580156112185750816060015163ffffffff1681105b156112775761018087015160608301516040517fef0c635200000000000000000000000000000000000000000000000000000000815260048101929092526024820185905263ffffffff166044820152606481018290526084016106ee565b5050600101611197565b505050505080600101905061107f565b506110328383611ebc565b6112a6878761290f565b6005548835908082146112ef576040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016106ee565b6112f7611e3b565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a13360009081526008602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561137f5761137f6143c5565b6002811115611390576113906143c5565b90525090506002816020015160028111156113ad576113ad6143c5565b1480156113e757506009816000015160ff16815481106113cf576113cf615294565b6000918252602090912001546001600160a01b031633145b61141d576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600061142b85602061523c565b61143688602061523c565b6114428b6101446154aa565b61144c91906154aa565b61145691906154aa565b905036811461149a576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016106ee565b5050505050505050505050565b3330146114e0576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516000808252602082019092528161151d565b60408051808201909152600080825260208201528152602001906001900390816114f65790505b50905060006115306101408701876154bd565b905011156115a7576115a46115496101408701876154bd565b6115596040890160208a016147b4565b604080516001600160a01b0390921660208301520160408051601f1981840301815291815261158e9060608b01908b016147b4565b61159c6101608b018b615525565b8a8a8a612966565b90505b6115b561012086018661558d565b15905080156115c657506080850135155b806115e857506115dc60608601604087016147b4565b6001600160a01b03163b155b8061163357506116317f85572ffb0000000000000000000000000000000000000000000000000000000061162260608801604089016147b4565b6001600160a01b031690612b8f565b155b1561163e57506117e1565b600a546040805160a08101909152610180870135815260009182916a01000000000000000000009091046001600160a01b031690633cf979839060208082019061168a908c018c6143a8565b67ffffffffffffffff1681526020018a60200160208101906116ac91906147b4565b604080516001600160a01b0390921660208301520160408051601f1981840301815291905281526020016116e46101208c018c61558d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200186905261138860808b013561173960608d0160408e016147b4565b6040518563ffffffff1660e01b81526004016117589493929190615637565b6000604051808303816000875af1158015611777573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261179f91908101906156fc565b5091509150816117dd57806040517f0a8d6e8c0000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b5050505b50505050565b6000546001600160a01b0316331480159061180d57506002546001600160a01b03163314155b15611844576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61184f600382612bab565b50565b6060806000611861600c612d90565b90508067ffffffffffffffff81111561187c5761187c614479565b6040519080825280602002602001820160405280156118a5578160200160208202803683370190505b5092508067ffffffffffffffff8111156118c1576118c1614479565b6040519080825280602002602001820160405280156118ea578160200160208202803683370190505b50915060005b8181101561197257600080611906600c84612d9b565b915091508086848151811061191d5761191d615294565b60200260200101906001600160a01b031690816001600160a01b0316815250508185848151811061195057611950615294565b6001600160a01b039092166020928302919091019091015250506001016118f0565b50509091565b611980611989565b61184f81612db9565b6000546001600160a01b031633146119fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016106ee565b565b600081806020019051810190611a159190615756565b60608101519091506001600160a01b0316611a5c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600a805460208085015160408087015160608089015163ffffffff9889167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909716969096176401000000009890941697909702929092177fffff00000000000000000000000000000000000000000000ffffffffffffffff166801000000000000000061ffff909316929092027fffff0000000000000000000000000000000000000000ffffffffffffffffffff16919091176a01000000000000000000006001600160a01b039485160217909355608080860151600b80547fffffffffffffffffffffffff000000000000000000000000000000000000000016918516919091179055835160e0810185527f00000000000000000000000075d23898771cc508234b5be8318a0c5ee8ebae06841681527f0000000000000000000000000000000000000000000000001fa3b5d5b7cd348b67ffffffffffffffff908116938201939093527f000000000000000000000000000000000000000000000000de41ba4fc9d91ad9909216828501527f000000000000000000000000f2e86c53c3305d37b161d30783869624cfaae6918316948201949094527f00000000000000000000000000000000000000000000000000000000000000008216938101939093527f0000000000000000000000008f4413e02265f65ef89fb908dba2915ff9f7f8cb811660a08401527f000000000000000000000000f49c561cf56149517c67793a3035d1877ffe2f041660c0830152517f7879e20bb60a503429de4a2c912b5904f08a39f2af054c10fb46434b5d61126091611cbd9184906157f5565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a604051602001611ced999897969594939291906158b7565b60408051601f1981840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611de482606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611dc891906151d3565b85608001516fffffffffffffffffffffffffffffffff16612e94565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6000610e5d836001600160a01b038416612ebc565b6000611e33846001600160a01b03851684612ec8565b949350505050565b467f000000000000000000000000000000000000000000000000000000000008274f146119fd576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000008274f60048201524660248201526044016106ee565b6040517f2cbc26bb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000de41ba4fc9d91ad960801b77ffffffffffffffff000000000000000000000000000000001660048201527f0000000000000000000000008f4413e02265f65ef89fb908dba2915ff9f7f8cb6001600160a01b031690632cbc26bb90602401602060405180830381865afa158015611f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9a919061593f565b15611fd1576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815151600081900361200e576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015151811461204c576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561206757612067614479565b604051908082528060200260200182016040528015612090578160200160208202803683370190505b50905060005b82811015612168576000856000015182815181106120b6576120b6615294565b602002602001015190506120ea817f3f796b88626ff0f1ec66c33052a8803d8cf4bed7cf9af19ac38f0006c21297a2612ede565b8383815181106120fc576120fc615294565b60200260200101818152505080610180015183838151811061212057612120615294565b60200260200101511461215f576040517f7185cf6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101612096565b508251604080860151606087015191517f32048875000000000000000000000000000000000000000000000000000000008152921515926000926001600160a01b037f00000000000000000000000075d23898771cc508234b5be8318a0c5ee8ebae0616926332048875926121e29288929160040161598d565b602060405180830381865afa1580156121ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222391906159c3565b90508060000361225f576040517fea75680100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b848110156117dd5760008760000151828151811061228257612282615294565b60200260200101519050600061229b826060015161062f565b905060008160038111156122b1576122b16143c5565b14806122ce575060038160038111156122cc576122cc6143c5565b145b61231457816060015167ffffffffffffffff167fe3dd0bec917c965a133ddb2c84874725ee1e2fd8d763c19efa36d6a11cd82b1f60405160405180910390a25050612907565b606085156123fa5788848151811061232e5761232e615294565b6020908102919091018101510151600a5490915060009063ffffffff1661235587426151d3565b119050808061237557506003836003811115612373576123736143c5565b145b6123ab576040517f6358b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8985815181106123bd576123bd615294565b6020026020010151600001516000146123f4578985815181106123e2576123e2615294565b60209081029190910101515160808501525b5061245e565b600082600381111561240e5761240e6143c5565b1461245e57606083015160405167ffffffffffffffff90911681527f67d9ba0f63d427c482c2736300e6d5a34c6691dbcdea8ad35828a1f1ba47e8729060200160405180910390a1505050612907565b60c083015167ffffffffffffffff16156126df576020808401516001600160a01b03166000908152600f909152604081205467ffffffffffffffff1690819003612649577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316156126495760208401516040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063856c824790602401602060405180830381865afa158015612557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257b919061537c565b60c085015190915067ffffffffffffffff166125988260016159dc565b67ffffffffffffffff16146125f95783602001516001600160a01b03168460c0015167ffffffffffffffff167fe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d60405160405180910390a350505050612907565b6020848101516001600160a01b03166000908152600f9091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790555b600083600381111561265d5761265d6143c5565b036126dd5760c084015167ffffffffffffffff1661267c8260016159dc565b67ffffffffffffffff16146126dd5783602001516001600160a01b03168460c0015167ffffffffffffffff167fd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf4123760405160405180910390a350505050612907565b505b60008a6020015185815181106126f7576126f7615294565b602002602001015190506127238460600151856000015186610140015151876101200151518551613039565b612732846060015160016131ba565b600080612740868486613264565b915091506127528660600151836131ba565b88156127be57600382600381111561276c5761276c6143c5565b036127be576000856003811115612785576127856143c5565b146127be57806040517fcf19edfd0000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b60028260038111156127d2576127d26143c5565b1461282a5760038260038111156127eb576127eb6143c5565b1461282a578560600151826040517f9e2616030000000000000000000000000000000000000000000000000000000081526004016106ee9291906159fd565b60c086015167ffffffffffffffff16156128b2576000856003811115612852576128526143c5565b036128b2576020808701516001600160a01b03166000908152600f90915260408120805467ffffffffffffffff169161288a83615a1b565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b856101800151866060015167ffffffffffffffff167fd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef6584846040516128f8929190615a38565b60405180910390a35050505050505b600101612262565b61296261291e82840184615a58565b604080516000808252602082019092529061295c565b6040805180820190915260008152606060208201528152602001906001900390816129345790505b50611ebc565b5050565b60608989808060200260200160405190810160405280939291908181526020016000905b828210156129b6576129a760408302860136819003810190615a8d565b8152602001906001019061298a565b505050505090506000805b8a811015612b715760008888838181106129dd576129dd615294565b90506020028101906129ef919061558d565b8101906129fc9190615aa9565b90508451600014612a5757848281518110612a1957612a19615294565b602002602001015163ffffffff16600014612a5757848281518110612a4057612a40615294565b602090810291909101015163ffffffff1660608201525b612ad78d8d84818110612a6c57612a6c615294565b905060400201602001358c8c848b8b88818110612a8b57612a8b615294565b9050602002810190612a9d919061558d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061333192505050565b848381518110612ae957612ae9615294565b6020026020010181905250612b25848381518110612b0957612b09615294565b602002602001015160000151600c6136fd90919063ffffffff16565b15612b6857612b5b848381518110612b3f57612b3f615294565b6020908102919091010151600b546001600160a01b0316613712565b612b6590846154aa565b92505b506001016129c1565b508015612b8157612b8181613833565b509998505050505050505050565b6000612b9a83613840565b8015610e5d5750610e5d83836138a4565b8154600090612bd490700100000000000000000000000000000000900463ffffffff16426151d3565b90508015612c765760018301548354612c1c916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612e94565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612c9c916fffffffffffffffffffffffffffffffff9081169116613974565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612d839084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60405180910390a1505050565b60006106a48261398a565b6000808080612daa8686613995565b909450925050505b9250929050565b336001600160a01b03821603612e2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016106ee565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000612eb385612ea4848661523c565b612eae90876154aa565b613974565b95945050505050565b6000610e5d83836139a4565b6000611e3384846001600160a01b0385166139c1565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151604051602001612f749897969594939291906001600160a01b039889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b6040516020818303038152906040528051906020012085610120015180519060200120866101400151604051602001612fad9190615b65565b60405160208183030381529060405280519060200120876101600151604051602001612fd99190615bd2565b60408051601f198184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b7f000000000000000000000000000000000000000000000000de41ba4fc9d91ad967ffffffffffffffff168467ffffffffffffffff16146130b2576040517f1279ec8a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526024016106ee565b600a5468010000000000000000900461ffff1683111561310a576040517f099d3f7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff861660048201526024016106ee565b80831461314f576040517f8808f8e700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff861660048201526024016106ee565b600a54640100000000900463ffffffff168211156131b357600a546040517f8693378900000000000000000000000000000000000000000000000000000000815264010000000090910463ffffffff166004820152602481018390526044016106ee565b5050505050565b600060026131c9608085615215565b67ffffffffffffffff166131dd919061523c565b905060006010816131ef608087615253565b67ffffffffffffffff168152602081019190915260400160002054905081613219600160046151d3565b901b191681836003811115613230576132306143c5565b901b178060106000613243608088615253565b67ffffffffffffffff16815260208101919091526040016000205550505050565b6040517fb6113fce000000000000000000000000000000000000000000000000000000008152600090606090309063b6113fce906132aa90889088908890600401615c1c565b600060405180830381600087803b1580156132c457600080fd5b505af19250505080156132d5575060015b613314573d808015613303576040519150601f19603f3d011682016040523d82523d6000602084013e613308565b606091505b50600392509050613329565b50506040805160208101909152600081526002905b935093915050565b6040805180820190915260008082526020820152600061335484602001516139de565b6040517fbbe4f6db0000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192506000917f000000000000000000000000f49c561cf56149517c67793a3035d1877ffe2f04169063bbe4f6db90602401602060405180830381865afa1580156133d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fd9190615da5565b90506001600160a01b038116158061344557506134436001600160a01b0382167faff2afbf00000000000000000000000000000000000000000000000000000000612b8f565b155b15613487576040517fae9b4ce90000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016106ee565b60008061349f8885896060015163ffffffff16613a84565b91509150600080600061359d6040518061010001604052808e81526020017f000000000000000000000000000000000000000000000000de41ba4fc9d91ad967ffffffffffffffff1681526020018d6001600160a01b031681526020018f8152602001896001600160a01b031681526020018c6000015181526020018c6040015181526020018b8152506040516024016135399190615dc2565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f390775370000000000000000000000000000000000000000000000000000000017905287866113886084613bc7565b925092509250826135dc57816040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b81516020146136245781516040517f78ef80240000000000000000000000000000000000000000000000000000000081526020600482015260248101919091526044016106ee565b60008280602001905181019061363a91906159c3565b9050866001600160a01b03168c6001600160a01b0316146136cf57600061366b8d8a613666868a6151d3565b613a84565b5090508681108061368557508161368288836151d3565b14155b156136cd576040517fa966e21f0000000000000000000000000000000000000000000000000000000081526004810183905260248101889052604481018290526064016106ee565b505b604080518082019091526001600160a01b039098168852602088015250949550505050505095945050505050565b6000610e5d836001600160a01b038416613ced565b81516040517fd02641a00000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260009182919084169063d02641a0906024016040805180830381865afa158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c9190615e8f565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81166000036138055783516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016106ee565b6020840151611e33907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff831690613cf9565b61184f6003826000613d36565b600061386c827f01ffc9a7000000000000000000000000000000000000000000000000000000006138a4565b80156106a4575061389d827fffffffff000000000000000000000000000000000000000000000000000000006138a4565b1592915050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000082166024820152600090819060440160408051601f19818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561395d575060208210155b80156139695750600081115b979650505050505050565b60008183106139835781610e5d565b5090919050565b60006106a482614085565b6000808080612daa8686614090565b60008181526002830160205260408120819055610e5d83836140bb565b60008281526002840160205260408120829055611e3384846140c7565b60008151602014613a1d57816040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b600082806020019051810190613a3391906159c3565b90506001600160a01b03811180613a4b575061040081105b156106a457826040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b6000806000806000613b1388604051602401613aaf91906001600160a01b0391909116815260200190565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a082310000000000000000000000000000000000000000000000000000000017905288886113886084613bc7565b92509250925082613b5257816040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016106ee9190614466565b6020825114613b9a5781516040517f78ef80240000000000000000000000000000000000000000000000000000000081526020600482015260248101919091526044016106ee565b81806020019051810190613bae91906159c3565b613bb882886151d3565b94509450505050935093915050565b6000606060008361ffff1667ffffffffffffffff811115613bea57613bea614479565b6040519080825280601f01601f191660200182016040528015613c14576020820181803683370190505b509150863b613c47577f0c3b563c0000000000000000000000000000000000000000000000000000000060005260046000fd5b5a85811015613c7a577fafa32a2c0000000000000000000000000000000000000000000000000000000060005260046000fd5b8590036040810481038710613cb3577f37c3be290000000000000000000000000000000000000000000000000000000060005260046000fd5b505a6000808a5160208c0160008c8cf193505a900390503d84811115613cd65750835b808352806000602085013e50955095509592505050565b6000610e5d83836140d3565b6000670de0b6b3a7640000613d2c837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff861661523c565b610e5d9190615ef1565b825474010000000000000000000000000000000000000000900460ff161580613d5d575081155b15613d6757505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090613dad90700100000000000000000000000000000000900463ffffffff16426151d3565b90508015613e6d5781831115613def576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154613e299083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612e94565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b84821015613f0a576001600160a01b038416613ebf576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016106ee565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b03851660448201526064016106ee565b848310156140035760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16906000908290613f4e90826151d3565b613f58878a6151d3565b613f6291906154aa565b613f6c9190615ef1565b90506001600160a01b038616613fb8576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016106ee565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b03871660448201526064016106ee565b61400d85846151d3565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60006106a4826140df565b6000808061409e85856140e9565b600081815260029690960160205260409095205494959350505050565b6000610e5d83836140f5565b6000610e5d83836141ef565b6000610e5d838361423e565b60006106a4825490565b6000610e5d8383614256565b600081815260018301602052604081205480156141de5760006141196001836151d3565b855490915060009061412d906001906151d3565b905081811461419257600086600001828154811061414d5761414d615294565b906000526020600020015490508087600001848154811061417057614170615294565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806141a3576141a3615f05565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106a4565b60009150506106a4565b5092915050565b6000818152600183016020526040812054614236575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106a4565b5060006106a4565b60008181526001830160205260408120541515610e5d565b600082600001828154811061426d5761426d615294565b9060005260206000200154905092915050565b8280548282559060005260206000209081019282156142ed579160200282015b828111156142ed57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039091161782556020909201916001909101906142a0565b506142f99291506142fd565b5090565b5b808211156142f957600081556001016142fe565b60e081016106a482846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b67ffffffffffffffff8116811461184f57600080fd5b80356143a381614382565b919050565b6000602082840312156143ba57600080fd5b8135610e5d81614382565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110614404576144046143c5565b9052565b602081016106a482846143f4565b60005b83811015614431578181015183820152602001614419565b50506000910152565b60008151808452614452816020860160208601614416565b601f01601f19169290920160200192915050565b602081526000610e5d602083018461443a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156144cb576144cb614479565b60405290565b6040516080810167ffffffffffffffff811182821017156144cb576144cb614479565b6040516101a0810167ffffffffffffffff811182821017156144cb576144cb614479565b604051601f8201601f1916810167ffffffffffffffff8111828210171561454157614541614479565b604052919050565b600067ffffffffffffffff82111561456357614563614479565b5060051b60200190565b6001600160a01b038116811461184f57600080fd5b80356143a38161456d565b600082601f83011261459e57600080fd5b813560206145b36145ae83614549565b614518565b8083825260208201915060208460051b8701019350868411156145d557600080fd5b602086015b848110156145fa5780356145ed8161456d565b83529183019183016145da565b509695505050505050565b803560ff811681146143a357600080fd5b600067ffffffffffffffff82111561463057614630614479565b50601f01601f191660200190565b600082601f83011261464f57600080fd5b813561465d6145ae82614616565b81815284602083860101111561467257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156146a857600080fd5b863567ffffffffffffffff808211156146c057600080fd5b6146cc8a838b0161458d565b975060208901359150808211156146e257600080fd5b6146ee8a838b0161458d565b96506146fc60408a01614605565b9550606089013591508082111561471257600080fd5b61471e8a838b0161463e565b945061472c60808a01614398565b935060a089013591508082111561474257600080fd5b5061474f89828a0161463e565b9150509295509295509295565b60008151808452602080850194506020840160005b838110156147965781516001600160a01b031687529582019590820190600101614771565b509495945050505050565b602081526000610e5d602083018461475c565b6000602082840312156147c657600080fd5b8135610e5d8161456d565b60a081016106a4828463ffffffff8082511683528060208301511660208401525061ffff604082015116604083015260608101516001600160a01b03808216606085015280608084015116608085015250505050565b60006020828403121561483957600080fd5b813567ffffffffffffffff81111561485057600080fd5b820160a08185031215610e5d57600080fd5b600082601f83011261487357600080fd5b813560206148836145ae83614549565b82815260069290921b840181019181810190868411156148a257600080fd5b8286015b848110156145fa57604081890312156148bf5760008081fd5b6148c76144a8565b81356148d28161456d565b8152818501356148e18161456d565b818601528352918301916040016148a6565b6000806040838503121561490657600080fd5b823567ffffffffffffffff8082111561491e57600080fd5b61492a86838701614862565b9350602085013591508082111561494057600080fd5b5061494d85828601614862565b9150509250929050565b801515811461184f57600080fd5b80356143a381614957565b60006040828403121561498257600080fd5b61498a6144a8565b905081356149978161456d565b808252506020820135602082015292915050565b600082601f8301126149bc57600080fd5b813560206149cc6145ae83614549565b8083825260208201915060208460061b8701019350868411156149ee57600080fd5b602086015b848110156145fa57614a058882614970565b8352918301916040016149f3565b600082601f830112614a2457600080fd5b81356020614a346145ae83614549565b82815260059290921b84018101918181019086841115614a5357600080fd5b8286015b848110156145fa57803567ffffffffffffffff811115614a775760008081fd5b614a858986838b010161463e565b845250918301918301614a57565b600082601f830112614aa457600080fd5b81356020614ab46145ae83614549565b82815260059290921b84018101918181019086841115614ad357600080fd5b8286015b848110156145fa57803567ffffffffffffffff811115614af75760008081fd5b614b058986838b0101614a13565b845250918301918301614ad7565b600082601f830112614b2457600080fd5b81356020614b346145ae83614549565b8083825260208201915060208460051b870101935086841115614b5657600080fd5b602086015b848110156145fa5780358352918301918301614b5b565b600060808284031215614b8457600080fd5b614b8c6144d1565b9050813567ffffffffffffffff80821115614ba657600080fd5b818401915084601f830112614bba57600080fd5b81356020614bca6145ae83614549565b82815260059290921b84018101918181019088841115614be957600080fd5b8286015b84811015614d4557803586811115614c0457600080fd5b87016101a0818c03601f19011215614c1b57600080fd5b614c236144f4565b614c2e868301614398565b8152614c3c60408301614582565b86820152614c4c60608301614582565b6040820152614c5d60808301614398565b606082015260a08201356080820152614c7860c08301614965565b60a0820152614c8960e08301614398565b60c0820152610100614c9c818401614582565b60e083015261012080840135828401526101409150818401358a811115614cc257600080fd5b614cd08f8a8388010161463e565b828501525050610160808401358a811115614cea57600080fd5b614cf88f8a838801016149ab565b83850152506101809150818401358a811115614d1357600080fd5b614d218f8a83880101614a13565b91840191909152506101a09290920135918101919091528352918301918301614bed565b5086525085810135935082841115614d5c57600080fd5b614d6887858801614a93565b90850152506040840135915080821115614d8157600080fd5b50614d8e84828501614b13565b6040830152506060820135606082015292915050565b63ffffffff8116811461184f57600080fd5b600082601f830112614dc757600080fd5b81356020614dd76145ae83614549565b8083825260208201915060208460051b870101935086841115614df957600080fd5b602086015b848110156145fa578035614e1181614da4565b8352918301918301614dfe565b6000806040808486031215614e3257600080fd5b833567ffffffffffffffff80821115614e4a57600080fd5b614e5687838801614b72565b9450602091508186013581811115614e6d57600080fd5b8601601f81018813614e7e57600080fd5b8035614e8c6145ae82614549565b81815260059190911b8201840190848101908a831115614eab57600080fd5b8584015b83811015614f1e57803586811115614ec75760008081fd5b8501808d03601f1901891315614edd5760008081fd5b614ee56144a8565b8882013581528982013588811115614efd5760008081fd5b614f0b8f8b83860101614db6565b828b015250845250918601918601614eaf565b50809750505050505050509250929050565b60008083601f840112614f4257600080fd5b50813567ffffffffffffffff811115614f5a57600080fd5b6020830191508360208260051b8501011115612db257600080fd5b60008060008060008060008060e0898b031215614f9157600080fd5b606089018a811115614fa257600080fd5b8998503567ffffffffffffffff80821115614fbc57600080fd5b818b0191508b601f830112614fd057600080fd5b813581811115614fdf57600080fd5b8c6020828501011115614ff157600080fd5b6020830199508098505060808b013591508082111561500f57600080fd5b61501b8c838d01614f30565b909750955060a08b013591508082111561503457600080fd5b506150418b828c01614f30565b999c989b50969995989497949560c00135949350505050565b6000806000806060858703121561507057600080fd5b843567ffffffffffffffff8082111561508857600080fd5b908601906101a0828903121561509d57600080fd5b909450602086013590808211156150b357600080fd5b6150bf88838901614f30565b909550935060408701359150808211156150d857600080fd5b506150e587828801614db6565b91505092959194509250565b80356fffffffffffffffffffffffffffffffff811681146143a357600080fd5b60006060828403121561512357600080fd5b6040516060810181811067ffffffffffffffff8211171561514657615146614479565b604052823561515481614957565b8152615162602084016150f1565b6020820152615173604084016150f1565b60408201529392505050565b604081526000615192604083018561475c565b8281036020840152612eb3818561475c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106a4576106a46151a4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff80841680615230576152306151e6565b92169190910692915050565b80820281158282048414176106a4576106a46151a4565b600067ffffffffffffffff8084168061526e5761526e6151e6565b92169190910492915050565b602081016003831061528e5761528e6143c5565b91905290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff8083168181036152dc576152dc6151a4565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526153168184018a61475c565b9050828103608084015261532a818961475c565b905060ff871660a084015282810360c0840152615347818761443a565b905067ffffffffffffffff851660e084015282810361010084015261536c818561443a565b9c9b505050505050505050505050565b60006020828403121561538e57600080fd5b8151610e5d81614382565b600082601f8301126153aa57600080fd5b81516153b86145ae82614616565b8181528460208386010111156153cd57600080fd5b611e33826020830160208701614416565b6000602082840312156153f057600080fd5b815167ffffffffffffffff8082111561540857600080fd5b908301906080828603121561541c57600080fd5b6154246144d1565b82518281111561543357600080fd5b61543f87828601615399565b82525060208301518281111561545457600080fd5b61546087828601615399565b60208301525060408301518281111561547857600080fd5b61548487828601615399565b6040830152506060830151925061549a83614da4565b6060810192909252509392505050565b808201808211156106a4576106a46151a4565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126154f257600080fd5b83018035915067ffffffffffffffff82111561550d57600080fd5b6020019150600681901b3603821315612db257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261555a57600080fd5b83018035915067ffffffffffffffff82111561557557600080fd5b6020019150600581901b3603821315612db257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155c257600080fd5b83018035915067ffffffffffffffff8211156155dd57600080fd5b602001915036819003821315612db257600080fd5b60008151808452602080850194506020840160005b8381101561479657815180516001600160a01b031688528301518388015260409096019590820190600101615607565b608081528451608082015267ffffffffffffffff60208601511660a08201526000604086015160a060c084015261567261012084018261443a565b905060608701517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808584030160e08601526156ae838361443a565b9250608089015191508085840301610100860152506156cd82826155f2565b925050506156e1602083018661ffff169052565b836040830152612eb360608301846001600160a01b03169052565b60008060006060848603121561571157600080fd5b835161571c81614957565b602085015190935067ffffffffffffffff81111561573957600080fd5b61574586828701615399565b925050604084015190509250925092565b600060a0828403121561576857600080fd5b60405160a0810181811067ffffffffffffffff8211171561578b5761578b614479565b604052825161579981614da4565b815260208301516157a981614da4565b6020820152604083015161ffff811681146157c357600080fd5b604082015260608301516157d68161456d565b606082015260808301516157e98161456d565b60808201529392505050565b610180810161586682856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b825163ffffffff90811660e0840152602084015116610100830152604083015161ffff1661012083015260608301516001600160a01b03908116610140840152608084015116610160830152610e5d565b60006101208b83526001600160a01b038b16602084015267ffffffffffffffff808b1660408501528160608501526158f18285018b61475c565b91508382036080850152615905828a61475c565b915060ff881660a085015283820360c0850152615922828861443a565b90861660e0850152838103610100850152905061536c818561443a565b60006020828403121561595157600080fd5b8151610e5d81614957565b60008151808452602080850194506020840160005b8381101561479657815187529582019590820190600101615971565b6060815260006159a0606083018661595c565b82810360208401526159b2818661595c565b915050826040830152949350505050565b6000602082840312156159d557600080fd5b5051919050565b67ffffffffffffffff8181168382160190808211156141e8576141e86151a4565b67ffffffffffffffff8316815260408101610e5d60208301846143f4565b600067ffffffffffffffff8083168181036152dc576152dc6151a4565b615a4281846143f4565b604060208201526000611e33604083018461443a565b600060208284031215615a6a57600080fd5b813567ffffffffffffffff811115615a8157600080fd5b611e3384828501614b72565b600060408284031215615a9f57600080fd5b610e5d8383614970565b600060208284031215615abb57600080fd5b813567ffffffffffffffff80821115615ad357600080fd5b9083019060808286031215615ae757600080fd5b615aef6144d1565b823582811115615afe57600080fd5b615b0a8782860161463e565b825250602083013582811115615b1f57600080fd5b615b2b8782860161463e565b602083015250604083013582811115615b4357600080fd5b615b4f8782860161463e565b6040830152506060830135925061549a83614da4565b602081526000610e5d60208301846155f2565b60008282518085526020808601955060208260051b8401016020860160005b84811015615bc557601f19868403018952615bb383835161443a565b98840198925090830190600101615b97565b5090979650505050505050565b602081526000610e5d6020830184615b78565b60008151808452602080850194506020840160005b8381101561479657815163ffffffff1687529582019590820190600101615bfa565b60608152615c3760608201855167ffffffffffffffff169052565b60006020850151615c5360808401826001600160a01b03169052565b5060408501516001600160a01b03811660a084015250606085015167ffffffffffffffff811660c084015250608085015160e083015260a0850151610100615c9e8185018315159052565b60c08701519150610120615cbd8186018467ffffffffffffffff169052565b60e08801519250610140615cdb818701856001600160a01b03169052565b828901519350610160925083838701528189015193506101a091506101808281880152615d0c61020088018661443a565b9450818a015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0808887030184890152615d4886846155f2565b948b01518886039091016101c0890152939450615d658585615b78565b9450808a01516101e0880152505050508281036020840152615d878186615b78565b90508281036040840152615d9b8185615be5565b9695505050505050565b600060208284031215615db757600080fd5b8151610e5d8161456d565b6020815260008251610100806020850152615de161012085018361443a565b91506020850151615dfe604086018267ffffffffffffffff169052565b5060408501516001600160a01b038116606086015250606085015160808501526080850151615e3860a08601826001600160a01b03169052565b5060a0850151601f19808685030160c0870152615e55848361443a565b935060c08701519150808685030160e0870152615e72848361443a565b935060e0870151915080868503018387015250615d9b838261443a565b600060408284031215615ea157600080fd5b615ea96144a8565b82517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114615ed557600080fd5b81526020830151615ee581614da4565b60208201529392505050565b600082615f0057615f006151e6565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000075d23898771cc508234b5be8318a0c5ee8ebae060000000000000000000000000000000000000000000000001fa3b5d5b7cd348b000000000000000000000000000000000000000000000000de41ba4fc9d91ad9000000000000000000000000f2e86c53c3305d37b161d30783869624cfaae69100000000000000000000000000000000000000000000000000000000000000000000000000000000000000008f4413e02265f65ef89fb908dba2915ff9f7f8cb000000000000000000000000f49c561cf56149517c67793a3035d1877ffe2f04000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000152d02c7e14af68000000000000000000000000000000000000000000000000000090d972f32323c0000
-----Decoded View---------------
Arg [0] : staticConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : rateLimiterConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000075d23898771cc508234b5be8318a0c5ee8ebae06
Arg [1] : 0000000000000000000000000000000000000000000000001fa3b5d5b7cd348b
Arg [2] : 000000000000000000000000000000000000000000000000de41ba4fc9d91ad9
Arg [3] : 000000000000000000000000f2e86c53c3305d37b161d30783869624cfaae691
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000008f4413e02265f65ef89fb908dba2915ff9f7f8cb
Arg [6] : 000000000000000000000000f49c561cf56149517c67793a3035d1877ffe2f04
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [8] : 00000000000000000000000000000000000000000000152d02c7e14af6800000
Arg [9] : 0000000000000000000000000000000000000000000000090d972f32323c0000
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.