Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 2,793 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transmit | 19509317 | 112 days ago | IN | 0 ETH | 0.00355194 | ||||
Transmit | 19325925 | 138 days ago | IN | 0 ETH | 0.00668951 | ||||
Transmit | 19325635 | 138 days ago | IN | 0 ETH | 0.0051346 | ||||
Transmit | 19325370 | 138 days ago | IN | 0 ETH | 0.00533314 | ||||
Transmit | 19325044 | 138 days ago | IN | 0 ETH | 0.00649209 | ||||
Transmit | 19324758 | 138 days ago | IN | 0 ETH | 0.00465002 | ||||
Transmit | 19324443 | 138 days ago | IN | 0 ETH | 0.00349736 | ||||
Transmit | 19324132 | 138 days ago | IN | 0 ETH | 0.00344105 | ||||
Transmit | 19323879 | 138 days ago | IN | 0 ETH | 0.00335964 | ||||
Transmit | 19323556 | 138 days ago | IN | 0 ETH | 0.00335862 | ||||
Transmit | 19323259 | 138 days ago | IN | 0 ETH | 0.00497859 | ||||
Transmit | 19322967 | 138 days ago | IN | 0 ETH | 0.00382514 | ||||
Transmit | 19322676 | 138 days ago | IN | 0 ETH | 0.00355196 | ||||
Transmit | 19322361 | 138 days ago | IN | 0 ETH | 0.00493148 | ||||
Transmit | 19322056 | 139 days ago | IN | 0 ETH | 0.0055383 | ||||
Transmit | 19254937 | 148 days ago | IN | 0 ETH | 0.0020668 | ||||
Transmit | 19254372 | 148 days ago | IN | 0 ETH | 0.00226787 | ||||
Transmit | 19254066 | 148 days ago | IN | 0 ETH | 0.00191141 | ||||
Transmit | 19253748 | 148 days ago | IN | 0 ETH | 0.00218256 | ||||
Transmit | 19253468 | 148 days ago | IN | 0 ETH | 0.00282335 | ||||
Transmit | 19253191 | 148 days ago | IN | 0 ETH | 0.0028673 | ||||
Transmit | 19252844 | 148 days ago | IN | 0 ETH | 0.00149874 | ||||
Transmit | 19252583 | 148 days ago | IN | 0 ETH | 0.00141453 | ||||
Transmit | 19252256 | 148 days ago | IN | 0 ETH | 0.00139949 | ||||
Transmit | 19251987 | 148 days ago | IN | 0 ETH | 0.00182796 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
EVM2EVMOffRamp
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 26000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; import {ICommitStore} from "../interfaces/ICommitStore.sol"; import {IARM} from "../interfaces/IARM.sol"; import {IPool} from "../interfaces/pools/IPool.sol"; import {IRouter} from "../interfaces/IRouter.sol"; import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol"; import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol"; import {IAny2EVMOffRamp} from "../interfaces/IAny2EVMOffRamp.sol"; import {Client} from "../libraries/Client.sol"; import {Internal} from "../libraries/Internal.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; import {OCR2BaseNoChecks} from "../ocr/OCR2BaseNoChecks.sol"; import {AggregateRateLimiter} from "../AggregateRateLimiter.sol"; import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol"; import {Address} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/Address.sol"; import {ERC165Checker} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/introspection/ERC165Checker.sol"; /// @notice EVM2EVMOffRamp enables OCR networks to execute multiple messages /// in an OffRamp in a single transaction. /// @dev We will always deploy an onRamp, commitStore, and offRamp at the same time /// and we will never do partial updates where e.g. only an offRamp gets replaced. /// If we would replace only the offRamp and connect it with an existing commitStore, /// a replay attack would be possible. contract EVM2EVMOffRamp is IAny2EVMOffRamp, AggregateRateLimiter, TypeAndVersionInterface, OCR2BaseNoChecks { using Address for address; using ERC165Checker for address; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; error AlreadyAttempted(uint64 sequenceNumber); error AlreadyExecuted(uint64 sequenceNumber); error ZeroAddressNotAllowed(); error CommitStoreAlreadyInUse(); error ExecutionError(bytes error); 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 InvalidManualExecutionGasLimit(uint256 index, uint256 newLimit); error RootNotCommitted(); error UnsupportedToken(IERC20 token); error CanOnlySelfCall(); error ReceiverError(bytes error); error TokenHandlingError(bytes error); error TokenRateLimitError(bytes error); error EmptyReport(); error BadARMSignal(); error InvalidMessageId(); error InvalidTokenPoolConfig(); error PoolAlreadyAdded(); error PoolDoesNotExist(); error TokenPoolMismatch(); error InvalidNewState(uint64 sequenceNumber, Internal.MessageExecutionState newState); event PoolAdded(address token, address pool); event PoolRemoved(address token, address pool); // this event is needed for Atlas; if their structs/signature changes, we must update the ABIs there event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig); event SkippedIncorrectNonce(uint64 indexed nonce, address indexed sender); event SkippedSenderWithPreviousRampMessageInflight(uint64 indexed nonce, address indexed sender); event ExecutionStateChanged( uint64 indexed sequenceNumber, bytes32 indexed messageId, Internal.MessageExecutionState state, bytes returnData ); /// @notice Static offRamp config 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 armProxy; // ------------ ARM proxy 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 address router; // ---------------------------------┘ Router address address priceRegistry; // -----┐ Price registry address uint16 maxTokensLength; // | Maximum number of distinct ERC20 tokens that can be sent per message uint32 maxDataSize; // --------┘ Maximum payload data size } // STATIC CONFIG // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "EVM2EVMOffRamp 1.0.0"; // The minimum amount of gas to perform the call with exact gas uint16 private constant GAS_FOR_CALL_EXACT_CHECK = 5_000; // Commit store address on the destination chain address internal immutable i_commitStore; // ChainSelector of the source chain uint64 internal immutable i_sourceChainSelector; // ChainSelector of this chain uint64 internal immutable i_chainSelector; // OnRamp address on the source chain address internal immutable i_onRamp; // metadataHash is a prefix for a message hash preimage to ensure uniqueness. bytes32 internal immutable i_metadataHash; /// @dev The address of previous-version OffRamp for this lane address internal immutable i_prevOffRamp; /// @dev The address of the arm proxy address internal immutable i_armProxy; // DYNAMIC CONFIG DynamicConfig internal s_dynamicConfig; // source token => token pool EnumerableMapAddresses.AddressToAddressMap private s_poolsBySourceToken; // dest token => token pool EnumerableMapAddresses.AddressToAddressMap private s_poolsByDestToken; // STATE // The expected nonce for a given sender. mapping(address sender => uint64 nonce) internal s_senderNonce; // 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. // This state makes sure we never execute a message twice. mapping(uint64 seqNum => uint256 executionStateBitmap) internal s_executionStates; constructor( StaticConfig memory staticConfig, IERC20[] memory sourceTokens, IPool[] memory pools, RateLimiter.Config memory rateLimiterConfig ) OCR2BaseNoChecks() AggregateRateLimiter(rateLimiterConfig) { if (sourceTokens.length != pools.length) revert InvalidTokenPoolConfig(); if (staticConfig.onRamp == address(0) || staticConfig.commitStore == 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_armProxy = staticConfig.armProxy; i_metadataHash = _metadataHash(Internal.EVM_2_EVM_MESSAGE_HASH); // Set new tokens and pools for (uint256 i = 0; i < sourceTokens.length; ++i) { s_poolsBySourceToken.set(address(sourceTokens[i]), address(pools[i])); s_poolsByDestToken.set(address(pools[i].getToken()), address(pools[i])); emit PoolAdded(address(sourceTokens[i]), address(pools[i])); } } // ================================================================ // | 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) public view returns (uint64 nonce) { uint256 senderNonce = s_senderNonce[sender]; if (senderNonce == 0 && 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. function manuallyExecute(Internal.ExecutionReport memory report, uint256[] memory gasLimitOverrides) external { // We do this here because the other _execute path is already covered OCR2BaseXXX. if (i_chainID != block.chainid) revert OCR2BaseNoChecks.ForkedChain(i_chainID, uint64(block.chainid)); uint256 numMsgs = report.messages.length; if (numMsgs != gasLimitOverrides.length) revert ManualExecutionGasLimitMismatch(); for (uint256 i = 0; i < numMsgs; ++i) { uint256 newLimit = gasLimitOverrides[i]; // Checks to ensure message cannot be executed with less gas than specified. if (newLimit != 0 && newLimit < report.messages[i].gasLimit) revert InvalidManualExecutionGasLimit(i, newLimit); } _execute(report, gasLimitOverrides); } /// @notice Entrypoint for execution, called by the OCR network /// @dev Expects an encoded ExecutionReport function _report(bytes calldata report) internal override { _execute(abi.decode(report, (Internal.ExecutionReport)), new uint256[](0)); } /// @notice Executes a report, executing each message in order. /// @param report The execution report containing the messages and proofs. /// @param manualExecGasLimits An array of gas limits to use for manual execution. /// If called from the DON, this array is always empty. /// If called from manual execution, this array is always same length as messages. function _execute(Internal.ExecutionReport memory report, uint256[] memory manualExecGasLimits) internal whenHealthy { 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(); } // SECURITY CRITICAL CHECK uint256 timestampCommitted = ICommitStore(i_commitStore).verify(hashedLeaves, report.proofs, report.proofFlagBits); if (timestampCommitted == 0) revert RootNotCommitted(); // Execute messages bool manualExecution = manualExecGasLimits.length != 0; 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 states are // IN_PROGRESS and SUCCESS, both should not be allowed to execute. if ( !(originalState == Internal.MessageExecutionState.UNTOUCHED || originalState == Internal.MessageExecutionState.FAILURE) ) revert AlreadyExecuted(message.sequenceNumber); if (manualExecution) { 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 (manualExecGasLimits[i] != 0) { message.gasLimit = manualExecGasLimits[i]; } } else { // DON can only execute a message once // Acceptable state transitions: UNTOUCHED->SUCCESS, UNTOUCHED->FAILURE if (originalState != Internal.MessageExecutionState.UNTOUCHED) revert AlreadyAttempted(message.sequenceNumber); } // 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 && 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. If in strict mode and nonce isn't bumped due to failure, // then we'll call the old offramp again until it succeeds. s_senderNonce[message.sender] = prevNonce; } // UNTOUCHED messages MUST be executed in order always if (originalState == Internal.MessageExecutionState.UNTOUCHED) { if (prevNonce + 1 != message.nonce) { // We skip the message if the nonce is incorrect emit SkippedIncorrectNonce(message.nonce, message.sender); continue; } } bytes[] memory offchainTokenData = report.offchainTokenData[i]; _isWellFormed(message, offchainTokenData.length); _setExecutionState(message.sequenceNumber, Internal.MessageExecutionState.IN_PROGRESS); (Internal.MessageExecutionState newState, bytes memory returnData) = _trialExecute(message, offchainTokenData); _setExecutionState(message.sequenceNumber, newState); // The only valid prior states are UNTOUCHED and FAILURE (checked above) // The only valid post states are FAILURE and SUCCESS (checked below) if (newState != Internal.MessageExecutionState.FAILURE && newState != Internal.MessageExecutionState.SUCCESS) revert InvalidNewState(message.sequenceNumber, newState); // Nonce changes per state transition strict // UNTOUCHED -> FAILURE no nonce bump // UNTOUCHED -> SUCCESS: nonce bump // FAILURE -> FAILURE: no nonce bump // FAILURE -> SUCCESS: nonce bump if (message.strict) { if (newState == Internal.MessageExecutionState.SUCCESS) { s_senderNonce[message.sender]++; } // Nonce changes per state transition non-strict // UNTOUCHED -> FAILURE nonce bump // UNTOUCHED -> SUCCESS nonce bump // FAILURE -> FAILURE no nonce bump // FAILURE -> SUCCESS no nonce bump } else 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 message The message to be validated. /// @dev reverts on validation failures. function _isWellFormed(Internal.EVM2EVMMessage memory message, uint256 offchainTokenDataLength) private view { if (message.sourceChainSelector != i_sourceChainSelector) revert InvalidSourceChain(message.sourceChainSelector); if (message.tokenAmounts.length > uint256(s_dynamicConfig.maxTokensLength)) revert UnsupportedNumberOfTokens(message.sequenceNumber); if (message.tokenAmounts.length != offchainTokenDataLength) revert TokenDataMismatch(message.sequenceNumber); if (message.data.length > uint256(s_dynamicConfig.maxDataSize)) revert MessageTooLarge(uint256(s_dynamicConfig.maxDataSize), message.data.length); } /// @notice Try executing a message. /// @param message Client.Any2EVMMessage 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 ) internal returns (Internal.MessageExecutionState, bytes memory) { try this.executeSingleMessage(message, offchainTokenData) {} catch (bytes memory err) { if (ReceiverError.selector == bytes4(err) || TokenHandlingError.selector == bytes4(err)) { // If CCIP receiver execution is not successful, bubble up receiver revert data, // prepended by the 4 bytes of ReceiverError.selector // 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); } else { // If revert is not caused by CCIP receiver, it is unexpected, bubble up the revert. revert ExecutionError(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 this can only be called by the contract itself. It is part of /// the Execute call, as we can only try/catch on external calls. function executeSingleMessage(Internal.EVM2EVMMessage memory message, bytes[] memory offchainTokenData) 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, offchainTokenData ); } if ( !message.receiver.isContract() || !message.receiver.supportsInterface(type(IAny2EVMMessageReceiver).interfaceId) ) return; (bool success, bytes memory returnData) = IRouter(s_dynamicConfig.router).routeMessage( Internal._toAny2EVMMessage(message, destTokenAmounts), 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. function getStaticConfig() external view returns (StaticConfig memory) { return StaticConfig({ commitStore: i_commitStore, chainSelector: i_chainSelector, sourceChainSelector: i_sourceChainSelector, onRamp: i_onRamp, prevOffRamp: i_prevOffRamp, armProxy: i_armProxy }); } /// @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, armProxy: i_armProxy }), dynamicConfig ); } // ================================================================ // | Tokens and pools | // ================================================================ /// @notice Get all supported source tokens /// @return sourceTokens of supported source tokens function getSupportedTokens() external view returns (IERC20[] memory sourceTokens) { sourceTokens = new IERC20[](s_poolsBySourceToken.length()); for (uint256 i = 0; i < sourceTokens.length; ++i) { (address token, ) = s_poolsBySourceToken.at(i); sourceTokens[i] = IERC20(token); } } /// @notice Get a token pool by its source token /// @param sourceToken token /// @return Token Pool function getPoolBySourceToken(IERC20 sourceToken) public view returns (IPool) { (bool success, address pool) = s_poolsBySourceToken.tryGet(address(sourceToken)); if (!success) revert UnsupportedToken(sourceToken); return IPool(pool); } /// @notice Get the destination token from the pool based on a given source token. /// @param sourceToken The source token /// @return the destination token function getDestinationToken(IERC20 sourceToken) external view returns (IERC20) { (bool success, address pool) = s_poolsBySourceToken.tryGet(address(sourceToken)); if (!success) revert UnsupportedToken(sourceToken); return IPool(pool).getToken(); } /// @notice Get a token pool by its dest token /// @param destToken token /// @return Token Pool function getPoolByDestToken(IERC20 destToken) external view returns (IPool) { (bool success, address pool) = s_poolsByDestToken.tryGet(address(destToken)); if (!success) revert UnsupportedToken(destToken); return IPool(pool); } /// @notice Get all configured destination tokens /// @return destTokens Array of configured destination tokens function getDestinationTokens() external view returns (IERC20[] memory destTokens) { destTokens = new IERC20[](s_poolsByDestToken.length()); for (uint256 i = 0; i < destTokens.length; ++i) { (address token, ) = s_poolsByDestToken.at(i); destTokens[i] = IERC20(token); } } /// @notice Adds and removed token pools. /// @param removes The tokens and pools to be removed /// @param adds The tokens and pools to be added. function applyPoolUpdates( Internal.PoolUpdate[] calldata removes, Internal.PoolUpdate[] calldata adds ) external onlyOwner { for (uint256 i = 0; i < removes.length; ++i) { address token = removes[i].token; address pool = removes[i].pool; // Check if the pool exists if (!s_poolsBySourceToken.contains(token)) revert PoolDoesNotExist(); // Sanity check if (s_poolsBySourceToken.get(token) != pool) revert TokenPoolMismatch(); s_poolsBySourceToken.remove(token); s_poolsByDestToken.remove(address(IPool(pool).getToken())); emit PoolRemoved(token, pool); } for (uint256 i = 0; i < adds.length; ++i) { address token = adds[i].token; address pool = adds[i].pool; if (token == address(0) || pool == address(0)) revert InvalidTokenPoolConfig(); // Check if the pool is already set if (s_poolsBySourceToken.contains(token)) revert PoolAlreadyAdded(); // Set the s_pools with new config values s_poolsBySourceToken.set(token, pool); s_poolsByDestToken.set(address(IPool(pool).getToken()), pool); emit PoolAdded(token, pool); } } /// @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 receiver The address that will receive the tokens. /// @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[] memory sourceTokenAmounts, bytes memory originalSender, address receiver, bytes[] memory offchainTokenData ) internal returns (Client.EVMTokenAmount[] memory) { Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](sourceTokenAmounts.length); for (uint256 i = 0; i < sourceTokenAmounts.length; ++i) { IPool pool = getPoolBySourceToken(IERC20(sourceTokenAmounts[i].token)); try pool.releaseOrMint( originalSender, receiver, sourceTokenAmounts[i].amount, i_sourceChainSelector, offchainTokenData[i] ) {} catch ( /// @dev we only want to revert on rate limiting errors, any other errors are /// wrapped in a TokenHandlingError, which is caught above and handled gracefully. bytes memory err ) { bytes4 errSig = bytes4(err); if ( RateLimiter.BucketOverfilled.selector == errSig || RateLimiter.AggregateValueMaxCapacityExceeded.selector == errSig || RateLimiter.AggregateValueRateLimitReached.selector == errSig || RateLimiter.TokenMaxCapacityExceeded.selector == errSig || RateLimiter.TokenRateLimitReached.selector == errSig ) { revert TokenRateLimitError(err); } else { revert TokenHandlingError(err); } } destTokenAmounts[i].token = address(pool.getToken()); destTokenAmounts[i].amount = sourceTokenAmounts[i].amount; } _rateLimitValue(destTokenAmounts, IPriceRegistry(s_dynamicConfig.priceRegistry)); return destTokenAmounts; } // ================================================================ // | Access and ARM | // ================================================================ /// @notice Reverts as this contract should not access CCIP messages function ccipReceive(Client.Any2EVMMessage calldata) external pure { // solhint-disable-next-line reason-string revert(); } /// @notice Ensure that the ARM has not emitted a bad signal, and that the latest heartbeat is not stale. modifier whenHealthy() { if (IARM(i_armProxy).isCursed()) revert BadARMSignal(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract TypeAndVersionInterface { function typeAndVersion() external pure virtual returns (string memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; 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: BUSL-1.1 pragma solidity ^0.8.0; /// @notice This interface contains the only ARM-related functions that might be used on-chain by other CCIP contracts. interface IARM { /// @notice A Merkle root tagged with the address of the commit store contract it is destined for. struct TaggedRoot { address commitStore; bytes32 root; } /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed. function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool); /// @notice When the ARM is "cursed", CCIP pauses until the curse is lifted. function isCursed() external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol"; // Shared public interface for multiple pool types. // Each pool type handles a different child token model (lock/unlock, mint/burn.) interface IPool { /// @notice Lock tokens into the pool or burn the tokens. /// @param originalSender Original sender of the tokens. /// @param receiver Receiver of the tokens on destination chain. /// @param amount Amount to lock or burn. /// @param destChainSelector Destination chain Id. /// @param extraArgs Additional data passed in by sender for lockOrBurn processing /// in custom pools on source chain. /// @return retData Optional field that contains bytes. Unused for now but already /// implemented to allow future upgrades while preserving the interface. function lockOrBurn( address originalSender, bytes calldata receiver, uint256 amount, uint64 destChainSelector, bytes calldata extraArgs ) external returns (bytes memory); /// @notice Releases or mints tokens to the receiver address. /// @param originalSender Original sender of the tokens. /// @param receiver Receiver of the tokens. /// @param amount Amount to release or mint. /// @param sourceChainSelector Source chain Id. /// @param extraData Additional data supplied offchain for releaseOrMint processing in /// custom pools on dest chain. This could be an attestation that was retrieved through a /// third party API. /// @dev offchainData can come from any untrusted source. function releaseOrMint( bytes memory originalSender, address receiver, uint256 amount, uint64 sourceChainSelector, bytes memory extraData ) external; /// @notice Gets the IERC20 token that this pool can lock or burn. /// @return token The IERC20 token representation. function getToken() external view returns (IERC20 token); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; 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. function routeMessage( Client.Any2EVMMessage calldata message, uint16 gasForCallExactCheck, uint256 gasLimit, address receiver ) external returns (bool success, bytes memory retBytes); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {Internal} from "../libraries/Internal.sol"; interface IPriceRegistry { /// @notice Update the price for given tokens and destination chain. /// @param priceUpdates The price updates to apply. function updatePrices(Internal.PriceUpdates memory priceUpdates) external; /// @notice Get the `tokenPrice` for a given token. /// @param token The token to get the price for. /// @return tokenPrice The tokenPrice for the given token. function getTokenPrice(address token) external view returns (Internal.TimestampedUint192Value memory); /// @notice Get the `tokenPrice` for a given token, checks if the price is valid. /// @param token The token to get the price for. /// @return tokenPrice The tokenPrice for the given token if it exists and is valid. function getValidatedTokenPrice(address token) external view returns (uint192); /// @notice Get the `tokenPrice` for an array of tokens. /// @param tokens The tokens to get prices for. /// @return tokenPrices The tokenPrices for the given tokens. function getTokenPrices(address[] calldata tokens) external view returns (Internal.TimestampedUint192Value[] memory); /// @notice Get the `gasPrice` for a given destination chain ID. /// @param destChainSelector The destination chain to get the price for. /// @return gasPrice The gasPrice for the given destination chain ID. function getDestinationChainGasPrice( uint64 destChainSelector ) external view returns (Internal.TimestampedUint192Value memory); /// @notice Gets the fee token price and the gas price, both denominated in dollars. /// @param token The source token to get the price for. /// @param destChainSelector The destination chain to get the gas price for. /// @return tokenPrice The price of the feeToken in 1e18 dollars per base unit. /// @return gasPrice The price of gas in 1e18 dollars per base unit. function getTokenAndGasPrices( address token, uint64 destChainSelector ) external view returns (uint192 tokenPrice, uint192 gasPrice); /// @notice Convert a given token amount to target token amount. /// @param fromToken The given token address. /// @param fromTokenAmount The given token amount. /// @param toToken The target token address. /// @return toTokenAmount The target token amount. function convertTokenAmount( address fromToken, uint256 fromTokenAmount, address toToken ) external view returns (uint256 toTokenAmount); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {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: BUSL-1.1 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: BUSL-1.1 pragma solidity ^0.8.0; // End consumer library. library Client { struct EVMTokenAmount { address token; // token address on the local chain. uint256 amount; // Amount of tokens. } struct Any2EVMMessage { bytes32 messageId; // MessageId corresponding to ccipSend on source. uint64 sourceChainSelector; // Source chain selector. bytes sender; // abi.decode(sender) if coming from an EVM chain. bytes data; // payload sent in original message. EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation. } // If extraArgs is empty bytes, the default is 200k gas limit and strict = false. struct EVM2AnyMessage { bytes receiver; // abi.encode(receiver address) for dest EVM chains bytes data; // Data payload EVMTokenAmount[] tokenAmounts; // Token transfers address feeToken; // Address of feeToken. address(0) means you will send msg.value. bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1) } // extraArgs will evolve to support new features // bytes4(keccak256("CCIP EVMExtraArgsV1")); bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9; struct EVMExtraArgsV1 { uint256 gasLimit; // ATTENTION!!! MAX GAS LIMIT 4M FOR BETA TESTING bool strict; // See strict sequencing details below. } function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) { return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {Client} from "./Client.sol"; import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol"; // Library for CCIP internal definitions common to multiple contracts. library Internal { struct PriceUpdates { TokenPriceUpdate[] tokenPriceUpdates; uint64 destChainSelector; // --┐ Destination chain selector uint192 usdPerUnitGas; // -----┘ 1e18 USD per smallest unit (e.g. wei) of destination chain gas } struct TokenPriceUpdate { address sourceToken; // Source token uint192 usdPerToken; // 1e18 USD per smallest unit of token } struct TimestampedUint192Value { uint192 value; // -------┐ The price, in 1e18 USD. uint64 timestamp; // ----┘ Timestamp of the most recent price update. } struct PoolUpdate { address token; // The IERC20 token address address pool; // The token pool address } struct ExecutionReport { EVM2EVMMessage[] messages; // Contains a bytes array for each message // each inner bytes array contains bytes per transferred token bytes[][] offchainTokenData; bytes32[] proofs; uint256 proofFlagBits; } // @notice The cross chain message that gets committed to EVM chains struct EVM2EVMMessage { uint64 sourceChainSelector; uint64 sequenceNumber; uint256 feeTokenAmount; address sender; uint64 nonce; uint256 gasLimit; bool strict; // User fields address receiver; bytes data; Client.EVMTokenAmount[] tokenAmounts; address feeToken; bytes32 messageId; } function _toAny2EVMMessage( EVM2EVMMessage memory original, Client.EVMTokenAmount[] memory destTokenAmounts ) internal pure returns (Client.Any2EVMMessage memory message) { message = Client.Any2EVMMessage({ messageId: original.messageId, sourceChainSelector: original.sourceChainSelector, sender: abi.encode(original.sender), data: original.data, destTokenAmounts: destTokenAmounts }); } bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageEvent"); function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) { return keccak256( abi.encode( MerkleMultiProof.LEAF_DOMAIN_SEPARATOR, metadataHash, original.sequenceNumber, original.nonce, original.sender, original.receiver, keccak256(original.data), keccak256(abi.encode(original.tokenAmounts)), original.gasLimit, original.strict, original.feeToken, original.feeTokenAmount ) ); } /// @notice Enum listing the possible message execution states within /// the offRamp contract. /// UNTOUCHED never executed /// IN_PROGRESS currently being executed, used a replay protection /// SUCCESS successfully executed. End state /// FAILURE unsuccessfully executed, manual execution is now enabled. enum MessageExecutionState { UNTOUCHED, IN_PROGRESS, SUCCESS, FAILURE } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// @notice Implements Token Bucket rate limiting. /// @dev uint128 is safe for rate limiter state. /// For USD value rate limiting, it can adequately store USD value in 18 decimals. /// For ERC20 token amount rate limiting, all tokens that will be listed will have at most /// a supply of uint128.max tokens, and it will therefore not overflow the bucket. /// In exceptional scenarios where tokens consumed may be larger than uint128, /// e.g. compromised issuer, an enabled RateLimiter will check and revert. library RateLimiter { error BucketOverfilled(); error OnlyCallableByAdminOrOwner(); error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress); error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress); error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested); error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available); event TokensConsumed(uint256 tokens); event ConfigChanged(Config config); struct TokenBucket { uint128 tokens; // ------┐ Current number of tokens that are in the bucket. uint32 lastUpdated; // | Timestamp in seconds of the last token refill, good for 100+ years. bool isEnabled; // ------┘ Indication whether the rate limiting is enabled or not uint128 capacity; // ----┐ Maximum number of tokens that can be in the bucket. uint128 rate; // --------┘ Number of tokens per second that the bucket is refilled. } struct Config { bool isEnabled; // Indication whether the rate limiting should be enabled uint128 capacity; // ----┐ Specifies the capacity of the rate limiter uint128 rate; // -------┘ Specifies the rate of the rate limiter } /// @notice _consume removes the given tokens from the pool, lowering the /// rate tokens allowed to be consumed for subsequent calls. /// @param requestTokens The total tokens to be consumed from the bucket. /// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity. /// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket /// @dev emits removal of requestTokens if requestTokens is > 0 function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal { // If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage if (!s_bucket.isEnabled || requestTokens == 0) { return; } uint256 tokens = s_bucket.tokens; uint256 capacity = s_bucket.capacity; uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { if (tokens > capacity) revert BucketOverfilled(); // Refill tokens when arriving at a new block time tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate); s_bucket.lastUpdated = uint32(block.timestamp); } if (capacity < requestTokens) { // Token address 0 indicates consuming aggregate value rate limit capacity. if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens); revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress); } if (tokens < requestTokens) { uint256 rate = s_bucket.rate; // Wait required until the bucket is refilled enough to accept this value, round up to next higher second // Consume is not guaranteed to succeed after wait time passes if there is competing traffic. // This acts as a lower bound of wait time. uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate; if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens); revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress); } tokens -= requestTokens; // Downcast is safe here, as tokens is not larger than capacity s_bucket.tokens = uint128(tokens); emit TokensConsumed(requestTokens); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function _currentTokenBucketState(TokenBucket memory bucket) internal view returns (TokenBucket memory) { // We update the bucket to reflect the status at the exact time of the // call. This means we might need to refill a part of the bucket based // on the time that has passed since the last update. bucket.tokens = uint128( _calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate) ); bucket.lastUpdated = uint32(block.timestamp); return bucket; } /// @notice Sets the rate limited config. /// @param s_bucket The token bucket /// @param config The new config function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal { // First update the bucket to make sure the proper rate is used for all the time // up until the config change. uint256 timeDiff = block.timestamp - s_bucket.lastUpdated; if (timeDiff != 0) { s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate)); s_bucket.lastUpdated = uint32(block.timestamp); } s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens)); s_bucket.isEnabled = config.isEnabled; s_bucket.capacity = config.capacity; s_bucket.rate = config.rate; emit ConfigChanged(config); } /// @notice Calculate refilled tokens /// @param capacity bucket capacity /// @param tokens current bucket tokens /// @param timeDiff block time difference since last refill /// @param rate bucket refill rate /// @return the value of tokens after refill function _calculateRefill( uint256 capacity, uint256 tokens, uint256 timeDiff, uint256 rate ) private pure returns (uint256) { return _min(capacity, tokens + timeDiff * rate); } /// @notice Return the smallest of two integers /// @param a first int /// @param b second int /// @return smallest function _min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; 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(string message); error WrongMessageLength(uint256 expected, uint256 actual); error ConfigDigestMismatch(bytes32 expected, bytes32 actual); error ForkedChain(uint256 expected, uint256 actual); error UnauthorizedTransmitter(); error OracleCannotBeZeroAddress(); // 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("too many transmitters"); if (f == 0) revert InvalidConfig("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); 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("repeated transmitter 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); // 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); 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); } /// @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: BUSL-1.1 pragma solidity 0.8.19; import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol"; import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol"; import {Client} from "./libraries/Client.sol"; import {RateLimiter} from "./libraries/RateLimiter.sol"; import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol"; contract AggregateRateLimiter is OwnerIsCreator { using RateLimiter for RateLimiter.TokenBucket; using USDPriceWith18Decimals for uint192; error PriceNotFoundForToken(address token); event AdminSet(address newAdmin); // The address of the token limit admin that has the same permissions as the owner. address internal s_admin; // The token bucket object that contains the bucket state. RateLimiter.TokenBucket private s_rateLimiter; /// @param config The RateLimiter.Config containing the capacity and refill rate /// of the bucket, plus the admin address. constructor(RateLimiter.Config memory config) { s_rateLimiter = RateLimiter.TokenBucket({ rate: config.rate, capacity: config.capacity, tokens: config.capacity, lastUpdated: uint32(block.timestamp), isEnabled: config.isEnabled }); } /// @notice Consumes value from the rate limiter bucket based on the /// token value given. First, calculate the prices function _rateLimitValue(Client.EVMTokenAmount[] memory tokenAmounts, IPriceRegistry priceRegistry) internal { uint256 numberOfTokens = tokenAmounts.length; uint256 value = 0; for (uint256 i = 0; i < numberOfTokens; ++i) { // not fetching validated price, as price staleness is not important for value-based rate limiting // we only need to verify price is not 0 uint192 pricePerToken = priceRegistry.getTokenPrice(tokenAmounts[i].token).value; if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmounts[i].token); value += pricePerToken._calcUSDValueFromTokenAmount(tokenAmounts[i].amount); } s_rateLimiter._consume(value, address(0)); } /// @notice Gets the token bucket with its values for the block it was requested at. /// @return The token bucket. function currentRateLimiterState() external view returns (RateLimiter.TokenBucket memory) { return s_rateLimiter._currentTokenBucketState(); } /// @notice Sets the rate limited config. /// @param config The new rate limiter config. /// @dev should only be callable by the owner or token limit admin. function setRateLimiterConfig(RateLimiter.Config memory config) external onlyAdminOrOwner { s_rateLimiter._setTokenBucketConfig(config); } // ================================================================ // | Access | // ================================================================ /// @notice Gets the token limit admin address. /// @return the token limit admin address. function getTokenLimitAdmin() external view returns (address) { return s_admin; } /// @notice Sets the token limit admin address. /// @param newAdmin the address of the new admin. /// @dev setting this to address(0) indicates there is no active admin. function setAdmin(address newAdmin) external onlyAdminOrOwner { s_admin = newAdmin; emit AdminSet(newAdmin); } /// @notice a modifier that allows the owner or the s_tokenLimitAdmin call the functions /// it is applied to. modifier onlyAdminOrOwner() { if (msg.sender != owner() && msg.sender != s_admin) revert RateLimiter.OnlyCallableByAdminOrOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/utils/structs/EnumerableMap.sol"; library EnumerableMapAddresses { using EnumerableMap for EnumerableMap.UintToAddressMap; struct AddressToAddressMap { EnumerableMap.UintToAddressMap _inner; } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) { return map._inner.set(uint256(uint160(key)), value); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function remove(AddressToAddressMap storage map, address key) internal returns (bool) { return map._inner.remove(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function contains(AddressToAddressMap storage map, address key) internal view returns (bool) { return map._inner.contains(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function length(AddressToAddressMap storage map) internal view returns (uint256) { return map._inner.length(); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function at(AddressToAddressMap storage map, uint256 index) internal view returns (address, address) { (uint256 key, address value) = map._inner.at(index); return (address(uint160(key)), value); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool, address) { return map._inner.tryGet(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function get(AddressToAddressMap storage map, address key) internal view returns (address) { return map._inner.get(uint256(uint160(key))); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function get( AddressToAddressMap storage map, address key, string memory errorMessage ) internal view returns (address) { return map._inner.get(uint256(uint160(key)), errorMessage); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; import "./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}. * * _Available since v3.4._ */ 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}. * Interface identification is specified in ERC-165. */ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { // prepare call bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, 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: BUSL-1.1 pragma solidity ^0.8.0; library MerkleMultiProof { /// @notice Leaf domain separator, should be used as the first 32 bytes of a leaf's preimage. bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000; /// @notice Internal domain separator, should be used as the first 32 bytes of an internal node's preiimage. bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000001; uint256 internal constant MAX_NUM_HASHES = 256; error InvalidProof(); error LeavesCannotBeEmpty(); /// @notice Computes the root based on provided pre-hashed leaf nodes in /// leaves, internal nodes in proofs, and using proofFlagBits' i-th bit to /// determine if an element of proofs or one of the previously computed leafs /// or internal nodes will be used for the i-th hash. /// @param leaves Should be pre-hashed and the first 32 bytes of a leaf's /// preimage should match LEAF_DOMAIN_SEPARATOR. /// @param proofs The hashes to be used instead of a leaf hash when the proofFlagBits /// indicates a proof should be used. /// @param proofFlagBits A single uint256 of which each bit indicates whether a leaf or /// a proof needs to be used in a hash operation. /// @dev the maximum number of hash operations it set to 256. Any input that would require /// more than 256 hashes to get to a root will revert. /// @dev For given input `leaves` = [a,b,c] `proofs` = [D] and `proofFlagBits` = 5 /// totalHashes = 3 + 1 - 1 = 3 /// ** round 1 ** /// proofFlagBits = (5 >> 0) & 1 = true /// hashes[0] = hashPair(a, b) /// (leafPos, hashPos, proofPos) = (2, 0, 0); /// /// ** round 2 ** /// proofFlagBits = (5 >> 1) & 1 = false /// hashes[1] = hashPair(D, c) /// (leafPos, hashPos, proofPos) = (3, 0, 1); /// /// ** round 3 ** /// proofFlagBits = (5 >> 2) & 1 = true /// hashes[2] = hashPair(hashes[0], hashes[1]) /// (leafPos, hashPos, proofPos) = (3, 2, 1); /// /// i = 3 and no longer < totalHashes. The algorithm is done /// return hashes[totalHashes - 1] = hashes[2]; the last hash we computed. // We mark this function as internal to force it to be inlined in contracts // that use it, but semantically it is public. // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function merkleRoot( bytes32[] memory leaves, bytes32[] memory proofs, uint256 proofFlagBits ) internal pure returns (bytes32) { unchecked { uint256 leavesLen = leaves.length; uint256 proofsLen = proofs.length; if (leavesLen == 0) revert LeavesCannotBeEmpty(); if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof(); uint256 totalHashes = leavesLen + proofsLen - 1; if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof(); if (totalHashes == 0) { return leaves[0]; } bytes32[] memory hashes = new bytes32[](totalHashes); (uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0); for (uint256 i = 0; i < totalHashes; ++i) { // Checks if the bit flag signals the use of a supplied proof or a leaf/previous hash. bytes32 a; if (proofFlagBits & (1 << i) == (1 << i)) { // Use a leaf or a previously computed hash. if (leafPos < leavesLen) { a = leaves[leafPos++]; } else { a = hashes[hashPos++]; } } else { // Use a supplied proof. a = proofs[proofPos++]; } // The second part of the hashed pair is never a proof as hashing two proofs would result in a // hash that can already be computed offchain. bytes32 b; if (leafPos < leavesLen) { b = leaves[leafPos++]; } else { b = hashes[hashPos++]; } if (!(hashPos <= i)) revert InvalidProof(); hashes[i] = _hashPair(a, b); } if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof(); // Return the last hash. return hashes[totalHashes - 1]; } } /// @notice Hashes two bytes32 objects in their given order, prepended by the /// INTERNAL_DOMAIN_SEPARATOR. function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) { return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right)); } /// @notice Hashes two bytes32 objects. The order is taken into account, /// using the lower value first. function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a); } }
// SPDX-License-Identifier: MIT 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; import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; abstract contract OCR2Abstract is TypeAndVersionInterface { // 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: BUSL-1.1 pragma solidity ^0.8.0; library USDPriceWith18Decimals { /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount, /// and amount of the smallest token denomination, /// calculates the value in USD with 18 decimals. /// @param tokenPrice The USD price of the token. /// @param tokenAmount Amount of the smallest token denomination. /// @return USD value with 18 decimals. /// @dev this function assumes that no more than 1e59 US dollar worth of token is passed in. /// If more is sent, this function will overflow and revert. /// Since there isn't even close to 1e59 dollars, this is ok for all legit tokens. function _calcUSDValueFromTokenAmount(uint192 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) { /// LINK Example: /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals /// tokenAmount: 2e18 -> 2 LINK /// result: 8e18 * 2e18 / 1e18 -> 16e18 with 18 decimals = $16 /// USDC Example: /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals /// tokenAmount: 5e6 -> 5 USDC /// result: 1e30 * 5e6 / 1e18 -> 5e18 with 18 decimals = $5 return (tokenPrice * tokenAmount) / 1e18; } /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount, /// and USD value with 18 decimals, /// calculates amount of the smallest token denomination. /// @param tokenPrice The USD price of the token. /// @param usdValue USD value with 18 decimals. /// @return Amount of the smallest token denomination. function _calcTokenAmountFromUSDValue(uint192 tokenPrice, uint256 usdValue) internal pure returns (uint256) { /// LINK Example: /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals /// usdValue: 16e18 -> $16 /// result: 16e18 * 1e18 / 8e18 -> 2e18 = 2 LINK /// USDC Example: /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals /// usdValue: 5e18 -> $5 /// result: 5e18 * 1e18 / 1e30 -> 5e6 = 5 USDC return (usdValue * 1e18) / tokenPrice; } }
// SPDX-License-Identifier: MIT // 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 // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./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 // 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 "./interfaces/OwnableInterface.sol"; /** * @title The ConfirmedOwner contract * @notice A contract with helpers for basic contract ownership. */ contract ConfirmedOwnerWithProposal is OwnableInterface { address private s_owner; address private s_pendingOwner; event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); constructor(address newOwner, address pendingOwner) { require(newOwner != address(0), "Cannot set owner to zero"); s_owner = newOwner; if (pendingOwner != address(0)) { _transferOwnership(pendingOwner); } } /** * @notice Allows an owner to begin transferring ownership to a new address, * pending. */ function transferOwnership(address to) public override onlyOwner { _transferOwnership(to); } /** * @notice Allows an ownership transfer to be completed by the recipient. */ function acceptOwnership() external override { require(msg.sender == s_pendingOwner, "Must be proposed owner"); address oldOwner = s_owner; s_owner = msg.sender; s_pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /** * @notice Get the current owner */ function owner() public view override returns (address) { return s_owner; } /** * @notice validate, transfer ownership, and emit relevant events */ function _transferOwnership(address to) private { require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; emit OwnershipTransferRequested(s_owner, to); } /** * @notice validate access */ function _validateOwnership() internal view { require(msg.sender == s_owner, "Only callable by owner"); } /** * @notice Reverts if called by anyone other than the contract owner. */ modifier onlyOwner() { _validateOwnership(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface OwnableInterface { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; }
{ "remappings": [ "@eth-optimism/=node_modules/@eth-optimism/", "@openzeppelin/=node_modules/@openzeppelin/", "ds-test/=foundry-lib/forge-std/lib/ds-test/src/", "erc4626-tests/=foundry-lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=foundry-lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 26000 }, "metadata": { "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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":"armProxy","type":"address"}],"internalType":"struct EVM2EVMOffRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"internalType":"contract IERC20[]","name":"sourceTokens","type":"address[]"},{"internalType":"contract IPool[]","name":"pools","type":"address[]"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"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":[{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"AlreadyAttempted","type":"error"},{"inputs":[{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"AlreadyExecuted","type":"error"},{"inputs":[],"name":"BadARMSignal","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":"EmptyReport","type":"error"},{"inputs":[{"internalType":"bytes","name":"error","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":"string","name":"message","type":"string"}],"name":"InvalidConfig","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","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":[],"name":"InvalidTokenPoolConfig","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":[],"name":"OnlyCallableByAdminOrOwner","type":"error"},{"inputs":[],"name":"OracleCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"PoolAlreadyAdded","type":"error"},{"inputs":[],"name":"PoolDoesNotExist","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"PriceNotFoundForToken","type":"error"},{"inputs":[{"internalType":"bytes","name":"error","type":"bytes"}],"name":"ReceiverError","type":"error"},{"inputs":[],"name":"RootNotCommitted","type":"error"},{"inputs":[{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"TokenDataMismatch","type":"error"},{"inputs":[{"internalType":"bytes","name":"error","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":[],"name":"TokenPoolMismatch","type":"error"},{"inputs":[{"internalType":"bytes","name":"error","type":"bytes"}],"name":"TokenRateLimitError","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":"contract IERC20","name":"token","type":"address"}],"name":"UnsupportedToken","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":[{"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":"armProxy","type":"address"}],"indexed":false,"internalType":"struct EVM2EVMOffRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint16","name":"maxTokensLength","type":"uint16"},{"internalType":"uint32","name":"maxDataSize","type":"uint32"}],"indexed":false,"internalType":"struct EVM2EVMOffRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"ConfigSet","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":[{"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":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"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":"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":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"removes","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"adds","type":"tuple[]"}],"name":"applyPoolUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"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":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"strict","type":"bool"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"internalType":"struct Internal.EVM2EVMMessage","name":"message","type":"tuple"},{"internalType":"bytes[]","name":"offchainTokenData","type":"bytes[]"}],"name":"executeSingleMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"sourceToken","type":"address"}],"name":"getDestinationToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDestinationTokens","outputs":[{"internalType":"contract IERC20[]","name":"destTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDynamicConfig","outputs":[{"components":[{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint16","name":"maxTokensLength","type":"uint16"},{"internalType":"uint32","name":"maxDataSize","type":"uint32"}],"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":"contract IERC20","name":"destToken","type":"address"}],"name":"getPoolByDestToken","outputs":[{"internalType":"contract IPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"sourceToken","type":"address"}],"name":"getPoolBySourceToken","outputs":[{"internalType":"contract IPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"getSenderNonce","outputs":[{"internalType":"uint64","name":"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":"armProxy","type":"address"}],"internalType":"struct EVM2EVMOffRamp.StaticConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedTokens","outputs":[{"internalType":"contract IERC20[]","name":"sourceTokens","type":"address[]"}],"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":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"strict","type":"bool"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"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"},{"internalType":"uint256[]","name":"gasLimitOverrides","type":"uint256[]"}],"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"}]
Contract Creation Code
6101806040523480156200001257600080fd5b5060405162006a1538038062006a15833981016040819052620000359162000891565b8033806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c08162000478565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080938401819052600380546001600160a01b031916909517600160801b9384021760ff60a01b1916600160a01b90920291909117909355909102909217600455504690528151835114620001705760405162d8548360e71b815260040160405180910390fd5b60608401516001600160a01b0316158062000193575083516001600160a01b0316155b15620001b2576040516342bcdf7f60e11b815260040160405180910390fd5b83600001516001600160a01b0316634120fccd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200021b9190620009a8565b6001600160401b03166001146200024557604051636fc2a20760e11b815260040160405180910390fd5b83516001600160a01b0390811660a090815260408601516001600160401b0390811660c05260208701511660e052606086015182166101005260808601518216610140528501511661016052620002bc7fbdd59ac4dd1d82276c9a9c5d2656546346b9dcdb1f9b4204aed4ec15c23d7d3a62000523565b6101205260005b83518110156200046d576200031d848281518110620002e657620002e6620009c6565b6020026020010151848381518110620003035762000303620009c6565b6020026020010151600c6200058a60201b9092919060201c565b50620003d2838281518110620003375762000337620009c6565b60200260200101516001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200037d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003a39190620009dc565b848381518110620003b857620003b8620009c6565b6020026020010151600f6200058a60201b9092919060201c565b507f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c848281518110620004095762000409620009c6565b6020026020010151848381518110620004265762000426620009c6565b6020026020010151604051620004529291906001600160a01b0392831681529116602082015260400190565b60405180910390a1620004658162000a03565b9050620002c3565b505050505062000a2b565b336001600160a01b03821603620004d25760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008160c05160e051610100516040516020016200056d94939291909384526001600160401b039283166020850152911660408301526001600160a01b0316606082015260800190565b604051602081830303815290604052805190602001209050919050565b6000620005a2846001600160a01b03851684620005aa565b949350505050565b6000620005a284846001600160a01b03851660008281526002840160205260408120829055620005a284846000620005e38383620005ec565b90505b92915050565b60008181526001830160205260408120546200063557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620005e6565b506000620005e6565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b03811182821017156200067957620006796200063e565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620006aa57620006aa6200063e565b604052919050565b6001600160a01b0381168114620006c857600080fd5b50565b80516001600160401b0381168114620006e357600080fd5b919050565b60006001600160401b038211156200070457620007046200063e565b5060051b60200190565b600082601f8301126200072057600080fd5b81516020620007396200073383620006e8565b6200067f565b82815260059290921b840181019181810190868411156200075957600080fd5b8286015b84811015620007815780516200077381620006b2565b83529183019183016200075d565b509695505050505050565b600082601f8301126200079e57600080fd5b81516020620007b16200073383620006e8565b82815260059290921b84018101918181019086841115620007d157600080fd5b8286015b8481101562000781578051620007eb81620006b2565b8352918301918301620007d5565b80516001600160801b0381168114620006e357600080fd5b6000606082840312156200082457600080fd5b604051606081016001600160401b03811182821017156200084957620008496200063e565b8060405250809150825180151581146200086257600080fd5b81526200087260208401620007f9565b60208201526200088560408401620007f9565b60408201525092915050565b600080600080848603610160811215620008aa57600080fd5b60c0811215620008b957600080fd5b50620008c462000654565b8551620008d181620006b2565b8152620008e160208701620006cb565b6020820152620008f460408701620006cb565b604082015260608601516200090981620006b2565b606082015260808601516200091e81620006b2565b608082015260a08601516200093381620006b2565b60a082015260c08601519094506001600160401b03808211156200095657600080fd5b62000964888389016200070e565b945060e08701519150808211156200097b57600080fd5b506200098a878288016200078c565b9250506200099d86610100870162000811565b905092959194509250565b600060208284031215620009bb57600080fd5b620005e382620006cb565b634e487b7160e01b600052603260045260246000fd5b600060208284031215620009ef57600080fd5b8151620009fc81620006b2565b9392505050565b60006001820162000a2457634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a05160c05160e05161010051610120516101405161016051615f0d62000b0860003960008181610309015281816120ef0152612b0b0152600081816102cd015281816114a001528181611522015281816120c501528181613080015261310701526000612cc4015260008181610291015261209e015260008181610231015261204c01526000818161026101528181612076015281816124650152613b0b0152600081816101f50152818161201e0152612db901526000818161182f0152818161187b01528181611c8f0152611cdb0152615f0d6000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c806381ff7048116100ee578063b1dc65a411610097578063d3c7c2c711610071578063d3c7c2c7146106a7578063d7e2bb50146106af578063e65bf00a146106c2578063f2fde38b146106d557600080fd5b8063b1dc65a41461066e578063b4069b3114610681578063c92b28321461069457600080fd5b80638da5cb5b116100c85780638da5cb5b1461061d578063afa0d3791461063b578063afcb95d71461064e57600080fd5b806381ff7048146105b357806385572ffb146105e3578063856c8247146105f157600080fd5b8063599f64311161015b578063681fba1611610135578063681fba16146104b8578063704b6c02146104cd5780637437ff9f146104e057806379ba5097146105ab57600080fd5b8063599f6431146104515780635d86f14114610490578063666cab8d146104a357600080fd5b80631ef381741161018c5780631ef38174146103c55780633a87ac53146103da578063546719cd146103ed57600080fd5b806306285c69146101b3578063142a98fc1461035c578063181f5a771461037c575b600080fd5b6103466040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526040518060c001604052807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516103539190614677565b60405180910390f35b61036f61036a36600461470e565b6106e8565b6040516103539190614795565b6103b86040518060400160405280601481526020017f45564d3245564d4f666652616d7020312e302e3000000000000000000000000081525081565b6040516103539190614811565b6103d86103d3366004614a7f565b610763565b005b6103d86103e8366004614b91565b610c22565b6103f5611032565b604051610353919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610353565b61046b61049e366004614bfd565b6110e7565b6104ab611150565b6040516103539190614c6b565b6104c06111bf565b6040516103539190614c7e565b6103d86104db366004614bfd565b611278565b61059e6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a081018252600a5463ffffffff808216835273ffffffffffffffffffffffffffffffffffffffff64010000000090920482166020840152600b549182169383019390935261ffff7401000000000000000000000000000000000000000082041660608301527601000000000000000000000000000000000000000000009004909116608082015290565b6040516103539190614cd8565b6103d8611368565b6007546005546040805163ffffffff80851682526401000000009094049093166020840152820152606001610353565b6103d86101ae366004614d3b565b6106046105ff366004614bfd565b611465565b60405167ffffffffffffffff9091168152602001610353565b60005473ffffffffffffffffffffffffffffffffffffffff1661046b565b6103d8610649366004614fa5565b61158d565b604080516001815260006020820181905291810191909152606001610353565b6103d861067c36600461504e565b6117d9565b61046b61068f366004614bfd565b611a6a565b6103d86106a2366004615153565b611b43565b6104c0611bc8565b61046b6106bd366004614bfd565b611c7d565b6103d86106d03660046153aa565b611c8c565b6103d86106e3366004614bfd565b611e0e565b60006106f660016004615494565b60026107036080856154d6565b67ffffffffffffffff1661071791906154fd565b60136000610726608087615514565b67ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002054901c16600381111561075d5761075d61472b565b92915050565b84518460ff16601f8211156107d9576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f6f206d616e79207472616e736d697474657273000000000000000000000060448201526064015b60405180910390fd5b80600003610843576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016107d0565b61084b611e1f565b61085485611ea2565b60095460005b818110156108e05760086000600983815481106108795761087961553b565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556108d98161556a565b905061085a565b50875160005b81811015610adc5760008a82815181106109025761090261553b565b602002602001015190506000600281111561091f5761091f61472b565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040902054610100900460ff16600281111561095e5761095e61472b565b146109c5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016107d0565b73ffffffffffffffffffffffffffffffffffffffff8116610a12576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526008602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610ac257610ac261472b565b02179055509050505080610ad59061556a565b90506108e6565b508851610af09060099060208c01906145e1565b506006805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908b161717905560078054610b76914691309190600090610b489063ffffffff166155a2565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168d8d8d8d8d8d61214f565b6005600001819055506000600760049054906101000a900463ffffffff16905043600760046101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600560000154600760009054906101000a900463ffffffff168e8e8e8e8e8e604051610c0d999897969594939291906155c5565b60405180910390a15050505050505050505050565b610c2a611e1f565b60005b83811015610e29576000858583818110610c4957610c4961553b565b610c5f9260206040909202019081019150614bfd565b90506000868684818110610c7557610c7561553b565b9050604002016020016020810190610c8d9190614bfd565b9050610c9a600c836121fa565b610cd0576040517f9c8787c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610cf2600c8461221c565b73ffffffffffffffffffffffffffffffffffffffff1614610d3f576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d4a600c8361223e565b50610dc58173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbd919061565b565b600f9061223e565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a1505080610e229061556a565b9050610c2d565b5060005b8181101561102b576000838383818110610e4957610e4961553b565b610e5f9260206040909202019081019150614bfd565b90506000848484818110610e7557610e7561553b565b9050604002016020016020810190610e8d9190614bfd565b905073ffffffffffffffffffffffffffffffffffffffff82161580610ec6575073ffffffffffffffffffffffffffffffffffffffff8116155b15610efd576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f08600c836121fa565b15610f3f576040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f4b600c8383612260565b50610fc78173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbe919061565b565b600f9083612260565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a15050806110249061556a565b9050610e2d565b5050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff1615159383019390935260045480841660608401520490911660808201526110e290612283565b905090565b600080806110f6600c85612335565b9150915081611149576040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107d0565b9392505050565b606060098054806020026020016040519081016040528092919081815260200182805480156111b557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161118a575b5050505050905090565b60606111cb600f612364565b67ffffffffffffffff8111156111e3576111e3614824565b60405190808252806020026020018201604052801561120c578160200160208202803683370190505b50905060005b8151811015611274576000611228600f8361236f565b5090508083838151811061123e5761123e61553b565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101525061126d8161556a565b9050611212565b5090565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906112b8575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156112ef576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c9060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff1633146113e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107d0565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b73ffffffffffffffffffffffffffffffffffffffff811660009081526012602052604081205467ffffffffffffffff16801580156114d857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b1561075d576040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111499190615678565b3330146115c6576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160008082526020820190925281611603565b60408051808201909152600080825260208201528152602001906001900390816115dc5790505b5061012084015151909150156116625761012083015160608401516040805173ffffffffffffffffffffffffffffffffffffffff909216602083015261165f9291016040516020818303038152906040528560e001518561238b565b90505b60e083015173ffffffffffffffffffffffffffffffffffffffff163b15806116cc575060e08301516116ca9073ffffffffffffffffffffffffffffffffffffffff167f85572ffb00000000000000000000000000000000000000000000000000000000612831565b155b156116d657505050565b600a546000908190640100000000900473ffffffffffffffffffffffffffffffffffffffff16633cf9798361170b878661284d565b6113888860a001518960e001516040518563ffffffff1660e01b815260040161173794939291906156e6565b6000604051808303816000875af1158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261179c91908101906157b8565b915091508161102b57806040517f0a8d6e8c0000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b6117e387876128fd565b60055488359080821461182c576040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016107d0565b467f0000000000000000000000000000000000000000000000000000000000000000146118ad576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201526044016107d0565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a13360009081526008602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156119355761193561472b565b60028111156119465761194661472b565b90525090506002816020015160028111156119635761196361472b565b1480156119aa57506009816000015160ff16815481106119855761198561553b565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6119e0576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060006119ee8560206154fd565b6119f98860206154fd565b611a058b610144615845565b611a0f9190615845565b611a199190615845565b9050368114611a5d576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016107d0565b5050505050505050505050565b60008080611a79600c85612335565b9150915081611acc576040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107d0565b8073ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3b919061565b565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611b83575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15611bba576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc5600382612924565b50565b6060611bd4600c612364565b67ffffffffffffffff811115611bec57611bec614824565b604051908082528060200260200182016040528015611c15578160200160208202803683370190505b50905060005b8151811015611274576000611c31600c8361236f565b50905080838381518110611c4757611c4761553b565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250611c768161556a565b9050611c1b565b600080806110f6600f85612335565b467f000000000000000000000000000000000000000000000000000000000000000014611d17576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600482015267ffffffffffffffff461660248201526044016107d0565b81515181518114611d54576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015611dfe576000838281518110611d7357611d7361553b565b6020026020010151905080600014158015611dac57508451805183908110611d9d57611d9d61553b565b602002602001015160a0015181105b15611ded576040517f085e39cf00000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016107d0565b50611df78161556a565b9050611d57565b50611e098383612b09565b505050565b611e16611e1f565b611bc581613545565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107d0565b565b600081806020019051810190611eb8919061586c565b602081015190915073ffffffffffffffffffffffffffffffffffffffff16611f0c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600a805460208085015173ffffffffffffffffffffffffffffffffffffffff908116640100000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931663ffffffff9586161792909217909255604080850151600b80546060808901516080808b0151909916760100000000000000000000000000000000000000000000027fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff61ffff90921674010000000000000000000000000000000000000000027fffffffffffffffffffff00000000000000000000000000000000000000000000909416958816959095179290921791909116929092179055815160c0810183527f00000000000000000000000000000000000000000000000000000000000000008416815267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116958201959095527f0000000000000000000000000000000000000000000000000000000000000000909416848301527f00000000000000000000000000000000000000000000000000000000000000008316908401527f00000000000000000000000000000000000000000000000000000000000000008216938301939093527f00000000000000000000000000000000000000000000000000000000000000001660a082015290517f737ef22d3f6615e342ed21c69e06620dbc5c8a261ed7cfb2ce214806b1f76eda91612143918490615907565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a604051602001612173999897969594939291906159d6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b60006111498373ffffffffffffffffffffffffffffffffffffffff841661363a565b60006111498373ffffffffffffffffffffffffffffffffffffffff8416613646565b60006111498373ffffffffffffffffffffffffffffffffffffffff8416613652565b6000611b3b8473ffffffffffffffffffffffffffffffffffffffff85168461365e565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261231182606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426122f59190615494565b85608001516fffffffffffffffffffffffffffffffff16613681565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6000806123588473ffffffffffffffffffffffffffffffffffffffff85166136a0565b915091505b9250929050565b600061075d826136af565b600080808061237e86866136ba565b9097909650945050505050565b60606000855167ffffffffffffffff8111156123a9576123a9614824565b6040519080825280602002602001820160405280156123ee57816020015b60408051808201909152600080825260208201528152602001906001900390816123c75790505b50905060005b86518110156128035760006124258883815181106124145761241461553b565b6020026020010151600001516110e7565b90508073ffffffffffffffffffffffffffffffffffffffff16638627fad688888b86815181106124575761245761553b565b6020026020010151602001517f00000000000000000000000000000000000000000000000000000000000000008a88815181106124965761249661553b565b60200260200101516040518663ffffffff1660e01b81526004016124be959493929190615a6b565b600060405180830381600087803b1580156124d857600080fd5b505af19250505080156124e9575060015b61270c573d808015612517576040519150601f19603f3d011682016040523d82523d6000602084013e61251c565b606091505b50600061252882615ace565b90507f9725942a000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821614806125bb57507ff94ebcd1000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061260757507f15279c08000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061265357507f1a76572a000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061269f57507fd0c8d23a000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b156126d857816040517f30dabb590000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b816040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b8073ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277b919061565b565b83838151811061278d5761278d61553b565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff909116905287518890839081106127c6576127c661553b565b6020026020010151602001518383815181106127e4576127e461553b565b6020908102919091018101510152506127fc8161556a565b90506123f4565b50600b5461282890829073ffffffffffffffffffffffffffffffffffffffff166136c9565b95945050505050565b600061283c836138a9565b80156111495750611149838361390d565b6040805160a08101825260008082526020820152606091810182905281810182905260808101919091526040518060a001604052808461016001518152602001846000015167ffffffffffffffff16815260200184606001516040516020016128d2919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6040516020818303038152906040528152602001846101000151815260200183815250905092915050565b61292061290c82840184615b1e565b604080516000815260208101909152612b09565b5050565b815460009061294d90700100000000000000000000000000000000900463ffffffff1642615494565b905080156129ef5760018301548354612995916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416613681565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612a15916fffffffffffffffffffffffffffffffff90811691166139dc565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612afc9084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b989190615b53565b15612bcf576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151516000819003612c0c576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260200151518114612c4a576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115612c6557612c65614824565b604051908082528060200260200182016040528015612c8e578160200160208202803683370190505b50905060005b82811015612d6e57600085600001518281518110612cb457612cb461553b565b60200260200101519050612ce8817f00000000000000000000000000000000000000000000000000000000000000006139f2565b838381518110612cfa57612cfa61553b565b602002602001018181525050806101600151838381518110612d1e57612d1e61553b565b602002602001015114612d5d576040517f7185cf6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50612d678161556a565b9050612c94565b50604080850151606086015191517f3204887500000000000000000000000000000000000000000000000000000000815260009273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001692633204887592612def92879291600401615ba0565b602060405180830381865afa158015612e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e309190615bd6565b905080600003612e6c576040517fea75680100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351151560005b8481101561353c57600087600001518281518110612e9357612e9361553b565b602002602001015190506000612eac82602001516106e8565b90506000816003811115612ec257612ec261472b565b1480612edf57506003816003811115612edd57612edd61472b565b145b612f275760208201516040517f50a6e05200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b8315612fe457600a5460009063ffffffff16612f438742615494565b1190508080612f6357506003826003811115612f6157612f6161472b565b145b612f99576040517f6358b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b888481518110612fab57612fab61553b565b6020026020010151600014612fde57888481518110612fcc57612fcc61553b565b60200260200101518360a00181815250505b50613041565b6000816003811115612ff857612ff861472b565b146130415760208201516040517f67d9ba0f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b606082015173ffffffffffffffffffffffffffffffffffffffff1660009081526012602052604090205467ffffffffffffffff16801580156130b857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b1561325a5760608301516040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063856c824790602401602060405180830381865afa158015613150573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131749190615678565b608084015190915067ffffffffffffffff16613191826001615bef565b67ffffffffffffffff16146131fe57826060015173ffffffffffffffffffffffffffffffffffffffff16836080015167ffffffffffffffff167fe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d60405160405180910390a350505061352c565b606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260126020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790555b600082600381111561326e5761326e61472b565b036132fa57608083015167ffffffffffffffff1661328d826001615bef565b67ffffffffffffffff16146132fa57826060015173ffffffffffffffffffffffffffffffffffffffff16836080015167ffffffffffffffff167fd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf4123760405160405180910390a350505061352c565b60008a6020015185815181106133125761331261553b565b60200260200101519050613327848251613b09565b61333684602001516001613cdf565b6000806133438684613d89565b91509150613355866020015183613cdf565b60038260038111156133695761336961472b565b14158015613389575060028260038111156133865761338661472b565b14155b156133c8578560200151826040517f9e2616030000000000000000000000000000000000000000000000000000000081526004016107d0929190615c10565b8560c00151156134575760028260038111156133e6576133e661472b565b0361345257606086015173ffffffffffffffffffffffffffffffffffffffff166000908152601260205260408120805467ffffffffffffffff169161342a83615c2e565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b6134d7565b600085600381111561346b5761346b61472b565b036134d757606086015173ffffffffffffffffffffffffffffffffffffffff166000908152601260205260408120805467ffffffffffffffff16916134af83615c2e565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b856101600151866020015167ffffffffffffffff167fd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef65848460405161351d929190615c4b565b60405180910390a35050505050505b6135358161556a565b9050612e73565b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036135c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107d0565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006111498383613f2c565b60006111498383613f38565b60006111498383613fc2565b6000611b3b848473ffffffffffffffffffffffffffffffffffffffff8516613fdf565b60006128288561369184866154fd565b61369b9087615845565b6139dc565b600080808061237e8686613ffc565b600061075d82614036565b600080808061237e8686614041565b81516000805b828110156138955760008473ffffffffffffffffffffffffffffffffffffffff1663d02641a08784815181106137075761370761553b565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016040805180830381865afa15801561377b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379f9190615c6b565b51905077ffffffffffffffffffffffffffffffffffffffffffffffff811660000361382d578582815181106137d6576137d661553b565b6020908102919091010151516040517f9a655f7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016107d0565b6138778683815181106138425761384261553b565b6020026020010151602001518277ffffffffffffffffffffffffffffffffffffffffffffffff1661406c90919063ffffffff16565b6138819084615845565b9250508061388e9061556a565b90506136cf565b506138a360038260006140a5565b50505050565b60006138d5827f01ffc9a70000000000000000000000000000000000000000000000000000000061390d565b801561075d5750613906827fffffffff0000000000000000000000000000000000000000000000000000000061390d565b1592915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d915060005190508280156139c5575060208210155b80156139d15750600081115b979650505050505050565b60008183106139eb5781611149565b5090919050565b60008060001b828460200151856080015186606001518760e0015188610100015180519060200120896101200151604051602001613a309190615cc9565b604051602081830303815290604052805190602001208a60a001518b60c001518c61014001518d60400151604051602001613aeb9c9b9a999897969594939291909b8c5260208c019a909a5267ffffffffffffffff98891660408c01529690971660608a015273ffffffffffffffffffffffffffffffffffffffff94851660808a015292841660a089015260c088019190915260e0870152610100860152911515610120850152166101408301526101608201526101800190565b60405160208183030381529060405280519060200120905092915050565b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff16826000015167ffffffffffffffff1614613b895781516040517f1279ec8a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b600b54610120830151517401000000000000000000000000000000000000000090910461ffff161015613bfa5760208201516040517f099d3f7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b808261012001515114613c4b5760208201516040517f8808f8e700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b600b546101008301515176010000000000000000000000000000000000000000000090910463ffffffff16101561292057600b54610100830151516040517f8693378900000000000000000000000000000000000000000000000000000000815276010000000000000000000000000000000000000000000090920463ffffffff16600483015260248201526044016107d0565b60006002613cee6080856154d6565b67ffffffffffffffff16613d0291906154fd565b90506000601381613d14608087615514565b67ffffffffffffffff168152602081019190915260400160002054905081613d3e60016004615494565b901b191681836003811115613d5557613d5561472b565b901b178060136000613d68608088615514565b67ffffffffffffffff16815260208101919091526040016000205550505050565b6040517fafa0d379000000000000000000000000000000000000000000000000000000008152600090606090309063afa0d37990613dcd9087908790600401615d52565b600060405180830381600087803b158015613de757600080fd5b505af1925050508015613df8575060015b613f11573d808015613e26576040519150601f19603f3d011682016040523d82523d6000602084013e613e2b565b606091505b50613e3581615ace565b7fffffffff00000000000000000000000000000000000000000000000000000000167f0a8d6e8c000000000000000000000000000000000000000000000000000000001480613ecd5750613e8881615ace565b7fffffffff00000000000000000000000000000000000000000000000000000000167fe1cd550900000000000000000000000000000000000000000000000000000000145b15613edd5760039250905061235d565b806040517fcf19edfd0000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b50506040805160208101909152600081526002909250929050565b60006111498383614428565b600081815260028301602052604081205480151580613f5c5750613f5c8484613f2c565b611149576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b6579000060448201526064016107d0565b600081815260028301602052604081208190556111498383614440565b60008281526002840160205260408120829055611b3b848461444c565b600081815260028301602052604081205481908061402b5761401e8585613f2c565b92506000915061235d9050565b60019250905061235d565b600061075d82614458565b6000808061404f8585614462565b600081815260029690960160205260409095205494959350505050565b6000670de0b6b3a764000061409b8377ffffffffffffffffffffffffffffffffffffffffffffffff86166154fd565b6111499190615ebd565b825474010000000000000000000000000000000000000000900460ff1615806140cc575081155b156140d657505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061411c90700100000000000000000000000000000000900463ffffffff1642615494565b905080156141dc578183111561415e576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546141989083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613681565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156142935773ffffffffffffffffffffffffffffffffffffffff841661423b576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016107d0565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016107d0565b848310156143a65760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906142d79082615494565b6142e1878a615494565b6142eb9190615845565b6142f59190615ebd565b905073ffffffffffffffffffffffffffffffffffffffff861661434e576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016107d0565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016107d0565b6143b08584615494565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60008181526001830160205260408120541515611149565b6000611149838361446e565b60006111498383614568565b600061075d825490565b600061114983836145b7565b60008181526001830160205260408120548015614557576000614492600183615494565b85549091506000906144a690600190615494565b905081811461450b5760008660000182815481106144c6576144c661553b565b90600052602060002001549050808760000184815481106144e9576144e961553b565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061451c5761451c615ed1565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061075d565b600091505061075d565b5092915050565b60008181526001830160205260408120546145af5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561075d565b50600061075d565b60008260000182815481106145ce576145ce61553b565b9060005260206000200154905092915050565b82805482825590600052602060002090810192821561465b579160200282015b8281111561465b57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614601565b506112749291505b808211156112745760008155600101614663565b60c0810161075d828473ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b67ffffffffffffffff81168114611bc557600080fd5b8035614709816146e8565b919050565b60006020828403121561472057600080fd5b8135611149816146e8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110614791577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6020810161075d828461475a565b60005b838110156147be5781810151838201526020016147a6565b50506000910152565b600081518084526147df8160208601602086016147a3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061114960208301846147c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561487657614876614824565b60405290565b604051610180810167ffffffffffffffff8111828210171561487657614876614824565b6040516080810167ffffffffffffffff8111828210171561487657614876614824565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561490a5761490a614824565b604052919050565b600067ffffffffffffffff82111561492c5761492c614824565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611bc557600080fd5b803561470981614936565b600082601f83011261497457600080fd5b8135602061498961498483614912565b6148c3565b82815260059290921b840181019181810190868411156149a857600080fd5b8286015b848110156149cc5780356149bf81614936565b83529183019183016149ac565b509695505050505050565b803560ff8116811461470957600080fd5b600067ffffffffffffffff821115614a0257614a02614824565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112614a3f57600080fd5b8135614a4d614984826149e8565b818152846020838601011115614a6257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c08789031215614a9857600080fd5b863567ffffffffffffffff80821115614ab057600080fd5b614abc8a838b01614963565b97506020890135915080821115614ad257600080fd5b614ade8a838b01614963565b9650614aec60408a016149d7565b95506060890135915080821115614b0257600080fd5b614b0e8a838b01614a2e565b9450614b1c60808a016146fe565b935060a0890135915080821115614b3257600080fd5b50614b3f89828a01614a2e565b9150509295509295509295565b60008083601f840112614b5e57600080fd5b50813567ffffffffffffffff811115614b7657600080fd5b6020830191508360208260061b850101111561235d57600080fd5b60008060008060408587031215614ba757600080fd5b843567ffffffffffffffff80821115614bbf57600080fd5b614bcb88838901614b4c565b90965094506020870135915080821115614be457600080fd5b50614bf187828801614b4c565b95989497509550505050565b600060208284031215614c0f57600080fd5b813561114981614936565b600081518084526020808501945080840160005b83811015614c6057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614c2e565b509495945050505050565b6020815260006111496020830184614c1a565b6020808252825182820181905260009190848201906040850190845b81811015614ccc57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614c9a565b50909695505050505050565b60a0810161075d828463ffffffff808251168352602082015173ffffffffffffffffffffffffffffffffffffffff8082166020860152806040850151166040860152505061ffff6060830151166060840152806080830151166080840152505050565b600060208284031215614d4d57600080fd5b813567ffffffffffffffff811115614d6457600080fd5b820160a0818503121561114957600080fd5b8015158114611bc557600080fd5b803561470981614d76565b600082601f830112614da057600080fd5b81356020614db061498483614912565b82815260069290921b84018101918181019086841115614dcf57600080fd5b8286015b848110156149cc5760408189031215614dec5760008081fd5b614df4614853565b8135614dff81614936565b81528185013585820152835291830191604001614dd3565b60006101808284031215614e2a57600080fd5b614e3261487c565b9050614e3d826146fe565b8152614e4b602083016146fe565b602082015260408201356040820152614e6660608301614958565b6060820152614e77608083016146fe565b608082015260a082013560a0820152614e9260c08301614d84565b60c0820152614ea360e08301614958565b60e08201526101008083013567ffffffffffffffff80821115614ec557600080fd5b614ed186838701614a2e565b83850152610120925082850135915080821115614eed57600080fd5b50614efa85828601614d8f565b828401525050610140614f0e818401614958565b818301525061016080830135818301525092915050565b600082601f830112614f3657600080fd5b81356020614f4661498483614912565b82815260059290921b84018101918181019086841115614f6557600080fd5b8286015b848110156149cc57803567ffffffffffffffff811115614f895760008081fd5b614f978986838b0101614a2e565b845250918301918301614f69565b60008060408385031215614fb857600080fd5b823567ffffffffffffffff80821115614fd057600080fd5b614fdc86838701614e17565b93506020850135915080821115614ff257600080fd5b50614fff85828601614f25565b9150509250929050565b60008083601f84011261501b57600080fd5b50813567ffffffffffffffff81111561503357600080fd5b6020830191508360208260051b850101111561235d57600080fd5b60008060008060008060008060e0898b03121561506a57600080fd5b606089018a81111561507b57600080fd5b8998503567ffffffffffffffff8082111561509557600080fd5b818b0191508b601f8301126150a957600080fd5b8135818111156150b857600080fd5b8c60208285010111156150ca57600080fd5b6020830199508098505060808b01359150808211156150e857600080fd5b6150f48c838d01615009565b909750955060a08b013591508082111561510d57600080fd5b5061511a8b828c01615009565b999c989b50969995989497949560c00135949350505050565b80356fffffffffffffffffffffffffffffffff8116811461470957600080fd5b60006060828403121561516557600080fd5b6040516060810181811067ffffffffffffffff8211171561518857615188614824565b604052823561519681614d76565b81526151a460208401615133565b60208201526151b560408401615133565b60408201529392505050565b600082601f8301126151d257600080fd5b813560206151e261498483614912565b82815260059290921b8401810191818101908684111561520157600080fd5b8286015b848110156149cc57803567ffffffffffffffff8111156152255760008081fd5b6152338986838b0101614f25565b845250918301918301615205565b600082601f83011261525257600080fd5b8135602061526261498483614912565b82815260059290921b8401810191818101908684111561528157600080fd5b8286015b848110156149cc5780358352918301918301615285565b6000608082840312156152ae57600080fd5b6152b66148a0565b9050813567ffffffffffffffff808211156152d057600080fd5b818401915084601f8301126152e457600080fd5b813560206152f461498483614912565b82815260059290921b8401810191818101908884111561531357600080fd5b8286015b8481101561534b5780358681111561532f5760008081fd5b61533d8b86838b0101614e17565b845250918301918301615317565b508652508581013593508284111561536257600080fd5b61536e878588016151c1565b9085015250604084013591508082111561538757600080fd5b5061539484828501615241565b6040830152506060820135606082015292915050565b600080604083850312156153bd57600080fd5b823567ffffffffffffffff808211156153d557600080fd5b6153e18683870161529c565b93506020915081850135818111156153f857600080fd5b85019050601f8101861361540b57600080fd5b803561541961498482614912565b81815260059190911b8201830190838101908883111561543857600080fd5b928401925b828410156154565783358252928401929084019061543d565b80955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561075d5761075d615465565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff808416806154f1576154f16154a7565b92169190910692915050565b808202811582820484141761075d5761075d615465565b600067ffffffffffffffff8084168061552f5761552f6154a7565b92169190910492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361559b5761559b615465565b5060010190565b600063ffffffff8083168181036155bb576155bb615465565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526155f58184018a614c1a565b905082810360808401526156098189614c1a565b905060ff871660a084015282810360c084015261562681876147c7565b905067ffffffffffffffff851660e084015282810361010084015261564b81856147c7565b9c9b505050505050505050505050565b60006020828403121561566d57600080fd5b815161114981614936565b60006020828403121561568a57600080fd5b8151611149816146e8565b600081518084526020808501945080840160005b83811015614c60578151805173ffffffffffffffffffffffffffffffffffffffff16885283015183880152604090960195908201906001016156a9565b608081528451608082015267ffffffffffffffff60208601511660a08201526000604086015160a060c08401526157216101208401826147c7565b905060608701517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808584030160e086015261575d83836147c7565b92506080890151915080858403016101008601525061577c8282615695565b92505050615790602083018661ffff169052565b836040830152612828606083018473ffffffffffffffffffffffffffffffffffffffff169052565b600080604083850312156157cb57600080fd5b82516157d681614d76565b602084015190925067ffffffffffffffff8111156157f357600080fd5b8301601f8101851361580457600080fd5b8051615812614984826149e8565b81815286602083850101111561582757600080fd5b6158388260208301602086016147a3565b8093505050509250929050565b8082018082111561075d5761075d615465565b805163ffffffff8116811461470957600080fd5b600060a0828403121561587e57600080fd5b60405160a0810181811067ffffffffffffffff821117156158a1576158a1614824565b6040526158ad83615858565b815260208301516158bd81614936565b602082015260408301516158d081614936565b6040820152606083015161ffff811681146158ea57600080fd5b60608201526158fb60808401615858565b60808201529392505050565b6101608101615979828573ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b825163ffffffff90811660c0840152602084015173ffffffffffffffffffffffffffffffffffffffff90811660e0850152604085015116610100840152606084015161ffff16610120840152608084015116610140830152611149565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152615a1d8285018b614c1a565b91508382036080850152615a31828a614c1a565b915060ff881660a085015283820360c0850152615a4e82886147c7565b90861660e0850152838103610100850152905061564b81856147c7565b60a081526000615a7e60a08301886147c7565b73ffffffffffffffffffffffffffffffffffffffff8716602084015285604084015267ffffffffffffffff851660608401528281036080840152615ac281856147c7565b98975050505050505050565b6000815160208301517fffffffff0000000000000000000000000000000000000000000000000000000080821693506004831015615b165780818460040360031b1b83161693505b505050919050565b600060208284031215615b3057600080fd5b813567ffffffffffffffff811115615b4757600080fd5b611b3b8482850161529c565b600060208284031215615b6557600080fd5b815161114981614d76565b600081518084526020808501945080840160005b83811015614c6057815187529582019590820190600101615b84565b606081526000615bb36060830186615b70565b8281036020840152615bc58186615b70565b915050826040830152949350505050565b600060208284031215615be857600080fd5b5051919050565b67ffffffffffffffff81811683821601908082111561456157614561615465565b67ffffffffffffffff8316815260408101611149602083018461475a565b600067ffffffffffffffff8083168181036155bb576155bb615465565b615c55818461475a565b604060208201526000611b3b60408301846147c7565b600060408284031215615c7d57600080fd5b615c85614853565b825177ffffffffffffffffffffffffffffffffffffffffffffffff81168114615cad57600080fd5b81526020830151615cbd816146e8565b60208201529392505050565b6020815260006111496020830184615695565b600082825180855260208086019550808260051b84010181860160005b84811015615d45577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018952615d338383516147c7565b98840198925090830190600101615cf9565b5090979650505050505050565b60408152615d6d60408201845167ffffffffffffffff169052565b60006020840151615d8a606084018267ffffffffffffffff169052565b5060408401516080830152606084015173ffffffffffffffffffffffffffffffffffffffff811660a084015250608084015167ffffffffffffffff811660c08401525060a084015160e083015260c0840151610100615dec8185018315159052565b60e08601519150610120615e178186018473ffffffffffffffffffffffffffffffffffffffff169052565b81870151925061018091506101408281870152615e386101c08701856147c7565b93508188015191506101607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030181880152615e768584615695565b9450818901519250615e9f8488018473ffffffffffffffffffffffffffffffffffffffff169052565b8801516101a087015250505082810360208401526128288185615cdc565b600082615ecc57615ecc6154a7565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a0000000000000000000000008befca744c6f2b567b1863dcf055c593afdc11a000000000000000000000000000000000000000000000000045849994fc9c7b1500000000000000000000000000000000000000000000000033d343f77863cab8000000000000000000000000ad1b1f2a6dd55627e3893b771a00cd43f69dce350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e81000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000152d02c7e14af68000000000000000000000000000000000000000000000000000090d972f32323c00000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000350a791bfc2c21f9ed5d10980dad2e2638ffa7f6000000000000000000000000b2f30a7c980f052f02563fb518dcc39e6bf381750000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c2291992a08ebfdfedfe248f2ccd34da63570df4000000000000000000000000057152db365b47851b0a0bd431644b8ee21fe1b4
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c806381ff7048116100ee578063b1dc65a411610097578063d3c7c2c711610071578063d3c7c2c7146106a7578063d7e2bb50146106af578063e65bf00a146106c2578063f2fde38b146106d557600080fd5b8063b1dc65a41461066e578063b4069b3114610681578063c92b28321461069457600080fd5b80638da5cb5b116100c85780638da5cb5b1461061d578063afa0d3791461063b578063afcb95d71461064e57600080fd5b806381ff7048146105b357806385572ffb146105e3578063856c8247146105f157600080fd5b8063599f64311161015b578063681fba1611610135578063681fba16146104b8578063704b6c02146104cd5780637437ff9f146104e057806379ba5097146105ab57600080fd5b8063599f6431146104515780635d86f14114610490578063666cab8d146104a357600080fd5b80631ef381741161018c5780631ef38174146103c55780633a87ac53146103da578063546719cd146103ed57600080fd5b806306285c69146101b3578063142a98fc1461035c578063181f5a771461037c575b600080fd5b6103466040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526040518060c001604052807f0000000000000000000000008befca744c6f2b567b1863dcf055c593afdc11a073ffffffffffffffffffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000045849994fc9c7b1567ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000033d343f77863cab867ffffffffffffffff1681526020017f000000000000000000000000ad1b1f2a6dd55627e3893b771a00cd43f69dce3573ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e8173ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516103539190614677565b60405180910390f35b61036f61036a36600461470e565b6106e8565b6040516103539190614795565b6103b86040518060400160405280601481526020017f45564d3245564d4f666652616d7020312e302e3000000000000000000000000081525081565b6040516103539190614811565b6103d86103d3366004614a7f565b610763565b005b6103d86103e8366004614b91565b610c22565b6103f5611032565b604051610353919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610353565b61046b61049e366004614bfd565b6110e7565b6104ab611150565b6040516103539190614c6b565b6104c06111bf565b6040516103539190614c7e565b6103d86104db366004614bfd565b611278565b61059e6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a081018252600a5463ffffffff808216835273ffffffffffffffffffffffffffffffffffffffff64010000000090920482166020840152600b549182169383019390935261ffff7401000000000000000000000000000000000000000082041660608301527601000000000000000000000000000000000000000000009004909116608082015290565b6040516103539190614cd8565b6103d8611368565b6007546005546040805163ffffffff80851682526401000000009094049093166020840152820152606001610353565b6103d86101ae366004614d3b565b6106046105ff366004614bfd565b611465565b60405167ffffffffffffffff9091168152602001610353565b60005473ffffffffffffffffffffffffffffffffffffffff1661046b565b6103d8610649366004614fa5565b61158d565b604080516001815260006020820181905291810191909152606001610353565b6103d861067c36600461504e565b6117d9565b61046b61068f366004614bfd565b611a6a565b6103d86106a2366004615153565b611b43565b6104c0611bc8565b61046b6106bd366004614bfd565b611c7d565b6103d86106d03660046153aa565b611c8c565b6103d86106e3366004614bfd565b611e0e565b60006106f660016004615494565b60026107036080856154d6565b67ffffffffffffffff1661071791906154fd565b60136000610726608087615514565b67ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002054901c16600381111561075d5761075d61472b565b92915050565b84518460ff16601f8211156107d9576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f6f206d616e79207472616e736d697474657273000000000000000000000060448201526064015b60405180910390fd5b80600003610843576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016107d0565b61084b611e1f565b61085485611ea2565b60095460005b818110156108e05760086000600983815481106108795761087961553b565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556108d98161556a565b905061085a565b50875160005b81811015610adc5760008a82815181106109025761090261553b565b602002602001015190506000600281111561091f5761091f61472b565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040902054610100900460ff16600281111561095e5761095e61472b565b146109c5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016107d0565b73ffffffffffffffffffffffffffffffffffffffff8116610a12576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526008602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610ac257610ac261472b565b02179055509050505080610ad59061556a565b90506108e6565b508851610af09060099060208c01906145e1565b506006805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908b161717905560078054610b76914691309190600090610b489063ffffffff166155a2565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168d8d8d8d8d8d61214f565b6005600001819055506000600760049054906101000a900463ffffffff16905043600760046101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600560000154600760009054906101000a900463ffffffff168e8e8e8e8e8e604051610c0d999897969594939291906155c5565b60405180910390a15050505050505050505050565b610c2a611e1f565b60005b83811015610e29576000858583818110610c4957610c4961553b565b610c5f9260206040909202019081019150614bfd565b90506000868684818110610c7557610c7561553b565b9050604002016020016020810190610c8d9190614bfd565b9050610c9a600c836121fa565b610cd0576040517f9c8787c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610cf2600c8461221c565b73ffffffffffffffffffffffffffffffffffffffff1614610d3f576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d4a600c8361223e565b50610dc58173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbd919061565b565b600f9061223e565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a1505080610e229061556a565b9050610c2d565b5060005b8181101561102b576000838383818110610e4957610e4961553b565b610e5f9260206040909202019081019150614bfd565b90506000848484818110610e7557610e7561553b565b9050604002016020016020810190610e8d9190614bfd565b905073ffffffffffffffffffffffffffffffffffffffff82161580610ec6575073ffffffffffffffffffffffffffffffffffffffff8116155b15610efd576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f08600c836121fa565b15610f3f576040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f4b600c8383612260565b50610fc78173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbe919061565b565b600f9083612260565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a15050806110249061556a565b9050610e2d565b5050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff1615159383019390935260045480841660608401520490911660808201526110e290612283565b905090565b600080806110f6600c85612335565b9150915081611149576040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107d0565b9392505050565b606060098054806020026020016040519081016040528092919081815260200182805480156111b557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161118a575b5050505050905090565b60606111cb600f612364565b67ffffffffffffffff8111156111e3576111e3614824565b60405190808252806020026020018201604052801561120c578160200160208202803683370190505b50905060005b8151811015611274576000611228600f8361236f565b5090508083838151811061123e5761123e61553b565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101525061126d8161556a565b9050611212565b5090565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906112b8575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156112ef576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c9060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff1633146113e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107d0565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b73ffffffffffffffffffffffffffffffffffffffff811660009081526012602052604081205467ffffffffffffffff16801580156114d857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b1561075d576040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111499190615678565b3330146115c6576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160008082526020820190925281611603565b60408051808201909152600080825260208201528152602001906001900390816115dc5790505b5061012084015151909150156116625761012083015160608401516040805173ffffffffffffffffffffffffffffffffffffffff909216602083015261165f9291016040516020818303038152906040528560e001518561238b565b90505b60e083015173ffffffffffffffffffffffffffffffffffffffff163b15806116cc575060e08301516116ca9073ffffffffffffffffffffffffffffffffffffffff167f85572ffb00000000000000000000000000000000000000000000000000000000612831565b155b156116d657505050565b600a546000908190640100000000900473ffffffffffffffffffffffffffffffffffffffff16633cf9798361170b878661284d565b6113888860a001518960e001516040518563ffffffff1660e01b815260040161173794939291906156e6565b6000604051808303816000875af1158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261179c91908101906157b8565b915091508161102b57806040517f0a8d6e8c0000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b6117e387876128fd565b60055488359080821461182c576040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016107d0565b467f0000000000000000000000000000000000000000000000000000000000000001146118ad576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000160048201524660248201526044016107d0565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a13360009081526008602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156119355761193561472b565b60028111156119465761194661472b565b90525090506002816020015160028111156119635761196361472b565b1480156119aa57506009816000015160ff16815481106119855761198561553b565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6119e0576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060006119ee8560206154fd565b6119f98860206154fd565b611a058b610144615845565b611a0f9190615845565b611a199190615845565b9050368114611a5d576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016107d0565b5050505050505050505050565b60008080611a79600c85612335565b9150915081611acc576040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107d0565b8073ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3b919061565b565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611b83575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15611bba576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc5600382612924565b50565b6060611bd4600c612364565b67ffffffffffffffff811115611bec57611bec614824565b604051908082528060200260200182016040528015611c15578160200160208202803683370190505b50905060005b8151811015611274576000611c31600c8361236f565b50905080838381518110611c4757611c4761553b565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250611c768161556a565b9050611c1b565b600080806110f6600f85612335565b467f000000000000000000000000000000000000000000000000000000000000000114611d17576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000001600482015267ffffffffffffffff461660248201526044016107d0565b81515181518114611d54576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015611dfe576000838281518110611d7357611d7361553b565b6020026020010151905080600014158015611dac57508451805183908110611d9d57611d9d61553b565b602002602001015160a0015181105b15611ded576040517f085e39cf00000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016107d0565b50611df78161556a565b9050611d57565b50611e098383612b09565b505050565b611e16611e1f565b611bc581613545565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107d0565b565b600081806020019051810190611eb8919061586c565b602081015190915073ffffffffffffffffffffffffffffffffffffffff16611f0c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600a805460208085015173ffffffffffffffffffffffffffffffffffffffff908116640100000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931663ffffffff9586161792909217909255604080850151600b80546060808901516080808b0151909916760100000000000000000000000000000000000000000000027fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff61ffff90921674010000000000000000000000000000000000000000027fffffffffffffffffffff00000000000000000000000000000000000000000000909416958816959095179290921791909116929092179055815160c0810183527f0000000000000000000000008befca744c6f2b567b1863dcf055c593afdc11a08416815267ffffffffffffffff7f00000000000000000000000000000000000000000000000045849994fc9c7b158116958201959095527f00000000000000000000000000000000000000000000000033d343f77863cab8909416848301527f000000000000000000000000ad1b1f2a6dd55627e3893b771a00cd43f69dce358316908401527f00000000000000000000000000000000000000000000000000000000000000008216938301939093527f000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e811660a082015290517f737ef22d3f6615e342ed21c69e06620dbc5c8a261ed7cfb2ce214806b1f76eda91612143918490615907565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a604051602001612173999897969594939291906159d6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b60006111498373ffffffffffffffffffffffffffffffffffffffff841661363a565b60006111498373ffffffffffffffffffffffffffffffffffffffff8416613646565b60006111498373ffffffffffffffffffffffffffffffffffffffff8416613652565b6000611b3b8473ffffffffffffffffffffffffffffffffffffffff85168461365e565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261231182606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426122f59190615494565b85608001516fffffffffffffffffffffffffffffffff16613681565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6000806123588473ffffffffffffffffffffffffffffffffffffffff85166136a0565b915091505b9250929050565b600061075d826136af565b600080808061237e86866136ba565b9097909650945050505050565b60606000855167ffffffffffffffff8111156123a9576123a9614824565b6040519080825280602002602001820160405280156123ee57816020015b60408051808201909152600080825260208201528152602001906001900390816123c75790505b50905060005b86518110156128035760006124258883815181106124145761241461553b565b6020026020010151600001516110e7565b90508073ffffffffffffffffffffffffffffffffffffffff16638627fad688888b86815181106124575761245761553b565b6020026020010151602001517f00000000000000000000000000000000000000000000000033d343f77863cab88a88815181106124965761249661553b565b60200260200101516040518663ffffffff1660e01b81526004016124be959493929190615a6b565b600060405180830381600087803b1580156124d857600080fd5b505af19250505080156124e9575060015b61270c573d808015612517576040519150601f19603f3d011682016040523d82523d6000602084013e61251c565b606091505b50600061252882615ace565b90507f9725942a000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821614806125bb57507ff94ebcd1000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061260757507f15279c08000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061265357507f1a76572a000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061269f57507fd0c8d23a000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b156126d857816040517f30dabb590000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b816040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b8073ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277b919061565b565b83838151811061278d5761278d61553b565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff909116905287518890839081106127c6576127c661553b565b6020026020010151602001518383815181106127e4576127e461553b565b6020908102919091018101510152506127fc8161556a565b90506123f4565b50600b5461282890829073ffffffffffffffffffffffffffffffffffffffff166136c9565b95945050505050565b600061283c836138a9565b80156111495750611149838361390d565b6040805160a08101825260008082526020820152606091810182905281810182905260808101919091526040518060a001604052808461016001518152602001846000015167ffffffffffffffff16815260200184606001516040516020016128d2919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6040516020818303038152906040528152602001846101000151815260200183815250905092915050565b61292061290c82840184615b1e565b604080516000815260208101909152612b09565b5050565b815460009061294d90700100000000000000000000000000000000900463ffffffff1642615494565b905080156129ef5760018301548354612995916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416613681565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612a15916fffffffffffffffffffffffffffffffff90811691166139dc565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612afc9084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60405180910390a1505050565b7f000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e8173ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b989190615b53565b15612bcf576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151516000819003612c0c576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260200151518114612c4a576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115612c6557612c65614824565b604051908082528060200260200182016040528015612c8e578160200160208202803683370190505b50905060005b82811015612d6e57600085600001518281518110612cb457612cb461553b565b60200260200101519050612ce8817f2a845d8b9147a9acfae80924b6c753a05356760481dae244cad47affe518368d6139f2565b838381518110612cfa57612cfa61553b565b602002602001018181525050806101600151838381518110612d1e57612d1e61553b565b602002602001015114612d5d576040517f7185cf6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50612d678161556a565b9050612c94565b50604080850151606086015191517f3204887500000000000000000000000000000000000000000000000000000000815260009273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000008befca744c6f2b567b1863dcf055c593afdc11a01692633204887592612def92879291600401615ba0565b602060405180830381865afa158015612e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e309190615bd6565b905080600003612e6c576040517fea75680100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351151560005b8481101561353c57600087600001518281518110612e9357612e9361553b565b602002602001015190506000612eac82602001516106e8565b90506000816003811115612ec257612ec261472b565b1480612edf57506003816003811115612edd57612edd61472b565b145b612f275760208201516040517f50a6e05200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b8315612fe457600a5460009063ffffffff16612f438742615494565b1190508080612f6357506003826003811115612f6157612f6161472b565b145b612f99576040517f6358b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b888481518110612fab57612fab61553b565b6020026020010151600014612fde57888481518110612fcc57612fcc61553b565b60200260200101518360a00181815250505b50613041565b6000816003811115612ff857612ff861472b565b146130415760208201516040517f67d9ba0f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b606082015173ffffffffffffffffffffffffffffffffffffffff1660009081526012602052604090205467ffffffffffffffff16801580156130b857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b1561325a5760608301516040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063856c824790602401602060405180830381865afa158015613150573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131749190615678565b608084015190915067ffffffffffffffff16613191826001615bef565b67ffffffffffffffff16146131fe57826060015173ffffffffffffffffffffffffffffffffffffffff16836080015167ffffffffffffffff167fe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d60405160405180910390a350505061352c565b606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260126020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790555b600082600381111561326e5761326e61472b565b036132fa57608083015167ffffffffffffffff1661328d826001615bef565b67ffffffffffffffff16146132fa57826060015173ffffffffffffffffffffffffffffffffffffffff16836080015167ffffffffffffffff167fd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf4123760405160405180910390a350505061352c565b60008a6020015185815181106133125761331261553b565b60200260200101519050613327848251613b09565b61333684602001516001613cdf565b6000806133438684613d89565b91509150613355866020015183613cdf565b60038260038111156133695761336961472b565b14158015613389575060028260038111156133865761338661472b565b14155b156133c8578560200151826040517f9e2616030000000000000000000000000000000000000000000000000000000081526004016107d0929190615c10565b8560c00151156134575760028260038111156133e6576133e661472b565b0361345257606086015173ffffffffffffffffffffffffffffffffffffffff166000908152601260205260408120805467ffffffffffffffff169161342a83615c2e565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b6134d7565b600085600381111561346b5761346b61472b565b036134d757606086015173ffffffffffffffffffffffffffffffffffffffff166000908152601260205260408120805467ffffffffffffffff16916134af83615c2e565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b856101600151866020015167ffffffffffffffff167fd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef65848460405161351d929190615c4b565b60405180910390a35050505050505b6135358161556a565b9050612e73565b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036135c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107d0565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006111498383613f2c565b60006111498383613f38565b60006111498383613fc2565b6000611b3b848473ffffffffffffffffffffffffffffffffffffffff8516613fdf565b60006128288561369184866154fd565b61369b9087615845565b6139dc565b600080808061237e8686613ffc565b600061075d82614036565b600080808061237e8686614041565b81516000805b828110156138955760008473ffffffffffffffffffffffffffffffffffffffff1663d02641a08784815181106137075761370761553b565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016040805180830381865afa15801561377b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379f9190615c6b565b51905077ffffffffffffffffffffffffffffffffffffffffffffffff811660000361382d578582815181106137d6576137d661553b565b6020908102919091010151516040517f9a655f7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016107d0565b6138778683815181106138425761384261553b565b6020026020010151602001518277ffffffffffffffffffffffffffffffffffffffffffffffff1661406c90919063ffffffff16565b6138819084615845565b9250508061388e9061556a565b90506136cf565b506138a360038260006140a5565b50505050565b60006138d5827f01ffc9a70000000000000000000000000000000000000000000000000000000061390d565b801561075d5750613906827fffffffff0000000000000000000000000000000000000000000000000000000061390d565b1592915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d915060005190508280156139c5575060208210155b80156139d15750600081115b979650505050505050565b60008183106139eb5781611149565b5090919050565b60008060001b828460200151856080015186606001518760e0015188610100015180519060200120896101200151604051602001613a309190615cc9565b604051602081830303815290604052805190602001208a60a001518b60c001518c61014001518d60400151604051602001613aeb9c9b9a999897969594939291909b8c5260208c019a909a5267ffffffffffffffff98891660408c01529690971660608a015273ffffffffffffffffffffffffffffffffffffffff94851660808a015292841660a089015260c088019190915260e0870152610100860152911515610120850152166101408301526101608201526101800190565b60405160208183030381529060405280519060200120905092915050565b7f00000000000000000000000000000000000000000000000033d343f77863cab867ffffffffffffffff16826000015167ffffffffffffffff1614613b895781516040517f1279ec8a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b600b54610120830151517401000000000000000000000000000000000000000090910461ffff161015613bfa5760208201516040517f099d3f7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b808261012001515114613c4b5760208201516040517f8808f8e700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b600b546101008301515176010000000000000000000000000000000000000000000090910463ffffffff16101561292057600b54610100830151516040517f8693378900000000000000000000000000000000000000000000000000000000815276010000000000000000000000000000000000000000000090920463ffffffff16600483015260248201526044016107d0565b60006002613cee6080856154d6565b67ffffffffffffffff16613d0291906154fd565b90506000601381613d14608087615514565b67ffffffffffffffff168152602081019190915260400160002054905081613d3e60016004615494565b901b191681836003811115613d5557613d5561472b565b901b178060136000613d68608088615514565b67ffffffffffffffff16815260208101919091526040016000205550505050565b6040517fafa0d379000000000000000000000000000000000000000000000000000000008152600090606090309063afa0d37990613dcd9087908790600401615d52565b600060405180830381600087803b158015613de757600080fd5b505af1925050508015613df8575060015b613f11573d808015613e26576040519150601f19603f3d011682016040523d82523d6000602084013e613e2b565b606091505b50613e3581615ace565b7fffffffff00000000000000000000000000000000000000000000000000000000167f0a8d6e8c000000000000000000000000000000000000000000000000000000001480613ecd5750613e8881615ace565b7fffffffff00000000000000000000000000000000000000000000000000000000167fe1cd550900000000000000000000000000000000000000000000000000000000145b15613edd5760039250905061235d565b806040517fcf19edfd0000000000000000000000000000000000000000000000000000000081526004016107d09190614811565b50506040805160208101909152600081526002909250929050565b60006111498383614428565b600081815260028301602052604081205480151580613f5c5750613f5c8484613f2c565b611149576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b6579000060448201526064016107d0565b600081815260028301602052604081208190556111498383614440565b60008281526002840160205260408120829055611b3b848461444c565b600081815260028301602052604081205481908061402b5761401e8585613f2c565b92506000915061235d9050565b60019250905061235d565b600061075d82614458565b6000808061404f8585614462565b600081815260029690960160205260409095205494959350505050565b6000670de0b6b3a764000061409b8377ffffffffffffffffffffffffffffffffffffffffffffffff86166154fd565b6111499190615ebd565b825474010000000000000000000000000000000000000000900460ff1615806140cc575081155b156140d657505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061411c90700100000000000000000000000000000000900463ffffffff1642615494565b905080156141dc578183111561415e576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546141989083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613681565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156142935773ffffffffffffffffffffffffffffffffffffffff841661423b576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016107d0565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016107d0565b848310156143a65760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906142d79082615494565b6142e1878a615494565b6142eb9190615845565b6142f59190615ebd565b905073ffffffffffffffffffffffffffffffffffffffff861661434e576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016107d0565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016107d0565b6143b08584615494565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60008181526001830160205260408120541515611149565b6000611149838361446e565b60006111498383614568565b600061075d825490565b600061114983836145b7565b60008181526001830160205260408120548015614557576000614492600183615494565b85549091506000906144a690600190615494565b905081811461450b5760008660000182815481106144c6576144c661553b565b90600052602060002001549050808760000184815481106144e9576144e961553b565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061451c5761451c615ed1565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061075d565b600091505061075d565b5092915050565b60008181526001830160205260408120546145af5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561075d565b50600061075d565b60008260000182815481106145ce576145ce61553b565b9060005260206000200154905092915050565b82805482825590600052602060002090810192821561465b579160200282015b8281111561465b57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614601565b506112749291505b808211156112745760008155600101614663565b60c0810161075d828473ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b67ffffffffffffffff81168114611bc557600080fd5b8035614709816146e8565b919050565b60006020828403121561472057600080fd5b8135611149816146e8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110614791577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6020810161075d828461475a565b60005b838110156147be5781810151838201526020016147a6565b50506000910152565b600081518084526147df8160208601602086016147a3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061114960208301846147c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561487657614876614824565b60405290565b604051610180810167ffffffffffffffff8111828210171561487657614876614824565b6040516080810167ffffffffffffffff8111828210171561487657614876614824565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561490a5761490a614824565b604052919050565b600067ffffffffffffffff82111561492c5761492c614824565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611bc557600080fd5b803561470981614936565b600082601f83011261497457600080fd5b8135602061498961498483614912565b6148c3565b82815260059290921b840181019181810190868411156149a857600080fd5b8286015b848110156149cc5780356149bf81614936565b83529183019183016149ac565b509695505050505050565b803560ff8116811461470957600080fd5b600067ffffffffffffffff821115614a0257614a02614824565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112614a3f57600080fd5b8135614a4d614984826149e8565b818152846020838601011115614a6257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c08789031215614a9857600080fd5b863567ffffffffffffffff80821115614ab057600080fd5b614abc8a838b01614963565b97506020890135915080821115614ad257600080fd5b614ade8a838b01614963565b9650614aec60408a016149d7565b95506060890135915080821115614b0257600080fd5b614b0e8a838b01614a2e565b9450614b1c60808a016146fe565b935060a0890135915080821115614b3257600080fd5b50614b3f89828a01614a2e565b9150509295509295509295565b60008083601f840112614b5e57600080fd5b50813567ffffffffffffffff811115614b7657600080fd5b6020830191508360208260061b850101111561235d57600080fd5b60008060008060408587031215614ba757600080fd5b843567ffffffffffffffff80821115614bbf57600080fd5b614bcb88838901614b4c565b90965094506020870135915080821115614be457600080fd5b50614bf187828801614b4c565b95989497509550505050565b600060208284031215614c0f57600080fd5b813561114981614936565b600081518084526020808501945080840160005b83811015614c6057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614c2e565b509495945050505050565b6020815260006111496020830184614c1a565b6020808252825182820181905260009190848201906040850190845b81811015614ccc57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614c9a565b50909695505050505050565b60a0810161075d828463ffffffff808251168352602082015173ffffffffffffffffffffffffffffffffffffffff8082166020860152806040850151166040860152505061ffff6060830151166060840152806080830151166080840152505050565b600060208284031215614d4d57600080fd5b813567ffffffffffffffff811115614d6457600080fd5b820160a0818503121561114957600080fd5b8015158114611bc557600080fd5b803561470981614d76565b600082601f830112614da057600080fd5b81356020614db061498483614912565b82815260069290921b84018101918181019086841115614dcf57600080fd5b8286015b848110156149cc5760408189031215614dec5760008081fd5b614df4614853565b8135614dff81614936565b81528185013585820152835291830191604001614dd3565b60006101808284031215614e2a57600080fd5b614e3261487c565b9050614e3d826146fe565b8152614e4b602083016146fe565b602082015260408201356040820152614e6660608301614958565b6060820152614e77608083016146fe565b608082015260a082013560a0820152614e9260c08301614d84565b60c0820152614ea360e08301614958565b60e08201526101008083013567ffffffffffffffff80821115614ec557600080fd5b614ed186838701614a2e565b83850152610120925082850135915080821115614eed57600080fd5b50614efa85828601614d8f565b828401525050610140614f0e818401614958565b818301525061016080830135818301525092915050565b600082601f830112614f3657600080fd5b81356020614f4661498483614912565b82815260059290921b84018101918181019086841115614f6557600080fd5b8286015b848110156149cc57803567ffffffffffffffff811115614f895760008081fd5b614f978986838b0101614a2e565b845250918301918301614f69565b60008060408385031215614fb857600080fd5b823567ffffffffffffffff80821115614fd057600080fd5b614fdc86838701614e17565b93506020850135915080821115614ff257600080fd5b50614fff85828601614f25565b9150509250929050565b60008083601f84011261501b57600080fd5b50813567ffffffffffffffff81111561503357600080fd5b6020830191508360208260051b850101111561235d57600080fd5b60008060008060008060008060e0898b03121561506a57600080fd5b606089018a81111561507b57600080fd5b8998503567ffffffffffffffff8082111561509557600080fd5b818b0191508b601f8301126150a957600080fd5b8135818111156150b857600080fd5b8c60208285010111156150ca57600080fd5b6020830199508098505060808b01359150808211156150e857600080fd5b6150f48c838d01615009565b909750955060a08b013591508082111561510d57600080fd5b5061511a8b828c01615009565b999c989b50969995989497949560c00135949350505050565b80356fffffffffffffffffffffffffffffffff8116811461470957600080fd5b60006060828403121561516557600080fd5b6040516060810181811067ffffffffffffffff8211171561518857615188614824565b604052823561519681614d76565b81526151a460208401615133565b60208201526151b560408401615133565b60408201529392505050565b600082601f8301126151d257600080fd5b813560206151e261498483614912565b82815260059290921b8401810191818101908684111561520157600080fd5b8286015b848110156149cc57803567ffffffffffffffff8111156152255760008081fd5b6152338986838b0101614f25565b845250918301918301615205565b600082601f83011261525257600080fd5b8135602061526261498483614912565b82815260059290921b8401810191818101908684111561528157600080fd5b8286015b848110156149cc5780358352918301918301615285565b6000608082840312156152ae57600080fd5b6152b66148a0565b9050813567ffffffffffffffff808211156152d057600080fd5b818401915084601f8301126152e457600080fd5b813560206152f461498483614912565b82815260059290921b8401810191818101908884111561531357600080fd5b8286015b8481101561534b5780358681111561532f5760008081fd5b61533d8b86838b0101614e17565b845250918301918301615317565b508652508581013593508284111561536257600080fd5b61536e878588016151c1565b9085015250604084013591508082111561538757600080fd5b5061539484828501615241565b6040830152506060820135606082015292915050565b600080604083850312156153bd57600080fd5b823567ffffffffffffffff808211156153d557600080fd5b6153e18683870161529c565b93506020915081850135818111156153f857600080fd5b85019050601f8101861361540b57600080fd5b803561541961498482614912565b81815260059190911b8201830190838101908883111561543857600080fd5b928401925b828410156154565783358252928401929084019061543d565b80955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561075d5761075d615465565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff808416806154f1576154f16154a7565b92169190910692915050565b808202811582820484141761075d5761075d615465565b600067ffffffffffffffff8084168061552f5761552f6154a7565b92169190910492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361559b5761559b615465565b5060010190565b600063ffffffff8083168181036155bb576155bb615465565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526155f58184018a614c1a565b905082810360808401526156098189614c1a565b905060ff871660a084015282810360c084015261562681876147c7565b905067ffffffffffffffff851660e084015282810361010084015261564b81856147c7565b9c9b505050505050505050505050565b60006020828403121561566d57600080fd5b815161114981614936565b60006020828403121561568a57600080fd5b8151611149816146e8565b600081518084526020808501945080840160005b83811015614c60578151805173ffffffffffffffffffffffffffffffffffffffff16885283015183880152604090960195908201906001016156a9565b608081528451608082015267ffffffffffffffff60208601511660a08201526000604086015160a060c08401526157216101208401826147c7565b905060608701517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808584030160e086015261575d83836147c7565b92506080890151915080858403016101008601525061577c8282615695565b92505050615790602083018661ffff169052565b836040830152612828606083018473ffffffffffffffffffffffffffffffffffffffff169052565b600080604083850312156157cb57600080fd5b82516157d681614d76565b602084015190925067ffffffffffffffff8111156157f357600080fd5b8301601f8101851361580457600080fd5b8051615812614984826149e8565b81815286602083850101111561582757600080fd5b6158388260208301602086016147a3565b8093505050509250929050565b8082018082111561075d5761075d615465565b805163ffffffff8116811461470957600080fd5b600060a0828403121561587e57600080fd5b60405160a0810181811067ffffffffffffffff821117156158a1576158a1614824565b6040526158ad83615858565b815260208301516158bd81614936565b602082015260408301516158d081614936565b6040820152606083015161ffff811681146158ea57600080fd5b60608201526158fb60808401615858565b60808201529392505050565b6101608101615979828573ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b825163ffffffff90811660c0840152602084015173ffffffffffffffffffffffffffffffffffffffff90811660e0850152604085015116610100840152606084015161ffff16610120840152608084015116610140830152611149565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152615a1d8285018b614c1a565b91508382036080850152615a31828a614c1a565b915060ff881660a085015283820360c0850152615a4e82886147c7565b90861660e0850152838103610100850152905061564b81856147c7565b60a081526000615a7e60a08301886147c7565b73ffffffffffffffffffffffffffffffffffffffff8716602084015285604084015267ffffffffffffffff851660608401528281036080840152615ac281856147c7565b98975050505050505050565b6000815160208301517fffffffff0000000000000000000000000000000000000000000000000000000080821693506004831015615b165780818460040360031b1b83161693505b505050919050565b600060208284031215615b3057600080fd5b813567ffffffffffffffff811115615b4757600080fd5b611b3b8482850161529c565b600060208284031215615b6557600080fd5b815161114981614d76565b600081518084526020808501945080840160005b83811015614c6057815187529582019590820190600101615b84565b606081526000615bb36060830186615b70565b8281036020840152615bc58186615b70565b915050826040830152949350505050565b600060208284031215615be857600080fd5b5051919050565b67ffffffffffffffff81811683821601908082111561456157614561615465565b67ffffffffffffffff8316815260408101611149602083018461475a565b600067ffffffffffffffff8083168181036155bb576155bb615465565b615c55818461475a565b604060208201526000611b3b60408301846147c7565b600060408284031215615c7d57600080fd5b615c85614853565b825177ffffffffffffffffffffffffffffffffffffffffffffffff81168114615cad57600080fd5b81526020830151615cbd816146e8565b60208201529392505050565b6020815260006111496020830184615695565b600082825180855260208086019550808260051b84010181860160005b84811015615d45577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018952615d338383516147c7565b98840198925090830190600101615cf9565b5090979650505050505050565b60408152615d6d60408201845167ffffffffffffffff169052565b60006020840151615d8a606084018267ffffffffffffffff169052565b5060408401516080830152606084015173ffffffffffffffffffffffffffffffffffffffff811660a084015250608084015167ffffffffffffffff811660c08401525060a084015160e083015260c0840151610100615dec8185018315159052565b60e08601519150610120615e178186018473ffffffffffffffffffffffffffffffffffffffff169052565b81870151925061018091506101408281870152615e386101c08701856147c7565b93508188015191506101607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030181880152615e768584615695565b9450818901519250615e9f8488018473ffffffffffffffffffffffffffffffffffffffff169052565b8801516101a087015250505082810360208401526128288185615cdc565b600082615ecc57615ecc6154a7565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008befca744c6f2b567b1863dcf055c593afdc11a000000000000000000000000000000000000000000000000045849994fc9c7b1500000000000000000000000000000000000000000000000033d343f77863cab8000000000000000000000000ad1b1f2a6dd55627e3893b771a00cd43f69dce350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e81000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000152d02c7e14af68000000000000000000000000000000000000000000000000000090d972f32323c00000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000350a791bfc2c21f9ed5d10980dad2e2638ffa7f6000000000000000000000000b2f30a7c980f052f02563fb518dcc39e6bf381750000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c2291992a08ebfdfedfe248f2ccd34da63570df4000000000000000000000000057152db365b47851b0a0bd431644b8ee21fe1b4
-----Decoded View---------------
Arg [0] : staticConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : sourceTokens (address[]): 0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6,0xb2F30A7C980f052f02563fb518dcc39e6bf38175
Arg [2] : pools (address[]): 0xC2291992A08eBFDfedfE248F2CCD34Da63570DF4,0x057152DB365B47851B0A0bd431644b8eE21fE1b4
Arg [3] : rateLimiterConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
17 Constructor Arguments found :
Arg [0] : 0000000000000000000000008befca744c6f2b567b1863dcf055c593afdc11a0
Arg [1] : 00000000000000000000000000000000000000000000000045849994fc9c7b15
Arg [2] : 00000000000000000000000000000000000000000000000033d343f77863cab8
Arg [3] : 000000000000000000000000ad1b1f2a6dd55627e3893b771a00cd43f69dce35
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 000000000000000000000000411de17f12d1a34ecc7f45f49844626267c75e81
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [7] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 00000000000000000000000000000000000000000000152d02c7e14af6800000
Arg [10] : 0000000000000000000000000000000000000000000000090d972f32323c0000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [12] : 000000000000000000000000350a791bfc2c21f9ed5d10980dad2e2638ffa7f6
Arg [13] : 000000000000000000000000b2f30a7c980f052f02563fb518dcc39e6bf38175
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [15] : 000000000000000000000000c2291992a08ebfdfedfe248f2ccd34da63570df4
Arg [16] : 000000000000000000000000057152db365b47851b0a0bd431644b8ee21fe1b4
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.