ETH Price: $3,046.38 (+2.81%)
Gas: 2 Gwei

Contract

0xE53289F32c8E690b7173aA33affE9B6B0CB0012F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Execute202271422024-07-03 16:21:473 days ago1720023707IN
0xE53289F3...B0CB0012F
0 ETH0.0012208212.14029553
Set Root202271352024-07-03 16:20:233 days ago1720023623IN
0xE53289F3...B0CB0012F
0 ETH0.0016243512.93430247
Execute202193192024-07-02 14:06:354 days ago1719929195IN
0xE53289F3...B0CB0012F
0 ETH0.000887498.82253874
Set Root202193112024-07-02 14:04:594 days ago1719929099IN
0xE53289F3...B0CB0012F
0 ETH0.001080968.60660041
Execute201925162024-06-28 20:16:358 days ago1719605795IN
0xE53289F3...B0CB0012F
0 ETH0.000250862.49766217
Execute201925102024-06-28 20:15:238 days ago1719605723IN
0xE53289F3...B0CB0012F
0 ETH0.000266922.60938369
Execute201925052024-06-28 20:14:238 days ago1719605663IN
0xE53289F3...B0CB0012F
0 ETH0.000262662.61517562
Execute201925012024-06-28 20:13:358 days ago1719605615IN
0xE53289F3...B0CB0012F
0 ETH0.000273392.69997013
Set Root201924942024-06-28 20:12:118 days ago1719605531IN
0xE53289F3...B0CB0012F
0 ETH0.00033162.6400075
Execute201860142024-06-27 22:29:359 days ago1719527375IN
0xE53289F3...B0CB0012F
0 ETH0.000576025.62826835
Execute201860092024-06-27 22:28:359 days ago1719527315IN
0xE53289F3...B0CB0012F
0 ETH0.000580315.68195558
Execute201860062024-06-27 22:27:599 days ago1719527279IN
0xE53289F3...B0CB0012F
0 ETH0.000597295.83534407
Execute201860022024-06-27 22:26:599 days ago1719527219IN
0xE53289F3...B0CB0012F
0 ETH0.000571855.67694651
Execute201859972024-06-27 22:25:599 days ago1719527159IN
0xE53289F3...B0CB0012F
0 ETH0.000570765.61516155
Execute201859922024-06-27 22:24:599 days ago1719527099IN
0xE53289F3...B0CB0012F
0 ETH0.000612846.0284736
Execute201859882024-06-27 22:24:119 days ago1719527051IN
0xE53289F3...B0CB0012F
0 ETH0.000672346.40498707
Execute201859842024-06-27 22:23:239 days ago1719527003IN
0xE53289F3...B0CB0012F
0 ETH0.000660556.28992296
Execute201859802024-06-27 22:22:239 days ago1719526943IN
0xE53289F3...B0CB0012F
0 ETH0.000655396.23723986
Execute201859762024-06-27 22:21:359 days ago1719526895IN
0xE53289F3...B0CB0012F
0 ETH0.000608866.22783495
Execute201859722024-06-27 22:20:479 days ago1719526847IN
0xE53289F3...B0CB0012F
0 ETH0.000609056.25643929
Set Root201859652024-06-27 22:19:239 days ago1719526763IN
0xE53289F3...B0CB0012F
0 ETH0.000740335.80805556
Execute201710982024-06-25 20:31:3511 days ago1719347495IN
0xE53289F3...B0CB0012F
0 ETH0.000775137.86225589
Execute201710922024-06-25 20:30:2311 days ago1719347423IN
0xE53289F3...B0CB0012F
0 ETH0.000852548.57588292
Set Root201710752024-06-25 20:26:4711 days ago1719347207IN
0xE53289F3...B0CB0012F
0 ETH0.000888917.13069425
Execute201640412024-06-24 20:51:1112 days ago1719262271IN
0xE53289F3...B0CB0012F
0 ETH0.000655956.41240135
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ManyChainMultiSig

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 9 : ManyChainMultiSig.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.19;

import "openzeppelin-contracts/utils/cryptography/MerkleProof.sol";
import "openzeppelin-contracts/access/Ownable2Step.sol";
import "openzeppelin-contracts/utils/cryptography/ECDSA.sol";

// Should be used as the first 32 bytes of the pre-image of the leaf that holds a
// op. This value is for domain separation of the different values stored in the
// Merkle tree.
bytes32 constant MANY_CHAIN_MULTI_SIG_DOMAIN_SEPARATOR_OP =
    keccak256("MANY_CHAIN_MULTI_SIG_DOMAIN_SEPARATOR_OP");

// Should be used as the first 32 bytes of the pre-image of the leaf that holds the
// root metadata. This value is for domain separation of the different values stored in the
// Merkle tree.
bytes32 constant MANY_CHAIN_MULTI_SIG_DOMAIN_SEPARATOR_METADATA =
    keccak256("MANY_CHAIN_MULTI_SIG_DOMAIN_SEPARATOR_METADATA");

