Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize | 13502977 | 1260 days ago | IN | 0 ETH | 0.01613367 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
L1CrossDomainMessenger
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Library Imports */ import {AddressAliasHelper} from '../../standards/AddressAliasHelper.sol'; import {Lib_AddressResolver} from '../../libraries/resolver/Lib_AddressResolver.sol'; import {Lib_OVMCodec} from '../../libraries/codec/Lib_OVMCodec.sol'; import {Lib_AddressManager} from '../../libraries/resolver/Lib_AddressManager.sol'; import {Lib_SecureMerkleTrie} from '../../libraries/trie/Lib_SecureMerkleTrie.sol'; import {Lib_DefaultValues} from '../../libraries/constants/Lib_DefaultValues.sol'; import {Lib_PredeployAddresses} from '../../libraries/constants/Lib_PredeployAddresses.sol'; import {Lib_CrossDomainUtils} from '../../libraries/bridge/Lib_CrossDomainUtils.sol'; /* Interface Imports */ import {IL1CrossDomainMessenger} from './IL1CrossDomainMessenger.sol'; import {ICanonicalTransactionChain} from '../rollup/ICanonicalTransactionChain.sol'; import {IStateCommitmentChain} from '../rollup/IStateCommitmentChain.sol'; /* External Imports */ import {OwnableUpgradeable} from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; import {PausableUpgradeable} from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol'; /** * @title L1CrossDomainMessenger * @dev The L1 Cross Domain Messenger contract sends messages from L1 to L2, and relays messages * from L2 onto L1. In the event that a message sent from L1 to L2 is rejected for exceeding the L2 * epoch gas limit, it can be resubmitted via this contract's replay function. * * Runtime target: EVM */ contract L1CrossDomainMessenger is IL1CrossDomainMessenger, Lib_AddressResolver, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable { /********** * Events * **********/ event MessageBlocked(bytes32 indexed _xDomainCalldataHash); event MessageAllowed(bytes32 indexed _xDomainCalldataHash); /********************** * Contract Variables * **********************/ mapping(bytes32 => bool) public blockedMessages; mapping(bytes32 => bool) public relayedMessages; mapping(bytes32 => bool) public successfulMessages; mapping(bytes32 => bool) public failedMessages; address internal xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER; /*************** * Constructor * ***************/ /** * This contract is intended to be behind a delegate proxy. * We pass the zero address to the address resolver just to satisfy the constructor. * We still need to set this value in initialize(). */ constructor() Lib_AddressResolver(address(0)) {} /******************** * Public Functions * ********************/ /** * @param _libAddressManager Address of the Address Manager. */ function initialize(address _libAddressManager) public initializer { require( address(libAddressManager) == address(0), 'L1CrossDomainMessenger already intialized.' ); libAddressManager = Lib_AddressManager(_libAddressManager); xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER; // Initialize upgradable OZ contracts __Context_init_unchained(); // Context is a dependency for both Ownable and Pausable __Ownable_init_unchained(); __Pausable_init_unchained(); __ReentrancyGuard_init_unchained(); } /** * Pause relaying. */ function pause() external onlyOwner { _pause(); } /** * Block a message. * @param _xDomainCalldataHash Hash of the message to block. */ function blockMessage(bytes32 _xDomainCalldataHash) external onlyOwner { blockedMessages[_xDomainCalldataHash] = true; emit MessageBlocked(_xDomainCalldataHash); } /** * Allow a message. * @param _xDomainCalldataHash Hash of the message to block. */ function allowMessage(bytes32 _xDomainCalldataHash) external onlyOwner { blockedMessages[_xDomainCalldataHash] = false; emit MessageAllowed(_xDomainCalldataHash); } function xDomainMessageSender() public view returns (address) { require( xDomainMsgSender != Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER, 'xDomainMessageSender is not set' ); return xDomainMsgSender; } /** * Sends a cross domain message to the target messenger. * @param _target Target contract address. * @param _message Message to send to the target. * @param _gasLimit Gas limit for the provided message. */ function sendMessage( address _target, bytes memory _message, uint32 _gasLimit ) public { address ovmCanonicalTransactionChain = resolve('CanonicalTransactionChain'); // Use the CTC queue length as nonce uint40 nonce = ICanonicalTransactionChain(ovmCanonicalTransactionChain) .getQueueLength(); bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata( _target, msg.sender, _message, nonce ); _sendXDomainMessage( ovmCanonicalTransactionChain, xDomainCalldata, _gasLimit ); emit SentMessage(_target, msg.sender, _message, nonce, _gasLimit); } /** * Relays a cross domain message to a contract. * @inheritdoc IL1CrossDomainMessenger */ function relayMessage( address _target, address _sender, bytes memory _message, uint256 _messageNonce, L2MessageInclusionProof memory _proof ) public nonReentrant whenNotPaused { bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata( _target, _sender, _message, _messageNonce ); require( _verifyXDomainMessage(xDomainCalldata, _proof) == true, 'Provided message could not be verified.' ); bytes32 xDomainCalldataHash = keccak256(xDomainCalldata); require( successfulMessages[xDomainCalldataHash] == false, 'Provided message has already been received.' ); require( blockedMessages[xDomainCalldataHash] == false, 'Provided message has been blocked.' ); require( _target != resolve('CanonicalTransactionChain'), 'Cannot send L2->L1 messages to L1 system contracts.' ); xDomainMsgSender = _sender; (bool success, ) = _target.call(_message); xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER; // Mark the message as received if the call was successful. Ensures that a message can be // relayed multiple times in the case that the call reverted. if (success == true) { successfulMessages[xDomainCalldataHash] = true; emit RelayedMessage(xDomainCalldataHash); } else { failedMessages[xDomainCalldataHash] = true; emit FailedRelayedMessage(xDomainCalldataHash); } // Store an identifier that can be used to prove that the given message was relayed by some // user. Gives us an easy way to pay relayers for their work. bytes32 relayId = keccak256( abi.encodePacked(xDomainCalldata, msg.sender, block.number) ); relayedMessages[relayId] = true; } /** * Replays a cross domain message to the target messenger. * @inheritdoc IL1CrossDomainMessenger */ function replayMessage( address _target, address _sender, bytes memory _message, uint256 _queueIndex, uint32 _oldGasLimit, uint32 _newGasLimit ) public { // Verify that the message is in the queue: address canonicalTransactionChain = resolve('CanonicalTransactionChain'); Lib_OVMCodec.QueueElement memory element = ICanonicalTransactionChain( canonicalTransactionChain ).getQueueElement(_queueIndex); // Compute the calldata that was originally used to send the message. bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata( _target, _sender, _message, _queueIndex ); // Compute the transactionHash bytes32 transactionHash = keccak256( abi.encode( AddressAliasHelper.applyL1ToL2Alias(address(this)), Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER, _oldGasLimit, xDomainCalldata ) ); // Now check that the provided message data matches the one in the queue element. require( transactionHash == element.transactionHash, 'Provided message has not been enqueued.' ); // Send the same message but with the new gas limit. _sendXDomainMessage( canonicalTransactionChain, xDomainCalldata, _newGasLimit ); } /********************** * Internal Functions * **********************/ /** * Verifies that the given message is valid. * @param _xDomainCalldata Calldata to verify. * @param _proof Inclusion proof for the message. * @return Whether or not the provided message is valid. */ function _verifyXDomainMessage( bytes memory _xDomainCalldata, L2MessageInclusionProof memory _proof ) internal view returns (bool) { return (_verifyStateRootProof(_proof) && _verifyStorageProof(_xDomainCalldata, _proof)); } /** * Verifies that the state root within an inclusion proof is valid. * @param _proof Message inclusion proof. * @return Whether or not the provided proof is valid. */ function _verifyStateRootProof(L2MessageInclusionProof memory _proof) internal view returns (bool) { IStateCommitmentChain ovmStateCommitmentChain = IStateCommitmentChain( resolve('StateCommitmentChain') ); return (ovmStateCommitmentChain.insideFraudProofWindow( _proof.stateRootBatchHeader ) == false && ovmStateCommitmentChain.verifyStateCommitment( _proof.stateRoot, _proof.stateRootBatchHeader, _proof.stateRootProof )); } /** * Verifies that the storage proof within an inclusion proof is valid. * @param _xDomainCalldata Encoded message calldata. * @param _proof Message inclusion proof. * @return Whether or not the provided proof is valid. */ function _verifyStorageProof( bytes memory _xDomainCalldata, L2MessageInclusionProof memory _proof ) internal view returns (bool) { bytes32 storageKey = keccak256( abi.encodePacked( keccak256( abi.encodePacked( _xDomainCalldata, Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER ) ), uint256(0) ) ); ( bool exists, bytes memory encodedMessagePassingAccount ) = Lib_SecureMerkleTrie.get( abi.encodePacked(Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER), _proof.stateTrieWitness, _proof.stateRoot ); require( exists == true, 'Message passing predeploy has not been initialized or invalid proof provided.' ); Lib_OVMCodec.EVMAccount memory account = Lib_OVMCodec.decodeEVMAccount( encodedMessagePassingAccount ); return Lib_SecureMerkleTrie.verifyInclusionProof( abi.encodePacked(storageKey), abi.encodePacked(uint8(1)), _proof.storageTrieWitness, account.storageRoot ); } /** * Sends a cross domain message. * @param _canonicalTransactionChain Address of the CanonicalTransactionChain instance. * @param _message Message to send. * @param _gasLimit OVM gas limit for the message. */ function _sendXDomainMessage( address _canonicalTransactionChain, bytes memory _message, uint256 _gasLimit ) internal { ICanonicalTransactionChain(_canonicalTransactionChain).enqueue( Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER, _gasLimit, _message ); } }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.8.7; library AddressAliasHelper { uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); /// @notice Utility function that converts the address in the L1 that submitted a tx to /// the inbox to the msg.sender viewed in the L2 /// @param l1Address the address in the L1 that triggered the tx to L2 /// @return l2Address L2 address as viewed in msg.sender function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { unchecked { l2Address = address(uint160(l1Address) + offset); } } /// @notice Utility function that converts the msg.sender viewed in the L2 to the /// address in the L1 that submitted a tx to the inbox /// @param l2Address L2 address as viewed in msg.sender /// @return l1Address the address in the L1 that triggered the tx to L2 function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) { unchecked { l1Address = address(uint160(l2Address) - offset); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Library Imports */ import {Lib_AddressManager} from './Lib_AddressManager.sol'; /** * @title Lib_AddressResolver */ abstract contract Lib_AddressResolver { /************* * Variables * *************/ Lib_AddressManager public libAddressManager; /*************** * Constructor * ***************/ /** * @param _libAddressManager Address of the Lib_AddressManager. */ constructor(address _libAddressManager) { libAddressManager = Lib_AddressManager(_libAddressManager); } /******************** * Public Functions * ********************/ /** * Resolves the address associated with a given name. * @param _name Name to resolve an address for. * @return Address associated with the given name. */ function resolve(string memory _name) public view returns (address) { return libAddressManager.getAddress(_name); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Library Imports */ import {Lib_RLPReader} from '../rlp/Lib_RLPReader.sol'; import {Lib_RLPWriter} from '../rlp/Lib_RLPWriter.sol'; import {Lib_BytesUtils} from '../utils/Lib_BytesUtils.sol'; import {Lib_Bytes32Utils} from '../utils/Lib_Bytes32Utils.sol'; /** * @title Lib_OVMCodec */ library Lib_OVMCodec { /********* * Enums * *********/ enum QueueOrigin { SEQUENCER_QUEUE, L1TOL2_QUEUE } /*********** * Structs * ***********/ struct EVMAccount { uint256 nonce; uint256 balance; bytes32 storageRoot; bytes32 codeHash; } struct ChainBatchHeader { uint256 batchIndex; bytes32 batchRoot; uint256 batchSize; uint256 prevTotalElements; bytes extraData; } struct ChainInclusionProof { uint256 index; bytes32[] siblings; } struct Transaction { uint256 timestamp; uint256 blockNumber; QueueOrigin l1QueueOrigin; address l1TxOrigin; address entrypoint; uint256 gasLimit; bytes data; } struct TransactionChainElement { bool isSequenced; uint256 queueIndex; // QUEUED TX ONLY uint256 timestamp; // SEQUENCER TX ONLY uint256 blockNumber; // SEQUENCER TX ONLY bytes txData; // SEQUENCER TX ONLY } struct QueueElement { bytes32 transactionHash; uint40 timestamp; uint40 blockNumber; } /********************** * Internal Functions * **********************/ /** * Encodes a standard OVM transaction. * @param _transaction OVM transaction to encode. * @return Encoded transaction bytes. */ function encodeTransaction(Transaction memory _transaction) internal pure returns (bytes memory) { return abi.encodePacked( _transaction.timestamp, _transaction.blockNumber, _transaction.l1QueueOrigin, _transaction.l1TxOrigin, _transaction.entrypoint, _transaction.gasLimit, _transaction.data ); } /** * Hashes a standard OVM transaction. * @param _transaction OVM transaction to encode. * @return Hashed transaction */ function hashTransaction(Transaction memory _transaction) internal pure returns (bytes32) { return keccak256(encodeTransaction(_transaction)); } /** * @notice Decodes an RLP-encoded account state into a useful struct. * @param _encoded RLP-encoded account state. * @return Account state struct. */ function decodeEVMAccount(bytes memory _encoded) internal pure returns (EVMAccount memory) { Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList( _encoded ); return EVMAccount({ nonce: Lib_RLPReader.readUint256(accountState[0]), balance: Lib_RLPReader.readUint256(accountState[1]), storageRoot: Lib_RLPReader.readBytes32(accountState[2]), codeHash: Lib_RLPReader.readBytes32(accountState[3]) }); } /** * Calculates a hash for a given batch header. * @param _batchHeader Header to hash. * @return Hash of the header. */ function hashBatchHeader(Lib_OVMCodec.ChainBatchHeader memory _batchHeader) internal pure returns (bytes32) { return keccak256( abi.encode( _batchHeader.batchRoot, _batchHeader.batchSize, _batchHeader.prevTotalElements, _batchHeader.extraData ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* External Imports */ import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; /** * @title Lib_AddressManager */ contract Lib_AddressManager is Ownable { /********** * Events * **********/ event AddressSet( string indexed _name, address _newAddress, address _oldAddress ); /************* * Variables * *************/ mapping(bytes32 => address) private addresses; /******************** * Public Functions * ********************/ /** * Changes the address associated with a particular name. * @param _name String name to associate an address with. * @param _address Address to associate with the name. */ function setAddress(string memory _name, address _address) external onlyOwner { bytes32 nameHash = _getNameHash(_name); address oldAddress = addresses[nameHash]; addresses[nameHash] = _address; emit AddressSet(_name, _address, oldAddress); } /** * Retrieves the address associated with a given name. * @param _name Name to retrieve an address for. * @return Address associated with the given name. */ function getAddress(string memory _name) external view returns (address) { return addresses[_getNameHash(_name)]; } /********************** * Internal Functions * **********************/ /** * Computes the hash of a name. * @param _name Name to compute a hash for. * @return Hash of the given name. */ function _getNameHash(string memory _name) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_name)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Library Imports */ import {Lib_MerkleTrie} from './Lib_MerkleTrie.sol'; /** * @title Lib_SecureMerkleTrie */ library Lib_SecureMerkleTrie { /********************** * Internal Functions * **********************/ /** * @notice Verifies a proof that a given key/value pair is present in the * Merkle trie. * @param _key Key of the node to search for, as a hex string. * @param _value Value of the node to search for, as a hex string. * @param _proof Merkle trie inclusion proof for the desired node. Unlike * traditional Merkle trees, this proof is executed top-down and consists * of a list of RLP-encoded nodes that make a path down to the target node. * @param _root Known root of the Merkle trie. Used to verify that the * included proof is correctly constructed. * @return _verified `true` if the k/v pair exists in the trie, `false` otherwise. */ function verifyInclusionProof( bytes memory _key, bytes memory _value, bytes memory _proof, bytes32 _root ) internal pure returns (bool _verified) { bytes memory key = _getSecureKey(_key); return Lib_MerkleTrie.verifyInclusionProof(key, _value, _proof, _root); } /** * @notice Updates a Merkle trie and returns a new root hash. * @param _key Key of the node to update, as a hex string. * @param _value Value of the node to update, as a hex string. * @param _proof Merkle trie inclusion proof for the node *nearest* the * target node. If the key exists, we can simply update the value. * Otherwise, we need to modify the trie to handle the new k/v pair. * @param _root Known root of the Merkle trie. Used to verify that the * included proof is correctly constructed. * @return _updatedRoot Root hash of the newly constructed trie. */ function update( bytes memory _key, bytes memory _value, bytes memory _proof, bytes32 _root ) internal pure returns (bytes32 _updatedRoot) { bytes memory key = _getSecureKey(_key); return Lib_MerkleTrie.update(key, _value, _proof, _root); } /** * @notice Retrieves the value associated with a given key. * @param _key Key to search for, as hex bytes. * @param _proof Merkle trie inclusion proof for the key. * @param _root Known root of the Merkle trie. * @return _exists Whether or not the key exists. * @return _value Value of the key if it exists. */ function get( bytes memory _key, bytes memory _proof, bytes32 _root ) internal pure returns (bool _exists, bytes memory _value) { bytes memory key = _getSecureKey(_key); return Lib_MerkleTrie.get(key, _proof, _root); } /** * Computes the root hash for a trie with a single node. * @param _key Key for the single node. * @param _value Value for the single node. * @return _updatedRoot Hash of the trie. */ function getSingleNodeRootHash(bytes memory _key, bytes memory _value) internal pure returns (bytes32 _updatedRoot) { bytes memory key = _getSecureKey(_key); return Lib_MerkleTrie.getSingleNodeRootHash(key, _value); } /********************* * Private Functions * *********************/ /** * Computes the secure counterpart to a key. * @param _key Key to get a secure key from. * @return _secureKey Secure version of the key. */ function _getSecureKey(bytes memory _key) private pure returns (bytes memory _secureKey) { return abi.encodePacked(keccak256(_key)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Lib_DefaultValues */ library Lib_DefaultValues { // The default x-domain message sender being set to a non-zero value makes // deployment a bit more expensive, but in exchange the refund on every call to // `relayMessage` by the L1 and L2 messengers will be higher. address internal constant DEFAULT_XDOMAIN_SENDER = 0x000000000000000000000000000000000000dEaD; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Lib_PredeployAddresses */ library Lib_PredeployAddresses { // solhint-disable max-line-length address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; address payable internal constant OVM_ETH = payable(0x4200000000000000000000000000000000000006); // solhint-disable-next-line max-line-length address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008; address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009; address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; address internal constant L2_STANDARD_TOKEN_FACTORY = 0x4200000000000000000000000000000000000012; address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Library Imports */ import {Lib_RLPReader} from '../rlp/Lib_RLPReader.sol'; /** * @title Lib_CrossDomainUtils */ library Lib_CrossDomainUtils { /** * Generates the correct cross domain calldata for a message. * @param _target Target contract address. * @param _sender Message sender address. * @param _message Message to send to the target. * @param _messageNonce Nonce for the provided message. * @return ABI encoded cross domain calldata. */ function encodeXDomainCalldata( address _target, address _sender, bytes memory _message, uint256 _messageNonce ) internal pure returns (bytes memory) { return abi.encodeWithSignature( 'relayMessage(address,address,bytes,uint256)', _target, _sender, _message, _messageNonce ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Library Imports */ import {Lib_OVMCodec} from '../../libraries/codec/Lib_OVMCodec.sol'; /* Interface Imports */ import {ICrossDomainMessenger} from '../../libraries/bridge/ICrossDomainMessenger.sol'; /** * @title IL1CrossDomainMessenger */ interface IL1CrossDomainMessenger is ICrossDomainMessenger { /******************* * Data Structures * *******************/ struct L2MessageInclusionProof { bytes32 stateRoot; Lib_OVMCodec.ChainBatchHeader stateRootBatchHeader; Lib_OVMCodec.ChainInclusionProof stateRootProof; bytes stateTrieWitness; bytes storageTrieWitness; } /******************** * Public Functions * ********************/ /** * Relays a cross domain message to a contract. * @param _target Target contract address. * @param _sender Message sender address. * @param _message Message to send to the target. * @param _messageNonce Nonce for the provided message. * @param _proof Inclusion proof for the given message. */ function relayMessage( address _target, address _sender, bytes memory _message, uint256 _messageNonce, L2MessageInclusionProof memory _proof ) external; /** * Replays a cross domain message to the target messenger. * @param _target Target contract address. * @param _sender Original sender address. * @param _message Message to send to the target. * @param _queueIndex CTC Queue index for the message to replay. * @param _oldGasLimit Original gas limit used to send the message. * @param _newGasLimit New gas limit to be used for this message. */ function replayMessage( address _target, address _sender, bytes memory _message, uint256 _queueIndex, uint32 _oldGasLimit, uint32 _newGasLimit ) external; }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; /* Library Imports */ import {Lib_OVMCodec} from '../../libraries/codec/Lib_OVMCodec.sol'; /* Interface Imports */ import {IChainStorageContainer} from './IChainStorageContainer.sol'; /** * @title ICanonicalTransactionChain */ interface ICanonicalTransactionChain { /********** * Events * **********/ event L2GasParamsUpdated( uint256 l2GasDiscountDivisor, uint256 enqueueGasCost, uint256 enqueueL2GasPrepaid ); event TransactionEnqueued( address indexed _l1TxOrigin, address indexed _target, uint256 _gasLimit, bytes _data, uint256 indexed _queueIndex, uint256 _timestamp ); event QueueBatchAppended( uint256 _startingQueueIndex, uint256 _numQueueElements, uint256 _totalElements ); event SequencerBatchAppended( uint256 _startingQueueIndex, uint256 _numQueueElements, uint256 _totalElements ); event TransactionBatchAppended( uint256 indexed _batchIndex, bytes32 _batchRoot, uint256 _batchSize, uint256 _prevTotalElements, bytes _extraData ); /*********** * Structs * ***********/ struct BatchContext { uint256 numSequencedTransactions; uint256 numSubsequentQueueTransactions; uint256 timestamp; uint256 blockNumber; } /******************************* * Authorized Setter Functions * *******************************/ /** * Allows the Burn Admin to update the parameters which determine the amount of gas to burn. * The value of enqueueL2GasPrepaid is immediately updated as well. */ function setGasParams(uint256 _l2GasDiscountDivisor, uint256 _enqueueGasCost) external; /******************** * Public Functions * ********************/ /** * Accesses the batch storage container. * @return Reference to the batch storage container. */ function batches() external view returns (IChainStorageContainer); /** * Accesses the queue storage container. * @return Reference to the queue storage container. */ function queue() external view returns (IChainStorageContainer); /** * Retrieves the total number of elements submitted. * @return _totalElements Total submitted elements. */ function getTotalElements() external view returns (uint256 _totalElements); /** * Retrieves the total number of batches submitted. * @return _totalBatches Total submitted batches. */ function getTotalBatches() external view returns (uint256 _totalBatches); /** * Returns the index of the next element to be enqueued. * @return Index for the next queue element. */ function getNextQueueIndex() external view returns (uint40); /** * Gets the queue element at a particular index. * @param _index Index of the queue element to access. * @return _element Queue element at the given index. */ function getQueueElement(uint256 _index) external view returns (Lib_OVMCodec.QueueElement memory _element); /** * Returns the timestamp of the last transaction. * @return Timestamp for the last transaction. */ function getLastTimestamp() external view returns (uint40); /** * Returns the blocknumber of the last transaction. * @return Blocknumber for the last transaction. */ function getLastBlockNumber() external view returns (uint40); /** * Get the number of queue elements which have not yet been included. * @return Number of pending queue elements. */ function getNumPendingQueueElements() external view returns (uint40); /** * Retrieves the length of the queue, including * both pending and canonical transactions. * @return Length of the queue. */ function getQueueLength() external view returns (uint40); /** * Adds a transaction to the queue. * @param _target Target contract to send the transaction to. * @param _gasLimit Gas limit for the given transaction. * @param _data Transaction data. */ function enqueue( address _target, uint256 _gasLimit, bytes memory _data ) external; /** * Allows the sequencer to append a batch of transactions. * @dev This function uses a custom encoding scheme for efficiency reasons. * .param _shouldStartAtElement Specific batch we expect to start appending to. * .param _totalElementsToAppend Total number of batch elements we expect to append. * .param _contexts Array of batch contexts. * .param _transactionDataFields Array of raw transaction data. */ function appendSequencerBatch( // uint40 _shouldStartAtElement, // uint24 _totalElementsToAppend, // BatchContext[] _contexts, // bytes[] _transactionDataFields ) external; }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; /* Library Imports */ import {Lib_OVMCodec} from '../../libraries/codec/Lib_OVMCodec.sol'; /** * @title IStateCommitmentChain */ interface IStateCommitmentChain { /********** * Events * **********/ event StateBatchAppended( uint256 indexed _batchIndex, bytes32 _batchRoot, uint256 _batchSize, uint256 _prevTotalElements, bytes _extraData ); event StateBatchDeleted(uint256 indexed _batchIndex, bytes32 _batchRoot); /******************** * Public Functions * ********************/ /** * Retrieves the total number of elements submitted. * @return _totalElements Total submitted elements. */ function getTotalElements() external view returns (uint256 _totalElements); /** * Retrieves the total number of batches submitted. * @return _totalBatches Total submitted batches. */ function getTotalBatches() external view returns (uint256 _totalBatches); /** * Retrieves the timestamp of the last batch submitted by the sequencer. * @return _lastSequencerTimestamp Last sequencer batch timestamp. */ function getLastSequencerTimestamp() external view returns (uint256 _lastSequencerTimestamp); /** * Appends a batch of state roots to the chain. * @param _batch Batch of state roots. * @param _shouldStartAtElement Index of the element at which this batch should start. */ function appendStateBatch( bytes32[] calldata _batch, uint256 _shouldStartAtElement ) external; /** * Deletes all state roots after (and including) a given batch. * @param _batchHeader Header of the batch to start deleting from. */ function deleteStateBatch(Lib_OVMCodec.ChainBatchHeader memory _batchHeader) external; /** * Verifies a batch inclusion proof. * @param _element Hash of the element to verify a proof for. * @param _batchHeader Header of the batch in which the element was included. * @param _proof Merkle inclusion proof for the element. */ function verifyStateCommitment( bytes32 _element, Lib_OVMCodec.ChainBatchHeader memory _batchHeader, Lib_OVMCodec.ChainInclusionProof memory _proof ) external view returns (bool _verified); /** * Checks whether a given batch is still inside its fraud proof window. * @param _batchHeader Header of the batch to check. * @return _inside Whether or not the batch is inside the fraud proof window. */ function insideFraudProofWindow( Lib_OVMCodec.ChainBatchHeader memory _batchHeader ) external view returns (bool _inside); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal initializer { __Context_init_unchained(); __Pausable_init_unchained(); } function __Pausable_init_unchained() internal initializer { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal initializer { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal initializer { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Lib_RLPReader * @dev Adapted from "RLPReader" by Hamdi Allam ([email protected]). */ library Lib_RLPReader { /************* * Constants * *************/ uint256 internal constant MAX_LIST_LENGTH = 32; /********* * Enums * *********/ enum RLPItemType { DATA_ITEM, LIST_ITEM } /*********** * Structs * ***********/ struct RLPItem { uint256 length; uint256 ptr; } /********************** * Internal Functions * **********************/ /** * Converts bytes to a reference to memory position and length. * @param _in Input bytes to convert. * @return Output memory reference. */ function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) { uint256 ptr; assembly { ptr := add(_in, 32) } return RLPItem({length: _in.length, ptr: ptr}); } /** * Reads an RLP list value into a list of RLP items. * @param _in RLP list value. * @return Decoded RLP list items. */ function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) { (uint256 listOffset, , RLPItemType itemType) = _decodeLength(_in); require(itemType == RLPItemType.LIST_ITEM, 'Invalid RLP list value.'); // Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by // writing to the length. Since we can't know the number of RLP items without looping over // the entire input, we'd have to loop twice to accurately size this array. It's easier to // simply set a reasonable maximum list length and decrease the size before we finish. RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH); uint256 itemCount = 0; uint256 offset = listOffset; while (offset < _in.length) { require( itemCount < MAX_LIST_LENGTH, 'Provided RLP list exceeds max list length.' ); (uint256 itemOffset, uint256 itemLength, ) = _decodeLength( RLPItem({length: _in.length - offset, ptr: _in.ptr + offset}) ); out[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: _in.ptr + offset }); itemCount += 1; offset += itemOffset + itemLength; } // Decrease the array size to match the actual item count. assembly { mstore(out, itemCount) } return out; } /** * Reads an RLP list value into a list of RLP items. * @param _in RLP list value. * @return Decoded RLP list items. */ function readList(bytes memory _in) internal pure returns (RLPItem[] memory) { return readList(toRLPItem(_in)); } /** * Reads an RLP bytes value into bytes. * @param _in RLP bytes value. * @return Decoded bytes. */ function readBytes(RLPItem memory _in) internal pure returns (bytes memory) { ( uint256 itemOffset, uint256 itemLength, RLPItemType itemType ) = _decodeLength(_in); require(itemType == RLPItemType.DATA_ITEM, 'Invalid RLP bytes value.'); return _copy(_in.ptr, itemOffset, itemLength); } /** * Reads an RLP bytes value into bytes. * @param _in RLP bytes value. * @return Decoded bytes. */ function readBytes(bytes memory _in) internal pure returns (bytes memory) { return readBytes(toRLPItem(_in)); } /** * Reads an RLP string value into a string. * @param _in RLP string value. * @return Decoded string. */ function readString(RLPItem memory _in) internal pure returns (string memory) { return string(readBytes(_in)); } /** * Reads an RLP string value into a string. * @param _in RLP string value. * @return Decoded string. */ function readString(bytes memory _in) internal pure returns (string memory) { return readString(toRLPItem(_in)); } /** * Reads an RLP bytes32 value into a bytes32. * @param _in RLP bytes32 value. * @return Decoded bytes32. */ function readBytes32(RLPItem memory _in) internal pure returns (bytes32) { require(_in.length <= 33, 'Invalid RLP bytes32 value.'); ( uint256 itemOffset, uint256 itemLength, RLPItemType itemType ) = _decodeLength(_in); require(itemType == RLPItemType.DATA_ITEM, 'Invalid RLP bytes32 value.'); uint256 ptr = _in.ptr + itemOffset; bytes32 out; assembly { out := mload(ptr) // Shift the bytes over to match the item size. if lt(itemLength, 32) { out := div(out, exp(256, sub(32, itemLength))) } } return out; } /** * Reads an RLP bytes32 value into a bytes32. * @param _in RLP bytes32 value. * @return Decoded bytes32. */ function readBytes32(bytes memory _in) internal pure returns (bytes32) { return readBytes32(toRLPItem(_in)); } /** * Reads an RLP uint256 value into a uint256. * @param _in RLP uint256 value. * @return Decoded uint256. */ function readUint256(RLPItem memory _in) internal pure returns (uint256) { return uint256(readBytes32(_in)); } /** * Reads an RLP uint256 value into a uint256. * @param _in RLP uint256 value. * @return Decoded uint256. */ function readUint256(bytes memory _in) internal pure returns (uint256) { return readUint256(toRLPItem(_in)); } /** * Reads an RLP bool value into a bool. * @param _in RLP bool value. * @return Decoded bool. */ function readBool(RLPItem memory _in) internal pure returns (bool) { require(_in.length == 1, 'Invalid RLP boolean value.'); uint256 ptr = _in.ptr; uint256 out; assembly { out := byte(0, mload(ptr)) } require( out == 0 || out == 1, 'Lib_RLPReader: Invalid RLP boolean value, must be 0 or 1' ); return out != 0; } /** * Reads an RLP bool value into a bool. * @param _in RLP bool value. * @return Decoded bool. */ function readBool(bytes memory _in) internal pure returns (bool) { return readBool(toRLPItem(_in)); } /** * Reads an RLP address value into a address. * @param _in RLP address value. * @return Decoded address. */ function readAddress(RLPItem memory _in) internal pure returns (address) { if (_in.length == 1) { return address(0); } require(_in.length == 21, 'Invalid RLP address value.'); return address(uint160(readUint256(_in))); } /** * Reads an RLP address value into a address. * @param _in RLP address value. * @return Decoded address. */ function readAddress(bytes memory _in) internal pure returns (address) { return readAddress(toRLPItem(_in)); } /** * Reads the raw bytes of an RLP item. * @param _in RLP item to read. * @return Raw RLP bytes. */ function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) { return _copy(_in); } /********************* * Private Functions * *********************/ /** * Decodes the length of an RLP item. * @param _in RLP item to decode. * @return Offset of the encoded data. * @return Length of the encoded data. * @return RLP item type (LIST_ITEM or DATA_ITEM). */ function _decodeLength(RLPItem memory _in) private pure returns ( uint256, uint256, RLPItemType ) { require(_in.length > 0, 'RLP item cannot be null.'); uint256 ptr = _in.ptr; uint256 prefix; assembly { prefix := byte(0, mload(ptr)) } if (prefix <= 0x7f) { // Single byte. return (0, 1, RLPItemType.DATA_ITEM); } else if (prefix <= 0xb7) { // Short string. uint256 strLen = prefix - 0x80; require(_in.length > strLen, 'Invalid RLP short string.'); return (1, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xbf) { // Long string. uint256 lenOfStrLen = prefix - 0xb7; require(_in.length > lenOfStrLen, 'Invalid RLP long string length.'); uint256 strLen; assembly { // Pick out the string length. strLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfStrLen))) } require(_in.length > lenOfStrLen + strLen, 'Invalid RLP long string.'); return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xf7) { // Short list. uint256 listLen = prefix - 0xc0; require(_in.length > listLen, 'Invalid RLP short list.'); return (1, listLen, RLPItemType.LIST_ITEM); } else { // Long list. uint256 lenOfListLen = prefix - 0xf7; require(_in.length > lenOfListLen, 'Invalid RLP long list length.'); uint256 listLen; assembly { // Pick out the list length. listLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfListLen))) } require(_in.length > lenOfListLen + listLen, 'Invalid RLP long list.'); return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM); } } /** * Copies the bytes from a memory location. * @param _src Pointer to the location to read from. * @param _offset Offset to start reading from. * @param _length Number of bytes to read. * @return Copied bytes. */ function _copy( uint256 _src, uint256 _offset, uint256 _length ) private pure returns (bytes memory) { bytes memory out = new bytes(_length); if (out.length == 0) { return out; } uint256 src = _src + _offset; uint256 dest; assembly { dest := add(out, 32) } // Copy over as many complete words as we can. for (uint256 i = 0; i < _length / 32; i++) { assembly { mstore(dest, mload(src)) } src += 32; dest += 32; } // Pick out the remaining bytes. uint256 mask; unchecked { mask = 256**(32 - (_length % 32)) - 1; } assembly { mstore(dest, or(and(mload(src), not(mask)), and(mload(dest), mask))) } return out; } /** * Copies an RLP item into bytes. * @param _in RLP item to copy. * @return Copied bytes. */ function _copy(RLPItem memory _in) private pure returns (bytes memory) { return _copy(_in.ptr, 0, _in.length); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Lib_RLPWriter * @author Bakaoh (with modifications) */ library Lib_RLPWriter { /********************** * Internal Functions * **********************/ /** * RLP encodes a byte string. * @param _in The byte string to encode. * @return The RLP encoded string in bytes. */ function writeBytes(bytes memory _in) internal pure returns (bytes memory) { bytes memory encoded; if (_in.length == 1 && uint8(_in[0]) < 128) { encoded = _in; } else { encoded = abi.encodePacked(_writeLength(_in.length, 128), _in); } return encoded; } /** * RLP encodes a list of RLP encoded byte byte strings. * @param _in The list of RLP encoded byte strings. * @return The RLP encoded list of items in bytes. */ function writeList(bytes[] memory _in) internal pure returns (bytes memory) { bytes memory list = _flatten(_in); return abi.encodePacked(_writeLength(list.length, 192), list); } /** * RLP encodes a string. * @param _in The string to encode. * @return The RLP encoded string in bytes. */ function writeString(string memory _in) internal pure returns (bytes memory) { return writeBytes(bytes(_in)); } /** * RLP encodes an address. * @param _in The address to encode. * @return The RLP encoded address in bytes. */ function writeAddress(address _in) internal pure returns (bytes memory) { return writeBytes(abi.encodePacked(_in)); } /** * RLP encodes a uint. * @param _in The uint256 to encode. * @return The RLP encoded uint256 in bytes. */ function writeUint(uint256 _in) internal pure returns (bytes memory) { return writeBytes(_toBinary(_in)); } /** * RLP encodes a bool. * @param _in The bool to encode. * @return The RLP encoded bool in bytes. */ function writeBool(bool _in) internal pure returns (bytes memory) { bytes memory encoded = new bytes(1); encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80)); return encoded; } /********************* * Private Functions * *********************/ /** * Encode the first byte, followed by the `len` in binary form if `length` is more than 55. * @param _len The length of the string or the payload. * @param _offset 128 if item is string, 192 if item is list. * @return RLP encoded bytes. */ function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) { bytes memory encoded; if (_len < 56) { encoded = new bytes(1); encoded[0] = bytes1(uint8(_len) + uint8(_offset)); } else { uint256 lenLen; uint256 i = 1; while (_len / i != 0) { lenLen++; i *= 256; } encoded = new bytes(lenLen + 1); encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55); for (i = 1; i <= lenLen; i++) { encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256)); } } return encoded; } /** * Encode integer in big endian binary form with no leading zeroes. * @notice TODO: This should be optimized with assembly to save gas costs. * @param _x The integer to encode. * @return RLP encoded bytes. */ function _toBinary(uint256 _x) private pure returns (bytes memory) { bytes memory b = abi.encodePacked(_x); uint256 i = 0; for (; i < 32; i++) { if (b[i] != 0) { break; } } bytes memory res = new bytes(32 - i); for (uint256 j = 0; j < res.length; j++) { res[j] = b[i++]; } return res; } /** * Copies a piece of memory to another location. * @notice From: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol. * @param _dest Destination location. * @param _src Source location. * @param _len Length of memory to copy. */ function _memcpy( uint256 _dest, uint256 _src, uint256 _len ) private pure { uint256 dest = _dest; uint256 src = _src; uint256 len = _len; for (; len >= 32; len -= 32) { assembly { mstore(dest, mload(src)) } dest += 32; src += 32; } uint256 mask; unchecked { mask = 256**(32 - len) - 1; } assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } /** * Flattens a list of byte strings into one byte string. * @notice From: https://github.com/sammayo/solidity-rlp-encoder/blob/master/RLPEncode.sol. * @param _list List of byte strings to flatten. * @return The flattened byte string. */ function _flatten(bytes[] memory _list) private pure returns (bytes memory) { if (_list.length == 0) { return new bytes(0); } uint256 len; uint256 i = 0; for (; i < _list.length; i++) { len += _list[i].length; } bytes memory flattened = new bytes(len); uint256 flattenedPtr; assembly { flattenedPtr := add(flattened, 0x20) } for (i = 0; i < _list.length; i++) { bytes memory item = _list[i]; uint256 listPtr; assembly { listPtr := add(item, 0x20) } _memcpy(flattenedPtr, listPtr, item.length); flattenedPtr += _list[i].length; } return flattened; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Lib_BytesUtils */ library Lib_BytesUtils { /********************** * Internal Functions * **********************/ function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, 'slice_overflow'); require(_start + _length >= _start, 'slice_overflow'); require(_bytes.length >= _start + _length, 'slice_outOfBounds'); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add( add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start ) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) { if (_start >= _bytes.length) { return bytes(''); } return slice(_bytes, _start, _bytes.length - _start); } function toBytes32(bytes memory _bytes) internal pure returns (bytes32) { if (_bytes.length < 32) { bytes32 ret; assembly { ret := mload(add(_bytes, 32)) } return ret; } return abi.decode(_bytes, (bytes32)); // will truncate if input length > 32 bytes } function toUint256(bytes memory _bytes) internal pure returns (uint256) { return uint256(toBytes32(_bytes)); } function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) { bytes memory nibbles = new bytes(_bytes.length * 2); for (uint256 i = 0; i < _bytes.length; i++) { nibbles[i * 2] = _bytes[i] >> 4; nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16); } return nibbles; } function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) { bytes memory ret = new bytes(_bytes.length / 2); for (uint256 i = 0; i < ret.length; i++) { ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]); } return ret; } function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) { return keccak256(_bytes) == keccak256(_other); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Lib_Byte32Utils */ library Lib_Bytes32Utils { /********************** * Internal Functions * **********************/ /** * Converts a bytes32 value to a boolean. Anything non-zero will be converted to "true." * @param _in Input bytes32 value. * @return Bytes32 as a boolean. */ function toBool(bytes32 _in) internal pure returns (bool) { return _in != 0; } /** * Converts a boolean to a bytes32 value. * @param _in Input boolean value. * @return Boolean as a bytes32. */ function fromBool(bool _in) internal pure returns (bytes32) { return bytes32(uint256(_in ? 1 : 0)); } /** * Converts a bytes32 value to an address. Takes the *last* 20 bytes. * @param _in Input bytes32 value. * @return Bytes32 as an address. */ function toAddress(bytes32 _in) internal pure returns (address) { return address(uint160(uint256(_in))); } /** * Converts an address to a bytes32. * @param _in Input address value. * @return Address as a bytes32. */ function fromAddress(address _in) internal pure returns (bytes32) { return bytes32(uint256(uint160(_in))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Library Imports */ import {Lib_BytesUtils} from '../utils/Lib_BytesUtils.sol'; import {Lib_RLPReader} from '../rlp/Lib_RLPReader.sol'; import {Lib_RLPWriter} from '../rlp/Lib_RLPWriter.sol'; /** * @title Lib_MerkleTrie */ library Lib_MerkleTrie { /******************* * Data Structures * *******************/ enum NodeType { BranchNode, ExtensionNode, LeafNode } struct TrieNode { bytes encoded; Lib_RLPReader.RLPItem[] decoded; } /********************** * Contract Constants * **********************/ // TREE_RADIX determines the number of elements per branch node. uint256 constant TREE_RADIX = 16; // Branch nodes have TREE_RADIX elements plus an additional `value` slot. uint256 constant BRANCH_NODE_LENGTH = TREE_RADIX + 1; // Leaf nodes and extension nodes always have two elements, a `path` and a `value`. uint256 constant LEAF_OR_EXTENSION_NODE_LENGTH = 2; // Prefixes are prepended to the `path` within a leaf or extension node and // allow us to differentiate between the two node types. `ODD` or `EVEN` is // determined by the number of nibbles within the unprefixed `path`. If the // number of nibbles if even, we need to insert an extra padding nibble so // the resulting prefixed `path` has an even number of nibbles. uint8 constant PREFIX_EXTENSION_EVEN = 0; uint8 constant PREFIX_EXTENSION_ODD = 1; uint8 constant PREFIX_LEAF_EVEN = 2; uint8 constant PREFIX_LEAF_ODD = 3; // Just a utility constant. RLP represents `NULL` as 0x80. bytes1 constant RLP_NULL = bytes1(0x80); bytes constant RLP_NULL_BYTES = hex'80'; bytes32 internal constant KECCAK256_RLP_NULL_BYTES = keccak256(RLP_NULL_BYTES); /********************** * Internal Functions * **********************/ /** * @notice Verifies a proof that a given key/value pair is present in the * Merkle trie. * @param _key Key of the node to search for, as a hex string. * @param _value Value of the node to search for, as a hex string. * @param _proof Merkle trie inclusion proof for the desired node. Unlike * traditional Merkle trees, this proof is executed top-down and consists * of a list of RLP-encoded nodes that make a path down to the target node. * @param _root Known root of the Merkle trie. Used to verify that the * included proof is correctly constructed. * @return _verified `true` if the k/v pair exists in the trie, `false` otherwise. */ function verifyInclusionProof( bytes memory _key, bytes memory _value, bytes memory _proof, bytes32 _root ) internal pure returns (bool _verified) { (bool exists, bytes memory value) = get(_key, _proof, _root); return (exists && Lib_BytesUtils.equal(_value, value)); } /** * @notice Updates a Merkle trie and returns a new root hash. * @param _key Key of the node to update, as a hex string. * @param _value Value of the node to update, as a hex string. * @param _proof Merkle trie inclusion proof for the node *nearest* the * target node. If the key exists, we can simply update the value. * Otherwise, we need to modify the trie to handle the new k/v pair. * @param _root Known root of the Merkle trie. Used to verify that the * included proof is correctly constructed. * @return _updatedRoot Root hash of the newly constructed trie. */ function update( bytes memory _key, bytes memory _value, bytes memory _proof, bytes32 _root ) internal pure returns (bytes32 _updatedRoot) { // Special case when inserting the very first node. if (_root == KECCAK256_RLP_NULL_BYTES) { return getSingleNodeRootHash(_key, _value); } TrieNode[] memory proof = _parseProof(_proof); (uint256 pathLength, bytes memory keyRemainder, ) = _walkNodePath( proof, _key, _root ); TrieNode[] memory newPath = _getNewPath( proof, pathLength, _key, keyRemainder, _value ); return _getUpdatedTrieRoot(newPath, _key); } /** * @notice Retrieves the value associated with a given key. * @param _key Key to search for, as hex bytes. * @param _proof Merkle trie inclusion proof for the key. * @param _root Known root of the Merkle trie. * @return _exists Whether or not the key exists. * @return _value Value of the key if it exists. */ function get( bytes memory _key, bytes memory _proof, bytes32 _root ) internal pure returns (bool _exists, bytes memory _value) { TrieNode[] memory proof = _parseProof(_proof); ( uint256 pathLength, bytes memory keyRemainder, bool isFinalNode ) = _walkNodePath(proof, _key, _root); bool exists = keyRemainder.length == 0; require(exists || isFinalNode, 'Provided proof is invalid.'); bytes memory value = exists ? _getNodeValue(proof[pathLength - 1]) : bytes(''); return (exists, value); } /** * Computes the root hash for a trie with a single node. * @param _key Key for the single node. * @param _value Value for the single node. * @return _updatedRoot Hash of the trie. */ function getSingleNodeRootHash(bytes memory _key, bytes memory _value) internal pure returns (bytes32 _updatedRoot) { return keccak256(_makeLeafNode(Lib_BytesUtils.toNibbles(_key), _value).encoded); } /********************* * Private Functions * *********************/ /** * @notice Walks through a proof using a provided key. * @param _proof Inclusion proof to walk through. * @param _key Key to use for the walk. * @param _root Known root of the trie. * @return _pathLength Length of the final path * @return _keyRemainder Portion of the key remaining after the walk. * @return _isFinalNode Whether or not we've hit a dead end. */ function _walkNodePath( TrieNode[] memory _proof, bytes memory _key, bytes32 _root ) private pure returns ( uint256 _pathLength, bytes memory _keyRemainder, bool _isFinalNode ) { uint256 pathLength = 0; bytes memory key = Lib_BytesUtils.toNibbles(_key); bytes32 currentNodeID = _root; uint256 currentKeyIndex = 0; uint256 currentKeyIncrement = 0; TrieNode memory currentNode; // Proof is top-down, so we start at the first element (root). for (uint256 i = 0; i < _proof.length; i++) { currentNode = _proof[i]; currentKeyIndex += currentKeyIncrement; // Keep track of the proof elements we actually need. // It's expensive to resize arrays, so this simply reduces gas costs. pathLength += 1; if (currentKeyIndex == 0) { // First proof element is always the root node. require( keccak256(currentNode.encoded) == currentNodeID, 'Invalid root hash' ); } else if (currentNode.encoded.length >= 32) { // Nodes 32 bytes or larger are hashed inside branch nodes. require( keccak256(currentNode.encoded) == currentNodeID, 'Invalid large internal hash' ); } else { // Nodes smaller than 31 bytes aren't hashed. require( Lib_BytesUtils.toBytes32(currentNode.encoded) == currentNodeID, 'Invalid internal node hash' ); } if (currentNode.decoded.length == BRANCH_NODE_LENGTH) { if (currentKeyIndex == key.length) { // We've hit the end of the key // meaning the value should be within this branch node. break; } else { // We're not at the end of the key yet. // Figure out what the next node ID should be and continue. uint8 branchKey = uint8(key[currentKeyIndex]); Lib_RLPReader.RLPItem memory nextNode = currentNode.decoded[ branchKey ]; currentNodeID = _getNodeID(nextNode); currentKeyIncrement = 1; continue; } } else if (currentNode.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) { bytes memory path = _getNodePath(currentNode); uint8 prefix = uint8(path[0]); uint8 offset = 2 - (prefix % 2); bytes memory pathRemainder = Lib_BytesUtils.slice(path, offset); bytes memory keyRemainder = Lib_BytesUtils.slice(key, currentKeyIndex); uint256 sharedNibbleLength = _getSharedNibbleLength( pathRemainder, keyRemainder ); if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) { if ( pathRemainder.length == sharedNibbleLength && keyRemainder.length == sharedNibbleLength ) { // The key within this leaf matches our key exactly. // Increment the key index to reflect that we have no remainder. currentKeyIndex += sharedNibbleLength; } // We've hit a leaf node, so our next node should be NULL. currentNodeID = bytes32(RLP_NULL); break; } else if ( prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD ) { if (sharedNibbleLength != pathRemainder.length) { // Our extension node is not identical to the remainder. // We've hit the end of this path // updates will need to modify this extension. currentNodeID = bytes32(RLP_NULL); break; } else { // Our extension shares some nibbles. // Carry on to the next node. currentNodeID = _getNodeID(currentNode.decoded[1]); currentKeyIncrement = sharedNibbleLength; continue; } } else { revert('Received a node with an unknown prefix'); } } else { revert('Received an unparseable node.'); } } // If our node ID is NULL, then we're at a dead end. bool isFinalNode = currentNodeID == bytes32(RLP_NULL); return ( pathLength, Lib_BytesUtils.slice(key, currentKeyIndex), isFinalNode ); } /** * @notice Creates new nodes to support a k/v pair insertion into a given Merkle trie path. * @param _path Path to the node nearest the k/v pair. * @param _pathLength Length of the path. Necessary because the provided path may include * additional nodes (e.g., it comes directly from a proof) and we can't resize in-memory * arrays without costly duplication. * @param _key Full original key. * @param _keyRemainder Portion of the initial key that must be inserted into the trie. * @param _value Value to insert at the given key. * @return _newPath A new path with the inserted k/v pair and extra supporting nodes. */ function _getNewPath( TrieNode[] memory _path, uint256 _pathLength, bytes memory _key, bytes memory _keyRemainder, bytes memory _value ) private pure returns (TrieNode[] memory _newPath) { bytes memory keyRemainder = _keyRemainder; // Most of our logic depends on the status of the last node in the path. TrieNode memory lastNode = _path[_pathLength - 1]; NodeType lastNodeType = _getNodeType(lastNode); // Create an array for newly created nodes. // We need up to three new nodes, depending on the contents of the last node. // Since array resizing is expensive, we'll keep track of the size manually. // We're using an explicit `totalNewNodes += 1` after insertions for clarity. TrieNode[] memory newNodes = new TrieNode[](3); uint256 totalNewNodes = 0; // solhint-disable-next-line max-line-length // Reference: https://github.com/ethereumjs/merkle-patricia-tree/blob/c0a10395aab37d42c175a47114ebfcbd7efcf059/src/baseTrie.ts#L294-L313 bool matchLeaf = false; if (lastNodeType == NodeType.LeafNode) { uint256 l = 0; if (_path.length > 0) { for (uint256 i = 0; i < _path.length - 1; i++) { if (_getNodeType(_path[i]) == NodeType.BranchNode) { l++; } else { l += _getNodeKey(_path[i]).length; } } } if ( _getSharedNibbleLength( _getNodeKey(lastNode), Lib_BytesUtils.slice(Lib_BytesUtils.toNibbles(_key), l) ) == _getNodeKey(lastNode).length && keyRemainder.length == 0 ) { matchLeaf = true; } } if (matchLeaf) { // We've found a leaf node with the given key. // Simply need to update the value of the node to match. newNodes[totalNewNodes] = _makeLeafNode(_getNodeKey(lastNode), _value); totalNewNodes += 1; } else if (lastNodeType == NodeType.BranchNode) { if (keyRemainder.length == 0) { // We've found a branch node with the given key. // Simply need to update the value of the node to match. newNodes[totalNewNodes] = _editBranchValue(lastNode, _value); totalNewNodes += 1; } else { // We've found a branch node, but it doesn't contain our key. // Reinsert the old branch for now. newNodes[totalNewNodes] = lastNode; totalNewNodes += 1; // Create a new leaf node, slicing our remainder since the first byte points // to our branch node. newNodes[totalNewNodes] = _makeLeafNode( Lib_BytesUtils.slice(keyRemainder, 1), _value ); totalNewNodes += 1; } } else { // Our last node is either an extension node or a leaf node with a different key. bytes memory lastNodeKey = _getNodeKey(lastNode); uint256 sharedNibbleLength = _getSharedNibbleLength( lastNodeKey, keyRemainder ); if (sharedNibbleLength != 0) { // We've got some shared nibbles between the last node and our key remainder. // We'll need to insert an extension node that covers these shared nibbles. bytes memory nextNodeKey = Lib_BytesUtils.slice( lastNodeKey, 0, sharedNibbleLength ); newNodes[totalNewNodes] = _makeExtensionNode( nextNodeKey, _getNodeHash(_value) ); totalNewNodes += 1; // Cut down the keys since we've just covered these shared nibbles. lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, sharedNibbleLength); keyRemainder = Lib_BytesUtils.slice(keyRemainder, sharedNibbleLength); } // Create an empty branch to fill in. TrieNode memory newBranch = _makeEmptyBranchNode(); if (lastNodeKey.length == 0) { // Key remainder was larger than the key for our last node. // The value within our last node is therefore going to be shifted into // a branch value slot. newBranch = _editBranchValue(newBranch, _getNodeValue(lastNode)); } else { // Last node key was larger than the key remainder. // We're going to modify some index of our branch. uint8 branchKey = uint8(lastNodeKey[0]); // Move on to the next nibble. lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, 1); if (lastNodeType == NodeType.LeafNode) { // We're dealing with a leaf node. // We'll modify the key and insert the old leaf node into the branch index. TrieNode memory modifiedLastNode = _makeLeafNode( lastNodeKey, _getNodeValue(lastNode) ); newBranch = _editBranchIndex( newBranch, branchKey, _getNodeHash(modifiedLastNode.encoded) ); } else if (lastNodeKey.length != 0) { // We're dealing with a shrinking extension node. // We need to modify the node to decrease the size of the key. TrieNode memory modifiedLastNode = _makeExtensionNode( lastNodeKey, _getNodeValue(lastNode) ); newBranch = _editBranchIndex( newBranch, branchKey, _getNodeHash(modifiedLastNode.encoded) ); } else { // We're dealing with an unnecessary extension node. // We're going to delete the node entirely. // Simply insert its current value into the branch index. newBranch = _editBranchIndex( newBranch, branchKey, _getNodeValue(lastNode) ); } } if (keyRemainder.length == 0) { // We've got nothing left in the key remainder. // Simply insert the value into the branch value slot. newBranch = _editBranchValue(newBranch, _value); // Push the branch into the list of new nodes. newNodes[totalNewNodes] = newBranch; totalNewNodes += 1; } else { // We've got some key remainder to work with. // We'll be inserting a leaf node into the trie. // First, move on to the next nibble. keyRemainder = Lib_BytesUtils.slice(keyRemainder, 1); // Push the branch into the list of new nodes. newNodes[totalNewNodes] = newBranch; totalNewNodes += 1; // Push a new leaf node for our k/v pair. newNodes[totalNewNodes] = _makeLeafNode(keyRemainder, _value); totalNewNodes += 1; } } // Finally, join the old path with our newly created nodes. // Since we're overwriting the last node in the path, we use `_pathLength - 1`. return _joinNodeArrays(_path, _pathLength - 1, newNodes, totalNewNodes); } /** * @notice Computes the trie root from a given path. * @param _nodes Path to some k/v pair. * @param _key Key for the k/v pair. * @return _updatedRoot Root hash for the updated trie. */ function _getUpdatedTrieRoot(TrieNode[] memory _nodes, bytes memory _key) private pure returns (bytes32 _updatedRoot) { bytes memory key = Lib_BytesUtils.toNibbles(_key); // Some variables to keep track of during iteration. TrieNode memory currentNode; NodeType currentNodeType; bytes memory previousNodeHash; // Run through the path backwards to rebuild our root hash. for (uint256 i = _nodes.length; i > 0; i--) { // Pick out the current node. currentNode = _nodes[i - 1]; currentNodeType = _getNodeType(currentNode); if (currentNodeType == NodeType.LeafNode) { // Leaf nodes are already correctly encoded. // Shift the key over to account for the nodes key. bytes memory nodeKey = _getNodeKey(currentNode); key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length); } else if (currentNodeType == NodeType.ExtensionNode) { // Shift the key over to account for the nodes key. bytes memory nodeKey = _getNodeKey(currentNode); key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length); // If this node is the last element in the path, it'll be correctly encoded // and we can skip this part. if (previousNodeHash.length > 0) { // Re-encode the node based on the previous node. currentNode = _editExtensionNodeValue(currentNode, previousNodeHash); } } else if (currentNodeType == NodeType.BranchNode) { // If this node is the last element in the path, it'll be correctly encoded // and we can skip this part. if (previousNodeHash.length > 0) { // Re-encode the node based on the previous node. uint8 branchKey = uint8(key[key.length - 1]); key = Lib_BytesUtils.slice(key, 0, key.length - 1); currentNode = _editBranchIndex( currentNode, branchKey, previousNodeHash ); } } // Compute the node hash for the next iteration. previousNodeHash = _getNodeHash(currentNode.encoded); } // Current node should be the root at this point. // Simply return the hash of its encoding. return keccak256(currentNode.encoded); } /** * @notice Parses an RLP-encoded proof into something more useful. * @param _proof RLP-encoded proof to parse. * @return _parsed Proof parsed into easily accessible structs. */ function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory _parsed) { Lib_RLPReader.RLPItem[] memory nodes = Lib_RLPReader.readList(_proof); TrieNode[] memory proof = new TrieNode[](nodes.length); for (uint256 i = 0; i < nodes.length; i++) { bytes memory encoded = Lib_RLPReader.readBytes(nodes[i]); proof[i] = TrieNode({ encoded: encoded, decoded: Lib_RLPReader.readList(encoded) }); } return proof; } /** * @notice Picks out the ID for a node. Node ID is referred to as the * "hash" within the specification, but nodes < 32 bytes are not actually * hashed. * @param _node Node to pull an ID for. * @return _nodeID ID for the node, depending on the size of its contents. */ function _getNodeID(Lib_RLPReader.RLPItem memory _node) private pure returns (bytes32 _nodeID) { bytes memory nodeID; if (_node.length < 32) { // Nodes smaller than 32 bytes are RLP encoded. nodeID = Lib_RLPReader.readRawBytes(_node); } else { // Nodes 32 bytes or larger are hashed. nodeID = Lib_RLPReader.readBytes(_node); } return Lib_BytesUtils.toBytes32(nodeID); } /** * @notice Gets the path for a leaf or extension node. * @param _node Node to get a path for. * @return _path Node path, converted to an array of nibbles. */ function _getNodePath(TrieNode memory _node) private pure returns (bytes memory _path) { return Lib_BytesUtils.toNibbles(Lib_RLPReader.readBytes(_node.decoded[0])); } /** * @notice Gets the key for a leaf or extension node. Keys are essentially * just paths without any prefix. * @param _node Node to get a key for. * @return _key Node key, converted to an array of nibbles. */ function _getNodeKey(TrieNode memory _node) private pure returns (bytes memory _key) { return _removeHexPrefix(_getNodePath(_node)); } /** * @notice Gets the path for a node. * @param _node Node to get a value for. * @return _value Node value, as hex bytes. */ function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory _value) { return Lib_RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]); } /** * @notice Computes the node hash for an encoded node. Nodes < 32 bytes * are not hashed, all others are keccak256 hashed. * @param _encoded Encoded node to hash. * @return _hash Hash of the encoded node. Simply the input if < 32 bytes. */ function _getNodeHash(bytes memory _encoded) private pure returns (bytes memory _hash) { if (_encoded.length < 32) { return _encoded; } else { return abi.encodePacked(keccak256(_encoded)); } } /** * @notice Determines the type for a given node. * @param _node Node to determine a type for. * @return _type Type of the node; BranchNode/ExtensionNode/LeafNode. */ function _getNodeType(TrieNode memory _node) private pure returns (NodeType _type) { if (_node.decoded.length == BRANCH_NODE_LENGTH) { return NodeType.BranchNode; } else if (_node.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) { bytes memory path = _getNodePath(_node); uint8 prefix = uint8(path[0]); if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) { return NodeType.LeafNode; } else if ( prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD ) { return NodeType.ExtensionNode; } } revert('Invalid node type'); } /** * @notice Utility; determines the number of nibbles shared between two * nibble arrays. * @param _a First nibble array. * @param _b Second nibble array. * @return _shared Number of shared nibbles. */ function _getSharedNibbleLength(bytes memory _a, bytes memory _b) private pure returns (uint256 _shared) { uint256 i = 0; while (_a.length > i && _b.length > i && _a[i] == _b[i]) { i++; } return i; } /** * @notice Utility; converts an RLP-encoded node into our nice struct. * @param _raw RLP-encoded node to convert. * @return _node Node as a TrieNode struct. */ function _makeNode(bytes[] memory _raw) private pure returns (TrieNode memory _node) { bytes memory encoded = Lib_RLPWriter.writeList(_raw); return TrieNode({encoded: encoded, decoded: Lib_RLPReader.readList(encoded)}); } /** * @notice Utility; converts an RLP-decoded node into our nice struct. * @param _items RLP-decoded node to convert. * @return _node Node as a TrieNode struct. */ function _makeNode(Lib_RLPReader.RLPItem[] memory _items) private pure returns (TrieNode memory _node) { bytes[] memory raw = new bytes[](_items.length); for (uint256 i = 0; i < _items.length; i++) { raw[i] = Lib_RLPReader.readRawBytes(_items[i]); } return _makeNode(raw); } /** * @notice Creates a new extension node. * @param _key Key for the extension node, unprefixed. * @param _value Value for the extension node. * @return _node New extension node with the given k/v pair. */ function _makeExtensionNode(bytes memory _key, bytes memory _value) private pure returns (TrieNode memory _node) { bytes[] memory raw = new bytes[](2); bytes memory key = _addHexPrefix(_key, false); raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key)); raw[1] = Lib_RLPWriter.writeBytes(_value); return _makeNode(raw); } /** * Creates a new extension node with the same key but a different value. * @param _node Extension node to copy and modify. * @param _value New value for the extension node. * @return New node with the same key and different value. */ function _editExtensionNodeValue(TrieNode memory _node, bytes memory _value) private pure returns (TrieNode memory) { bytes[] memory raw = new bytes[](2); bytes memory key = _addHexPrefix(_getNodeKey(_node), false); raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key)); if (_value.length < 32) { raw[1] = _value; } else { raw[1] = Lib_RLPWriter.writeBytes(_value); } return _makeNode(raw); } /** * @notice Creates a new leaf node. * @dev This function is essentially identical to `_makeExtensionNode`. * Although we could route both to a single method with a flag, it's * more gas efficient to keep them separate and duplicate the logic. * @param _key Key for the leaf node, unprefixed. * @param _value Value for the leaf node. * @return _node New leaf node with the given k/v pair. */ function _makeLeafNode(bytes memory _key, bytes memory _value) private pure returns (TrieNode memory _node) { bytes[] memory raw = new bytes[](2); bytes memory key = _addHexPrefix(_key, true); raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key)); raw[1] = Lib_RLPWriter.writeBytes(_value); return _makeNode(raw); } /** * @notice Creates an empty branch node. * @return _node Empty branch node as a TrieNode struct. */ function _makeEmptyBranchNode() private pure returns (TrieNode memory _node) { bytes[] memory raw = new bytes[](BRANCH_NODE_LENGTH); for (uint256 i = 0; i < raw.length; i++) { raw[i] = RLP_NULL_BYTES; } return _makeNode(raw); } /** * @notice Modifies the value slot for a given branch. * @param _branch Branch node to modify. * @param _value Value to insert into the branch. * @return _updatedNode Modified branch node. */ function _editBranchValue(TrieNode memory _branch, bytes memory _value) private pure returns (TrieNode memory _updatedNode) { bytes memory encoded = Lib_RLPWriter.writeBytes(_value); _branch.decoded[_branch.decoded.length - 1] = Lib_RLPReader.toRLPItem( encoded ); return _makeNode(_branch.decoded); } /** * @notice Modifies a slot at an index for a given branch. * @param _branch Branch node to modify. * @param _index Slot index to modify. * @param _value Value to insert into the slot. * @return _updatedNode Modified branch node. */ function _editBranchIndex( TrieNode memory _branch, uint8 _index, bytes memory _value ) private pure returns (TrieNode memory _updatedNode) { bytes memory encoded = _value.length < 32 ? _value : Lib_RLPWriter.writeBytes(_value); _branch.decoded[_index] = Lib_RLPReader.toRLPItem(encoded); return _makeNode(_branch.decoded); } /** * @notice Utility; adds a prefix to a key. * @param _key Key to prefix. * @param _isLeaf Whether or not the key belongs to a leaf. * @return _prefixedKey Prefixed key. */ function _addHexPrefix(bytes memory _key, bool _isLeaf) private pure returns (bytes memory _prefixedKey) { uint8 prefix = _isLeaf ? uint8(0x02) : uint8(0x00); uint8 offset = uint8(_key.length % 2); bytes memory prefixed = new bytes(2 - offset); prefixed[0] = bytes1(prefix + offset); return abi.encodePacked(prefixed, _key); } /** * @notice Utility; removes a prefix from a path. * @param _path Path to remove the prefix from. * @return _unprefixedKey Unprefixed key. */ function _removeHexPrefix(bytes memory _path) private pure returns (bytes memory _unprefixedKey) { if (uint8(_path[0]) % 2 == 0) { return Lib_BytesUtils.slice(_path, 2); } else { return Lib_BytesUtils.slice(_path, 1); } } /** * @notice Utility; combines two node arrays. Array lengths are required * because the actual lengths may be longer than the filled lengths. * Array resizing is extremely costly and should be avoided. * @param _a First array to join. * @param _aLength Length of the first array. * @param _b Second array to join. * @param _bLength Length of the second array. * @return _joined Combined node array. */ function _joinNodeArrays( TrieNode[] memory _a, uint256 _aLength, TrieNode[] memory _b, uint256 _bLength ) private pure returns (TrieNode[] memory _joined) { TrieNode[] memory ret = new TrieNode[](_aLength + _bLength); // Copy elements from the first array. for (uint256 i = 0; i < _aLength; i++) { ret[i] = _a[i]; } // Copy elements from the second array. for (uint256 i = 0; i < _bLength; i++) { ret[i + _aLength] = _b[i]; } return ret; } }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; /** * @title ICrossDomainMessenger */ interface ICrossDomainMessenger { /********** * Events * **********/ event SentMessage( address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit ); event RelayedMessage(bytes32 indexed msgHash); event FailedRelayedMessage(bytes32 indexed msgHash); /************* * Variables * *************/ function xDomainMessageSender() external view returns (address); /******************** * Public Functions * ********************/ /** * Sends a cross domain message to the target messenger. * @param _target Target contract address. * @param _message Message to send to the target. * @param _gasLimit Gas limit for the provided message. */ function sendMessage( address _target, bytes calldata _message, uint32 _gasLimit ) external; }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; /** * @title IChainStorageContainer */ interface IChainStorageContainer { /******************** * Public Functions * ********************/ /** * Sets the container's global metadata field. We're using `bytes27` here because we use five * bytes to maintain the length of the underlying data structure, meaning we have an extra * 27 bytes to store arbitrary data. * @param _globalMetadata New global metadata to set. */ function setGlobalMetadata(bytes27 _globalMetadata) external; /** * Retrieves the container's global metadata field. * @return Container global metadata field. */ function getGlobalMetadata() external view returns (bytes27); /** * Retrieves the number of objects stored in the container. * @return Number of objects in the container. */ function length() external view returns (uint256); /** * Pushes an object into the container. * @param _object A 32 byte value to insert into the container. */ function push(bytes32 _object) external; /** * Pushes an object into the container. Function allows setting the global metadata since * we'll need to touch the "length" storage slot anyway, which also contains the global * metadata (it's an optimization). * @param _object A 32 byte value to insert into the container. * @param _globalMetadata New global metadata for the container. */ function push(bytes32 _object, bytes27 _globalMetadata) external; /** * Retrieves an object from the container. * @param _index Index of the particular object to access. * @return 32 byte object value. */ function get(uint256 _index) external view returns (bytes32); /** * Removes all objects after and including a given index. * @param _index Object index to delete from. */ function deleteElementsAfterInclusive(uint256 _index) external; /** * Removes all objects after and including a given index. Also allows setting the global * metadata field. * @param _index Object index to delete from. * @param _globalMetadata New global metadata for the container. */ function deleteElementsAfterInclusive(uint256 _index, bytes27 _globalMetadata) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
{ "optimizer": { "enabled": true, "runs": 10000 }, "metadata": { "bytecodeHash": "none", "useLiteralContent": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"FailedRelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"MessageAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"MessageBlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"RelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"messageNonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"SentMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"allowMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"blockMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"blockedMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"failedMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_libAddressManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"libAddressManager","outputs":[{"internalType":"contract Lib_AddressManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint256","name":"_messageNonce","type":"uint256"},{"components":[{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"components":[{"internalType":"uint256","name":"batchIndex","type":"uint256"},{"internalType":"bytes32","name":"batchRoot","type":"bytes32"},{"internalType":"uint256","name":"batchSize","type":"uint256"},{"internalType":"uint256","name":"prevTotalElements","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct Lib_OVMCodec.ChainBatchHeader","name":"stateRootBatchHeader","type":"tuple"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes32[]","name":"siblings","type":"bytes32[]"}],"internalType":"struct Lib_OVMCodec.ChainInclusionProof","name":"stateRootProof","type":"tuple"},{"internalType":"bytes","name":"stateTrieWitness","type":"bytes"},{"internalType":"bytes","name":"storageTrieWitness","type":"bytes"}],"internalType":"struct IL1CrossDomainMessenger.L2MessageInclusionProof","name":"_proof","type":"tuple"}],"name":"relayMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"relayedMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint256","name":"_queueIndex","type":"uint256"},{"internalType":"uint32","name":"_oldGasLimit","type":"uint32"},{"internalType":"uint32","name":"_newGasLimit","type":"uint32"}],"name":"replayMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"resolve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint32","name":"_gasLimit","type":"uint32"}],"name":"sendMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"successfulMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"xDomainMessageSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405260cd80546001600160a01b03191661dead17905534801561002457600080fd5b50600080546001600160a01b0319169055613c7e806100446000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c806381ada46c116100b2578063b1b1b20911610081578063c6b94ab011610066578063c6b94ab0146102b3578063d7fd19dd146102d6578063f2fde38b146102e957600080fd5b8063b1b1b2091461027d578063c4d66de8146102a057600080fd5b806381ada46c146102215780638456cb59146102345780638da5cb5b1461023c578063a4e7f8bd1461025a57600080fd5b8063461a4478116101095780636e296e45116100ee5780636e296e45146101fe5780636f1c8d4714610206578063715018a61461021957600080fd5b8063461a4478146101e05780635c975abb146101f357600080fd5b80630ecf2eea1461013b57806321d800ec14610150578063299ca478146101885780633dbb202b146101cd575b600080fd5b61014e610149366004613170565b6102fc565b005b61017361015e366004613170565b60ca6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6000546101a89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161017f565b61014e6101db3660046132e8565b6103ab565b6101a86101ee366004613348565b6104f3565b60655460ff16610173565b6101a86105a0565b61014e610214366004613399565b61062a565b61014e610811565b61014e61022f366004613170565b610884565b61014e61092b565b60335473ffffffffffffffffffffffffffffffffffffffff166101a8565b610173610268366004613170565b60cc6020526000908152604090205460ff1681565b61017361028b366004613170565b60cb6020526000908152604090205460ff1681565b61014e6102ae366004613425565b61099a565b6101736102c1366004613170565b60c96020526000908152604090205460ff1681565b61014e6102e436600461358b565b610be7565b61014e6102f7366004613425565b6110cb565b60335473ffffffffffffffffffffffffffffffffffffffff1633146103685760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600081815260c96020526040808220805460ff191660011790555182917ff52508d5339edf0d7e5060a416df98db067af561bdc60872d29c0439eaa13a0291a250565b60006103eb6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104f3565b905060008173ffffffffffffffffffffffffffffffffffffffff1663b8f770056040518163ffffffff1660e01b815260040160206040518083038186803b15801561043557600080fd5b505afa158015610449573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046d91906136d9565b905060006104848633878564ffffffffff166111c7565b905061049783828663ffffffff16611242565b8573ffffffffffffffffffffffffffffffffffffffff167fcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a338785886040516104e39493929190613750565b60405180910390a2505050505050565b600080546040517fbf40fac100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063bf40fac19061054a9085906004016137a3565b60206040518083038186803b15801561056257600080fd5b505afa158015610576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059a91906137b6565b92915050565b60cd5460009073ffffffffffffffffffffffffffffffffffffffff1661dead141561060d5760405162461bcd60e51b815260206004820152601f60248201527f78446f6d61696e4d65737361676553656e646572206973206e6f742073657400604482015260640161035f565b5060cd5473ffffffffffffffffffffffffffffffffffffffff1690565b600061066a6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104f3565b6040517f2a7f18be0000000000000000000000000000000000000000000000000000000081526004810186905290915060009073ffffffffffffffffffffffffffffffffffffffff831690632a7f18be9060240160606040518083038186803b1580156106d657600080fd5b505afa1580156106ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070e91906137d3565b9050600061071e898989896111c7565b90506000731111000000000000000000000000000000001111300173420000000000000000000000000000000000000787846040516020016107639493929190613838565b604051602081830303815290604052805190602001209050826000015181146107f45760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520686173206e6f74206265656e20656e60448201527f7175657565642e00000000000000000000000000000000000000000000000000606482015260840161035f565b61080584838763ffffffff16611242565b50505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108785760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b61088260006112e3565b565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108eb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b600081815260c96020526040808220805460ff191690555182917f52c8a2680a9f4cc0ad0bf88f32096eadbebf0646ea611d93a0ce6a29a024040591a250565b60335473ffffffffffffffffffffffffffffffffffffffff1633146109925760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b61088261135a565b6000547501000000000000000000000000000000000000000000900460ff16806109df575060005474010000000000000000000000000000000000000000900460ff16155b610a515760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff16158015610ab857600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b60005473ffffffffffffffffffffffffffffffffffffffff1615610b445760405162461bcd60e51b815260206004820152602a60248201527f4c3143726f7373446f6d61696e4d657373656e67657220616c7265616479206960448201527f6e7469616c697a65642e00000000000000000000000000000000000000000000606482015260840161035f565b6000805473ffffffffffffffffffffffffffffffffffffffff84167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560cd805490911661dead179055610b9c61140c565b610ba461155b565b610bac611682565b610bb46117db565b8015610be357600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555b5050565b60026097541415610c3a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161035f565b600260975560655460ff1615610c925760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161035f565b6000610ca0868686866111c7565b9050610cac818361192f565b1515600114610d235760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520636f756c64206e6f7420626520766560448201527f7269666965642e00000000000000000000000000000000000000000000000000606482015260840161035f565b8051602080830191909120600081815260cb90925260409091205460ff1615610db45760405162461bcd60e51b815260206004820152602b60248201527f50726f7669646564206d6573736167652068617320616c72656164792062656560448201527f6e2072656365697665642e000000000000000000000000000000000000000000606482015260840161035f565b600081815260c9602052604090205460ff1615610e395760405162461bcd60e51b815260206004820152602260248201527f50726f7669646564206d65737361676520686173206265656e20626c6f636b6560448201527f642e000000000000000000000000000000000000000000000000000000000000606482015260840161035f565b610e776040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104f3565b73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161415610f185760405162461bcd60e51b815260206004820152603360248201527f43616e6e6f742073656e64204c322d3e4c31206d6573736167657320746f204c60448201527f312073797374656d20636f6e7472616374732e00000000000000000000000000606482015260840161035f565b60cd80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88811691909117909155604051600091891690610f7190889061387d565b6000604051808303816000865af19150503d8060008114610fae576040519150601f19603f3d011682016040523d82523d6000602084013e610fb3565b606091505b505060cd80547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905590508015156001141561103357600082815260cb6020526040808220805460ff191660011790555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a2611074565b600082815260cc6020526040808220805460ff191660011790555183917f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f91a25b600083334360405160200161108b93929190613899565b60408051601f198184030181529181528151602092830120600090815260ca9092529020805460ff19166001908117909155609755505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff1633146111325760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b73ffffffffffffffffffffffffffffffffffffffff81166111bb5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161035f565b6111c4816112e3565b50565b6060848484846040516024016111e094939291906138eb565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcbd4ece9000000000000000000000000000000000000000000000000000000001790529050949350505050565b6040517f6fee07e000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690636fee07e0906112ac907342000000000000000000000000000000000000079085908790600401613935565b600060405180830381600087803b1580156112c657600080fd5b505af11580156112da573d6000803e3d6000fd5b50505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60655460ff16156113ad5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161035f565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586113e23390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000547501000000000000000000000000000000000000000000900460ff1680611451575060005474010000000000000000000000000000000000000000900460ff16155b6114c35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff1615801561152a57600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b80156111c457600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff16806115a0575060005474010000000000000000000000000000000000000000900460ff16155b6116125760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff1615801561167957600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b61152a336112e3565b6000547501000000000000000000000000000000000000000000900460ff16806116c7575060005474010000000000000000000000000000000000000000900460ff16155b6117395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff161580156117a057600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6065805460ff1916905580156111c457600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff1680611820575060005474010000000000000000000000000000000000000000900460ff16155b6118925760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff161580156118f957600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b600160975580156111c457600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b600061193a82611952565b801561194b575061194b8383611af4565b9392505050565b6000806119936040518060400160405280601481526020017f5374617465436f6d6d69746d656e74436861696e0000000000000000000000008152506104f3565b60208401516040517f9418bddd00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff831691639418bddd916119eb916004016139a7565b60206040518083038186803b158015611a0357600080fd5b505afa158015611a17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3b91906139ba565b15801561194b57508251602084015160408086015190517f4d69ee5700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851693634d69ee5793611aa49391929091906004016139dc565b60206040518083038186803b158015611abc57600080fd5b505afa158015611ad0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194b91906139ba565b60008083734200000000000000000000000000000000000007604051602001611b1e929190613a54565b60408051601f1981840301815282825280516020918201209083015260009082015260600160408051601f198184030181529082905280516020918201207f42000000000000000000000000000000000000000000000000000000000000009183019190915291506000908190611bae9060340160408051601f1981840301815291905260608701518751611cd8565b9092509050600182151514611c515760405162461bcd60e51b815260206004820152604d60248201527f4d6573736167652070617373696e67207072656465706c6f7920686173206e6f60448201527f74206265656e20696e697469616c697a6564206f7220696e76616c696420707260648201527f6f6f662070726f76696465642e00000000000000000000000000000000000000608482015260a40161035f565b6000611c5c82611d01565b9050611ccd84604051602001611c7491815260200190565b60408051601f19818403018152908290527f010000000000000000000000000000000000000000000000000000000000000060208301529060210160405160208183030381529060405288608001518460400151611dc5565b979650505050505050565b600060606000611ce786611de9565b9050611cf4818686611e1b565b9250925050935093915050565b604080516080810182526000808252602082018190529181018290526060810182905290611d2e83611ef6565b90506040518060800160405280611d5e83600081518110611d5157611d51613a9e565b6020026020010151611f29565b8152602001611d7983600181518110611d5157611d51613a9e565b8152602001611da183600281518110611d9457611d94613a9e565b6020026020010151611f30565b8152602001611dbc83600381518110611d9457611d94613a9e565b90529392505050565b600080611dd186611de9565b9050611ddf81868686612032565b9695505050505050565b60608180519060200120604051602001611e0591815260200190565b6040516020818303038152906040529050919050565b600060606000611e2a85612068565b90506000806000611e3c848a89612163565b81519295509093509150158080611e505750815b611e9c5760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e000000000000604482015260640161035f565b600081611eb85760405180602001604052806000815250611ee4565b611ee486611ec7600188613afc565b81518110611ed757611ed7613a9e565b60200260200101516125fe565b919b919a509098505050505050505050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061059a90612628565b600061059a825b6000602182600001511115611f875760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e000000000000604482015260640161035f565b6000806000611f9585612827565b919450925090506000816001811115611fb057611fb0613b13565b14611ffd5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e000000000000604482015260640161035f565b600083866020015161200f9190613b42565b80519091506020841015611ddf5760208490036101000a90049695505050505050565b6000806000612042878686611e1b565b91509150818015611ccd5750805160208083019190912087519188019190912014611ccd565b6060600061207583611ef6565b90506000815167ffffffffffffffff811115612093576120936131ab565b6040519080825280602002602001820160405280156120d857816020015b60408051808201909152606080825260208201528152602001906001900390816120b15790505b50905060005b825181101561215b57600061210b8483815181106120fe576120fe613a9e565b6020026020010151612b78565b9050604051806040016040528082815260200161212783611ef6565b81525083838151811061213c5761213c613a9e565b602002602001018190525050808061215390613b5a565b9150506120de565b509392505050565b6000606081808061217387612c08565b9050600086905060008061219a604051806040016040528060608152602001606081525090565b60005b8c518110156125ba578c81815181106121b8576121b8613a9e565b6020026020010151915082846121ce9190613b42565b93506121db600188613b42565b96508361223f5781518051602090910120851461223a5760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726f6f742068617368000000000000000000000000000000604482015260640161035f565b6122fc565b8151516020116122a15781518051602090910120851461223a5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c20686173680000000000604482015260640161035f565b846122af8360000151612d8b565b146122fc5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f64652068617368000000000000604482015260640161035f565b61230860106001613b42565b8260200151511415612381578551841415612322576125ba565b600086858151811061233657612336613a9e565b602001015160f81c60f81b60f81c9050600083602001518260ff168151811061236157612361613a9e565b6020026020010151905061237481612db3565b96506001945050506125a8565b6002826020015151141561256057600061239a83612de9565b90506000816000815181106123b1576123b1613a9e565b016020015160f81c905060006123c8600283613bc2565b6123d3906002613be4565b905060006123e4848360ff16612e0d565b905060006123f28b8a612e0d565b905060006124008383612e43565b905060ff851660021480612417575060ff85166003145b1561246d5780835114801561242c5750808251145b1561243e5761243b818b613b42565b99505b507f800000000000000000000000000000000000000000000000000000000000000099506125ba945050505050565b60ff85161580612480575060ff85166001145b156124f257825181146124bc57507f800000000000000000000000000000000000000000000000000000000000000099506125ba945050505050565b6124e388602001516001815181106124d6576124d6613a9e565b6020026020010151612db3565b9a5097506125a8945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e2060448201527f7072656669780000000000000000000000000000000000000000000000000000606482015260840161035f565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e000000604482015260640161035f565b806125b281613b5a565b91505061219d565b507f80000000000000000000000000000000000000000000000000000000000000008414866125e98786612e0d565b909e909d50909b509950505050505050505050565b6020810151805160609161059a9161261890600190613afc565b815181106120fe576120fe613a9e565b606060008061263684612827565b9193509091506001905081600181111561265257612652613b13565b1461269f5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e000000000000000000604482015260640161035f565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816126b85790505090506000835b865181101561281c57602082106127645760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e00000000000000000000000000000000000000000000606482015260840161035f565b6000806127a16040518060400160405280858c600001516127859190613afc565b8152602001858c6020015161279a9190613b42565b9052612827565b5091509150604051806040016040528083836127bd9190613b42565b8152602001848b602001516127d29190613b42565b8152508585815181106127e7576127e7613a9e565b60209081029190910101526127fd600185613b42565b93506128098183613b42565b6128139084613b42565b925050506126e5565b508152949350505050565b60008060008084600001511161287f5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e0000000000000000604482015260640161035f565b6020840151805160001a607f81116128a4576000600160009450945094505050612b71565b60b781116129205760006128b9608083613afc565b90508087600001511161290e5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e00000000000000604482015260640161035f565b60019550935060009250612b71915050565b60bf8111612a0f57600061293560b783613afc565b90508087600001511161298a5760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e00604482015260640161035f565b600183015160208290036101000a90046129a48183613b42565b8851116129f35760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e0000000000000000604482015260640161035f565b6129fe826001613b42565b9650945060009350612b7192505050565b60f78111612a8a576000612a2460c083613afc565b905080876000015111612a795760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e000000000000000000604482015260640161035f565b600195509350849250612b71915050565b6000612a9760f783613afc565b905080876000015111612aec5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e000000604482015260640161035f565b600183015160208290036101000a9004612b068183613b42565b885111612b555760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e00000000000000000000604482015260640161035f565b612b60826001613b42565b9650945060019350612b7192505050565b9193909250565b60606000806000612b8885612827565b919450925090506000816001811115612ba357612ba3613b13565b14612bf05760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e0000000000000000604482015260640161035f565b612bff85602001518484612eef565b95945050505050565b6060600082516002612c1a9190613c07565b67ffffffffffffffff811115612c3257612c326131ab565b6040519080825280601f01601f191660200182016040528015612c5c576020820181803683370190505b50905060005b8351811015612d84576004848281518110612c7f57612c7f613a9e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c82612cb4836002613c07565b81518110612cc457612cc4613a9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506010848281518110612d0757612d07613a9e565b0160200151612d19919060f81c613bc2565b60f81b82612d28836002613c07565b612d33906001613b42565b81518110612d4357612d43613a9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080612d7c81613b5a565b915050612c62565b5092915050565b6000602082511015612d9f57506020015190565b8180602001905181019061059a9190613c44565b60006060602083600001511015612dd457612dcd83612fce565b9050612de0565b612ddd83612b78565b90505b61194b81612d8b565b606061059a612e0883602001516000815181106120fe576120fe613a9e565b612c08565b606082518210612e2c575060408051602081019091526000815261059a565b61194b8383848651612e3e9190613afc565b612fd9565b6000805b808451118015612e575750808351115b8015612ed85750828181518110612e7057612e70613a9e565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916848281518110612eaf57612eaf613a9e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b1561194b5780612ee781613b5a565b915050612e47565b606060008267ffffffffffffffff811115612f0c57612f0c6131ab565b6040519080825280601f01601f191660200182016040528015612f36576020820181803683370190505b509050805160001415612f4a57905061194b565b6000612f568587613b42565b90506020820160005b612f6a602087613c5d565b811015612fa15782518252612f80602084613b42565b9250612f8d602083613b42565b915080612f9981613b5a565b915050612f5f565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b606061059a8261315a565b606081612fe781601f613b42565b10156130355760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161035f565b826130408382613b42565b101561308e5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161035f565b6130988284613b42565b845110156130e85760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161035f565b6060821580156131075760405191506000825260208201604052613151565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015613140578051835260209283019201613128565b5050858452601f01601f1916604052505b50949350505050565b606061059a826020015160008460000151612eef565b60006020828403121561318257600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146111c457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156131fd576131fd6131ab565b60405290565b60405160a0810167ffffffffffffffff811182821017156131fd576131fd6131ab565b604051601f8201601f1916810167ffffffffffffffff8111828210171561324f5761324f6131ab565b604052919050565b600067ffffffffffffffff831115613271576132716131ab565b6132846020601f19601f86011601613226565b905082815283838301111561329857600080fd5b828260208301376000602084830101529392505050565b600082601f8301126132c057600080fd5b61194b83833560208501613257565b803563ffffffff811681146132e357600080fd5b919050565b6000806000606084860312156132fd57600080fd5b833561330881613189565b9250602084013567ffffffffffffffff81111561332457600080fd5b613330868287016132af565b92505061333f604085016132cf565b90509250925092565b60006020828403121561335a57600080fd5b813567ffffffffffffffff81111561337157600080fd5b8201601f8101841361338257600080fd5b61339184823560208401613257565b949350505050565b60008060008060008060c087890312156133b257600080fd5b86356133bd81613189565b955060208701356133cd81613189565b9450604087013567ffffffffffffffff8111156133e957600080fd5b6133f589828a016132af565b9450506060870135925061340b608088016132cf565b915061341960a088016132cf565b90509295509295509295565b60006020828403121561343757600080fd5b813561194b81613189565b600060a0828403121561345457600080fd5b60405160a0810167ffffffffffffffff8282108183111715613478576134786131ab565b816040528293508435835260208501356020840152604085013560408401526060850135606084015260808501359150808211156134b557600080fd5b506134c2858286016132af565b6080830152505092915050565b6000604082840312156134e157600080fd5b6134e96131da565b90508135815260208083013567ffffffffffffffff8082111561350b57600080fd5b818501915085601f83011261351f57600080fd5b813581811115613531576135316131ab565b8060051b9150613542848301613226565b818152918301840191848101908884111561355c57600080fd5b938501935b8385101561357a57843582529385019390850190613561565b808688015250505050505092915050565b600080600080600060a086880312156135a357600080fd5b85356135ae81613189565b945060208601356135be81613189565b9350604086013567ffffffffffffffff808211156135db57600080fd5b6135e789838a016132af565b945060608801359350608088013591508082111561360457600080fd5b9087019060a0828a03121561361857600080fd5b613620613203565b8235815260208301358281111561363657600080fd5b6136428b828601613442565b60208301525060408301358281111561365a57600080fd5b6136668b8286016134cf565b60408301525060608301358281111561367e57600080fd5b61368a8b8286016132af565b6060830152506080830135828111156136a257600080fd5b6136ae8b8286016132af565b6080830152508093505050509295509295909350565b805164ffffffffff811681146132e357600080fd5b6000602082840312156136eb57600080fd5b61194b826136c4565b60005b8381101561370f5781810151838201526020016136f7565b8381111561371e576000848401525b50505050565b6000815180845261373c8160208601602086016136f4565b601f01601f19169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8516815260806020820152600061377f6080830186613724565b905064ffffffffff8416604083015263ffffffff8316606083015295945050505050565b60208152600061194b6020830184613724565b6000602082840312156137c857600080fd5b815161194b81613189565b6000606082840312156137e557600080fd5b6040516060810181811067ffffffffffffffff82111715613808576138086131ab565b6040528251815261381b602084016136c4565b602082015261382c604084016136c4565b60408201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525063ffffffff8416604083015260806060830152611ddf6080830184613724565b6000825161388f8184602087016136f4565b9190910192915050565b600084516138ab8184602089016136f4565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250608060408301526139246080830185613724565b905082606083015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000612bff6060830184613724565b805182526020810151602083015260408101516040830152606081015160608301526000608082015160a0608085015261339160a0850182613724565b60208152600061194b602083018461396a565b6000602082840312156139cc57600080fd5b8151801515811461194b57600080fd5b838152600060206060818401526139f6606084018661396a565b83810360408501526040810185518252828601516040848401528181518084526060850191508583019450600093505b80841015613a465784518252938501936001939093019290850190613a26565b509998505050505050505050565b60008351613a668184602088016136f4565b60609390931b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169190920190815260140192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613b0e57613b0e613acd565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60008219821115613b5557613b55613acd565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613b8c57613b8c613acd565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff831680613bd557613bd5613b93565b8060ff84160691505092915050565b600060ff821660ff841680821015613bfe57613bfe613acd565b90039392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613c3f57613c3f613acd565b500290565b600060208284031215613c5657600080fd5b5051919050565b600082613c6c57613c6c613b93565b50049056fea164736f6c6343000809000a
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101365760003560e01c806381ada46c116100b2578063b1b1b20911610081578063c6b94ab011610066578063c6b94ab0146102b3578063d7fd19dd146102d6578063f2fde38b146102e957600080fd5b8063b1b1b2091461027d578063c4d66de8146102a057600080fd5b806381ada46c146102215780638456cb59146102345780638da5cb5b1461023c578063a4e7f8bd1461025a57600080fd5b8063461a4478116101095780636e296e45116100ee5780636e296e45146101fe5780636f1c8d4714610206578063715018a61461021957600080fd5b8063461a4478146101e05780635c975abb146101f357600080fd5b80630ecf2eea1461013b57806321d800ec14610150578063299ca478146101885780633dbb202b146101cd575b600080fd5b61014e610149366004613170565b6102fc565b005b61017361015e366004613170565b60ca6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6000546101a89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161017f565b61014e6101db3660046132e8565b6103ab565b6101a86101ee366004613348565b6104f3565b60655460ff16610173565b6101a86105a0565b61014e610214366004613399565b61062a565b61014e610811565b61014e61022f366004613170565b610884565b61014e61092b565b60335473ffffffffffffffffffffffffffffffffffffffff166101a8565b610173610268366004613170565b60cc6020526000908152604090205460ff1681565b61017361028b366004613170565b60cb6020526000908152604090205460ff1681565b61014e6102ae366004613425565b61099a565b6101736102c1366004613170565b60c96020526000908152604090205460ff1681565b61014e6102e436600461358b565b610be7565b61014e6102f7366004613425565b6110cb565b60335473ffffffffffffffffffffffffffffffffffffffff1633146103685760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600081815260c96020526040808220805460ff191660011790555182917ff52508d5339edf0d7e5060a416df98db067af561bdc60872d29c0439eaa13a0291a250565b60006103eb6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104f3565b905060008173ffffffffffffffffffffffffffffffffffffffff1663b8f770056040518163ffffffff1660e01b815260040160206040518083038186803b15801561043557600080fd5b505afa158015610449573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046d91906136d9565b905060006104848633878564ffffffffff166111c7565b905061049783828663ffffffff16611242565b8573ffffffffffffffffffffffffffffffffffffffff167fcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a338785886040516104e39493929190613750565b60405180910390a2505050505050565b600080546040517fbf40fac100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063bf40fac19061054a9085906004016137a3565b60206040518083038186803b15801561056257600080fd5b505afa158015610576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059a91906137b6565b92915050565b60cd5460009073ffffffffffffffffffffffffffffffffffffffff1661dead141561060d5760405162461bcd60e51b815260206004820152601f60248201527f78446f6d61696e4d65737361676553656e646572206973206e6f742073657400604482015260640161035f565b5060cd5473ffffffffffffffffffffffffffffffffffffffff1690565b600061066a6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104f3565b6040517f2a7f18be0000000000000000000000000000000000000000000000000000000081526004810186905290915060009073ffffffffffffffffffffffffffffffffffffffff831690632a7f18be9060240160606040518083038186803b1580156106d657600080fd5b505afa1580156106ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070e91906137d3565b9050600061071e898989896111c7565b90506000731111000000000000000000000000000000001111300173420000000000000000000000000000000000000787846040516020016107639493929190613838565b604051602081830303815290604052805190602001209050826000015181146107f45760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520686173206e6f74206265656e20656e60448201527f7175657565642e00000000000000000000000000000000000000000000000000606482015260840161035f565b61080584838763ffffffff16611242565b50505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108785760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b61088260006112e3565b565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108eb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b600081815260c96020526040808220805460ff191690555182917f52c8a2680a9f4cc0ad0bf88f32096eadbebf0646ea611d93a0ce6a29a024040591a250565b60335473ffffffffffffffffffffffffffffffffffffffff1633146109925760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b61088261135a565b6000547501000000000000000000000000000000000000000000900460ff16806109df575060005474010000000000000000000000000000000000000000900460ff16155b610a515760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff16158015610ab857600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b60005473ffffffffffffffffffffffffffffffffffffffff1615610b445760405162461bcd60e51b815260206004820152602a60248201527f4c3143726f7373446f6d61696e4d657373656e67657220616c7265616479206960448201527f6e7469616c697a65642e00000000000000000000000000000000000000000000606482015260840161035f565b6000805473ffffffffffffffffffffffffffffffffffffffff84167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560cd805490911661dead179055610b9c61140c565b610ba461155b565b610bac611682565b610bb46117db565b8015610be357600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555b5050565b60026097541415610c3a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161035f565b600260975560655460ff1615610c925760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161035f565b6000610ca0868686866111c7565b9050610cac818361192f565b1515600114610d235760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520636f756c64206e6f7420626520766560448201527f7269666965642e00000000000000000000000000000000000000000000000000606482015260840161035f565b8051602080830191909120600081815260cb90925260409091205460ff1615610db45760405162461bcd60e51b815260206004820152602b60248201527f50726f7669646564206d6573736167652068617320616c72656164792062656560448201527f6e2072656365697665642e000000000000000000000000000000000000000000606482015260840161035f565b600081815260c9602052604090205460ff1615610e395760405162461bcd60e51b815260206004820152602260248201527f50726f7669646564206d65737361676520686173206265656e20626c6f636b6560448201527f642e000000000000000000000000000000000000000000000000000000000000606482015260840161035f565b610e776040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104f3565b73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161415610f185760405162461bcd60e51b815260206004820152603360248201527f43616e6e6f742073656e64204c322d3e4c31206d6573736167657320746f204c60448201527f312073797374656d20636f6e7472616374732e00000000000000000000000000606482015260840161035f565b60cd80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88811691909117909155604051600091891690610f7190889061387d565b6000604051808303816000865af19150503d8060008114610fae576040519150601f19603f3d011682016040523d82523d6000602084013e610fb3565b606091505b505060cd80547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905590508015156001141561103357600082815260cb6020526040808220805460ff191660011790555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a2611074565b600082815260cc6020526040808220805460ff191660011790555183917f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f91a25b600083334360405160200161108b93929190613899565b60408051601f198184030181529181528151602092830120600090815260ca9092529020805460ff19166001908117909155609755505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff1633146111325760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161035f565b73ffffffffffffffffffffffffffffffffffffffff81166111bb5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161035f565b6111c4816112e3565b50565b6060848484846040516024016111e094939291906138eb565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcbd4ece9000000000000000000000000000000000000000000000000000000001790529050949350505050565b6040517f6fee07e000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690636fee07e0906112ac907342000000000000000000000000000000000000079085908790600401613935565b600060405180830381600087803b1580156112c657600080fd5b505af11580156112da573d6000803e3d6000fd5b50505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60655460ff16156113ad5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161035f565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586113e23390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000547501000000000000000000000000000000000000000000900460ff1680611451575060005474010000000000000000000000000000000000000000900460ff16155b6114c35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff1615801561152a57600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b80156111c457600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff16806115a0575060005474010000000000000000000000000000000000000000900460ff16155b6116125760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff1615801561167957600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b61152a336112e3565b6000547501000000000000000000000000000000000000000000900460ff16806116c7575060005474010000000000000000000000000000000000000000900460ff16155b6117395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff161580156117a057600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6065805460ff1916905580156111c457600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff1680611820575060005474010000000000000000000000000000000000000000900460ff16155b6118925760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161035f565b6000547501000000000000000000000000000000000000000000900460ff161580156118f957600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b600160975580156111c457600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b600061193a82611952565b801561194b575061194b8383611af4565b9392505050565b6000806119936040518060400160405280601481526020017f5374617465436f6d6d69746d656e74436861696e0000000000000000000000008152506104f3565b60208401516040517f9418bddd00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff831691639418bddd916119eb916004016139a7565b60206040518083038186803b158015611a0357600080fd5b505afa158015611a17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3b91906139ba565b15801561194b57508251602084015160408086015190517f4d69ee5700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851693634d69ee5793611aa49391929091906004016139dc565b60206040518083038186803b158015611abc57600080fd5b505afa158015611ad0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194b91906139ba565b60008083734200000000000000000000000000000000000007604051602001611b1e929190613a54565b60408051601f1981840301815282825280516020918201209083015260009082015260600160408051601f198184030181529082905280516020918201207f42000000000000000000000000000000000000000000000000000000000000009183019190915291506000908190611bae9060340160408051601f1981840301815291905260608701518751611cd8565b9092509050600182151514611c515760405162461bcd60e51b815260206004820152604d60248201527f4d6573736167652070617373696e67207072656465706c6f7920686173206e6f60448201527f74206265656e20696e697469616c697a6564206f7220696e76616c696420707260648201527f6f6f662070726f76696465642e00000000000000000000000000000000000000608482015260a40161035f565b6000611c5c82611d01565b9050611ccd84604051602001611c7491815260200190565b60408051601f19818403018152908290527f010000000000000000000000000000000000000000000000000000000000000060208301529060210160405160208183030381529060405288608001518460400151611dc5565b979650505050505050565b600060606000611ce786611de9565b9050611cf4818686611e1b565b9250925050935093915050565b604080516080810182526000808252602082018190529181018290526060810182905290611d2e83611ef6565b90506040518060800160405280611d5e83600081518110611d5157611d51613a9e565b6020026020010151611f29565b8152602001611d7983600181518110611d5157611d51613a9e565b8152602001611da183600281518110611d9457611d94613a9e565b6020026020010151611f30565b8152602001611dbc83600381518110611d9457611d94613a9e565b90529392505050565b600080611dd186611de9565b9050611ddf81868686612032565b9695505050505050565b60608180519060200120604051602001611e0591815260200190565b6040516020818303038152906040529050919050565b600060606000611e2a85612068565b90506000806000611e3c848a89612163565b81519295509093509150158080611e505750815b611e9c5760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e000000000000604482015260640161035f565b600081611eb85760405180602001604052806000815250611ee4565b611ee486611ec7600188613afc565b81518110611ed757611ed7613a9e565b60200260200101516125fe565b919b919a509098505050505050505050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061059a90612628565b600061059a825b6000602182600001511115611f875760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e000000000000604482015260640161035f565b6000806000611f9585612827565b919450925090506000816001811115611fb057611fb0613b13565b14611ffd5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e000000000000604482015260640161035f565b600083866020015161200f9190613b42565b80519091506020841015611ddf5760208490036101000a90049695505050505050565b6000806000612042878686611e1b565b91509150818015611ccd5750805160208083019190912087519188019190912014611ccd565b6060600061207583611ef6565b90506000815167ffffffffffffffff811115612093576120936131ab565b6040519080825280602002602001820160405280156120d857816020015b60408051808201909152606080825260208201528152602001906001900390816120b15790505b50905060005b825181101561215b57600061210b8483815181106120fe576120fe613a9e565b6020026020010151612b78565b9050604051806040016040528082815260200161212783611ef6565b81525083838151811061213c5761213c613a9e565b602002602001018190525050808061215390613b5a565b9150506120de565b509392505050565b6000606081808061217387612c08565b9050600086905060008061219a604051806040016040528060608152602001606081525090565b60005b8c518110156125ba578c81815181106121b8576121b8613a9e565b6020026020010151915082846121ce9190613b42565b93506121db600188613b42565b96508361223f5781518051602090910120851461223a5760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726f6f742068617368000000000000000000000000000000604482015260640161035f565b6122fc565b8151516020116122a15781518051602090910120851461223a5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c20686173680000000000604482015260640161035f565b846122af8360000151612d8b565b146122fc5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f64652068617368000000000000604482015260640161035f565b61230860106001613b42565b8260200151511415612381578551841415612322576125ba565b600086858151811061233657612336613a9e565b602001015160f81c60f81b60f81c9050600083602001518260ff168151811061236157612361613a9e565b6020026020010151905061237481612db3565b96506001945050506125a8565b6002826020015151141561256057600061239a83612de9565b90506000816000815181106123b1576123b1613a9e565b016020015160f81c905060006123c8600283613bc2565b6123d3906002613be4565b905060006123e4848360ff16612e0d565b905060006123f28b8a612e0d565b905060006124008383612e43565b905060ff851660021480612417575060ff85166003145b1561246d5780835114801561242c5750808251145b1561243e5761243b818b613b42565b99505b507f800000000000000000000000000000000000000000000000000000000000000099506125ba945050505050565b60ff85161580612480575060ff85166001145b156124f257825181146124bc57507f800000000000000000000000000000000000000000000000000000000000000099506125ba945050505050565b6124e388602001516001815181106124d6576124d6613a9e565b6020026020010151612db3565b9a5097506125a8945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e2060448201527f7072656669780000000000000000000000000000000000000000000000000000606482015260840161035f565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e000000604482015260640161035f565b806125b281613b5a565b91505061219d565b507f80000000000000000000000000000000000000000000000000000000000000008414866125e98786612e0d565b909e909d50909b509950505050505050505050565b6020810151805160609161059a9161261890600190613afc565b815181106120fe576120fe613a9e565b606060008061263684612827565b9193509091506001905081600181111561265257612652613b13565b1461269f5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e000000000000000000604482015260640161035f565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816126b85790505090506000835b865181101561281c57602082106127645760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e00000000000000000000000000000000000000000000606482015260840161035f565b6000806127a16040518060400160405280858c600001516127859190613afc565b8152602001858c6020015161279a9190613b42565b9052612827565b5091509150604051806040016040528083836127bd9190613b42565b8152602001848b602001516127d29190613b42565b8152508585815181106127e7576127e7613a9e565b60209081029190910101526127fd600185613b42565b93506128098183613b42565b6128139084613b42565b925050506126e5565b508152949350505050565b60008060008084600001511161287f5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e0000000000000000604482015260640161035f565b6020840151805160001a607f81116128a4576000600160009450945094505050612b71565b60b781116129205760006128b9608083613afc565b90508087600001511161290e5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e00000000000000604482015260640161035f565b60019550935060009250612b71915050565b60bf8111612a0f57600061293560b783613afc565b90508087600001511161298a5760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e00604482015260640161035f565b600183015160208290036101000a90046129a48183613b42565b8851116129f35760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e0000000000000000604482015260640161035f565b6129fe826001613b42565b9650945060009350612b7192505050565b60f78111612a8a576000612a2460c083613afc565b905080876000015111612a795760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e000000000000000000604482015260640161035f565b600195509350849250612b71915050565b6000612a9760f783613afc565b905080876000015111612aec5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e000000604482015260640161035f565b600183015160208290036101000a9004612b068183613b42565b885111612b555760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e00000000000000000000604482015260640161035f565b612b60826001613b42565b9650945060019350612b7192505050565b9193909250565b60606000806000612b8885612827565b919450925090506000816001811115612ba357612ba3613b13565b14612bf05760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e0000000000000000604482015260640161035f565b612bff85602001518484612eef565b95945050505050565b6060600082516002612c1a9190613c07565b67ffffffffffffffff811115612c3257612c326131ab565b6040519080825280601f01601f191660200182016040528015612c5c576020820181803683370190505b50905060005b8351811015612d84576004848281518110612c7f57612c7f613a9e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c82612cb4836002613c07565b81518110612cc457612cc4613a9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506010848281518110612d0757612d07613a9e565b0160200151612d19919060f81c613bc2565b60f81b82612d28836002613c07565b612d33906001613b42565b81518110612d4357612d43613a9e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080612d7c81613b5a565b915050612c62565b5092915050565b6000602082511015612d9f57506020015190565b8180602001905181019061059a9190613c44565b60006060602083600001511015612dd457612dcd83612fce565b9050612de0565b612ddd83612b78565b90505b61194b81612d8b565b606061059a612e0883602001516000815181106120fe576120fe613a9e565b612c08565b606082518210612e2c575060408051602081019091526000815261059a565b61194b8383848651612e3e9190613afc565b612fd9565b6000805b808451118015612e575750808351115b8015612ed85750828181518110612e7057612e70613a9e565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916848281518110612eaf57612eaf613a9e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b1561194b5780612ee781613b5a565b915050612e47565b606060008267ffffffffffffffff811115612f0c57612f0c6131ab565b6040519080825280601f01601f191660200182016040528015612f36576020820181803683370190505b509050805160001415612f4a57905061194b565b6000612f568587613b42565b90506020820160005b612f6a602087613c5d565b811015612fa15782518252612f80602084613b42565b9250612f8d602083613b42565b915080612f9981613b5a565b915050612f5f565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b606061059a8261315a565b606081612fe781601f613b42565b10156130355760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161035f565b826130408382613b42565b101561308e5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161035f565b6130988284613b42565b845110156130e85760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161035f565b6060821580156131075760405191506000825260208201604052613151565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015613140578051835260209283019201613128565b5050858452601f01601f1916604052505b50949350505050565b606061059a826020015160008460000151612eef565b60006020828403121561318257600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146111c457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156131fd576131fd6131ab565b60405290565b60405160a0810167ffffffffffffffff811182821017156131fd576131fd6131ab565b604051601f8201601f1916810167ffffffffffffffff8111828210171561324f5761324f6131ab565b604052919050565b600067ffffffffffffffff831115613271576132716131ab565b6132846020601f19601f86011601613226565b905082815283838301111561329857600080fd5b828260208301376000602084830101529392505050565b600082601f8301126132c057600080fd5b61194b83833560208501613257565b803563ffffffff811681146132e357600080fd5b919050565b6000806000606084860312156132fd57600080fd5b833561330881613189565b9250602084013567ffffffffffffffff81111561332457600080fd5b613330868287016132af565b92505061333f604085016132cf565b90509250925092565b60006020828403121561335a57600080fd5b813567ffffffffffffffff81111561337157600080fd5b8201601f8101841361338257600080fd5b61339184823560208401613257565b949350505050565b60008060008060008060c087890312156133b257600080fd5b86356133bd81613189565b955060208701356133cd81613189565b9450604087013567ffffffffffffffff8111156133e957600080fd5b6133f589828a016132af565b9450506060870135925061340b608088016132cf565b915061341960a088016132cf565b90509295509295509295565b60006020828403121561343757600080fd5b813561194b81613189565b600060a0828403121561345457600080fd5b60405160a0810167ffffffffffffffff8282108183111715613478576134786131ab565b816040528293508435835260208501356020840152604085013560408401526060850135606084015260808501359150808211156134b557600080fd5b506134c2858286016132af565b6080830152505092915050565b6000604082840312156134e157600080fd5b6134e96131da565b90508135815260208083013567ffffffffffffffff8082111561350b57600080fd5b818501915085601f83011261351f57600080fd5b813581811115613531576135316131ab565b8060051b9150613542848301613226565b818152918301840191848101908884111561355c57600080fd5b938501935b8385101561357a57843582529385019390850190613561565b808688015250505050505092915050565b600080600080600060a086880312156135a357600080fd5b85356135ae81613189565b945060208601356135be81613189565b9350604086013567ffffffffffffffff808211156135db57600080fd5b6135e789838a016132af565b945060608801359350608088013591508082111561360457600080fd5b9087019060a0828a03121561361857600080fd5b613620613203565b8235815260208301358281111561363657600080fd5b6136428b828601613442565b60208301525060408301358281111561365a57600080fd5b6136668b8286016134cf565b60408301525060608301358281111561367e57600080fd5b61368a8b8286016132af565b6060830152506080830135828111156136a257600080fd5b6136ae8b8286016132af565b6080830152508093505050509295509295909350565b805164ffffffffff811681146132e357600080fd5b6000602082840312156136eb57600080fd5b61194b826136c4565b60005b8381101561370f5781810151838201526020016136f7565b8381111561371e576000848401525b50505050565b6000815180845261373c8160208601602086016136f4565b601f01601f19169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8516815260806020820152600061377f6080830186613724565b905064ffffffffff8416604083015263ffffffff8316606083015295945050505050565b60208152600061194b6020830184613724565b6000602082840312156137c857600080fd5b815161194b81613189565b6000606082840312156137e557600080fd5b6040516060810181811067ffffffffffffffff82111715613808576138086131ab565b6040528251815261381b602084016136c4565b602082015261382c604084016136c4565b60408201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525063ffffffff8416604083015260806060830152611ddf6080830184613724565b6000825161388f8184602087016136f4565b9190910192915050565b600084516138ab8184602089016136f4565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250608060408301526139246080830185613724565b905082606083015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000612bff6060830184613724565b805182526020810151602083015260408101516040830152606081015160608301526000608082015160a0608085015261339160a0850182613724565b60208152600061194b602083018461396a565b6000602082840312156139cc57600080fd5b8151801515811461194b57600080fd5b838152600060206060818401526139f6606084018661396a565b83810360408501526040810185518252828601516040848401528181518084526060850191508583019450600093505b80841015613a465784518252938501936001939093019290850190613a26565b509998505050505050505050565b60008351613a668184602088016136f4565b60609390931b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169190920190815260140192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613b0e57613b0e613acd565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60008219821115613b5557613b55613acd565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613b8c57613b8c613acd565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff831680613bd557613bd5613b93565b8060ff84160691505092915050565b600060ff821660ff841680821015613bfe57613bfe613acd565b90039392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613c3f57613c3f613acd565b500290565b600060208284031215613c5657600080fd5b5051919050565b600082613c6c57613c6c613b93565b50049056fea164736f6c6343000809000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.