OP Sepolia Testnet

Contract

0x610A7e97C6D2F1E09e6390F013BFCc39B8EE49e2

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Set Root187762062024-10-19 16:22:3215 days ago1729354952IN
0x610A7e97...9B8EE49e2
0 ETH0.0000038605180.00100025
Register Block187762042024-10-19 16:22:2815 days ago1729354948IN
0x610A7e97...9B8EE49e2
0 ETH0.0000001229510.00100025
Set Root183001322024-10-08 15:53:2426 days ago1728402804IN
0x610A7e97...9B8EE49e2
0 ETH0.0000009402530.00100025
Register Block183001302024-10-08 15:53:2026 days ago1728402800IN
0x610A7e97...9B8EE49e2
0 ETH0.0000000471280.00100025
Set Root180273552024-10-02 8:20:5032 days ago1727857250IN
0x610A7e97...9B8EE49e2
0 ETH0.0001240156080.00100026
Register Block180273492024-10-02 8:20:3832 days ago1727857238IN
0x610A7e97...9B8EE49e2
0 ETH0.000003237310.00100026
Set Root180273442024-10-02 8:20:2832 days ago1727857228IN
0x610A7e97...9B8EE49e2
0 ETH0.0001228428750.00100026
Register Block180273422024-10-02 8:20:2432 days ago1727857224IN
0x610A7e97...9B8EE49e2
0 ETH0.000003237310.00100026
Set Root180273402024-10-02 8:20:2032 days ago1727857220IN
0x610A7e97...9B8EE49e2
0 ETH0.0001228428750.00100026
Register Block180273342024-10-02 8:20:0832 days ago1727857208IN
0x610A7e97...9B8EE49e2
0 ETH0.0000032401110.00100026
Set Root180273312024-10-02 8:20:0232 days ago1727857202IN
0x610A7e97...9B8EE49e2
0 ETH0.0001186203850.00100025
Register Block180273272024-10-02 8:19:5432 days ago1727857194IN
0x610A7e97...9B8EE49e2
0 ETH0.0000031298750.00100025
Register Block180272892024-10-02 8:18:3832 days ago1727857118IN
0x610A7e97...9B8EE49e2
0 ETH0.0000032507940.00100025
Set Root180272772024-10-02 8:18:1432 days ago1727857094IN
0x610A7e97...9B8EE49e2
0 ETH0.0001172355330.00100025
Register Block180272742024-10-02 8:18:0832 days ago1727857088IN
0x610A7e97...9B8EE49e2
0 ETH0.0000030776190.00100025
Set Root180272702024-10-02 8:18:0032 days ago1727857080IN
0x610A7e97...9B8EE49e2
0 ETH0.0001172355330.00100025
Register Block180272672024-10-02 8:17:5432 days ago1727857074IN
0x610A7e97...9B8EE49e2
0 ETH0.0000030804190.00100025
Register Block180272292024-10-02 8:16:3832 days ago1727856998IN
0x610A7e97...9B8EE49e2
0 ETH0.0000032125250.00100026
Register Block180272142024-10-02 8:16:0832 days ago1727856968IN
0x610A7e97...9B8EE49e2
0 ETH0.0000031199020.00100026
Register Block180271992024-10-02 8:15:3832 days ago1727856938IN
0x610A7e97...9B8EE49e2
0 ETH0.0000034292670.00111126
Register Block180271842024-10-02 8:15:0832 days ago1727856908IN
0x610A7e97...9B8EE49e2
0 ETH0.00000353550.00100025
Set Root180271792024-10-02 8:14:5832 days ago1727856898IN
0x610A7e97...9B8EE49e2
0 ETH0.0001361834650.00100025
Register Block180271772024-10-02 8:14:5432 days ago1727856894IN
0x610A7e97...9B8EE49e2
0 ETH0.0000035721740.00100025
Set Root180271732024-10-02 8:14:4632 days ago1727856886IN
0x610A7e97...9B8EE49e2
0 ETH0.000135739740.00100025
Register Block180271692024-10-02 8:14:3832 days ago1727856878IN
0x610A7e97...9B8EE49e2
0 ETH0.0000038974180.00100025
View all transactions

Advanced mode:
Parent Transaction Hash Block From To
View All Internal Transactions
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)

File 1 of 7 : BridgedKeyStoreFromExecutionRoot.sol
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;
    }
}

File 2 of 7 : RLPReader.sol
// 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))
            }
        }
    }
}

File 3 of 7 : MerkleTrie.sol
// 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_;
            }
        }
    }
}

File 4 of 7 : IL1BlockOracle.sol
pragma solidity ^0.8.19;

interface IL1BlockOracle {
    /// @notice The latest L1 block hash.
    function hash() external returns (bytes32);
}

File 5 of 7 : RingBuffer.sol
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];
        }
    }
}

File 6 of 7 : Bytes.sol
// 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);
    }
}

File 7 of 7 : RLPReader.sol
// 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) }
        }
    }
}

Settings
{
  "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": {}
}

Contract ABI

[{"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"}]

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.