/// @notice This is a multi-sig contract that supports signing many transactions (called "ops" in
/// the context of this contract to prevent confusion with transactions on the underlying chain)
/// targeting many chains with a single set of signatures. Authorized ops along with some metadata
/// are stored in a Merkle tree, which is generated offchain. Each op has an associated chain id,
/// ManyChainMultiSig contract address and nonce. The nonce enables us to enforce the
/// (per-ManyChainMultiSig contract instance) ordering of ops.
///
/// At any time, this contract stores at most one Merkle root. In the typical case, all ops
/// in the Merkle tree are expected to be executed before another root is set. Since the Merkle root
/// itself reveals ~ no information about the tree's contents, we take two measures to improve
/// transparency. First, we attach an expiration time to each Merkle root after which it cannot
/// be used any more. Second, we embed metadata in the tree itself that has to be proven/revealed
/// to the contract when a new root is set; the metadata contains the range of nonces (and thus
/// number of ops) in the tree intended for the ManyChainMultiSig contract instance on which the
/// root is being set.
///
/// Once a root is registered, *anyone* is allowed to furnish proofs of op inclusion in the Merkle
/// tree and execute the corresponding op. The contract enforces that ops are executed in the
/// correct order and with the correct arguments. A notable exception to this is the gas limit of
/// the call, which can be freely determined by the executor. We expect (transitive) callees to
/// implement standard behavior of simply reverting if insufficient gas is provided. In particular,
/// this means callees should not have non-reverting gas-dependent branches.
///
/// Note: In the typical case, we expect the time from a root being set to all of the ops
/// therein having been executed to be on the order of a couple of minutes.
contract ManyChainMultiSig is Ownable2Step {
    receive() external payable {}

    uint8 public constant NUM_GROUPS = 32;
    uint8 public constant MAX_NUM_SIGNERS = 200;

    struct Signer {
        address addr;
        uint8 index; // index of signer in s_config.signers
        uint8 group; // 0 <= group < NUM_GROUPS. Each signer can only be in one group.
    }

    // s_signers is used to easily validate the existence of the signer by its address. We still
    // have signers stored in s_config in order to easily deactivate them when a new config is set.
    mapping(address => Signer) s_signers;

    // Signing groups are arranged in a tree. Each group is an interior node and has its own quorum.
    // Signers are the leaves of the tree. A signer/leaf node is successful iff it furnishes a valid
    // signature. A group/interior node is successful iff a quorum of its children are successful.
    // setRoot succeeds only if the root group is successful.
    // Here is an example:
    //
    //                    ┌──────┐
    //                 ┌─►│2-of-3│◄───────┐
    //                 │  └──────┘        │
    //                 │        ▲         │
    //                 │        │         │
    //              ┌──┴───┐ ┌──┴───┐ ┌───┴────┐
    //          ┌──►│1-of-2│ │2-of-2│ │signer A│
    //          │   └──────┘ └──────┘ └────────┘
    //          │       ▲      ▲  ▲
    //          │       │      │  │     ┌──────┐
    //          │       │      │  └─────┤1-of-2│◄─┐
    //          │       │      │        └──────┘  │
    //  ┌───────┴┐ ┌────┴───┐ ┌┴───────┐ ▲        │
    //  │signer B│ │signer C│ │signer D│ │        │
    //  └────────┘ └────────┘ └────────┘ │        │
    //                                   │        │
    //                            ┌──────┴─┐ ┌────┴───┐
    //                            │signer E│ │signer F│
    //                            └────────┘ └────────┘
    //
    // - If signers [A, B] sign, they can set a root.
    // - If signers [B, D, E] sign, they can set a root.
    // - If signers [B, D, E, F] sign, they can set a root. (Either E's or F's signature was
    //   superfluous.)
    // - If signers [B, C, D] sign, they cannot set a root, because the 2-of-2 group on the second
    //   level isn't successful and therefore the root group isn't successful either.
    //
    // To map this tree to a Config, we:
    // - create an entry in signers for each signer (sorted by address in ascending order)
    // - assign the root group to index 0 and have it be its own parent
    // - assign an index to each non-root group, such that each group's parent has a lower index
    //   than the group itself
    // For example, we could transform the above tree structure into:
    // groupQuorums = [2, 1, 2, 1] + [0, 0, ...] (rightpad with 0s to NUM_GROUPS)
    // groupParents = [0, 0, 0, 2] + [0, 0, ...] (rightpad with 0s to NUM_GROUPS)
    // and assuming that address(A) < address(C) < address(E) < address(F) < address(D) < address(B)
    // signers = [
    //    {addr: address(A), index: 0, group: 0}, {addr: address(C), index: 1, group: 1},
    //    {addr: address(E), index: 2, group: 3}, {addr: address(F), index: 3, group: 3},
    //    {addr: address(D), index: 4, group: 2}, {addr: address(B), index: 5, group: 1},
    //  ]
    struct Config {
        Signer[] signers;
        // groupQuorums[i] stores the quorum for the i-th signer group. Any group with
        // groupQuorums[i] = 0 is considered disabled. The i-th group is successful if
        // it is enabled and at least groupQuorums[i] of its children are successful.
        uint8[NUM_GROUPS] groupQuorums;
        // groupParents[i] stores the parent group of the i-th signer group. We ensure that the
        // groups form a tree structure (where the root/0-th signer group points to itself as
        // parent) by enforcing
        // - (i != 0) implies (groupParents[i] < i)
        // - groupParents[0] == 0
        uint8[NUM_GROUPS] groupParents;
    }

    Config s_config;

    // Remember signedHashes that this contract has seen. Each signedHash can only be set once.
    mapping(bytes32 => bool) s_seenSignedHashes;

    // MerkleRoots are a bit tricky since they reveal almost no information about the contents of
    // the tree they authenticate. To mitigate this, we enforce that this contract can only execute
    // ops from a single root at any given point in time. We further associate an expiry
    // with each root to ensure that messages are executed in a timely manner. setRoot and various
    // execute calls are expected to happen in quick succession. We put the expiring root and
    // opCount in same struct in order to reduce gas costs of reading and writing.
    struct ExpiringRootAndOpCount {
        bytes32 root;
        // We prefer using block.timestamp instead of block.number, as a single
        // root may target many chains. We assume that block.timestamp can
        // be manipulated by block producers but only within relatively tight
        // bounds (a few minutes at most).
        uint32 validUntil;
        // each ManyChainMultiSig instance has it own independent opCount.
        uint40 opCount;
    }

    ExpiringRootAndOpCount s_expiringRootAndOpCount;

    /// @notice Each root also authenticates metadata about itself (stored as one of the leaves)
    /// which must be revealed when the root is set.
    ///
    /// @dev We need to be careful that abi.encode(MANY_CHAIN_MULTI_SIG_DOMAIN_SEPARATOR_METADATA, RootMetadata)
    /// is greater than 64 bytes to prevent collisions with internal nodes in the Merkle tree. See
    /// openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol:15 for details.
    struct RootMetadata {
        // chainId and multiSig uniquely identify a ManyChainMultiSig contract instance that the
        // root is destined for.
        // uint256 since it is unclear if we can represent chainId as uint64. There is a proposal (
        // https://ethereum-magicians.org/t/eip-2294-explicit-bound-to-chain-id/11090) to
        // bound chainid to 64 bits, but it is still unresolved.
        uint256 chainId;
        address multiSig;
        // opCount before adding this root
        uint40 preOpCount;
        // opCount after executing all ops in this root
        uint40 postOpCount;
        // override whatever root was already stored in this contract even if some of its
        // ops weren't executed.
        // Important: it is strongly recommended that offchain code set this to false by default.
        // Be careful setting this to true as it may break assumptions about what transactions from
        // the previous root have already been executed.
        bool overridePreviousRoot;
    }

    RootMetadata s_rootMetadata;

    /// @notice An ECDSA signature.
    struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    /// @notice setRoot Sets a new expiring root.
    ///
    /// @param root is the new expiring root.
    /// @param validUntil is the time by which root is valid
    /// @param metadata is the authenticated metadata about the root, which is stored as one of
    /// the leaves.
    /// @param metadataProof is the MerkleProof of inclusion of the metadata in the Merkle tree.
    /// @param signatures the ECDSA signatures on (root, validUntil).
    ///
    /// @dev the message (root, validUntil) should be signed by a sufficient set of signers.
    /// This signature authenticates also the metadata.
    ///
    /// @dev this method can be executed by anyone who has the root and valid signatures.
    /// as we validate the correctness of signatures, this imposes no risk.
    function setRoot(
        bytes32 root,
        uint32 validUntil,
        RootMetadata calldata metadata,
        bytes32[] calldata metadataProof,
        Signature[] calldata signatures
    ) external {
        bytes32 signedHash = ECDSA.toEthSignedMessageHash(keccak256(abi.encode(root, validUntil)));

        // Each (root, validUntil) tuple can only bet set once. For example, this prevents a
        // scenario where there are two signed roots with overridePreviousRoot = true and
        // an adversary keeps alternatively calling setRoot(root1), setRoot(root2),
        // setRoot(root1), ...
        if (s_seenSignedHashes[signedHash]) {
            revert SignedHashAlreadySeen();
        }

        // verify ECDSA signatures on (root, validUntil) and ensure that the root group is successful
        {
            // verify sigs and count number of signers in each group
            Signer memory signer;
            address prevAddress = address(0x0);
            uint8[NUM_GROUPS] memory groupVoteCounts; // number of votes per group
            for (uint256 i = 0; i < signatures.length; i++) {
                Signature calldata sig = signatures[i];
                address signerAddress = ECDSA.recover(signedHash, sig.v, sig.r, sig.s);
                // the off-chain system is required to sort the signatures by the
                // signer address in an increasing order
                if (prevAddress >= signerAddress) {
                    revert SignersAddressesMustBeStrictlyIncreasing();
                }
                prevAddress = signerAddress;

                signer = s_signers[signerAddress];
                if (signer.addr != signerAddress) {
                    revert InvalidSigner();
                }
                uint8 group = signer.group;
                while (true) {
                    groupVoteCounts[group]++;
                    if (groupVoteCounts[group] != s_config.groupQuorums[group]) {
                        // bail out unless we just hit the quorum. we only hit each quorum once,
                        // so we never move on to the parent of a group more than once.
                        break;
                    }
                    if (group == 0) {
                        // reached root
                        break;
                    }

                    group = s_config.groupParents[group];
                }
            }
            // the group at the root of the tree (with index 0) determines whether the vote passed,
            // we cannot proceed if it isn't configured with a valid (non-zero) quorum
            if (s_config.groupQuorums[0] == 0) {
                revert MissingConfig();
            }
            // did the root group reach its quorum?
            if (groupVoteCounts[0] < s_config.groupQuorums[0]) {
                revert InsufficientSigners();
            }
        }

        if (validUntil < block.timestamp) {
            revert ValidUntilHasAlreadyPassed();
        }

        {
            // verify metadataProof
            bytes32 hashedLeaf =
                keccak256(abi.encode(MANY_CHAIN_MULTI_SIG_DOMAIN_SEPARATOR_METADATA, metadata));
            if (!MerkleProof.verify(metadataProof, root, hashedLeaf)) {
                revert ProofCannotBeVerified();
            }
        }

        if (block.chainid != metadata.chainId) {
            revert WrongChainId();
        }

        if (address(this) != metadata.multiSig) {
            revert WrongMultiSig();
        }

        uint40 opCount = s_expiringRootAndOpCount.opCount;

        // don't allow a new root to be set if there are still outstanding ops that have not been
        // executed, unless overridePreviousRoot is set
        if (opCount != s_rootMetadata.postOpCount && !metadata.overridePreviousRoot) {
            revert PendingOps();
        }

        // the signers are responsible for tracking opCount offchain and ensuring that
        // preOpCount equals to opCount
        if (opCount != metadata.preOpCount) {
            revert WrongPreOpCount();
        }

        if (metadata.preOpCount > metadata.postOpCount) {
            revert WrongPostOpCount();
        }

        // done with validation, persist in in contract state
        s_seenSignedHashes[signedHash] = true;
        s_expiringRootAndOpCount = ExpiringRootAndOpCount({
            root: root,
            validUntil: validUntil,
            opCount: metadata.preOpCount
        });
        s_rootMetadata = metadata;
        emit NewRoot(root, validUntil, metadata);
    }

    /// @notice an op to be executed by the ManyChainMultiSig contract
    ///
    /// @dev We need to be careful that abi.encode(LEAF_OP_DOMAIN_SEPARATOR, RootMetadata)
    /// is greater than 64 bytes to prevent collisions with internal nodes in the Merkle tree. See
    /// openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol:15 for details.
    struct Op {
        uint256 chainId;
        address multiSig;
        uint40 nonce;
        address to;
        uint256 value;
        bytes data;
    }

    /// @notice Execute the received op after verifying the proof of its inclusion in the
    /// current Merkle tree. The op should be the next op according to the order
    /// enforced by the merkle tree whose root is stored in s_expiringRootAndOpCount, i.e., the
    /// nonce of the op should be equal to s_expiringRootAndOpCount.opCount.
    ///
    /// @param op is Op to be executed
    /// @param proof is the MerkleProof for the op's inclusion in the MerkleTree which its
    /// root is the s_expiringRootAndOpCount.root.
    ///
    /// @dev ANYONE can call this function! That's intentional. Callers can only execute verified,
    /// ordered ops in the Merkle tree.
    ///
    /// @dev we perform a raw call to each target. Raw calls to targets that don't have associated
    /// contract code will always succeed regardless of data.
    ///
    /// @dev the gas limit of the call can be freely determined by the caller of this function.
    /// We expect callees to revert if they run out of gas.
    function execute(Op calldata op, bytes32[] calldata proof) external {
        ExpiringRootAndOpCount memory currentExpiringRootAndOpCount = s_expiringRootAndOpCount;

        if (s_rootMetadata.postOpCount <= currentExpiringRootAndOpCount.opCount) {
            revert PostOpCountReached();
        }

        if (op.chainId != block.chainid) {
            revert WrongChainId();
        }

        if (op.multiSig != address(this)) {
            revert WrongMultiSig();
        }

        if (block.timestamp > currentExpiringRootAndOpCount.validUntil) {
            revert RootExpired();
        }

        if (op.nonce != currentExpiringRootAndOpCount.opCount) {
            revert WrongNonce();
        }

        // verify that the op exists in the merkle tree
        bytes32 hashedLeaf = keccak256(abi.encode(MANY_CHAIN_MULTI_SIG_DOMAIN_SEPARATOR_OP, op));
        if (!MerkleProof.verify(proof, currentExpiringRootAndOpCount.root, hashedLeaf)) {
            revert ProofCannotBeVerified();
        }

        // increase the counter *before* execution to prevent reentrancy issues
        s_expiringRootAndOpCount.opCount = currentExpiringRootAndOpCount.opCount + 1;

        _execute(op.to, op.value, op.data);
        emit OpExecuted(op.nonce, op.to, op.data, op.value);
    }

    /// @notice sets a new s_config. If clearRoot is true, then it also invalidates
    /// s_expiringRootAndOpCount.root.
    ///
    /// @param signerAddresses holds the addresses of the active signers. The addresses must be in
    /// ascending order.
    /// @param signerGroups maps each signer to its group
    /// @param groupQuorums holds the required number of valid signatures in each group.
    /// A group i is called successful group if at least groupQuorum[i] distinct signers provide a
    /// valid signature.
    /// @param groupParents holds each group's parent. The groups must be arranged in a tree s.t.
    /// group 0 is the root of the tree and the i-th group's parent has index j less than i.
    /// Iff setRoot is called with a set of signatures that causes the root group to be successful,
    /// setRoot allows a root to be set.
    /// @param clearRoot, if set to true, invalidates the current root. This option is needed to
    /// invalidate the current root, so to prevent further ops from being executed. This
    /// might be used when the current root was signed under a loser group configuration or when
    /// some previous signers aren't trusted any more.
    function setConfig(
        address[] calldata signerAddresses,
        uint8[] calldata signerGroups,
        uint8[NUM_GROUPS] calldata groupQuorums,
        uint8[NUM_GROUPS] calldata groupParents,
        bool clearRoot
    ) external onlyOwner {
        if (signerAddresses.length == 0 || signerAddresses.length > MAX_NUM_SIGNERS) {
            revert OutOfBoundsNumOfSigners();
        }

        if (signerAddresses.length != signerGroups.length) {
            revert SignerGroupsLengthMismatch();
        }

        {
            // validate group structure
            // counts the number of children of each group
            uint8[NUM_GROUPS] memory groupChildrenCounts;
            // first, we count the signers as children
            for (uint256 i = 0; i < signerGroups.length; i++) {
                if (signerGroups[i] >= NUM_GROUPS) {
                    revert OutOfBoundsGroup();
                }
                groupChildrenCounts[signerGroups[i]]++;
            }
            // second, we iterate backwards so as to check each group and propagate counts from
            // child group to parent groups up the tree to the root
            for (uint256 j = 0; j < NUM_GROUPS; j++) {
                uint256 i = NUM_GROUPS - 1 - j;
                // ensure we have a well-formed group tree. the root should have itself as parent
                if ((i != 0 && groupParents[i] >= i) || (i == 0 && groupParents[i] != 0)) {
                    revert GroupTreeNotWellFormed();
                }
                bool disabled = groupQuorums[i] == 0;
                if (disabled) {
                    // a disabled group shouldn't have any children
                    if (0 < groupChildrenCounts[i]) {
                        revert SignerInDisabledGroup();
                    }
                } else {
                    // ensure that the group quorum can be met
                    if (groupChildrenCounts[i] < groupQuorums[i]) {
                        revert OutOfBoundsGroupQuorum();
                    }
                    groupChildrenCounts[groupParents[i]]++;
                    // the above line clobbers groupChildrenCounts[0] in last iteration, don't use it after the loop ends
                }
            }
        }

        Signer[] memory oldSigners = s_config.signers;
        // remove any old signer addresses
        for (uint256 i = 0; i < oldSigners.length; i++) {
            address oldSignerAddress = oldSigners[i].addr;
            delete s_signers[oldSignerAddress];
            s_config.signers.pop();
        }

        // we cannot just write s_config = Config({...}) because solc doesn't support that
        assert(s_config.signers.length == 0);
        s_config.groupQuorums = groupQuorums;
        s_config.groupParents = groupParents;

        // add new signers' addresses, we require that the signers' list be a strictly monotone
        // increasing sequence
        address prevSigner = address(0x0);
        for (uint256 i = 0; i < signerAddresses.length; i++) {
            if (prevSigner >= signerAddresses[i]) {
                revert SignersAddressesMustBeStrictlyIncreasing();
            }
            Signer memory signer =
                Signer({addr: signerAddresses[i], index: uint8(i), group: signerGroups[i]});
            s_signers[signerAddresses[i]] = signer;
            s_config.signers.push(signer);
            prevSigner = signerAddresses[i];
        }

        if (clearRoot) {
            // clearRoot is equivalent to overriding with a completely empty root
            uint40 opCount = s_expiringRootAndOpCount.opCount;
            s_expiringRootAndOpCount =
                ExpiringRootAndOpCount({root: 0, validUntil: 0, opCount: opCount});
            s_rootMetadata = RootMetadata({
                chainId: block.chainid,
                multiSig: address(this),
                preOpCount: opCount,
                postOpCount: opCount,
                overridePreviousRoot: true
            });
        }
        emit ConfigSet(s_config, clearRoot);
    }

    /// @notice Execute an op's call. Performs a raw call that always succeeds if the
    /// target isn't a contract.
    function _execute(address target, uint256 value, bytes calldata data) internal virtual {
        (bool success, bytes memory ret) = target.call{value: value}(data);
        if (!success) {
            revert CallReverted(ret);
        }
    }

    /*
     * Getters
     */

    function getConfig() public view returns (Config memory) {
        return s_config;
    }

    function getOpCount() public view returns (uint40) {
        return s_expiringRootAndOpCount.opCount;
    }

    function getRoot() public view returns (bytes32 root, uint32 validUntil) {
        ExpiringRootAndOpCount memory currentRootAndOpCount = s_expiringRootAndOpCount;
        return (currentRootAndOpCount.root, currentRootAndOpCount.validUntil);
    }

    function getRootMetadata() public view returns (RootMetadata memory) {
        return s_rootMetadata;
    }

    /*
     * Events and Errors
     */

    /// @notice Emitted when a new root is set.
    event NewRoot(bytes32 indexed root, uint32 validUntil, RootMetadata metadata);

    /// @notice Emitted when a new config is set.
    event ConfigSet(Config config, bool isRootCleared);

    /// @notice Emitted when an op gets successfully executed.
    event OpExecuted(uint40 indexed nonce, address to, bytes data, uint256 value);

    /// @notice Thrown when number of signers is 0 or greater than MAX_NUM_SIGNERS.
    error OutOfBoundsNumOfSigners();

    /// @notice Thrown when signerAddresses and signerGroups have different lengths.
    error SignerGroupsLengthMismatch();

    /// @notice Thrown when number of some signer's group is greater than (NUM_GROUPS-1).
    error OutOfBoundsGroup();

    /// @notice Thrown when the group tree isn't well-formed.
    error GroupTreeNotWellFormed();

    /// @notice Thrown when the quorum of some group is larger than the number of signers in it.
    error OutOfBoundsGroupQuorum();

    /// @notice Thrown when a disabled group contains a signer.
    error SignerInDisabledGroup();

    /// @notice Thrown when the signers' addresses are not a strictly increasing monotone sequence.
    /// Prevents signers from including more than one signature.
    error SignersAddressesMustBeStrictlyIncreasing();

    /// @notice Thrown when the signature corresponds to invalid signer.
    error InvalidSigner();

    /// @notice Thrown when there is no sufficient set of valid signatures provided to make the
    /// root group successful.
    error InsufficientSigners();

    /// @notice Thrown when attempt to set metadata or execute op for another chain.
    error WrongChainId();

    /// @notice Thrown when the multiSig address in metadata or op is
    /// incompatible with the address of this contract.
    error WrongMultiSig();

    /// @notice Thrown when the preOpCount <= postOpCount invariant is violated.
    error WrongPostOpCount();

    /// @notice Thrown when attempting to set a new root while there are still pending ops
    /// from the previous root without explicitly overriding it.
    error PendingOps();

    /// @notice Thrown when preOpCount in metadata is incompatible with the current opCount.
    error WrongPreOpCount();

    /// @notice Thrown when the provided merkle proof cannot be verified.
    error ProofCannotBeVerified();

    /// @notice Thrown when attempt to execute an op after
    /// s_expiringRootAndOpCount.validUntil has passed.
    error RootExpired();

    /// @notice Thrown when attempt to bypass the enforced ops' order in the merkle tree or
    /// re-execute an op.
    error WrongNonce();

    /// @notice Thrown when attempting to execute an op even though opCount equals
    /// metadata.postOpCount.
    error PostOpCountReached();

    /// @notice Thrown when the underlying call in _execute() reverts.
    error CallReverted(bytes error);

    /// @notice Thrown when attempt to set past validUntil for the root.
    error ValidUntilHasAlreadyPassed();

    /// @notice Thrown when setRoot() is called before setting a config.
    error MissingConfig();

    /// @notice Thrown when attempt to set the same (root, validUntil) in setRoot().
    error SignedHashAlreadySeen();
}

