Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 45 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Root | 18776206 | 15 days ago | IN | 0 ETH | 0.000003860518 | ||||
Register Block | 18776204 | 15 days ago | IN | 0 ETH | 0.000000122951 | ||||
Set Root | 18300132 | 26 days ago | IN | 0 ETH | 0.000000940253 | ||||
Register Block | 18300130 | 26 days ago | IN | 0 ETH | 0.000000047128 | ||||
Set Root | 18027355 | 32 days ago | IN | 0 ETH | 0.000124015608 | ||||
Register Block | 18027349 | 32 days ago | IN | 0 ETH | 0.00000323731 | ||||
Set Root | 18027344 | 32 days ago | IN | 0 ETH | 0.000122842875 | ||||
Register Block | 18027342 | 32 days ago | IN | 0 ETH | 0.00000323731 | ||||
Set Root | 18027340 | 32 days ago | IN | 0 ETH | 0.000122842875 | ||||
Register Block | 18027334 | 32 days ago | IN | 0 ETH | 0.000003240111 | ||||
Set Root | 18027331 | 32 days ago | IN | 0 ETH | 0.000118620385 | ||||
Register Block | 18027327 | 32 days ago | IN | 0 ETH | 0.000003129875 | ||||
Register Block | 18027289 | 32 days ago | IN | 0 ETH | 0.000003250794 | ||||
Set Root | 18027277 | 32 days ago | IN | 0 ETH | 0.000117235533 | ||||
Register Block | 18027274 | 32 days ago | IN | 0 ETH | 0.000003077619 | ||||
Set Root | 18027270 | 32 days ago | IN | 0 ETH | 0.000117235533 | ||||
Register Block | 18027267 | 32 days ago | IN | 0 ETH | 0.000003080419 | ||||
Register Block | 18027229 | 32 days ago | IN | 0 ETH | 0.000003212525 | ||||
Register Block | 18027214 | 32 days ago | IN | 0 ETH | 0.000003119902 | ||||
Register Block | 18027199 | 32 days ago | IN | 0 ETH | 0.000003429267 | ||||
Register Block | 18027184 | 32 days ago | IN | 0 ETH | 0.0000035355 | ||||
Set Root | 18027179 | 32 days ago | IN | 0 ETH | 0.000136183465 | ||||
Register Block | 18027177 | 32 days ago | IN | 0 ETH | 0.000003572174 | ||||
Set Root | 18027173 | 32 days ago | IN | 0 ETH | 0.00013573974 | ||||
Register Block | 18027169 | 32 days ago | IN | 0 ETH | 0.000003897418 |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
BridgedKeyStoreFromExecutionRoot
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 999999 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.8.19; import {RLPReader} from "Solidity-RLP/RLPReader.sol"; import {MerkleTrie} from "optimism/packages/contracts-bedrock/src/libraries/trie/MerkleTrie.sol"; import {IL1BlockOracle} from "./IL1BlockOracle.sol"; import {RingBuffer10} from "./RingBuffer.sol"; contract BridgedKeyStoreFromExecutionRoot { using RLPReader for RLPReader.RLPItem; using RLPReader for RLPReader.Iterator; using RLPReader for bytes; /// @notice Block header structure returned by `_parseBlockHeader()`. struct BlockHeader { /// @notice The block hash. bytes32 hash; /// @notice The state root hash. bytes32 stateRootHash; /// @notice The block number. uint256 number; /// @notice The block timestamp. uint256 timestamp; } /// @dev Consant used to by `_parseBlockHeader()` to parse the RLP encoded block header. uint256 private constant _HEADER_STATE_ROOT_INDEX = 3; /// @dev Consant used to by `_parseBlockHeader()` to parse the RLP encoded block header. uint256 private constant _HEADER_NUMBER_INDEX = 8; /// @dev Consant used to by `_parseBlockHeader()` to parse the RLP encoded block header. uint256 private constant _HEADER_TIMESTAMP_INDEX = 11; /// @notice The KeyStore contract address on L1. address public immutable l1KeyStore; /// @notice The keccak256 hash of the slot where the root is stored on the KeyStore contract on L1. bytes32 public immutable slotHash; /// @notice The L1 block oracle from which to query for L1 block hash. IL1BlockOracle public immutable l1BlockOracle; /// @notice The latest KeyStore root. uint256 public root; /// @notice The 10 latest KeyStore roots. RingBuffer10 public roots; /// @notice The latest L1 block hash that has been registered by calling `registerBlock()`. bytes32 public latestBlockHashRegistered; /// @notice The proof's L1 block numer used when setting the new `root`. uint256 public latestBlockNumber; /// @notice Emitted when the KeyStore root is updated. event RootUpdated(uint256 indexed root); /// @notice Thrown in `setRoot()` when trying to use a stale proof to set the new `root`. /// /// @param blockNumber The proof's block number. /// @param latestBlockNumber The latest block number proved. error StaleProof(uint256 blockNumber, uint256 latestBlockNumber); /// @notice Thrown in `setRoot()` when the proof's block hash does not match with the `latestBlockHashRegistered`. /// /// @param blockHash The proof's block hash. /// @param latestBlockHashRegistered The latest block hash registered. error InvalidProofBlockHash(bytes32 blockHash, bytes32 latestBlockHashRegistered); /// @notice BridgedKeyStoreFromExecutionRoot constructor. /// /// @param l1KeyStore_ The KeyStore contract address on L1. /// @param slotHash_ The keccak256 hash of the slot where the root is stored on the KeyStore contract on L1. /// @param l1BlockOracle_ The L1 block oracle from which to query for L1 block hash. constructor(address l1KeyStore_, bytes32 slotHash_, address l1BlockOracle_) { l1KeyStore = l1KeyStore_; slotHash = slotHash_; l1BlockOracle = IL1BlockOracle(l1BlockOracle_); } /// @notice Register the current L1 block hash. function registerBlock() external { latestBlockHashRegistered = l1BlockOracle.hash(); } /// @notice Update the KeyStore root with Merkle proofs from the current L1 block. /// /// @dev Reverts if trying to prove a L1 block whose number is below the latest proved L1 block. /// /// @param blockHeaderRlp The RLP-encoded L1 block header from eth_getBlockByNumber. /// @param accountProof The account proof from eth_getProof. /// @param slotProof The storage slot proof from eth_getProof. function setRoot(bytes memory blockHeaderRlp, bytes[] memory accountProof, bytes[] memory slotProof) external { BlockHeader memory header = _parseBlockHeader(blockHeaderRlp); // Ensre we're not proving a stale L1 block. if (latestBlockNumber > header.number) { revert StaleProof({blockNumber: header.number, latestBlockNumber: latestBlockNumber}); } // Ensure the block hash has been registered if (header.hash != latestBlockHashRegistered) { revert InvalidProofBlockHash({blockHash: header.hash, latestBlockHashRegistered: latestBlockHashRegistered}); } // MerkleTrie.get reverts if the slot does not exist. bytes32 accountHash = keccak256(abi.encodePacked(l1KeyStore)); bytes memory accountFields = MerkleTrie.get({_key: abi.encodePacked(accountHash), _proof: accountProof, _root: header.stateRootHash}); bytes32 storageRoot = bytes32(accountFields.toRlpItem().toList()[2].toUint()); uint256 slotValue = MerkleTrie.get({_key: abi.encodePacked(slotHash), _proof: slotProof, _root: storageRoot}) .toRlpItem().toUint(); root = uint256(bytes32(slotValue)); roots.append(root); latestBlockNumber = header.number; emit RootUpdated(root); } /// @notice Parses RLP-encoded block header. /// /// @dev Implementation is from https://github.com/lidofinance/curve-merkle-oracle/blob/fffd375659358af54a6e8bbf8c3aa44188894c81/contracts/StateProofVerifier.sol. /// /// @param headerRlpBytes The encoded RLP-encoded block header. /// /// @return The decoded `BlockHeader`. function _parseBlockHeader(bytes memory headerRlpBytes) private pure returns (BlockHeader memory) { BlockHeader memory result; RLPReader.RLPItem[] memory headerFields = headerRlpBytes.toRlpItem().toList(); result.stateRootHash = bytes32(headerFields[_HEADER_STATE_ROOT_INDEX].toUint()); result.number = headerFields[_HEADER_NUMBER_INDEX].toUint(); result.timestamp = headerFields[_HEADER_TIMESTAMP_INDEX].toUint(); result.hash = keccak256(headerRlpBytes); return result; } }
// SPDX-License-Identifier: Apache-2.0 /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity >=0.5.10 <0.9.0; library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint256 len; uint256 memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint256 nextPtr; // Position of the next item in the list. } /* * @dev Returns the next element in the iteration. Reverts if it has not next element. * @param self The iterator. * @return The next element in the iteration. */ function next(Iterator memory self) internal pure returns (RLPItem memory) { require(hasNext(self)); uint256 ptr = self.nextPtr; uint256 itemLength = _itemLength(ptr); self.nextPtr = ptr + itemLength; return RLPItem(itemLength, ptr); } /* * @dev Returns true if the iteration has more elements. * @param self The iterator. * @return true if the iteration has more elements. */ function hasNext(Iterator memory self) internal pure returns (bool) { RLPItem memory item = self.item; return self.nextPtr < item.memPtr + item.len; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint256 memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @dev Create an iterator. Reverts if item is not a list. * @param self The RLP item. * @return An 'Iterator' over the item. */ function iterator(RLPItem memory self) internal pure returns (Iterator memory) { require(isList(self)); uint256 ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param the RLP item. */ function rlpLen(RLPItem memory item) internal pure returns (uint256) { return item.len; } /* * @param the RLP item. * @return (memPtr, len) pair: location of the item's payload in memory. */ function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) { uint256 offset = _payloadOffset(item.memPtr); uint256 memPtr = item.memPtr + offset; uint256 len = item.len - offset; // data length return (memPtr, len); } /* * @param the RLP item. */ function payloadLen(RLPItem memory item) internal pure returns (uint256) { (, uint256 len) = payloadLocation(item); return len; } /* * @param the RLP item containing the encoded list. */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint256 items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 dataLen; for (uint256 i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /* * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory. * @return keccak256 hash of RLP encoded bytes. */ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) { uint256 ptr = item.memPtr; uint256 len = item.len; bytes32 result; assembly { result := keccak256(ptr, len) } return result; } /* * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory. * @return keccak256 hash of the item payload. */ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) { (uint256 memPtr, uint256 len) = payloadLocation(item); bytes32 result; assembly { result := keccak256(memPtr, len) } return result; } /** RLPItem conversions into data types **/ // @returns raw rlp encoding in bytes function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) { bytes memory result = new bytes(item.len); if (result.length == 0) return result; uint256 ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte except "0x80" is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint256 result; uint256 memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } // SEE Github Issue #5. // Summary: Most commonly used RLP libraries (i.e Geth) will encode // "0" as "0x80" instead of as "0". We handle this edge case explicitly // here. if (result == 0 || result == STRING_SHORT_START) { return false; } else { return true; } } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(uint160(toUint(item))); } function toUint(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33); (uint256 memPtr, uint256 len) = payloadLocation(item); uint256 result; assembly { result := mload(memPtr) // shift to the correct location if neccesary if lt(len, 32) { result := div(result, exp(256, sub(32, len))) } } return result; } // enforces 32 byte length function toUintStrict(RLPItem memory item) internal pure returns (uint256) { // one byte prefix require(item.len == 33); uint256 result; uint256 memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); (uint256 memPtr, uint256 len) = payloadLocation(item); bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(0x20, result) } copy(memPtr, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint256 memPtr) private pure returns (uint256) { uint256 itemLen; uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { itemLen = 1; } else if (byte0 < STRING_LONG_START) { itemLen = byte0 - STRING_SHORT_START + 1; } else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint256 memPtr) private pure returns (uint256) { uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { return 0; } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) { return 1; } else if (byte0 < LIST_SHORT_START) { // being explicit return byte0 - (STRING_LONG_START - 1) + 1; } else { return byte0 - (LIST_LONG_START - 1) + 1; } } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy(uint256 src, uint256 dest, uint256 len) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } if (len > 0) { // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256**(WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Bytes } from "../Bytes.sol"; import { RLPReader } from "../rlp/RLPReader.sol"; /// @title MerkleTrie /// @notice MerkleTrie is a small library for verifying standard Ethereum Merkle-Patricia trie /// inclusion proofs. By default, this library assumes a hexary trie. One can change the /// trie radix constant to support other trie radixes. library MerkleTrie { /// @notice Struct representing a node in the trie. /// @custom:field encoded The RLP-encoded node. /// @custom:field decoded The RLP-decoded node. struct TrieNode { bytes encoded; RLPReader.RLPItem[] decoded; } /// @notice Determines the number of elements per branch node. uint256 internal constant TREE_RADIX = 16; /// @notice Branch nodes have TREE_RADIX elements and one value element. uint256 internal constant BRANCH_NODE_LENGTH = TREE_RADIX + 1; /// @notice Leaf nodes and extension nodes have two elements, a `path` and a `value`. uint256 internal constant LEAF_OR_EXTENSION_NODE_LENGTH = 2; /// @notice Prefix for even-nibbled extension node paths. uint8 internal constant PREFIX_EXTENSION_EVEN = 0; /// @notice Prefix for odd-nibbled extension node paths. uint8 internal constant PREFIX_EXTENSION_ODD = 1; /// @notice Prefix for even-nibbled leaf node paths. uint8 internal constant PREFIX_LEAF_EVEN = 2; /// @notice Prefix for odd-nibbled leaf node paths. uint8 internal constant PREFIX_LEAF_ODD = 3; /// @notice Verifies a proof that a given key/value pair is present in the 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 valid_ Whether or not the proof is valid. function verifyInclusionProof( bytes memory _key, bytes memory _value, bytes[] memory _proof, bytes32 _root ) internal pure returns (bool valid_) { valid_ = Bytes.equal(_value, get(_key, _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 value_ Value of the key if it exists. function get(bytes memory _key, bytes[] memory _proof, bytes32 _root) internal pure returns (bytes memory value_) { require(_key.length > 0, "MerkleTrie: empty key"); TrieNode[] memory proof = _parseProof(_proof); bytes memory key = Bytes.toNibbles(_key); bytes memory currentNodeID = abi.encodePacked(_root); uint256 currentKeyIndex = 0; // Proof is top-down, so we start at the first element (root). for (uint256 i = 0; i < proof.length; i++) { TrieNode memory currentNode = proof[i]; // Key index should never exceed total key length or we'll be out of bounds. require(currentKeyIndex <= key.length, "MerkleTrie: key index exceeds total key length"); if (currentKeyIndex == 0) { // First proof element is always the root node. require( Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID), "MerkleTrie: invalid root hash" ); } else if (currentNode.encoded.length >= 32) { // Nodes 32 bytes or larger are hashed inside branch nodes. require( Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID), "MerkleTrie: invalid large internal hash" ); } else { // Nodes smaller than 32 bytes aren't hashed. require(Bytes.equal(currentNode.encoded, currentNodeID), "MerkleTrie: invalid internal node hash"); } if (currentNode.decoded.length == BRANCH_NODE_LENGTH) { if (currentKeyIndex == key.length) { // Value is the last element of the decoded list (for branch nodes). There's // some ambiguity in the Merkle trie specification because bytes(0) is a // valid value to place into the trie, but for branch nodes bytes(0) can exist // even when the value wasn't explicitly placed there. Geth treats a value of // bytes(0) as "key does not exist" and so we do the same. value_ = RLPReader.readBytes(currentNode.decoded[TREE_RADIX]); require(value_.length > 0, "MerkleTrie: value length must be greater than zero (branch)"); // Extra proof elements are not allowed. require(i == proof.length - 1, "MerkleTrie: value node must be last node in proof (branch)"); return value_; } 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]); RLPReader.RLPItem memory nextNode = currentNode.decoded[branchKey]; currentNodeID = _getNodeID(nextNode); currentKeyIndex += 1; } } 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 = Bytes.slice(path, offset); bytes memory keyRemainder = Bytes.slice(key, currentKeyIndex); uint256 sharedNibbleLength = _getSharedNibbleLength(pathRemainder, keyRemainder); // Whether this is a leaf node or an extension node, the path remainder MUST be a // prefix of the key remainder (or be equal to the key remainder) or the proof is // considered invalid. require( pathRemainder.length == sharedNibbleLength, "MerkleTrie: path remainder must share all nibbles with key" ); if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) { // Prefix of 2 or 3 means this is a leaf node. For the leaf node to be valid, // the key remainder must be exactly equal to the path remainder. We already // did the necessary byte comparison, so it's more efficient here to check that // the key remainder length equals the shared nibble length, which implies // equality with the path remainder (since we already did the same check with // the path remainder and the shared nibble length). require( keyRemainder.length == sharedNibbleLength, "MerkleTrie: key remainder must be identical to path remainder" ); // Our Merkle Trie is designed specifically for the purposes of the Ethereum // state trie. Empty values are not allowed in the state trie, so we can safely // say that if the value is empty, the key should not exist and the proof is // invalid. value_ = RLPReader.readBytes(currentNode.decoded[1]); require(value_.length > 0, "MerkleTrie: value length must be greater than zero (leaf)"); // Extra proof elements are not allowed. require(i == proof.length - 1, "MerkleTrie: value node must be last node in proof (leaf)"); return value_; } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) { // Prefix of 0 or 1 means this is an extension node. We move onto the next node // in the proof and increment the key index by the length of the path remainder // which is equal to the shared nibble length. currentNodeID = _getNodeID(currentNode.decoded[1]); currentKeyIndex += sharedNibbleLength; } else { revert("MerkleTrie: received a node with an unknown prefix"); } } else { revert("MerkleTrie: received an unparseable node"); } } revert("MerkleTrie: ran out of proof elements"); } /// @notice Parses an array of proof elements into a new array that contains both the original /// encoded element and the RLP-decoded element. /// @param _proof Array of proof elements to parse. /// @return proof_ Proof parsed into easily accessible structs. function _parseProof(bytes[] memory _proof) private pure returns (TrieNode[] memory proof_) { uint256 length = _proof.length; proof_ = new TrieNode[](length); for (uint256 i = 0; i < length;) { proof_[i] = TrieNode({ encoded: _proof[i], decoded: RLPReader.readList(_proof[i]) }); unchecked { ++i; } } } /// @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 id_ ID for the node, depending on the size of its contents. function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes memory id_) { id_ = _node.length < 32 ? RLPReader.readRawBytes(_node) : RLPReader.readBytes(_node); } /// @notice Gets the path for a leaf or extension node. /// @param _node Node to get a path for. /// @return nibbles_ Node path, converted to an array of nibbles. function _getNodePath(TrieNode memory _node) private pure returns (bytes memory nibbles_) { nibbles_ = Bytes.toNibbles(RLPReader.readBytes(_node.decoded[0])); } /// @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 max = (_a.length < _b.length) ? _a.length : _b.length; for (; shared_ < max && _a[shared_] == _b[shared_];) { unchecked { ++shared_; } } } }
pragma solidity ^0.8.19; interface IL1BlockOracle { /// @notice The latest L1 block hash. function hash() external returns (bytes32); }
pragma solidity ^0.8.19; struct RingBuffer10 { uint256[10] items; uint8 start; uint8 end; uint8 size; } using RingBufferLib for RingBuffer10 global; library RingBufferLib { error RingBufferLengthMismatch(uint256 expected, uint256 actual); function append(RingBuffer10 storage buffer, uint256 value) internal { buffer.items[buffer.end] = value; buffer.end = (buffer.end + 1) % uint8(buffer.items.length); if (buffer.size < buffer.items.length) { buffer.size += 1; } else { buffer.start = (buffer.start + 1) % uint8(buffer.items.length); } } function getItem(RingBuffer10 storage buffer, uint256 index) internal view returns (uint256) { return buffer.items[(buffer.start + index) % buffer.items.length]; } function getItem(RingBuffer10 memory buffer, uint256 index) internal pure returns (uint256) { return buffer.items[(buffer.start + index) % buffer.items.length]; } function update(RingBuffer10 storage buffer, RingBuffer10 memory newBuffer) internal { if (buffer.items.length != newBuffer.items.length) { revert RingBufferLengthMismatch(buffer.items.length, newBuffer.items.length); } buffer.start = newBuffer.start; buffer.end = newBuffer.end; buffer.size = newBuffer.size; for (uint256 i = 0; i < buffer.items.length; i++) { buffer.items[i] = newBuffer.items[i]; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Bytes /// @notice Bytes is a library for manipulating byte arrays. library Bytes { /// @custom:attribution https://github.com/GNSPS/solidity-bytes-utils /// @notice Slices a byte array with a given starting index and length. Returns a new byte array /// as opposed to a pointer to the original array. Will throw if trying to slice more /// bytes than exist in the array. /// @param _bytes Byte array to slice. /// @param _start Starting index of the slice. /// @param _length Length of the slice. /// @return Slice of the input byte array. function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { unchecked { 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; } /// @notice Slices a byte array with a given starting index up to the end of the original byte /// array. Returns a new array rathern than a pointer to the original. /// @param _bytes Byte array to slice. /// @param _start Starting index of the slice. /// @return Slice of the input byte array. 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); } /// @notice Converts a byte array into a nibble array by splitting each byte into two nibbles. /// Resulting nibble array will be exactly twice as long as the input byte array. /// @param _bytes Input byte array to convert. /// @return Resulting nibble array. function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) { bytes memory _nibbles; assembly { // Grab a free memory offset for the new array _nibbles := mload(0x40) // Load the length of the passed bytes array from memory let bytesLength := mload(_bytes) // Calculate the length of the new nibble array // This is the length of the input array times 2 let nibblesLength := shl(0x01, bytesLength) // Update the free memory pointer to allocate memory for the new array. // To do this, we add the length of the new array + 32 bytes for the array length // rounded up to the nearest 32 byte boundary to the current free memory pointer. mstore(0x40, add(_nibbles, and(not(0x1F), add(nibblesLength, 0x3F)))) // Store the length of the new array in memory mstore(_nibbles, nibblesLength) // Store the memory offset of the _bytes array's contents on the stack let bytesStart := add(_bytes, 0x20) // Store the memory offset of the nibbles array's contents on the stack let nibblesStart := add(_nibbles, 0x20) // Loop through each byte in the input array for { let i := 0x00 } lt(i, bytesLength) { i := add(i, 0x01) } { // Get the starting offset of the next 2 bytes in the nibbles array let offset := add(nibblesStart, shl(0x01, i)) // Load the byte at the current index within the `_bytes` array let b := byte(0x00, mload(add(bytesStart, i))) // Pull out the first nibble and store it in the new array mstore8(offset, shr(0x04, b)) // Pull out the second nibble and store it in the new array mstore8(add(offset, 0x01), and(b, 0x0F)) } } return _nibbles; } /// @notice Compares two byte arrays by comparing their keccak256 hashes. /// @param _bytes First byte array to compare. /// @param _other Second byte array to compare. /// @return True if the two byte arrays are equal, false otherwise. 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.8; /// @custom:attribution https://github.com/hamdiallam/Solidity-RLP /// @title RLPReader /// @notice RLPReader is a library for parsing RLP-encoded byte arrays into Solidity types. Adapted /// from Solidity-RLP (https://github.com/hamdiallam/Solidity-RLP) by Hamdi Allam with /// various tweaks to improve readability. library RLPReader { /// @notice Custom pointer type to avoid confusion between pointers and uint256s. type MemoryPointer is uint256; /// @notice RLP item types. /// @custom:value DATA_ITEM Represents an RLP data item (NOT a list). /// @custom:value LIST_ITEM Represents an RLP list item. enum RLPItemType { DATA_ITEM, LIST_ITEM } /// @notice Struct representing an RLP item. /// @custom:field length Length of the RLP item. /// @custom:field ptr Pointer to the RLP item in memory. struct RLPItem { uint256 length; MemoryPointer ptr; } /// @notice Max list length that this library will accept. uint256 internal constant MAX_LIST_LENGTH = 32; /// @notice Converts bytes to a reference to memory position and length. /// @param _in Input bytes to convert. /// @return out_ Output memory reference. function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory out_) { // Empty arrays are not RLP items. require(_in.length > 0, "RLPReader: length of an RLP item must be greater than zero to be decodable"); MemoryPointer ptr; assembly { ptr := add(_in, 32) } out_ = RLPItem({ length: _in.length, ptr: ptr }); } /// @notice Reads an RLP list value into a list of RLP items. /// @param _in RLP list value. /// @return out_ Decoded RLP list items. function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory out_) { (uint256 listOffset, uint256 listLength, RLPItemType itemType) = _decodeLength(_in); require(itemType == RLPItemType.LIST_ITEM, "RLPReader: decoded item type for list is not a list item"); require(listOffset + listLength == _in.length, "RLPReader: list item has an invalid data remainder"); // 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. out_ = new RLPItem[](MAX_LIST_LENGTH); uint256 itemCount = 0; uint256 offset = listOffset; while (offset < _in.length) { (uint256 itemOffset, uint256 itemLength,) = _decodeLength( RLPItem({ length: _in.length - offset, ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset) }) ); // We don't need to check itemCount < out.length explicitly because Solidity already // handles this check on our behalf, we'd just be wasting gas. out_[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset) }); itemCount += 1; offset += itemOffset + itemLength; } // Decrease the array size to match the actual item count. assembly { mstore(out_, itemCount) } } /// @notice Reads an RLP list value into a list of RLP items. /// @param _in RLP list value. /// @return out_ Decoded RLP list items. function readList(bytes memory _in) internal pure returns (RLPItem[] memory out_) { out_ = readList(toRLPItem(_in)); } /// @notice Reads an RLP bytes value into bytes. /// @param _in RLP bytes value. /// @return out_ Decoded bytes. function readBytes(RLPItem memory _in) internal pure returns (bytes memory out_) { (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in); require(itemType == RLPItemType.DATA_ITEM, "RLPReader: decoded item type for bytes is not a data item"); require(_in.length == itemOffset + itemLength, "RLPReader: bytes value contains an invalid remainder"); out_ = _copy(_in.ptr, itemOffset, itemLength); } /// @notice Reads an RLP bytes value into bytes. /// @param _in RLP bytes value. /// @return out_ Decoded bytes. function readBytes(bytes memory _in) internal pure returns (bytes memory out_) { out_ = readBytes(toRLPItem(_in)); } /// @notice Reads the raw bytes of an RLP item. /// @param _in RLP item to read. /// @return out_ Raw RLP bytes. function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory out_) { out_ = _copy(_in.ptr, 0, _in.length); } /// @notice Decodes the length of an RLP item. /// @param _in RLP item to decode. /// @return offset_ Offset of the encoded data. /// @return length_ Length of the encoded data. /// @return type_ RLP item type (LIST_ITEM or DATA_ITEM). function _decodeLength(RLPItem memory _in) private pure returns (uint256 offset_, uint256 length_, RLPItemType type_) { // Short-circuit if there's nothing to decode, note that we perform this check when // the user creates an RLP item via toRLPItem, but it's always possible for them to bypass // that function and create an RLP item directly. So we need to check this anyway. require(_in.length > 0, "RLPReader: length of an RLP item must be greater than zero to be decodable"); MemoryPointer 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. // slither-disable-next-line variable-scope uint256 strLen = prefix - 0x80; require( _in.length > strLen, "RLPReader: length of content must be greater than string length (short string)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( strLen != 1 || firstByteOfContent >= 0x80, "RLPReader: invalid prefix, single byte < 0x80 are not prefixed (short string)" ); return (1, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xbf) { // Long string. uint256 lenOfStrLen = prefix - 0xb7; require( _in.length > lenOfStrLen, "RLPReader: length of content must be > than length of string length (long string)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( firstByteOfContent != 0x00, "RLPReader: length of content must not have any leading zeros (long string)" ); uint256 strLen; assembly { strLen := shr(sub(256, mul(8, lenOfStrLen)), mload(add(ptr, 1))) } require(strLen > 55, "RLPReader: length of content must be greater than 55 bytes (long string)"); require( _in.length > lenOfStrLen + strLen, "RLPReader: length of content must be greater than total length (long string)" ); return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xf7) { // Short list. // slither-disable-next-line variable-scope uint256 listLen = prefix - 0xc0; require(_in.length > listLen, "RLPReader: length of content must be greater than list length (short list)"); return (1, listLen, RLPItemType.LIST_ITEM); } else { // Long list. uint256 lenOfListLen = prefix - 0xf7; require( _in.length > lenOfListLen, "RLPReader: length of content must be > than length of list length (long list)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( firstByteOfContent != 0x00, "RLPReader: length of content must not have any leading zeros (long list)" ); uint256 listLen; assembly { listLen := shr(sub(256, mul(8, lenOfListLen)), mload(add(ptr, 1))) } require(listLen > 55, "RLPReader: length of content must be greater than 55 bytes (long list)"); require( _in.length > lenOfListLen + listLen, "RLPReader: length of content must be greater than total length (long list)" ); return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM); } } /// @notice 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 out_ Copied bytes. function _copy(MemoryPointer _src, uint256 _offset, uint256 _length) private pure returns (bytes memory out_) { out_ = new bytes(_length); if (_length == 0) { return out_; } // Mostly based on Solidity's copy_memory_to_memory: // https://github.com/ethereum/solidity/blob/34dd30d71b4da730488be72ff6af7083cf2a91f6/libsolidity/codegen/YulUtilFunctions.cpp#L102-L114 uint256 src = MemoryPointer.unwrap(_src) + _offset; assembly { let dest := add(out_, 32) let i := 0 for { } lt(i, _length) { i := add(i, 32) } { mstore(add(dest, i), mload(add(src, i))) } if gt(i, _length) { mstore(add(dest, _length), 0) } } } }
{ "remappings": [ "forge-std/=lib/forge-std/src/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@account-abstraction/=lib/account-abstraction/contracts/", "@poseidon-solidity/=lib/poseidon-solidity/contracts/", "@webauthn-sol/=lib/webauthn-sol/src/", "eip-4788-proof/=lib/eip-4788-proof/src/", "FreshCryptoLib/=lib/webauthn-sol/lib/FreshCryptoLib/solidity/src/", "Solidity-RLP/=lib/Solidity-RLP/contracts/", "account-abstraction/=lib/account-abstraction/contracts/", "clones-with-immutable-args/=lib/optimism/packages/contracts-bedrock/lib/clones-with-immutable-args/src/", "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "kontrol-cheatcodes/=lib/optimism/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/", "lib-keccak/=lib/optimism/packages/contracts-bedrock/lib/lib-keccak/contracts/", "openzeppelin-contracts-upgradeable/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "optimism/=lib/optimism/", "poseidon-solidity/=lib/poseidon-solidity/contracts/", "safe-contracts/=lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts/", "solady/=lib/webauthn-sol/lib/solady/src/", "solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/src/", "webauthn-sol/=lib/webauthn-sol/src/" ], "optimizer": { "enabled": true, "runs": 999999 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": true, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"l1KeyStore_","type":"address"},{"internalType":"bytes32","name":"slotHash_","type":"bytes32"},{"internalType":"address","name":"l1BlockOracle_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"latestBlockHashRegistered","type":"bytes32"}],"name":"InvalidProofBlockHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"latestBlockNumber","type":"uint256"}],"name":"StaleProof","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"root","type":"uint256"}],"name":"RootUpdated","type":"event"},{"inputs":[],"name":"l1BlockOracle","outputs":[{"internalType":"contract IL1BlockOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1KeyStore","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBlockHashRegistered","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"roots","outputs":[{"internalType":"uint8","name":"start","type":"uint8"},{"internalType":"uint8","name":"end","type":"uint8"},{"internalType":"uint8","name":"size","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"blockHeaderRlp","type":"bytes"},{"internalType":"bytes[]","name":"accountProof","type":"bytes[]"},{"internalType":"bytes[]","name":"slotProof","type":"bytes[]"}],"name":"setRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slotHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60e0346100ac57601f612d5e38819003918201601f19168301916001600160401b038311848410176100b0578084926060946040528339810103126100ac57610047816100c4565b906100596040602083015192016100c4565b60809290925260a0526001600160a01b031660c052604051612c8590816100d982396080518181816103fa01526106dc015260a0518181816104df01526105e0015260c05181818160e901526107720152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036100ac5756fe60806040526004361015610011575f80fd5b5f3560e01c806304901fc1146100a45780630e9754b61461009f578063141db3201461009a57806319d389cf14610095578063393fe1cd146100905780634599c7881461008b57806355c7f09514610086578063ccac0007146100815763ebf0c7171461007c575f80fd5b6107e5565b610700565b610692565b610657565b610603565b6105ab565b610308565b610116565b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660805260206080f35b5f80fd5b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576020600c54604051908152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761019a57604052565b610151565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761019a57604052565b604051906101ef60408361019f565b565b67ffffffffffffffff811161019a57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f8201121561011257803590610242826101f1565b92610250604051948561019f565b8284526020838301011161011257815f926020809301838601378301015290565b67ffffffffffffffff811161019a5760051b60200190565b9080601f830112156101125781356102a081610271565b926102ae604051948561019f565b81845260208085019260051b820101918383116101125760208201905b8382106102da57505050505090565b813567ffffffffffffffff8111610112576020916102fd8784809488010161022b565b8152019101906102cb565b346101125760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125760043567ffffffffffffffff81116101125761035790369060040161022b565b60243567ffffffffffffffff811161011257610377903690600401610289565b60443567ffffffffffffffff81116101125761039a6103a0913690600401610289565b926108cb565b90600d54916040810192835180821161057d5750508051600c549081810361054f5750506104bd610527946104d26104cc6104c76104c26104bd6104896105159960206105109a6104b560405183810190610474816104487f0000000000000000000000000000000000000000000000000000000000000000857fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060149260601b1681520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261019f565b51902060405195869185830160209181520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810186528561019f565b015191611070565b6114da565b611500565b61084c565b516115e9565b9060405161050b816104487f00000000000000000000000000000000000000000000000000000000000000006020830160209181520190565b611070565b6115e9565b5f556105215f5461165a565b51600d55565b5f547fb0644cedd466048fffec12002a45bb9b94385438367a9762bb7f6f025b3c19fc5f80a2005b7f72f6b175000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feb398a78000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576060600b5460ff604051918181168352818160081c16602084015260101c166040820152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576020600d54604051908152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011257602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576040517f09bd5a600000000000000000000000000000000000000000000000000000000081526020816004815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af180156107da575f906107a757600c55005b005b506020813d6020116107d2575b816107c16020938361019f565b810103126101125751600c556107a5005b3d91506107b4565b6040513d5f823e3d90fd5b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125760205f54604051908152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80516002101561085c5760600190565b61081f565b80516001101561085c5760400190565b80516010101561085c576102200190565b805182101561085c5760209160051b010190565b604051906080820182811067ffffffffffffffff82111761019a576040525f6060838281528260208201528260408201520152565b6108d3610896565b506108dc610896565b906108e96104c2826114da565b80516003101561085c5761090060808201516115e9565b602084015280516008101561085c5761091d6101208201516115e9565b60408401528051600b101561085c5761018061093a9101516115e9565b606083015260208151910120815290565b1561095257565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d65726b6c65547269653a20656d707479206b657900000000000000000000006044820152fd5b156109b757565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201527f74616c206b6579206c656e6774680000000000000000000000000000000000006064820152fd5b15610a4257565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f6460448201527f65206861736800000000000000000000000000000000000000000000000000006064820152fd5b15610acd57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e60448201527f616c2068617368000000000000000000000000000000000000000000000000006064820152fd5b15610b5857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9060018201809211610bf157565b610bb6565b6001019081600111610bf157565b91908201809211610bf157565b80511561085c5760200190565b90815181101561085c570160200190565b60ff166002039060ff8211610bf157565b15610c4757565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152fd5b15610cd257565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152fd5b15610d5d57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152fd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff098201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff498201918211610bf157565b91908203918211610bf157565b15610ed657565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152fd5b15610f6157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152fd5b15610fec57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152fd5b91906110aa6110966110906104489361108b8751151561094b565b61176d565b94611842565b926040519283916020830160209181520190565b5f80926011905b855185101561143d576110c48587610882565b51936110d382518511156109b0565b836113e557611114611119916104486111018851602081519101206040519283916020830160209181520190565b6020815191012090602081519101201490565b610b51565b602084019382855151145f146111db57508051830361116b575050509061116261114f6111496111689451610871565b51611b2b565b9361115c85511515610f5a565b51610de1565b14610fe5565b90565b919390926111cf6111c96111c360019360ff6111b96111b361118d8c8b610c1e565b517fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b9151911690610882565b51611a45565b95610be3565b915b01939290916110b1565b60028596959492945151145f14611360576111f5906118b1565b916112246112086111b361118d86610c11565b9361121e61121860018716610c2f565b60ff1690565b906118d1565b9360ff61123184836118d1565b9461124861123f87896119a8565b80985114610c40565b16600281148015611356575b1561128f5750505050611149611168946112766112899461127c945114610ccb565b51610861565b9361115c85511515610d56565b14610ecf565b8091959397929694501590811561134b575b50156112c6576001916112ba6111c36112c09351610861565b96610c04565b916111d1565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f6465207769746860448201527f20616e20756e6b6e6f776e2070726566697800000000000000000000000000006064820152608490fd5b60019150145f6112a1565b5060038114611254565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e70617273656160448201527f626c65206e6f64650000000000000000000000000000000000000000000000006064820152608490fd5b84518051602011611424575061141a61141f916104486111018851602081519101206040519283916020830160209181520190565b610ac6565b611119565b80516020918201208251919092012061141f9114610a3b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c6560448201527f6d656e74730000000000000000000000000000000000000000000000000000006064820152608490fd5b604051906114cf8261017e565b5f6020838281520152565b6114e26114c2565b506020815191604051926114f58461017e565b835201602082015290565b61150981611bea565b156101125761151781611c0e565b61152081610271565b9161152e604051938461019f565b8183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061155b83610271565b015f5b8181106115d2575050602061157e91015161157881611c90565b90610c04565b5f905b82821061158e5750505090565b6115ca8161159d600193611cfb565b906115a66101e0565b8281528160208201526115b98689610882565b526115c48588610882565b50610c04565b910190611581565b6020906115dd6114c2565b8282880101520161155e565b8051801515908161163c575b501561011257602081019061160a8251611c90565b915190828201809211610bf15751918203918211610bf157519060208110611630575090565b6020036101000a900490565b6021915011155f6115f5565b60ff60019116019060ff8211610bf157565b60ff600b5460081c16600a81101561085c57600101556116c661169161168760ff600b5460081c16611648565b60ff600a91160690565b600b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff61ff0083549260081b169116179055565b600b54600a601082901c60ff16101561172b57506101ef6116f56116f0600b5460ff9060101c1690565b611648565b600b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff62ff000083549260101b169116179055565b61173e6116876116f06101ef9360ff1690565b600b9060ff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b90815161177981610271565b611786604051918261019f565b8181527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06117b383610271565b015f5b81811061181d57505080935f5b8381106117d05750505050565b806117dd60019284610882565b516117f16117eb8386610882565b51611db5565b6117f96101e0565b918252602082015261180b8286610882565b526118168185610882565b50016117c3565b60209060405161182c8161017e565b60608152606083820152828286010152016117b6565b604051908051908160011b603f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016840160405283525f5b8281106118895750505090565b80600191821b85016021600f602084870101515f1a8060041c6020850153169101530161187c565b6020015180511561085c576118cc6020611168920151611b2b565b611842565b90815181101561199257815181810390808211610bf15782906118f983601f81011015611ec4565b61191483830161190b84821015611ec4565b86511015611f29565b0361192c575050506040515f81526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b80841061197f5750508252601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660405290565b9092602080918551815201930190611949565b50506040516119a260208261019f565b5f815290565b805182515f949391859180821015611a3c575094505b5b848110806119db575b156119d5576001016119bf565b93505050565b507fff00000000000000000000000000000000000000000000000000000000000000611a078285610c1e565b51167fff00000000000000000000000000000000000000000000000000000000000000611a348385610c1e565b5116146119c8565b905094506119be565b60208151105f14611a605760208101519051611168916129bc565b61116890611b2b565b60021115611a7357565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b15611aa757565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527f616e20696e76616c69642072656d61696e6465720000000000000000000000006064820152fd5b611b34816127da565b6002819392931015611a7357611b6657602083611b5f6111689551611b598686610c04565b14611aa0565b0151612a47565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152fd5b805115611c0957602060c0910151515f1a10611c0557600190565b5f90565b505f90565b805115611c09575f9060208101908151611c2781611c90565b8101809111610bf157915190518101809111610bf15791905b828110611c4d5750905090565b611c5681611cfb565b8101809111610bf157907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610bf15760010190611c40565b515f1a6080811015611ca157505f90565b60b881108015611ce5575b15611cb75750600190565b60c0811015611cd65761116890611cd19060b75b90610ec2565b610be3565b61116890611cd19060f7611ccb565b5060c08110158015611cac575060f88110611cac565b80515f1a906080821015611d10575050600190565b60b8821015611d265750611cd161116891610e3b565b60c0821015611d675760010151602082900360b7016101000a9004017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a0190565b60f8821015611d7d5750611cd161116891610e0e565b60010151602082900360f7016101000a9004017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a0190565b90611dbe6114c2565b50611dcb82511515611f8e565b81519160405192611ddb8461017e565b8352602080840191018152611e0f611e1d611e156001611dfa876127da565b611e0981979397949294611a69565b14612ada565b83610c04565b855114612b65565b611e25612bf0565b925f915b855180821015611eb95790611578611eae611e6a611e4a84611eb496610ec2565b611e55858a51610c04565b611e5d6101e0565b91825260208201526127da565b50919096611e788884610c04565b611e83868b51610c04565b611e8b6101e0565b9182526020820152611e9d828c610882565b52611ea8818b610882565b50610be3565b95610c04565b611e29565b505093509050815290565b15611ecb57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152fd5b15611f3057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152fd5b15611f9557565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c65000000000000000000000000000000000000000000006084820152fd5b1561204657565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201527f6820286c6f6e67206c69737429000000000000000000000000000000000000006084820152fd5b156120f757565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e67206c697374290000000000000000000000000000000000000000000000006084820152fd5b156121a857565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f206c6973742900000000000000000000000000000000000000000000000000006084820152fd5b1561225957565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e67206c69737429000000000000000000000000000000000000000000006084820152fd5b1561230a57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e206c697374206c656e67746820287360648201527f686f7274206c69737429000000000000000000000000000000000000000000006084820152fd5b156123bb57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527f67746820286c6f6e6720737472696e67290000000000000000000000000000006084820152fd5b1561246c57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e6720737472696e6729000000000000000000000000000000000000000000006084820152fd5b1561251d57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f20737472696e67290000000000000000000000000000000000000000000000006084820152fd5b156125ce57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e6720737472696e672900000000000000000000000000000000000000006084820152fd5b1561267f57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201527f2873686f727420737472696e67290000000000000000000000000000000000006084820152fd5b1561273057565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201527f73686f727420737472696e6729000000000000000000000000000000000000006084820152fd5b906127e782511515611f8e565b602082015180515f1a90607f821161280557505f9250600191839150565b60b782116128925760017fff000000000000000000000000000000000000000000000000000000000000009161284961284061285f95610e3b565b80975111612678565b0151166001841490811591612867575b50612729565b600191905f90565b7f8000000000000000000000000000000000000000000000000000000000000000915010155f612859565b60bf821161291a5761290f60016128ab61291494610e95565b926128b8848851116123b4565b016128e77fff000000000000000000000000000000000000000000000000000000000000008251161515612465565b518260031b610100031c946128fe60378711612516565b516129098684610c04565b106125c7565b610bf6565b91905f90565b60f78211612940575061292f61293891610e0e565b80935111612303565b600191908290565b61290f60016129516129b594610e68565b9261295e8488511161203f565b0161298d7fff0000000000000000000000000000000000000000000000000000000000000082511615156120f0565b518260031b610100031c946129a4603787116121a1565b516129af8684610c04565b10612252565b9190600190565b91906129c7816101f1565b926129d5604051948561019f565b8184527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612a02836101f1565b013660208601378382156119d5575081905f905b828210612a30575011612a265750565b60205f9184010152565b915080602091830151828288010152018291612a16565b92919092612a54826101f1565b93612a62604051958661019f565b8285527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612a8f846101f1565b01366020870137848315612ad357508101809111610bf15781905f905b828210612abc575011612a265750565b915080602091830151828288010152018291612aac565b9450505050565b15612ae157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152fd5b15612b6c57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e766160448201527f6c696420646174612072656d61696e64657200000000000000000000000000006064820152fd5b6040516104209190612c02838261019f565b60208152917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001825f5b828110612c3857505050565b602090612c436114c2565b82828501015201612c2c56fea2646970667358221220e5d51da4c15ff2505b1efe152de0add6fbf332ed6918655c8e83c7c48d78e92164736f6c634300081a003300000000000000000000000045b924ee3ee404e4a9e2a3afd0ad357eff79fc49290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630000000000000000000000004200000000000000000000000000000000000015
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806304901fc1146100a45780630e9754b61461009f578063141db3201461009a57806319d389cf14610095578063393fe1cd146100905780634599c7881461008b57806355c7f09514610086578063ccac0007146100815763ebf0c7171461007c575f80fd5b6107e5565b610700565b610692565b610657565b610603565b6105ab565b610308565b610116565b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000042000000000000000000000000000000000000151660805260206080f35b5f80fd5b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576020600c54604051908152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761019a57604052565b610151565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761019a57604052565b604051906101ef60408361019f565b565b67ffffffffffffffff811161019a57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f8201121561011257803590610242826101f1565b92610250604051948561019f565b8284526020838301011161011257815f926020809301838601378301015290565b67ffffffffffffffff811161019a5760051b60200190565b9080601f830112156101125781356102a081610271565b926102ae604051948561019f565b81845260208085019260051b820101918383116101125760208201905b8382106102da57505050505090565b813567ffffffffffffffff8111610112576020916102fd8784809488010161022b565b8152019101906102cb565b346101125760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125760043567ffffffffffffffff81116101125761035790369060040161022b565b60243567ffffffffffffffff811161011257610377903690600401610289565b60443567ffffffffffffffff81116101125761039a6103a0913690600401610289565b926108cb565b90600d54916040810192835180821161057d5750508051600c549081810361054f5750506104bd610527946104d26104cc6104c76104c26104bd6104896105159960206105109a6104b560405183810190610474816104487f00000000000000000000000045b924ee3ee404e4a9e2a3afd0ad357eff79fc49857fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060149260601b1681520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261019f565b51902060405195869185830160209181520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810186528561019f565b015191611070565b6114da565b611500565b61084c565b516115e9565b9060405161050b816104487f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5636020830160209181520190565b611070565b6115e9565b5f556105215f5461165a565b51600d55565b5f547fb0644cedd466048fffec12002a45bb9b94385438367a9762bb7f6f025b3c19fc5f80a2005b7f72f6b175000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feb398a78000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125760206040517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5638152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576060600b5460ff604051918181168352818160081c16602084015260101c166040820152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576020600d54604051908152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011257602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000045b924ee3ee404e4a9e2a3afd0ad357eff79fc49168152f35b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610112576040517f09bd5a600000000000000000000000000000000000000000000000000000000081526020816004815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004200000000000000000000000000000000000015165af180156107da575f906107a757600c55005b005b506020813d6020116107d2575b816107c16020938361019f565b810103126101125751600c556107a5005b3d91506107b4565b6040513d5f823e3d90fd5b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125760205f54604051908152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80516002101561085c5760600190565b61081f565b80516001101561085c5760400190565b80516010101561085c576102200190565b805182101561085c5760209160051b010190565b604051906080820182811067ffffffffffffffff82111761019a576040525f6060838281528260208201528260408201520152565b6108d3610896565b506108dc610896565b906108e96104c2826114da565b80516003101561085c5761090060808201516115e9565b602084015280516008101561085c5761091d6101208201516115e9565b60408401528051600b101561085c5761018061093a9101516115e9565b606083015260208151910120815290565b1561095257565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d65726b6c65547269653a20656d707479206b657900000000000000000000006044820152fd5b156109b757565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201527f74616c206b6579206c656e6774680000000000000000000000000000000000006064820152fd5b15610a4257565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f6460448201527f65206861736800000000000000000000000000000000000000000000000000006064820152fd5b15610acd57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e60448201527f616c2068617368000000000000000000000000000000000000000000000000006064820152fd5b15610b5857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9060018201809211610bf157565b610bb6565b6001019081600111610bf157565b91908201809211610bf157565b80511561085c5760200190565b90815181101561085c570160200190565b60ff166002039060ff8211610bf157565b15610c4757565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152fd5b15610cd257565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152fd5b15610d5d57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152fd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff098201918211610bf157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff498201918211610bf157565b91908203918211610bf157565b15610ed657565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152fd5b15610f6157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152fd5b15610fec57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152fd5b91906110aa6110966110906104489361108b8751151561094b565b61176d565b94611842565b926040519283916020830160209181520190565b5f80926011905b855185101561143d576110c48587610882565b51936110d382518511156109b0565b836113e557611114611119916104486111018851602081519101206040519283916020830160209181520190565b6020815191012090602081519101201490565b610b51565b602084019382855151145f146111db57508051830361116b575050509061116261114f6111496111689451610871565b51611b2b565b9361115c85511515610f5a565b51610de1565b14610fe5565b90565b919390926111cf6111c96111c360019360ff6111b96111b361118d8c8b610c1e565b517fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b9151911690610882565b51611a45565b95610be3565b915b01939290916110b1565b60028596959492945151145f14611360576111f5906118b1565b916112246112086111b361118d86610c11565b9361121e61121860018716610c2f565b60ff1690565b906118d1565b9360ff61123184836118d1565b9461124861123f87896119a8565b80985114610c40565b16600281148015611356575b1561128f5750505050611149611168946112766112899461127c945114610ccb565b51610861565b9361115c85511515610d56565b14610ecf565b8091959397929694501590811561134b575b50156112c6576001916112ba6111c36112c09351610861565b96610c04565b916111d1565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f6465207769746860448201527f20616e20756e6b6e6f776e2070726566697800000000000000000000000000006064820152608490fd5b60019150145f6112a1565b5060038114611254565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e70617273656160448201527f626c65206e6f64650000000000000000000000000000000000000000000000006064820152608490fd5b84518051602011611424575061141a61141f916104486111018851602081519101206040519283916020830160209181520190565b610ac6565b611119565b80516020918201208251919092012061141f9114610a3b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c6560448201527f6d656e74730000000000000000000000000000000000000000000000000000006064820152608490fd5b604051906114cf8261017e565b5f6020838281520152565b6114e26114c2565b506020815191604051926114f58461017e565b835201602082015290565b61150981611bea565b156101125761151781611c0e565b61152081610271565b9161152e604051938461019f565b8183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061155b83610271565b015f5b8181106115d2575050602061157e91015161157881611c90565b90610c04565b5f905b82821061158e5750505090565b6115ca8161159d600193611cfb565b906115a66101e0565b8281528160208201526115b98689610882565b526115c48588610882565b50610c04565b910190611581565b6020906115dd6114c2565b8282880101520161155e565b8051801515908161163c575b501561011257602081019061160a8251611c90565b915190828201809211610bf15751918203918211610bf157519060208110611630575090565b6020036101000a900490565b6021915011155f6115f5565b60ff60019116019060ff8211610bf157565b60ff600b5460081c16600a81101561085c57600101556116c661169161168760ff600b5460081c16611648565b60ff600a91160690565b600b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff61ff0083549260081b169116179055565b600b54600a601082901c60ff16101561172b57506101ef6116f56116f0600b5460ff9060101c1690565b611648565b600b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff62ff000083549260101b169116179055565b61173e6116876116f06101ef9360ff1690565b600b9060ff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b90815161177981610271565b611786604051918261019f565b8181527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06117b383610271565b015f5b81811061181d57505080935f5b8381106117d05750505050565b806117dd60019284610882565b516117f16117eb8386610882565b51611db5565b6117f96101e0565b918252602082015261180b8286610882565b526118168185610882565b50016117c3565b60209060405161182c8161017e565b60608152606083820152828286010152016117b6565b604051908051908160011b603f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016840160405283525f5b8281106118895750505090565b80600191821b85016021600f602084870101515f1a8060041c6020850153169101530161187c565b6020015180511561085c576118cc6020611168920151611b2b565b611842565b90815181101561199257815181810390808211610bf15782906118f983601f81011015611ec4565b61191483830161190b84821015611ec4565b86511015611f29565b0361192c575050506040515f81526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b80841061197f5750508252601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660405290565b9092602080918551815201930190611949565b50506040516119a260208261019f565b5f815290565b805182515f949391859180821015611a3c575094505b5b848110806119db575b156119d5576001016119bf565b93505050565b507fff00000000000000000000000000000000000000000000000000000000000000611a078285610c1e565b51167fff00000000000000000000000000000000000000000000000000000000000000611a348385610c1e565b5116146119c8565b905094506119be565b60208151105f14611a605760208101519051611168916129bc565b61116890611b2b565b60021115611a7357565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b15611aa757565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527f616e20696e76616c69642072656d61696e6465720000000000000000000000006064820152fd5b611b34816127da565b6002819392931015611a7357611b6657602083611b5f6111689551611b598686610c04565b14611aa0565b0151612a47565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152fd5b805115611c0957602060c0910151515f1a10611c0557600190565b5f90565b505f90565b805115611c09575f9060208101908151611c2781611c90565b8101809111610bf157915190518101809111610bf15791905b828110611c4d5750905090565b611c5681611cfb565b8101809111610bf157907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610bf15760010190611c40565b515f1a6080811015611ca157505f90565b60b881108015611ce5575b15611cb75750600190565b60c0811015611cd65761116890611cd19060b75b90610ec2565b610be3565b61116890611cd19060f7611ccb565b5060c08110158015611cac575060f88110611cac565b80515f1a906080821015611d10575050600190565b60b8821015611d265750611cd161116891610e3b565b60c0821015611d675760010151602082900360b7016101000a9004017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a0190565b60f8821015611d7d5750611cd161116891610e0e565b60010151602082900360f7016101000a9004017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a0190565b90611dbe6114c2565b50611dcb82511515611f8e565b81519160405192611ddb8461017e565b8352602080840191018152611e0f611e1d611e156001611dfa876127da565b611e0981979397949294611a69565b14612ada565b83610c04565b855114612b65565b611e25612bf0565b925f915b855180821015611eb95790611578611eae611e6a611e4a84611eb496610ec2565b611e55858a51610c04565b611e5d6101e0565b91825260208201526127da565b50919096611e788884610c04565b611e83868b51610c04565b611e8b6101e0565b9182526020820152611e9d828c610882565b52611ea8818b610882565b50610be3565b95610c04565b611e29565b505093509050815290565b15611ecb57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152fd5b15611f3057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152fd5b15611f9557565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c65000000000000000000000000000000000000000000006084820152fd5b1561204657565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201527f6820286c6f6e67206c69737429000000000000000000000000000000000000006084820152fd5b156120f757565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e67206c697374290000000000000000000000000000000000000000000000006084820152fd5b156121a857565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f206c6973742900000000000000000000000000000000000000000000000000006084820152fd5b1561225957565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e67206c69737429000000000000000000000000000000000000000000006084820152fd5b1561230a57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e206c697374206c656e67746820287360648201527f686f7274206c69737429000000000000000000000000000000000000000000006084820152fd5b156123bb57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527f67746820286c6f6e6720737472696e67290000000000000000000000000000006084820152fd5b1561246c57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e6720737472696e6729000000000000000000000000000000000000000000006084820152fd5b1561251d57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f20737472696e67290000000000000000000000000000000000000000000000006084820152fd5b156125ce57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e6720737472696e672900000000000000000000000000000000000000006084820152fd5b1561267f57565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201527f2873686f727420737472696e67290000000000000000000000000000000000006084820152fd5b1561273057565b60a46040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201527f73686f727420737472696e6729000000000000000000000000000000000000006084820152fd5b906127e782511515611f8e565b602082015180515f1a90607f821161280557505f9250600191839150565b60b782116128925760017fff000000000000000000000000000000000000000000000000000000000000009161284961284061285f95610e3b565b80975111612678565b0151166001841490811591612867575b50612729565b600191905f90565b7f8000000000000000000000000000000000000000000000000000000000000000915010155f612859565b60bf821161291a5761290f60016128ab61291494610e95565b926128b8848851116123b4565b016128e77fff000000000000000000000000000000000000000000000000000000000000008251161515612465565b518260031b610100031c946128fe60378711612516565b516129098684610c04565b106125c7565b610bf6565b91905f90565b60f78211612940575061292f61293891610e0e565b80935111612303565b600191908290565b61290f60016129516129b594610e68565b9261295e8488511161203f565b0161298d7fff0000000000000000000000000000000000000000000000000000000000000082511615156120f0565b518260031b610100031c946129a4603787116121a1565b516129af8684610c04565b10612252565b9190600190565b91906129c7816101f1565b926129d5604051948561019f565b8184527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612a02836101f1565b013660208601378382156119d5575081905f905b828210612a30575011612a265750565b60205f9184010152565b915080602091830151828288010152018291612a16565b92919092612a54826101f1565b93612a62604051958661019f565b8285527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612a8f846101f1565b01366020870137848315612ad357508101809111610bf15781905f905b828210612abc575011612a265750565b915080602091830151828288010152018291612aac565b9450505050565b15612ae157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152fd5b15612b6c57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e766160448201527f6c696420646174612072656d61696e64657200000000000000000000000000006064820152fd5b6040516104209190612c02838261019f565b60208152917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001825f5b828110612c3857505050565b602090612c436114c2565b82828501015201612c2c56fea2646970667358221220e5d51da4c15ff2505b1efe152de0add6fbf332ed6918655c8e83c7c48d78e92164736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000045b924ee3ee404e4a9e2a3afd0ad357eff79fc49290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630000000000000000000000004200000000000000000000000000000000000015
-----Decoded View---------------
Arg [0] : l1KeyStore_ (address): 0x45b924Ee3EE404E4a9E2a3AFD0AD357eFf79fC49
Arg [1] : slotHash_ (bytes32): 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563
Arg [2] : l1BlockOracle_ (address): 0x4200000000000000000000000000000000000015
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000045b924ee3ee404e4a9e2a3afd0ad357eff79fc49
Arg [1] : 290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563
Arg [2] : 0000000000000000000000004200000000000000000000000000000000000015
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.