File 2 of 9 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     *
     * _Available since v4.7._
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     *
     * _Available since v4.7._
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     *
     * _Available since v4.7._
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            require(proofPos == proofLen, "MerkleProof: invalid multiproof");
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            require(proofPos == proofLen, "MerkleProof: invalid multiproof");
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 3 of 9 : Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;

import "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }
}

File 4 of 9 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32")
            mstore(0x1c, hash)
            message := keccak256(0x00, 0x3c)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, "\x19\x01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            data := keccak256(ptr, 0x42)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Data with intended validator, created from a
     * `validator` and `data` according to the version 0 of EIP-191.
     *
     * See {recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x00", validator, data));
    }
}

File 5 of 9 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 6 of 9 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 7 of 9 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 8 of 9 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 9 of 9 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "safe-contracts/=lib/safe-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"bytes","name":"error","type":"bytes"}],"name":"CallReverted","type":"error"},{"inputs":[],"name":"GroupTreeNotWellFormed","type":"error"},{"inputs":[],"name":"InsufficientSigners","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"MissingConfig","type":"error"},{"inputs":[],"name":"OutOfBoundsGroup","type":"error"},{"inputs":[],"name":"OutOfBoundsGroupQuorum","type":"error"},{"inputs":[],"name":"OutOfBoundsNumOfSigners","type":"error"},{"inputs":[],"name":"PendingOps","type":"error"},{"inputs":[],"name":"PostOpCountReached","type":"error"},{"inputs":[],"name":"ProofCannotBeVerified","type":"error"},{"inputs":[],"name":"RootExpired","type":"error"},{"inputs":[],"name":"SignedHashAlreadySeen","type":"error"},{"inputs":[],"name":"SignerGroupsLengthMismatch","type":"error"},{"inputs":[],"name":"SignerInDisabledGroup","type":"error"},{"inputs":[],"name":"SignersAddressesMustBeStrictlyIncreasing","type":"error"},{"inputs":[],"name":"ValidUntilHasAlreadyPassed","type":"error"},{"inputs":[],"name":"WrongChainId","type":"error"},{"inputs":[],"name":"WrongMultiSig","type":"error"},{"inputs":[],"name":"WrongNonce","type":"error"},{"inputs":[],"name":"WrongPostOpCount","type":"error"},{"inputs":[],"name":"WrongPreOpCount","type":"error"},{"anonymous":false,"inputs":[{"components":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint8","name":"group","type":"uint8"}],"internalType":"struct ManyChainMultiSig.Signer[]","name":"signers","type":"tuple[]"},{"internalType":"uint8[32]","name":"groupQuorums","type":"uint8[32]"},{"internalType":"uint8[32]","name":"groupParents","type":"uint8[32]"}],"indexed":false,"internalType":"struct ManyChainMultiSig.Config","name":"config","type":"tuple"},{"indexed":false,"internalType":"bool","name":"isRootCleared","type":"bool"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"root","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"validUntil","type":"uint32"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"multiSig","type":"address"},{"internalType":"uint40","name":"preOpCount","type":"uint40"},{"internalType":"uint40","name":"postOpCount","type":"uint40"},{"internalType":"bool","name":"overridePreviousRoot","type":"bool"}],"indexed":false,"internalType":"struct ManyChainMultiSig.RootMetadata","name":"metadata","type":"tuple"}],"name":"NewRoot","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint40","name":"nonce","type":"uint40"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"OpExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"MAX_NUM_SIGNERS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NUM_GROUPS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"multiSig","type":"address"},{"internalType":"uint40","name":"nonce","type":"uint40"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ManyChainMultiSig.Op","name":"op","type":"tuple"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint8","name":"group","type":"uint8"}],"internalType":"struct ManyChainMultiSig.Signer[]","name":"signers","type":"tuple[]"},{"internalType":"uint8[32]","name":"groupQuorums","type":"uint8[32]"},{"internalType":"uint8[32]","name":"groupParents","type":"uint8[32]"}],"internalType":"struct ManyChainMultiSig.Config","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOpCount","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoot","outputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"uint32","name":"validUntil","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRootMetadata","outputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"multiSig","type":"address"},{"internalType":"uint40","name":"preOpCount","type":"uint40"},{"internalType":"uint40","name":"postOpCount","type":"uint40"},{"internalType":"bool","name":"overridePreviousRoot","type":"bool"}],"internalType":"struct ManyChainMultiSig.RootMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signerAddresses","type":"address[]"},{"internalType":"uint8[]","name":"signerGroups","type":"uint8[]"},{"internalType":"uint8[32]","name":"groupQuorums","type":"uint8[32]"},{"internalType":"uint8[32]","name":"groupParents","type":"uint8[32]"},{"internalType":"bool","name":"clearRoot","type":"bool"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"uint32","name":"validUntil","type":"uint32"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"multiSig","type":"address"},{"internalType":"uint40","name":"preOpCount","type":"uint40"},{"internalType":"uint40","name":"postOpCount","type":"uint40"},{"internalType":"bool","name":"overridePreviousRoot","type":"bool"}],"internalType":"struct ManyChainMultiSig.RootMetadata","name":"metadata","type":"tuple"},{"internalType":"bytes32[]","name":"metadataProof","type":"bytes32[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ManyChainMultiSig.Signature[]","name":"signatures","type":"tuple[]"}],"name":"setRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b5062000032620000266200003860201b60201c565b6200004060201b60201c565b6200013d565b600033905090565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905562000076816200007960201b60201c565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b614db8806200014d6000396000f3fe6080604052600436106100e15760003560e01c8063846c67ef1161007f578063b759d68511610059578063b759d68514610270578063c3f909d414610299578063e30c3978146102c4578063f2fde38b146102ef576100e8565b8063846c67ef146101f15780638da5cb5b1461021a578063a76f559814610245576100e8565b80636b45fb3e116100bb5780636b45fb3e1461016f578063715018a61461019a57806379ba5097146101b15780637cc38b28146101c8576100e8565b80635a2519ef146100ed5780635ca1e16514610118578063627e8a3b14610144576100e8565b366100e857005b600080fd5b3480156100f957600080fd5b50610102610318565b60405161010f919061276f565b60405180910390f35b34801561012457600080fd5b5061012d61031d565b60405161013b9291906127c2565b60405180910390f35b34801561015057600080fd5b5061015961039d565b604051610166919061280b565b60405180910390f35b34801561017b57600080fd5b506101846103bb565b6040516101919190612912565b60405180910390f35b3480156101a657600080fd5b506101af6104a2565b005b3480156101bd57600080fd5b506101c66104b6565b005b3480156101d457600080fd5b506101ef60048036038101906101ea9190612a6e565b610543565b005b3480156101fd57600080fd5b5061021860048036038101906102139190612c25565b610e03565b005b34801561022657600080fd5b5061022f61196d565b60405161023c9190612cf3565b60405180910390f35b34801561025157600080fd5b5061025a611996565b604051610267919061276f565b60405180910390f35b34801561027c57600080fd5b5061029760048036038101906102929190612d2d565b61199b565b005b3480156102a557600080fd5b506102ae611d76565b6040516102bb9190612f97565b60405180910390f35b3480156102d057600080fd5b506102d9611f51565b6040516102e69190612cf3565b60405180910390f35b3480156102fb57600080fd5b5061031660048036038101906103119190612fe5565b611f7b565b005b602081565b60008060006007604051806060016040529081600082015481526020016001820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160049054906101000a900464ffffffffff1664ffffffffff1664ffffffffff168152505090508060000151816020015192509250509091565b6000600760010160049054906101000a900464ffffffffff16905090565b6103c36125b7565b60096040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160149054906101000a900464ffffffffff1664ffffffffff1664ffffffffff1681526020016001820160199054906101000a900464ffffffffff1664ffffffffff1664ffffffffff16815260200160018201601e9054906101000a900460ff161515151581525050905090565b6104aa612028565b6104b460006120a6565b565b60006104c06120d7565b90508073ffffffffffffffffffffffffffffffffffffffff166104e1611f51565b73ffffffffffffffffffffffffffffffffffffffff1614610537576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052e90613095565b60405180910390fd5b610540816120a6565b50565b6000610576888860405160200161055b9291906127c2565b604051602081830303815290604052805190602001206120df565b90506006600082815260200190815260200160002060009054906101000a900460ff16156105d0576040517f48c2688b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105d861260c565b60006105e2612649565b60005b868690508110156108d55736878783818110610604576106036130b5565b5b90506060020190506000610634878360000160208101906106259190613110565b84602001358560400135612115565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161061069b576040517f4a36ec0800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b809450600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1660ff1660ff1681526020016000820160159054906101000a900460ff1660ff1660ff168152505095508073ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff16146107e3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000866040015190505b6001156108bf57848160ff166020811061080a576108096130b5565b5b60200201805180919061081c9061316c565b60ff1660ff168152505060036001018160ff16602081106108405761083f6130b5565b5b602091828204019190069054906101000a900460ff1660ff16858260ff166020811061086f5761086e6130b5565b5b602002015160ff16036108bf5760008160ff1603156108bf5760036002018160ff16602081106108a2576108a16130b5565b5b602091828204019190069054906101000a900460ff1690506107ed565b50505080806108cd90613195565b9150506105e5565b50600060036001016000602081106108f0576108ef6130b5565b5b602091828204019190069054906101000a900460ff1660ff1603610940576040517faa6185ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003600101600060208110610958576109576130b5565b5b602091828204019190069054906101000a900460ff1660ff1681600060208110610985576109846130b5565b5b602002015160ff1610156109c5576040517fc2ee9b9e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050428763ffffffff161015610a08576040517fb057a45200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fe6b82be989101b4eb519770114b997b97b3c8707515286748a871717f0e4ea1c87604051602001610a3d929190613321565b604051602081830303815290604052805190602001209050610aa1868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508a83612140565b610ad7576040517f2522a1c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5085600001354614610b15576040517f5f87bc0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856020016020810190610b289190612fe5565b73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614610b8c576040517f9a84601500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600760010160049054906101000a900464ffffffffff169050600960010160199054906101000a900464ffffffffff1664ffffffffff168164ffffffffff1614158015610beb5750866080016020810190610be9919061334a565b155b15610c22576040517f3230825b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b866040016020810190610c359190613377565b64ffffffffff168164ffffffffff1614610c7b576040517fa255a76300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b866060016020810190610c8e9190613377565b64ffffffffff16876040016020810190610ca89190613377565b64ffffffffff161115610ce7576040517fc61352f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016006600084815260200190815260200160002060006101000a81548160ff02191690831515021790555060405180606001604052808a81526020018963ffffffff168152602001886040016020810190610d439190613377565b64ffffffffff1681525060076000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160010160046101000a81548164ffffffffff021916908364ffffffffff1602179055509050508660098181610dbb919061378a565b905050887f7ea643ae44677f24e0d6f40168893712daaf729b0a38fe7702d21cb544c841018989604051610df0929190613798565b60405180910390a2505050505050505050565b610e0b612028565b6000878790501480610e23575060c860ff1687879050115b15610e5a576040517ff0ec1ca400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b848490508787905014610e99576040517ff1f3053000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ea1612649565b60005b86869050811015610f8257602060ff16878783818110610ec757610ec66130b5565b5b9050602002016020810190610edc9190613110565b60ff1610610f16576040517fb9ae8e5200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81878783818110610f2a57610f296130b5565b5b9050602002016020810190610f3f9190613110565b60ff1660208110610f5357610f526130b5565b5b602002018051809190610f659061316c565b60ff1660ff16815250508080610f7a90613195565b915050610ea4565b5060005b602060ff168110156111da5760008160016020610fa391906137c1565b60ff16610fb091906137f6565b905060008114158015610feb575080858260208110610fd257610fd16130b5565b5b602002016020810190610fe59190613110565b60ff1610155b8061102b575060008114801561102a57506000858260208110611011576110106130b5565b5b6020020160208101906110249190613110565b60ff1614155b5b15611062576040517fff063a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080878360208110611078576110776130b5565b5b60200201602081019061108b9190613110565b60ff1614905080156110f1578382602081106110aa576110a96130b5565b5b602002015160ff16600010156110ec576040517f8db4e75d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111c5565b868260208110611104576111036130b5565b5b6020020160208101906111179190613110565b60ff1684836020811061112d5761112c6130b5565b5b602002015160ff16101561116d576040517fbb00136e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83868360208110611181576111806130b5565b5b6020020160208101906111949190613110565b60ff16602081106111a8576111a76130b5565b5b6020020180518091906111ba9061316c565b60ff1660ff16815250505b505080806111d290613195565b915050610f86565b505060006003600001805480602002602001604051908101604052809291908181526020016000905b828210156112c1578382906000526020600020016040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1660ff1660ff1681526020016000820160159054906101000a900460ff1660ff1660ff168152505081526020019060010190611203565b50505050905060005b81518110156114145760008282815181106112e8576112e76130b5565b5b6020026020010151600001519050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549060ff02191690556000820160156101000a81549060ff02191690555050600360000180548061139c5761139b61382a565b5b60019003818190600052602060002001600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549060ff02191690556000820160156101000a81549060ff02191690555050905550808061140c90613195565b9150506112ca565b5060006003600001805490501461142e5761142d613859565b5b83600360010190602061144292919061266c565b5082600360020190602061145792919061266c565b506000805b898990508110156117635789898281811061147a576114796130b5565b5b905060200201602081019061148f9190612fe5565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16106114f3576040517f4a36ec0800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060405180606001604052808c8c85818110611513576115126130b5565b5b90506020020160208101906115289190612fe5565b73ffffffffffffffffffffffffffffffffffffffff1681526020018360ff1681526020018a8a8581811061155f5761155e6130b5565b5b90506020020160208101906115749190613110565b60ff16815250905080600260008d8d86818110611594576115936130b5565b5b90506020020160208101906115a99190612fe5565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff021916908360ff16021790555060408201518160000160156101000a81548160ff021916908360ff1602179055509050506003600001819080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff021916908360ff16021790555060408201518160000160156101000a81548160ff021916908360ff16021790555050508a8a83818110611738576117376130b5565b5b905060200201602081019061174d9190612fe5565b925050808061175b90613195565b91505061145c565b508215611928576000600760010160049054906101000a900464ffffffffff16905060405180606001604052806000801b8152602001600063ffffffff1681526020018264ffffffffff1681525060076000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160010160046101000a81548164ffffffffff021916908364ffffffffff1602179055509050506040518060a001604052804681526020013073ffffffffffffffffffffffffffffffffffffffff1681526020018264ffffffffff1681526020018264ffffffffff1681526020016001151581525060096000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160146101000a81548164ffffffffff021916908364ffffffffff16021790555060608201518160010160196101000a81548164ffffffffff021916908364ffffffffff160217905550608082015181600101601e6101000a81548160ff021916908315150217905550905050505b7f0a4974ad206b9c736f9ab2feac1c9b1d043fe4ef377c70ae45659f2ef089f03e60038460405161195a92919061473c565b60405180910390a1505050505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60c881565b60006007604051806060016040529081600082015481526020016001820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160049054906101000a900464ffffffffff1664ffffffffff1664ffffffffff16815250509050806040015164ffffffffff16600960010160199054906101000a900464ffffffffff1664ffffffffff1611611a66576040517fadb1331800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46846000013514611aa3576040517f5f87bc0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16846020016020810190611acd9190612fe5565b73ffffffffffffffffffffffffffffffffffffffff1614611b1a576040517f9a84601500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806020015163ffffffff16421115611b5e576040517f9ba6743000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015164ffffffffff16846040016020810190611b7d9190613377565b64ffffffffff1614611bbb576040517fd9c6386f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f08d275622006c4ca82d03f498e90163cafd53c663a48470c3b52ac8bfbd9f52c85604051602001611bf09291906148f7565b604051602081830303815290604052805190602001209050611c58848480806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050836000015183612140565b611c8e576040517f2522a1c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018260400151611c9f9190614927565b600760010160046101000a81548164ffffffffff021916908364ffffffffff160217905550611cf4856060016020810190611cda9190612fe5565b8660800135878060a00190611cef919061496f565b612157565b846040016020810190611d079190613377565b64ffffffffff167f87d58fdd48be753fb9ef4ec8a5895086c401506da8b4d752abc90602c3e62d1d866060016020810190611d429190612fe5565b878060a00190611d52919061496f565b8960800135604051611d679493929190614a1f565b60405180910390a25050505050565b611d7e612709565b600360405180606001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611e6e578382906000526020600020016040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1660ff1660ff1681526020016000820160159054906101000a900460ff1660ff1660ff168152505081526020019060010190611db0565b50505050815260200160018201602080602002604051908101604052809291908260208015611ed8576020028201916000905b82829054906101000a900460ff1660ff1681526020019060010190602082600001049283019260010382029150808411611ea15790505b5050505050815260200160028201602080602002604051908101604052809291908260208015611f43576020028201916000905b82829054906101000a900460ff1660ff1681526020019060010190602082600001049283019260010382029150808411611f0c5790505b505050505081525050905090565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611f83612028565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611fe361196d565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6120306120d7565b73ffffffffffffffffffffffffffffffffffffffff1661204e61196d565b73ffffffffffffffffffffffffffffffffffffffff16146120a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161209b90614aab565b60405180910390fd5b565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556120d481612213565b50565b600033905090565b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005281601c52603c6000209050919050565b6000806000612126878787876122d7565b91509150612133816123b9565b8192505050949350505050565b60008261214d858461251f565b1490509392505050565b6000808573ffffffffffffffffffffffffffffffffffffffff16858585604051612182929190614afb565b60006040518083038185875af1925050503d80600081146121bf576040519150601f19603f3d011682016040523d82523d6000602084013e6121c4565b606091505b50915091508161220b57806040517f70de1b4b0000000000000000000000000000000000000000000000000000000081526004016122029190614b82565b60405180910390fd5b505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c11156123125760006003915091506123b0565b6000600187878787604051600081526020016040526040516123379493929190614ba4565b6020604051602081039080840390855afa158015612359573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036123a7576000600192509250506123b0565b80600092509250505b94509492505050565b600060048111156123cd576123cc614be9565b5b8160048111156123e0576123df614be9565b5b031561251c57600160048111156123fa576123f9614be9565b5b81600481111561240d5761240c614be9565b5b0361244d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161244490614c64565b60405180910390fd5b6002600481111561246157612460614be9565b5b81600481111561247457612473614be9565b5b036124b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ab90614cd0565b60405180910390fd5b600360048111156124c8576124c7614be9565b5b8160048111156124db576124da614be9565b5b0361251b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161251290614d62565b60405180910390fd5b5b50565b60008082905060005b845181101561256a5761255582868381518110612548576125476130b5565b5b6020026020010151612575565b9150808061256290613195565b915050612528565b508091505092915050565b600081831061258d5761258882846125a0565b612598565b61259783836125a0565b5b905092915050565b600082600052816020526040600020905092915050565b6040518060a0016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600064ffffffffff168152602001600064ffffffffff1681526020016000151581525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b604051806104000160405280602090602082028036833780820191505090505090565b826020601f016020900481019282156126f85791602002820160005b838211156126c957833560ff1683826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302612688565b80156126f65782816101000a81549060ff02191690556001016020816000010492830192600103026126c9565b505b5090506127059190612736565b5090565b604051806060016040528060608152602001612723612649565b8152602001612730612649565b81525090565b5b8082111561274f576000816000905550600101612737565b5090565b600060ff82169050919050565b61276981612753565b82525050565b60006020820190506127846000830184612760565b92915050565b6000819050919050565b61279d8161278a565b82525050565b600063ffffffff82169050919050565b6127bc816127a3565b82525050565b60006040820190506127d76000830185612794565b6127e460208301846127b3565b9392505050565b600064ffffffffff82169050919050565b612805816127eb565b82525050565b600060208201905061282060008301846127fc565b92915050565b6000819050919050565b61283981612826565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061286a8261283f565b9050919050565b61287a8161285f565b82525050565b612889816127eb565b82525050565b60008115159050919050565b6128a48161288f565b82525050565b60a0820160008201516128c06000850182612830565b5060208201516128d36020850182612871565b5060408201516128e66040850182612880565b5060608201516128f96060850182612880565b50608082015161290c608085018261289b565b50505050565b600060a08201905061292760008301846128aa565b92915050565b600080fd5b600080fd5b6129408161278a565b811461294b57600080fd5b50565b60008135905061295d81612937565b92915050565b61296c816127a3565b811461297757600080fd5b50565b60008135905061298981612963565b92915050565b600080fd5b600060a082840312156129aa576129a961298f565b5b81905092915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126129d8576129d76129b3565b5b8235905067ffffffffffffffff8111156129f5576129f46129b8565b5b602083019150836020820283011115612a1157612a106129bd565b5b9250929050565b60008083601f840112612a2e57612a2d6129b3565b5b8235905067ffffffffffffffff811115612a4b57612a4a6129b8565b5b602083019150836060820283011115612a6757612a666129bd565b5b9250929050565b6000806000806000806000610120888a031215612a8e57612a8d61292d565b5b6000612a9c8a828b0161294e565b9750506020612aad8a828b0161297a565b9650506040612abe8a828b01612994565b95505060e088013567ffffffffffffffff811115612adf57612ade612932565b5b612aeb8a828b016129c2565b945094505061010088013567ffffffffffffffff811115612b0f57612b0e612932565b5b612b1b8a828b01612a18565b925092505092959891949750929550565b60008083601f840112612b4257612b416129b3565b5b8235905067ffffffffffffffff811115612b5f57612b5e6129b8565b5b602083019150836020820283011115612b7b57612b7a6129bd565b5b9250929050565b60008083601f840112612b9857612b976129b3565b5b8235905067ffffffffffffffff811115612bb557612bb46129b8565b5b602083019150836020820283011115612bd157612bd06129bd565b5b9250929050565b6000819050826020800282011115612bf357612bf26129bd565b5b92915050565b612c028161288f565b8114612c0d57600080fd5b50565b600081359050612c1f81612bf9565b92915050565b6000806000806000806000610860888a031215612c4557612c4461292d565b5b600088013567ffffffffffffffff811115612c6357612c62612932565b5b612c6f8a828b01612b2c565b9750975050602088013567ffffffffffffffff811115612c9257612c91612932565b5b612c9e8a828b01612b82565b95509550506040612cb18a828b01612bd8565b935050610440612cc38a828b01612bd8565b925050610840612cd58a828b01612c10565b91505092959891949750929550565b612ced8161285f565b82525050565b6000602082019050612d086000830184612ce4565b92915050565b600060c08284031215612d2457612d2361298f565b5b81905092915050565b600080600060408486031215612d4657612d4561292d565b5b600084013567ffffffffffffffff811115612d6457612d63612932565b5b612d7086828701612d0e565b935050602084013567ffffffffffffffff811115612d9157612d90612932565b5b612d9d868287016129c2565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612dde81612753565b82525050565b606082016000820151612dfa6000850182612871565b506020820151612e0d6020850182612dd5565b506040820151612e206040850182612dd5565b50505050565b6000612e328383612de4565b60608301905092915050565b6000602082019050919050565b6000612e5682612da9565b612e608185612db4565b9350612e6b83612dc5565b8060005b83811015612e9c578151612e838882612e26565b9750612e8e83612e3e565b925050600181019050612e6f565b5085935050505092915050565b600060209050919050565b600081905092915050565b6000819050919050565b6000612ed58383612dd5565b60208301905092915050565b6000602082019050919050565b612ef781612ea9565b612f018184612eb4565b9250612f0c82612ebf565b8060005b83811015612f3d578151612f248782612ec9565b9650612f2f83612ee1565b925050600181019050612f10565b505050505050565b6000610820830160008301518482036000860152612f638282612e4b565b9150506020830151612f786020860182612eee565b506040830151612f8c610420860182612eee565b508091505092915050565b60006020820190508181036000830152612fb18184612f45565b905092915050565b612fc28161285f565b8114612fcd57600080fd5b50565b600081359050612fdf81612fb9565b92915050565b600060208284031215612ffb57612ffa61292d565b5b600061300984828501612fd0565b91505092915050565b600082825260208201905092915050565b7f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060008201527f6e6577206f776e65720000000000000000000000000000000000000000000000602082015250565b600061307f602983613012565b915061308a82613023565b604082019050919050565b600060208201905081810360008301526130ae81613072565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6130ed81612753565b81146130f857600080fd5b50565b60008135905061310a816130e4565b92915050565b6000602082840312156131265761312561292d565b5b6000613134848285016130fb565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061317782612753565b915060ff820361318a5761318961313d565b5b600182019050919050565b60006131a082612826565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036131d2576131d161313d565b5b600182019050919050565b6131e681612826565b81146131f157600080fd5b50565b600081359050613203816131dd565b92915050565b600061321860208401846131f4565b905092915050565b600061322f6020840184612fd0565b905092915050565b613240816127eb565b811461324b57600080fd5b50565b60008135905061325d81613237565b92915050565b6000613272602084018461324e565b905092915050565b60006132896020840184612c10565b905092915050565b60a082016132a26000830183613209565b6132af6000850182612830565b506132bd6020830183613220565b6132ca6020850182612871565b506132d86040830183613263565b6132e56040850182612880565b506132f36060830183613263565b6133006060850182612880565b5061330e608083018361327a565b61331b608085018261289b565b50505050565b600060c0820190506133366000830185612794565b6133436020830184613291565b9392505050565b6000602082840312156133605761335f61292d565b5b600061336e84828501612c10565b91505092915050565b60006020828403121561338d5761338c61292d565b5b600061339b8482850161324e565b91505092915050565b600081356133b1816131dd565b80915050919050565b60008160001b9050919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6133f3846133ba565b9350801983169250808416831791505092915050565b6000819050919050565b600061342e61342961342484612826565b613409565b612826565b9050919050565b6000819050919050565b61344882613413565b61345b61345482613435565b83546133c7565b8255505050565b6000813561346f81612fb9565b80915050919050565b600073ffffffffffffffffffffffffffffffffffffffff613498846133ba565b9350801983169250808416831791505092915050565b60006134c96134c46134bf8461283f565b613409565b61283f565b9050919050565b60006134db826134ae565b9050919050565b60006134ed826134d0565b9050919050565b6000819050919050565b613507826134e2565b61351a613513826134f4565b8354613478565b8255505050565b6000813561352e81613237565b80915050919050565b60008160a01b9050919050565b600078ffffffffff000000000000000000000000000000000000000061356984613537565b9350801983169250808416831791505092915050565b600061359a613595613590846127eb565b613409565b6127eb565b9050919050565b6000819050919050565b6135b48261357f565b6135c76135c0826135a1565b8354613544565b8255505050565b60008160c81b9050919050565b60007dffffffffff00000000000000000000000000000000000000000000000000613605846135ce565b9350801983169250808416831791505092915050565b6136248261357f565b613637613630826135a1565b83546135db565b8255505050565b6000813561364b81612bf9565b80915050919050565b60008160f01b9050919050565b60007eff00000000000000000000000000000000000000000000000000000000000061368c84613654565b9350801983169250808416831791505092915050565b60006136ad8261288f565b9050919050565b6000819050919050565b6136c7826136a2565b6136da6136d3826136b4565b8354613661565b8255505050565b6000810160008301806136f3816133a4565b90506136ff818461343f565b50505060018101602083018061371481613462565b905061372081846134fe565b50505060018101604083018061373581613521565b905061374181846135ab565b50505060018101606083018061375681613521565b9050613762818461361b565b5050506001810160808301806137778161363e565b905061378381846136be565b5050505050565b61379482826136e1565b5050565b600060c0820190506137ad60008301856127b3565b6137ba6020830184613291565b9392505050565b60006137cc82612753565b91506137d783612753565b9250828203905060ff8111156137f0576137ef61313d565b5b92915050565b600061380182612826565b915061380c83612826565b92508282039050818111156138245761382361313d565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600081549050919050565b60008190508160005260206000209050919050565b60008160001c9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006138e86138e3836138a8565b6138b5565b9050919050565b60008160a01c9050919050565b600060ff82169050919050565b600061391c613917836138ef565b6138fc565b9050919050565b60008160a81c9050919050565b600061394361393e83613923565b6138fc565b9050919050565b60608201600080830154905061395f816138d5565b61396c6000860182612871565b5061397681613909565b6139836020860182612dd5565b5061398d81613930565b61399a6040860182612dd5565b5050505050565b60006139ad838361394a565b60608301905092915050565b6000600182019050919050565b60006139d182613888565b6139db8185612db4565b93506139e683613893565b8060005b83811015613a1657816139fd88826139a1565b9750613a08836139b9565b9250506001810190506139ea565b5085935050505092915050565b600060209050919050565b6000819050919050565b6000613a4b613a46836138a8565b6138fc565b9050919050565b60008160081c9050919050565b6000613a72613a6d83613a52565b6138fc565b9050919050565b60008160101c9050919050565b6000613a99613a9483613a79565b6138fc565b9050919050565b60008160181c9050919050565b6000613ac0613abb83613aa0565b6138fc565b9050919050565b60008160201c9050919050565b6000613ae7613ae283613ac7565b6138fc565b9050919050565b60008160281c9050919050565b6000613b0e613b0983613aee565b6138fc565b9050919050565b60008160301c9050919050565b6000613b35613b3083613b15565b6138fc565b9050919050565b60008160381c9050919050565b6000613b5c613b5783613b3c565b6138fc565b9050919050565b60008160401c9050919050565b6000613b83613b7e83613b63565b6138fc565b9050919050565b60008160481c9050919050565b6000613baa613ba583613b8a565b6138fc565b9050919050565b60008160501c9050919050565b6000613bd1613bcc83613bb1565b6138fc565b9050919050565b60008160581c9050919050565b6000613bf8613bf383613bd8565b6138fc565b9050919050565b60008160601c9050919050565b6000613c1f613c1a83613bff565b6138fc565b9050919050565b60008160681c9050919050565b6000613c46613c4183613c26565b6138fc565b9050919050565b60008160701c9050919050565b6000613c6d613c6883613c4d565b6138fc565b9050919050565b60008160781c9050919050565b6000613c94613c8f83613c74565b6138fc565b9050919050565b60008160801c9050919050565b6000613cbb613cb683613c9b565b6138fc565b9050919050565b60008160881c9050919050565b6000613ce2613cdd83613cc2565b6138fc565b9050919050565b60008160901c9050919050565b6000613d09613d0483613ce9565b6138fc565b9050919050565b60008160981c9050919050565b6000613d30613d2b83613d10565b6138fc565b9050919050565b60008160b01c9050919050565b6000613d57613d5283613d37565b6138fc565b9050919050565b60008160b81c9050919050565b6000613d7e613d7983613d5e565b6138fc565b9050919050565b60008160c01c9050919050565b6000613da5613da083613d85565b6138fc565b9050919050565b60008160c81c9050919050565b6000613dcc613dc783613dac565b6138fc565b9050919050565b60008160d01c9050919050565b6000613df3613dee83613dd3565b6138fc565b9050919050565b60008160d81c9050919050565b6000613e1a613e1583613dfa565b6138fc565b9050919050565b60008160e01c9050919050565b6000613e41613e3c83613e21565b6138fc565b9050919050565b60008160e81c9050919050565b6000613e68613e6383613e48565b6138fc565b9050919050565b60008160f01c9050919050565b6000613e8f613e8a83613e6f565b6138fc565b9050919050565b60008160f81c9050919050565b6000613eb6613eb183613e96565b6138fc565b9050919050565b613ec681613a23565b613ed08184612eb4565b925082613edc83613a2e565b6000600115614209575b83600160200382011015614208578154613f0887613f0383613a38565b612dd5565b602087019650613f2087613f1b83613a5f565b612dd5565b602087019650613f3887613f3383613a86565b612dd5565b602087019650613f5087613f4b83613aad565b612dd5565b602087019650613f6887613f6383613ad4565b612dd5565b602087019650613f8087613f7b83613afb565b612dd5565b602087019650613f9887613f9383613b22565b612dd5565b602087019650613fb087613fab83613b49565b612dd5565b602087019650613fc887613fc383613b70565b612dd5565b602087019650613fe087613fdb83613b97565b612dd5565b602087019650613ff887613ff383613bbe565b612dd5565b6020870196506140108761400b83613be5565b612dd5565b6020870196506140288761402383613c0c565b612dd5565b6020870196506140408761403b83613c33565b612dd5565b6020870196506140588761405383613c5a565b612dd5565b6020870196506140708761406b83613c81565b612dd5565b6020870196506140888761408383613ca8565b612dd5565b6020870196506140a08761409b83613ccf565b612dd5565b6020870196506140b8876140b383613cf6565b612dd5565b6020870196506140d0876140cb83613d1d565b612dd5565b6020870196506140e8876140e383613909565b612dd5565b602087019650614100876140fb83613930565b612dd5565b6020870196506141188761411383613d44565b612dd5565b6020870196506141308761412b83613d6b565b612dd5565b6020870196506141488761414383613d92565b612dd5565b6020870196506141608761415b83613db9565b612dd5565b6020870196506141788761417383613de0565b612dd5565b6020870196506141908761418b83613e07565b612dd5565b6020870196506141a8876141a383613e2e565b612dd5565b6020870196506141c0876141bb83613e55565b612dd5565b6020870196506141d8876141d383613e7c565b612dd5565b6020870196506141f0876141eb83613ea3565b612dd5565b60208701965060018301925050602081019050613ee6565b5b6000156146d45781546000156142385761422b8761422683613a38565b612dd5565b6020870196506001820191505b60001561425e576142518761424c83613a5f565b612dd5565b6020870196506001820191505b600015614284576142778761427283613a86565b612dd5565b6020870196506001820191505b6000156142aa5761429d8761429883613aad565b612dd5565b6020870196506001820191505b6000156142d0576142c3876142be83613ad4565b612dd5565b6020870196506001820191505b6000156142f6576142e9876142e483613afb565b612dd5565b6020870196506001820191505b60001561431c5761430f8761430a83613b22565b612dd5565b6020870196506001820191505b600015614342576143358761433083613b49565b612dd5565b6020870196506001820191505b6000156143685761435b8761435683613b70565b612dd5565b6020870196506001820191505b60001561438e576143818761437c83613b97565b612dd5565b6020870196506001820191505b6000156143b4576143a7876143a283613bbe565b612dd5565b6020870196506001820191505b6000156143da576143cd876143c883613be5565b612dd5565b6020870196506001820191505b600015614400576143f3876143ee83613c0c565b612dd5565b6020870196506001820191505b600015614426576144198761441483613c33565b612dd5565b6020870196506001820191505b60001561444c5761443f8761443a83613c5a565b612dd5565b6020870196506001820191505b600015614472576144658761446083613c81565b612dd5565b6020870196506001820191505b6000156144985761448b8761448683613ca8565b612dd5565b6020870196506001820191505b6000156144be576144b1876144ac83613ccf565b612dd5565b6020870196506001820191505b6000156144e4576144d7876144d283613cf6565b612dd5565b6020870196506001820191505b60001561450a576144fd876144f883613d1d565b612dd5565b6020870196506001820191505b600015614530576145238761451e83613909565b612dd5565b6020870196506001820191505b600015614556576145498761454483613930565b612dd5565b6020870196506001820191505b60001561457c5761456f8761456a83613d44565b612dd5565b6020870196506001820191505b6000156145a2576145958761459083613d6b565b612dd5565b6020870196506001820191505b6000156145c8576145bb876145b683613d92565b612dd5565b6020870196506001820191505b6000156145ee576145e1876145dc83613db9565b612dd5565b6020870196506001820191505b600015614614576146078761460283613de0565b612dd5565b6020870196506001820191505b60001561463a5761462d8761462883613e07565b612dd5565b6020870196506001820191505b600015614660576146538761464e83613e2e565b612dd5565b6020870196506001820191505b600015614686576146798761467483613e55565b612dd5565b6020870196506001820191505b6000156146ac5761469f8761469a83613e7c565b612dd5565b6020870196506001820191505b6000156146d2576146c5876146c083613ea3565b612dd5565b6020870196506001820191505b505b505050505050565b60006108208301600080840185830360008701526146fa83826139c6565b9250506001840161470e6020870182613ebd565b5060028401614721610420870182613ebd565b50819250505092915050565b6147368161288f565b82525050565b6000604082019050818103600083015261475681856146dc565b9050614765602083018461472d565b9392505050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261479857614797614776565b5b83810192508235915060208301925067ffffffffffffffff8211156147c0576147bf61476c565b5b6001820236038313156147d6576147d5614771565b5b509250929050565b600082825260208201905092915050565b82818337600083830152505050565b6000601f19601f8301169050919050565b600061481b83856147de565b93506148288385846147ef565b614831836147fe565b840190509392505050565b600060c0830161484f6000840184613209565b61485c6000860182612830565b5061486a6020840184613220565b6148776020860182612871565b506148856040840184613263565b6148926040860182612880565b506148a06060840184613220565b6148ad6060860182612871565b506148bb6080840184613209565b6148c86080860182612830565b506148d660a084018461477b565b85830360a08701526148e983828461480f565b925050508091505092915050565b600060408201905061490c6000830185612794565b818103602083015261491e818461483c565b90509392505050565b6000614932826127eb565b915061493d836127eb565b9250828201905064ffffffffff81111561495a5761495961313d565b5b92915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261498c5761498b614960565b5b80840192508235915067ffffffffffffffff8211156149ae576149ad614965565b5b6020830192506001820236038313156149ca576149c961496a565b5b509250929050565b600082825260208201905092915050565b60006149ef83856149d2565b93506149fc8385846147ef565b614a05836147fe565b840190509392505050565b614a1981612826565b82525050565b6000606082019050614a346000830187612ce4565b8181036020830152614a478185876149e3565b9050614a566040830184614a10565b95945050505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614a95602083613012565b9150614aa082614a5f565b602082019050919050565b60006020820190508181036000830152614ac481614a88565b9050919050565b600081905092915050565b6000614ae28385614acb565b9350614aef8385846147ef565b82840190509392505050565b6000614b08828486614ad6565b91508190509392505050565b600081519050919050565b60005b83811015614b3d578082015181840152602081019050614b22565b60008484015250505050565b6000614b5482614b14565b614b5e81856149d2565b9350614b6e818560208601614b1f565b614b77816147fe565b840191505092915050565b60006020820190508181036000830152614b9c8184614b49565b905092915050565b6000608082019050614bb96000830187612794565b614bc66020830186612760565b614bd36040830185612794565b614be06060830184612794565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b6000614c4e601883613012565b9150614c5982614c18565b602082019050919050565b60006020820190508181036000830152614c7d81614c41565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b6000614cba601f83613012565b9150614cc582614c84565b602082019050919050565b60006020820190508181036000830152614ce981614cad565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b6000614d4c602283613012565b9150614d5782614cf0565b604082019050919050565b60006020820190508181036000830152614d7b81614d3f565b905091905056fea264697066735822122045cbf269b54ca7c198dd51529c489b5618483f78020dd299a004081b92511b7464736f6c63430008130033

Deployed Bytecode

0x6080604052600436106100e15760003560e01c8063846c67ef1161007f578063b759d68511610059578063b759d68514610270578063c3f909d414610299578063e30c3978146102c4578063f2fde38b146102ef576100e8565b8063846c67ef146101f15780638da5cb5b1461021a578063a76f559814610245576100e8565b80636b45fb3e116100bb5780636b45fb3e1461016f578063715018a61461019a57806379ba5097146101b15780637cc38b28146101c8576100e8565b80635a2519ef146100ed5780635ca1e16514610118578063627e8a3b14610144576100e8565b366100e857005b600080fd5b3480156100f957600080fd5b50610102610318565b60405161010f919061276f565b60405180910390f35b34801561012457600080fd5b5061012d61031d565b60405161013b9291906127c2565b60405180910390f35b34801561015057600080fd5b5061015961039d565b604051610166919061280b565b60405180910390f35b34801561017b57600080fd5b506101846103bb565b6040516101919190612912565b60405180910390f35b3480156101a657600080fd5b506101af6104a2565b005b3480156101bd57600080fd5b506101c66104b6565b005b3480156101d457600080fd5b506101ef60048036038101906101ea9190612a6e565b610543565b005b3480156101fd57600080fd5b5061021860048036038101906102139190612c25565b610e03565b005b34801561022657600080fd5b5061022f61196d565b60405161023c9190612cf3565b60405180910390f35b34801561025157600080fd5b5061025a611996565b604051610267919061276f565b60405180910390f35b34801561027c57600080fd5b5061029760048036038101906102929190612d2d565b61199b565b005b3480156102a557600080fd5b506102ae611d76565b6040516102bb9190612f97565b60405180910390f35b3480156102d057600080fd5b506102d9611f51565b6040516102e69190612cf3565b60405180910390f35b3480156102fb57600080fd5b5061031660048036038101906103119190612fe5565b611f7b565b005b602081565b60008060006007604051806060016040529081600082015481526020016001820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160049054906101000a900464ffffffffff1664ffffffffff1664ffffffffff168152505090508060000151816020015192509250509091565b6000600760010160049054906101000a900464ffffffffff16905090565b6103c36125b7565b60096040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160149054906101000a900464ffffffffff1664ffffffffff1664ffffffffff1681526020016001820160199054906101000a900464ffffffffff1664ffffffffff1664ffffffffff16815260200160018201601e9054906101000a900460ff161515151581525050905090565b6104aa612028565b6104b460006120a6565b565b60006104c06120d7565b90508073ffffffffffffffffffffffffffffffffffffffff166104e1611f51565b73ffffffffffffffffffffffffffffffffffffffff1614610537576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052e90613095565b60405180910390fd5b610540816120a6565b50565b6000610576888860405160200161055b9291906127c2565b604051602081830303815290604052805190602001206120df565b90506006600082815260200190815260200160002060009054906101000a900460ff16156105d0576040517f48c2688b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105d861260c565b60006105e2612649565b60005b868690508110156108d55736878783818110610604576106036130b5565b5b90506060020190506000610634878360000160208101906106259190613110565b84602001358560400135612115565b90508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161061069b576040517f4a36ec0800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b809450600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1660ff1660ff1681526020016000820160159054906101000a900460ff1660ff1660ff168152505095508073ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff16146107e3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000866040015190505b6001156108bf57848160ff166020811061080a576108096130b5565b5b60200201805180919061081c9061316c565b60ff1660ff168152505060036001018160ff16602081106108405761083f6130b5565b5b602091828204019190069054906101000a900460ff1660ff16858260ff166020811061086f5761086e6130b5565b5b602002015160ff16036108bf5760008160ff1603156108bf5760036002018160ff16602081106108a2576108a16130b5565b5b602091828204019190069054906101000a900460ff1690506107ed565b50505080806108cd90613195565b9150506105e5565b50600060036001016000602081106108f0576108ef6130b5565b5b602091828204019190069054906101000a900460ff1660ff1603610940576040517faa6185ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003600101600060208110610958576109576130b5565b5b602091828204019190069054906101000a900460ff1660ff1681600060208110610985576109846130b5565b5b602002015160ff1610156109c5576040517fc2ee9b9e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050428763ffffffff161015610a08576040517fb057a45200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fe6b82be989101b4eb519770114b997b97b3c8707515286748a871717f0e4ea1c87604051602001610a3d929190613321565b604051602081830303815290604052805190602001209050610aa1868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508a83612140565b610ad7576040517f2522a1c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5085600001354614610b15576040517f5f87bc0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856020016020810190610b289190612fe5565b73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614610b8c576040517f9a84601500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600760010160049054906101000a900464ffffffffff169050600960010160199054906101000a900464ffffffffff1664ffffffffff168164ffffffffff1614158015610beb5750866080016020810190610be9919061334a565b155b15610c22576040517f3230825b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b866040016020810190610c359190613377565b64ffffffffff168164ffffffffff1614610c7b576040517fa255a76300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b866060016020810190610c8e9190613377565b64ffffffffff16876040016020810190610ca89190613377565b64ffffffffff161115610ce7576040517fc61352f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016006600084815260200190815260200160002060006101000a81548160ff02191690831515021790555060405180606001604052808a81526020018963ffffffff168152602001886040016020810190610d439190613377565b64ffffffffff1681525060076000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160010160046101000a81548164ffffffffff021916908364ffffffffff1602179055509050508660098181610dbb919061378a565b905050887f7ea643ae44677f24e0d6f40168893712daaf729b0a38fe7702d21cb544c841018989604051610df0929190613798565b60405180910390a2505050505050505050565b610e0b612028565b6000878790501480610e23575060c860ff1687879050115b15610e5a576040517ff0ec1ca400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b848490508787905014610e99576040517ff1f3053000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ea1612649565b60005b86869050811015610f8257602060ff16878783818110610ec757610ec66130b5565b5b9050602002016020810190610edc9190613110565b60ff1610610f16576040517fb9ae8e5200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81878783818110610f2a57610f296130b5565b5b9050602002016020810190610f3f9190613110565b60ff1660208110610f5357610f526130b5565b5b602002018051809190610f659061316c565b60ff1660ff16815250508080610f7a90613195565b915050610ea4565b5060005b602060ff168110156111da5760008160016020610fa391906137c1565b60ff16610fb091906137f6565b905060008114158015610feb575080858260208110610fd257610fd16130b5565b5b602002016020810190610fe59190613110565b60ff1610155b8061102b575060008114801561102a57506000858260208110611011576110106130b5565b5b6020020160208101906110249190613110565b60ff1614155b5b15611062576040517fff063a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080878360208110611078576110776130b5565b5b60200201602081019061108b9190613110565b60ff1614905080156110f1578382602081106110aa576110a96130b5565b5b602002015160ff16600010156110ec576040517f8db4e75d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111c5565b868260208110611104576111036130b5565b5b6020020160208101906111179190613110565b60ff1684836020811061112d5761112c6130b5565b5b602002015160ff16101561116d576040517fbb00136e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83868360208110611181576111806130b5565b5b6020020160208101906111949190613110565b60ff16602081106111a8576111a76130b5565b5b6020020180518091906111ba9061316c565b60ff1660ff16815250505b505080806111d290613195565b915050610f86565b505060006003600001805480602002602001604051908101604052809291908181526020016000905b828210156112c1578382906000526020600020016040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1660ff1660ff1681526020016000820160159054906101000a900460ff1660ff1660ff168152505081526020019060010190611203565b50505050905060005b81518110156114145760008282815181106112e8576112e76130b5565b5b6020026020010151600001519050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549060ff02191690556000820160156101000a81549060ff02191690555050600360000180548061139c5761139b61382a565b5b60019003818190600052602060002001600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549060ff02191690556000820160156101000a81549060ff02191690555050905550808061140c90613195565b9150506112ca565b5060006003600001805490501461142e5761142d613859565b5b83600360010190602061144292919061266c565b5082600360020190602061145792919061266c565b506000805b898990508110156117635789898281811061147a576114796130b5565b5b905060200201602081019061148f9190612fe5565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16106114f3576040517f4a36ec0800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060405180606001604052808c8c85818110611513576115126130b5565b5b90506020020160208101906115289190612fe5565b73ffffffffffffffffffffffffffffffffffffffff1681526020018360ff1681526020018a8a8581811061155f5761155e6130b5565b5b90506020020160208101906115749190613110565b60ff16815250905080600260008d8d86818110611594576115936130b5565b5b90506020020160208101906115a99190612fe5565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff021916908360ff16021790555060408201518160000160156101000a81548160ff021916908360ff1602179055509050506003600001819080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548160ff021916908360ff16021790555060408201518160000160156101000a81548160ff021916908360ff16021790555050508a8a83818110611738576117376130b5565b5b905060200201602081019061174d9190612fe5565b925050808061175b90613195565b91505061145c565b508215611928576000600760010160049054906101000a900464ffffffffff16905060405180606001604052806000801b8152602001600063ffffffff1681526020018264ffffffffff1681525060076000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160010160046101000a81548164ffffffffff021916908364ffffffffff1602179055509050506040518060a001604052804681526020013073ffffffffffffffffffffffffffffffffffffffff1681526020018264ffffffffff1681526020018264ffffffffff1681526020016001151581525060096000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160146101000a81548164ffffffffff021916908364ffffffffff16021790555060608201518160010160196101000a81548164ffffffffff021916908364ffffffffff160217905550608082015181600101601e6101000a81548160ff021916908315150217905550905050505b7f0a4974ad206b9c736f9ab2feac1c9b1d043fe4ef377c70ae45659f2ef089f03e60038460405161195a92919061473c565b60405180910390a1505050505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60c881565b60006007604051806060016040529081600082015481526020016001820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160049054906101000a900464ffffffffff1664ffffffffff1664ffffffffff16815250509050806040015164ffffffffff16600960010160199054906101000a900464ffffffffff1664ffffffffff1611611a66576040517fadb1331800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46846000013514611aa3576040517f5f87bc0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16846020016020810190611acd9190612fe5565b73ffffffffffffffffffffffffffffffffffffffff1614611b1a576040517f9a84601500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806020015163ffffffff16421115611b5e576040517f9ba6743000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015164ffffffffff16846040016020810190611b7d9190613377565b64ffffffffff1614611bbb576040517fd9c6386f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f08d275622006c4ca82d03f498e90163cafd53c663a48470c3b52ac8bfbd9f52c85604051602001611bf09291906148f7565b604051602081830303815290604052805190602001209050611c58848480806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050836000015183612140565b611c8e576040517f2522a1c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018260400151611c9f9190614927565b600760010160046101000a81548164ffffffffff021916908364ffffffffff160217905550611cf4856060016020810190611cda9190612fe5565b8660800135878060a00190611cef919061496f565b612157565b846040016020810190611d079190613377565b64ffffffffff167f87d58fdd48be753fb9ef4ec8a5895086c401506da8b4d752abc90602c3e62d1d866060016020810190611d429190612fe5565b878060a00190611d52919061496f565b8960800135604051611d679493929190614a1f565b60405180910390a25050505050565b611d7e612709565b600360405180606001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611e6e578382906000526020600020016040518060600160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a900460ff1660ff1660ff1681526020016000820160159054906101000a900460ff1660ff1660ff168152505081526020019060010190611db0565b50505050815260200160018201602080602002604051908101604052809291908260208015611ed8576020028201916000905b82829054906101000a900460ff1660ff1681526020019060010190602082600001049283019260010382029150808411611ea15790505b5050505050815260200160028201602080602002604051908101604052809291908260208015611f43576020028201916000905b82829054906101000a900460ff1660ff1681526020019060010190602082600001049283019260010382029150808411611f0c5790505b505050505081525050905090565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611f83612028565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611fe361196d565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6120306120d7565b73ffffffffffffffffffffffffffffffffffffffff1661204e61196d565b73ffffffffffffffffffffffffffffffffffffffff16146120a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161209b90614aab565b60405180910390fd5b565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556120d481612213565b50565b600033905090565b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005281601c52603c6000209050919050565b6000806000612126878787876122d7565b91509150612133816123b9565b8192505050949350505050565b60008261214d858461251f565b1490509392505050565b6000808573ffffffffffffffffffffffffffffffffffffffff16858585604051612182929190614afb565b60006040518083038185875af1925050503d80600081146121bf576040519150601f19603f3d011682016040523d82523d6000602084013e6121c4565b606091505b50915091508161220b57806040517f70de1b4b0000000000000000000000000000000000000000000000000000000081526004016122029190614b82565b60405180910390fd5b505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c11156123125760006003915091506123b0565b6000600187878787604051600081526020016040526040516123379493929190614ba4565b6020604051602081039080840390855afa158015612359573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036123a7576000600192509250506123b0565b80600092509250505b94509492505050565b600060048111156123cd576123cc614be9565b5b8160048111156123e0576123df614be9565b5b031561251c57600160048111156123fa576123f9614be9565b5b81600481111561240d5761240c614be9565b5b0361244d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161244490614c64565b60405180910390fd5b6002600481111561246157612460614be9565b5b81600481111561247457612473614be9565b5b036124b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ab90614cd0565b60405180910390fd5b600360048111156124c8576124c7614be9565b5b8160048111156124db576124da614be9565b5b0361251b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161251290614d62565b60405180910390fd5b5b50565b60008082905060005b845181101561256a5761255582868381518110612548576125476130b5565b5b6020026020010151612575565b9150808061256290613195565b915050612528565b508091505092915050565b600081831061258d5761258882846125a0565b612598565b61259783836125a0565b5b905092915050565b600082600052816020526040600020905092915050565b6040518060a0016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600064ffffffffff168152602001600064ffffffffff1681526020016000151581525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b604051806104000160405280602090602082028036833780820191505090505090565b826020601f016020900481019282156126f85791602002820160005b838211156126c957833560ff1683826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302612688565b80156126f65782816101000a81549060ff02191690556001016020816000010492830192600103026126c9565b505b5090506127059190612736565b5090565b604051806060016040528060608152602001612723612649565b8152602001612730612649565b81525090565b5b8082111561274f576000816000905550600101612737565b5090565b600060ff82169050919050565b61276981612753565b82525050565b60006020820190506127846000830184612760565b92915050565b6000819050919050565b61279d8161278a565b82525050565b600063ffffffff82169050919050565b6127bc816127a3565b82525050565b60006040820190506127d76000830185612794565b6127e460208301846127b3565b9392505050565b600064ffffffffff82169050919050565b612805816127eb565b82525050565b600060208201905061282060008301846127fc565b92915050565b6000819050919050565b61283981612826565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061286a8261283f565b9050919050565b61287a8161285f565b82525050565b612889816127eb565b82525050565b60008115159050919050565b6128a48161288f565b82525050565b60a0820160008201516128c06000850182612830565b5060208201516128d36020850182612871565b5060408201516128e66040850182612880565b5060608201516128f96060850182612880565b50608082015161290c608085018261289b565b50505050565b600060a08201905061292760008301846128aa565b92915050565b600080fd5b600080fd5b6129408161278a565b811461294b57600080fd5b50565b60008135905061295d81612937565b92915050565b61296c816127a3565b811461297757600080fd5b50565b60008135905061298981612963565b92915050565b600080fd5b600060a082840312156129aa576129a961298f565b5b81905092915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126129d8576129d76129b3565b5b8235905067ffffffffffffffff8111156129f5576129f46129b8565b5b602083019150836020820283011115612a1157612a106129bd565b5b9250929050565b60008083601f840112612a2e57612a2d6129b3565b5b8235905067ffffffffffffffff811115612a4b57612a4a6129b8565b5b602083019150836060820283011115612a6757612a666129bd565b5b9250929050565b6000806000806000806000610120888a031215612a8e57612a8d61292d565b5b6000612a9c8a828b0161294e565b9750506020612aad8a828b0161297a565b9650506040612abe8a828b01612994565b95505060e088013567ffffffffffffffff811115612adf57612ade612932565b5b612aeb8a828b016129c2565b945094505061010088013567ffffffffffffffff811115612b0f57612b0e612932565b5b612b1b8a828b01612a18565b925092505092959891949750929550565b60008083601f840112612b4257612b416129b3565b5b8235905067ffffffffffffffff811115612b5f57612b5e6129b8565b5b602083019150836020820283011115612b7b57612b7a6129bd565b5b9250929050565b60008083601f840112612b9857612b976129b3565b5b8235905067ffffffffffffffff811115612bb557612bb46129b8565b5b602083019150836020820283011115612bd157612bd06129bd565b5b9250929050565b6000819050826020800282011115612bf357612bf26129bd565b5b92915050565b612c028161288f565b8114612c0d57600080fd5b50565b600081359050612c1f81612bf9565b92915050565b6000806000806000806000610860888a031215612c4557612c4461292d565b5b600088013567ffffffffffffffff811115612c6357612c62612932565b5b612c6f8a828b01612b2c565b9750975050602088013567ffffffffffffffff811115612c9257612c91612932565b5b612c9e8a828b01612b82565b95509550506040612cb18a828b01612bd8565b935050610440612cc38a828b01612bd8565b925050610840612cd58a828b01612c10565b91505092959891949750929550565b612ced8161285f565b82525050565b6000602082019050612d086000830184612ce4565b92915050565b600060c08284031215612d2457612d2361298f565b5b81905092915050565b600080600060408486031215612d4657612d4561292d565b5b600084013567ffffffffffffffff811115612d6457612d63612932565b5b612d7086828701612d0e565b935050602084013567ffffffffffffffff811115612d9157612d90612932565b5b612d9d868287016129c2565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612dde81612753565b82525050565b606082016000820151612dfa6000850182612871565b506020820151612e0d6020850182612dd5565b506040820151612e206040850182612dd5565b50505050565b6000612e328383612de4565b60608301905092915050565b6000602082019050919050565b6000612e5682612da9565b612e608185612db4565b9350612e6b83612dc5565b8060005b83811015612e9c578151612e838882612e26565b9750612e8e83612e3e565b925050600181019050612e6f565b5085935050505092915050565b600060209050919050565b600081905092915050565b6000819050919050565b6000612ed58383612dd5565b60208301905092915050565b6000602082019050919050565b612ef781612ea9565b612f018184612eb4565b9250612f0c82612ebf565b8060005b83811015612f3d578151612f248782612ec9565b9650612f2f83612ee1565b925050600181019050612f10565b505050505050565b6000610820830160008301518482036000860152612f638282612e4b565b9150506020830151612f786020860182612eee565b506040830151612f8c610420860182612eee565b508091505092915050565b60006020820190508181036000830152612fb18184612f45565b905092915050565b612fc28161285f565b8114612fcd57600080fd5b50565b600081359050612fdf81612fb9565b92915050565b600060208284031215612ffb57612ffa61292d565b5b600061300984828501612fd0565b91505092915050565b600082825260208201905092915050565b7f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060008201527f6e6577206f776e65720000000000000000000000000000000000000000000000602082015250565b600061307f602983613012565b915061308a82613023565b604082019050919050565b600060208201905081810360008301526130ae81613072565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6130ed81612753565b81146130f857600080fd5b50565b60008135905061310a816130e4565b92915050565b6000602082840312156131265761312561292d565b5b6000613134848285016130fb565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061317782612753565b915060ff820361318a5761318961313d565b5b600182019050919050565b60006131a082612826565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036131d2576131d161313d565b5b600182019050919050565b6131e681612826565b81146131f157600080fd5b50565b600081359050613203816131dd565b92915050565b600061321860208401846131f4565b905092915050565b600061322f6020840184612fd0565b905092915050565b613240816127eb565b811461324b57600080fd5b50565b60008135905061325d81613237565b92915050565b6000613272602084018461324e565b905092915050565b60006132896020840184612c10565b905092915050565b60a082016132a26000830183613209565b6132af6000850182612830565b506132bd6020830183613220565b6132ca6020850182612871565b506132d86040830183613263565b6132e56040850182612880565b506132f36060830183613263565b6133006060850182612880565b5061330e608083018361327a565b61331b608085018261289b565b50505050565b600060c0820190506133366000830185612794565b6133436020830184613291565b9392505050565b6000602082840312156133605761335f61292d565b5b600061336e84828501612c10565b91505092915050565b60006020828403121561338d5761338c61292d565b5b600061339b8482850161324e565b91505092915050565b600081356133b1816131dd565b80915050919050565b60008160001b9050919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6133f3846133ba565b9350801983169250808416831791505092915050565b6000819050919050565b600061342e61342961342484612826565b613409565b612826565b9050919050565b6000819050919050565b61344882613413565b61345b61345482613435565b83546133c7565b8255505050565b6000813561346f81612fb9565b80915050919050565b600073ffffffffffffffffffffffffffffffffffffffff613498846133ba565b9350801983169250808416831791505092915050565b60006134c96134c46134bf8461283f565b613409565b61283f565b9050919050565b60006134db826134ae565b9050919050565b60006134ed826134d0565b9050919050565b6000819050919050565b613507826134e2565b61351a613513826134f4565b8354613478565b8255505050565b6000813561352e81613237565b80915050919050565b60008160a01b9050919050565b600078ffffffffff000000000000000000000000000000000000000061356984613537565b9350801983169250808416831791505092915050565b600061359a613595613590846127eb565b613409565b6127eb565b9050919050565b6000819050919050565b6135b48261357f565b6135c76135c0826135a1565b8354613544565b8255505050565b60008160c81b9050919050565b60007dffffffffff00000000000000000000000000000000000000000000000000613605846135ce565b9350801983169250808416831791505092915050565b6136248261357f565b613637613630826135a1565b83546135db565b8255505050565b6000813561364b81612bf9565b80915050919050565b60008160f01b9050919050565b60007eff00000000000000000000000000000000000000000000000000000000000061368c84613654565b9350801983169250808416831791505092915050565b60006136ad8261288f565b9050919050565b6000819050919050565b6136c7826136a2565b6136da6136d3826136b4565b8354613661565b8255505050565b6000810160008301806136f3816133a4565b90506136ff818461343f565b50505060018101602083018061371481613462565b905061372081846134fe565b50505060018101604083018061373581613521565b905061374181846135ab565b50505060018101606083018061375681613521565b9050613762818461361b565b5050506001810160808301806137778161363e565b905061378381846136be565b5050505050565b61379482826136e1565b5050565b600060c0820190506137ad60008301856127b3565b6137ba6020830184613291565b9392505050565b60006137cc82612753565b91506137d783612753565b9250828203905060ff8111156137f0576137ef61313d565b5b92915050565b600061380182612826565b915061380c83612826565b92508282039050818111156138245761382361313d565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600081549050919050565b60008190508160005260206000209050919050565b60008160001c9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006138e86138e3836138a8565b6138b5565b9050919050565b60008160a01c9050919050565b600060ff82169050919050565b600061391c613917836138ef565b6138fc565b9050919050565b60008160a81c9050919050565b600061394361393e83613923565b6138fc565b9050919050565b60608201600080830154905061395f816138d5565b61396c6000860182612871565b5061397681613909565b6139836020860182612dd5565b5061398d81613930565b61399a6040860182612dd5565b5050505050565b60006139ad838361394a565b60608301905092915050565b6000600182019050919050565b60006139d182613888565b6139db8185612db4565b93506139e683613893565b8060005b83811015613a1657816139fd88826139a1565b9750613a08836139b9565b9250506001810190506139ea565b5085935050505092915050565b600060209050919050565b6000819050919050565b6000613a4b613a46836138a8565b6138fc565b9050919050565b60008160081c9050919050565b6000613a72613a6d83613a52565b6138fc565b9050919050565b60008160101c9050919050565b6000613a99613a9483613a79565b6138fc565b9050919050565b60008160181c9050919050565b6000613ac0613abb83613aa0565b6138fc565b9050919050565b60008160201c9050919050565b6000613ae7613ae283613ac7565b6138fc565b9050919050565b60008160281c9050919050565b6000613b0e613b0983613aee565b6138fc565b9050919050565b60008160301c9050919050565b6000613b35613b3083613b15565b6138fc565b9050919050565b60008160381c9050919050565b6000613b5c613b5783613b3c565b6138fc565b9050919050565b60008160401c9050919050565b6000613b83613b7e83613b63565b6138fc565b9050919050565b60008160481c9050919050565b6000613baa613ba583613b8a565b6138fc565b9050919050565b60008160501c9050919050565b6000613bd1613bcc83613bb1565b6138fc565b9050919050565b60008160581c9050919050565b6000613bf8613bf383613bd8565b6138fc565b9050919050565b60008160601c9050919050565b6000613c1f613c1a83613bff565b6138fc565b9050919050565b60008160681c9050919050565b6000613c46613c4183613c26565b6138fc565b9050919050565b60008160701c9050919050565b6000613c6d613c6883613c4d565b6138fc565b9050919050565b60008160781c9050919050565b6000613c94613c8f83613c74565b6138fc565b9050919050565b60008160801c9050919050565b6000613cbb613cb683613c9b565b6138fc565b9050919050565b60008160881c9050919050565b6000613ce2613cdd83613cc2565b6138fc565b9050919050565b60008160901c9050919050565b6000613d09613d0483613ce9565b6138fc565b9050919050565b60008160981c9050919050565b6000613d30613d2b83613d10565b6138fc565b9050919050565b60008160b01c9050919050565b6000613d57613d5283613d37565b6138fc565b9050919050565b60008160b81c9050919050565b6000613d7e613d7983613d5e565b6138fc565b9050919050565b60008160c01c9050919050565b6000613da5613da083613d85565b6138fc565b9050919050565b60008160c81c9050919050565b6000613dcc613dc783613dac565b6138fc565b9050919050565b60008160d01c9050919050565b6000613df3613dee83613dd3565b6138fc565b9050919050565b60008160d81c9050919050565b6000613e1a613e1583613dfa565b6138fc565b9050919050565b60008160e01c9050919050565b6000613e41613e3c83613e21565b6138fc565b9050919050565b60008160e81c9050919050565b6000613e68613e6383613e48565b6138fc565b9050919050565b60008160f01c9050919050565b6000613e8f613e8a83613e6f565b6138fc565b9050919050565b60008160f81c9050919050565b6000613eb6613eb183613e96565b6138fc565b9050919050565b613ec681613a23565b613ed08184612eb4565b925082613edc83613a2e565b6000600115614209575b83600160200382011015614208578154613f0887613f0383613a38565b612dd5565b602087019650613f2087613f1b83613a5f565b612dd5565b602087019650613f3887613f3383613a86565b612dd5565b602087019650613f5087613f4b83613aad565b612dd5565b602087019650613f6887613f6383613ad4565b612dd5565b602087019650613f8087613f7b83613afb565b612dd5565b602087019650613f9887613f9383613b22565b612dd5565b602087019650613fb087613fab83613b49565b612dd5565b602087019650613fc887613fc383613b70565b612dd5565b602087019650613fe087613fdb83613b97565b612dd5565b602087019650613ff887613ff383613bbe565b612dd5565b6020870196506140108761400b83613be5565b612dd5565b6020870196506140288761402383613c0c565b612dd5565b6020870196506140408761403b83613c33565b612dd5565b6020870196506140588761405383613c5a565b612dd5565b6020870196506140708761406b83613c81565b612dd5565b6020870196506140888761408383613ca8565b612dd5565b6020870196506140a08761409b83613ccf565b612dd5565b6020870196506140b8876140b383613cf6565b612dd5565b6020870196506140d0876140cb83613d1d565b612dd5565b6020870196506140e8876140e383613909565b612dd5565b602087019650614100876140fb83613930565b612dd5565b6020870196506141188761411383613d44565b612dd5565b6020870196506141308761412b83613d6b565b612dd5565b6020870196506141488761414383613d92565b612dd5565b6020870196506141608761415b83613db9565b612dd5565b6020870196506141788761417383613de0565b612dd5565b6020870196506141908761418b83613e07565b612dd5565b6020870196506141a8876141a383613e2e565b612dd5565b6020870196506141c0876141bb83613e55565b612dd5565b6020870196506141d8876141d383613e7c565b612dd5565b6020870196506141f0876141eb83613ea3565b612dd5565b60208701965060018301925050602081019050613ee6565b5b6000156146d45781546000156142385761422b8761422683613a38565b612dd5565b6020870196506001820191505b60001561425e576142518761424c83613a5f565b612dd5565b6020870196506001820191505b600015614284576142778761427283613a86565b612dd5565b6020870196506001820191505b6000156142aa5761429d8761429883613aad565b612dd5565b6020870196506001820191505b6000156142d0576142c3876142be83613ad4565b612dd5565b6020870196506001820191505b6000156142f6576142e9876142e483613afb565b612dd5565b6020870196506001820191505b60001561431c5761430f8761430a83613b22565b612dd5565b6020870196506001820191505b600015614342576143358761433083613b49565b612dd5565b6020870196506001820191505b6000156143685761435b8761435683613b70565b612dd5565b6020870196506001820191505b60001561438e576143818761437c83613b97565b612dd5565b6020870196506001820191505b6000156143b4576143a7876143a283613bbe565b612dd5565b6020870196506001820191505b6000156143da576143cd876143c883613be5565b612dd5565b6020870196506001820191505b600015614400576143f3876143ee83613c0c565b612dd5565b6020870196506001820191505b600015614426576144198761441483613c33565b612dd5565b6020870196506001820191505b60001561444c5761443f8761443a83613c5a565b612dd5565b6020870196506001820191505b600015614472576144658761446083613c81565b612dd5565b6020870196506001820191505b6000156144985761448b8761448683613ca8565b612dd5565b6020870196506001820191505b6000156144be576144b1876144ac83613ccf565b612dd5565b6020870196506001820191505b6000156144e4576144d7876144d283613cf6565b612dd5565b6020870196506001820191505b60001561450a576144fd876144f883613d1d565b612dd5565b6020870196506001820191505b600015614530576145238761451e83613909565b612dd5565b6020870196506001820191505b600015614556576145498761454483613930565b612dd5565b6020870196506001820191505b60001561457c5761456f8761456a83613d44565b612dd5565b6020870196506001820191505b6000156145a2576145958761459083613d6b565b612dd5565b6020870196506001820191505b6000156145c8576145bb876145b683613d92565b612dd5565b6020870196506001820191505b6000156145ee576145e1876145dc83613db9565b612dd5565b6020870196506001820191505b600015614614576146078761460283613de0565b612dd5565b6020870196506001820191505b60001561463a5761462d8761462883613e07565b612dd5565b6020870196506001820191505b600015614660576146538761464e83613e2e565b612dd5565b6020870196506001820191505b600015614686576146798761467483613e55565b612dd5565b6020870196506001820191505b6000156146ac5761469f8761469a83613e7c565b612dd5565b6020870196506001820191505b6000156146d2576146c5876146c083613ea3565b612dd5565b6020870196506001820191505b505b505050505050565b60006108208301600080840185830360008701526146fa83826139c6565b9250506001840161470e6020870182613ebd565b5060028401614721610420870182613ebd565b50819250505092915050565b6147368161288f565b82525050565b6000604082019050818103600083015261475681856146dc565b9050614765602083018461472d565b9392505050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261479857614797614776565b5b83810192508235915060208301925067ffffffffffffffff8211156147c0576147bf61476c565b5b6001820236038313156147d6576147d5614771565b5b509250929050565b600082825260208201905092915050565b82818337600083830152505050565b6000601f19601f8301169050919050565b600061481b83856147de565b93506148288385846147ef565b614831836147fe565b840190509392505050565b600060c0830161484f6000840184613209565b61485c6000860182612830565b5061486a6020840184613220565b6148776020860182612871565b506148856040840184613263565b6148926040860182612880565b506148a06060840184613220565b6148ad6060860182612871565b506148bb6080840184613209565b6148c86080860182612830565b506148d660a084018461477b565b85830360a08701526148e983828461480f565b925050508091505092915050565b600060408201905061490c6000830185612794565b818103602083015261491e818461483c565b90509392505050565b6000614932826127eb565b915061493d836127eb565b9250828201905064ffffffffff81111561495a5761495961313d565b5b92915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261498c5761498b614960565b5b80840192508235915067ffffffffffffffff8211156149ae576149ad614965565b5b6020830192506001820236038313156149ca576149c961496a565b5b509250929050565b600082825260208201905092915050565b60006149ef83856149d2565b93506149fc8385846147ef565b614a05836147fe565b840190509392505050565b614a1981612826565b82525050565b6000606082019050614a346000830187612ce4565b8181036020830152614a478185876149e3565b9050614a566040830184614a10565b95945050505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000614a95602083613012565b9150614aa082614a5f565b602082019050919050565b60006020820190508181036000830152614ac481614a88565b9050919050565b600081905092915050565b6000614ae28385614acb565b9350614aef8385846147ef565b82840190509392505050565b6000614b08828486614ad6565b91508190509392505050565b600081519050919050565b60005b83811015614b3d578082015181840152602081019050614b22565b60008484015250505050565b6000614b5482614b14565b614b5e81856149d2565b9350614b6e818560208601614b1f565b614b77816147fe565b840191505092915050565b60006020820190508181036000830152614b9c8184614b49565b905092915050565b6000608082019050614bb96000830187612794565b614bc66020830186612760565b614bd36040830185612794565b614be06060830184612794565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b6000614c4e601883613012565b9150614c5982614c18565b602082019050919050565b60006020820190508181036000830152614c7d81614c41565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b6000614cba601f83613012565b9150614cc582614c84565b602082019050919050565b60006020820190508181036000830152614ce981614cad565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b6000614d4c602283613012565b9150614d5782614cf0565b604082019050919050565b60006020820190508181036000830152614d7b81614d3f565b905091905056fea264697066735822122045cbf269b54ca7c198dd51529c489b5618483f78020dd299a004081b92511b7464736f6c63430008130033

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
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.