Sepolia Testnet

Contract

0xAcAaaa98b9E23725046edA88D371B4864d90496b

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Request Batch Ve...57116142024-04-16 15:37:36341 days ago1713281856
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116142024-04-16 15:37:36341 days ago1713281856
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57116122024-04-16 15:37:12341 days ago1713281832
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116122024-04-16 15:37:12341 days ago1713281832
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57116102024-04-16 15:36:48341 days ago1713281808
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116102024-04-16 15:36:48341 days ago1713281808
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57116082024-04-16 15:36:24341 days ago1713281784
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116082024-04-16 15:36:24341 days ago1713281784
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57116062024-04-16 15:36:00341 days ago1713281760
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116062024-04-16 15:36:00341 days ago1713281760
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57116042024-04-16 15:35:36341 days ago1713281736
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116042024-04-16 15:35:36341 days ago1713281736
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57116022024-04-16 15:35:12341 days ago1713281712
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116022024-04-16 15:35:12341 days ago1713281712
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57116002024-04-16 15:34:48341 days ago1713281688
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57116002024-04-16 15:34:48341 days ago1713281688
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57115982024-04-16 15:34:24341 days ago1713281664
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57115982024-04-16 15:34:24341 days ago1713281664
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57115962024-04-16 15:34:00341 days ago1713281640
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57115962024-04-16 15:34:00341 days ago1713281640
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57115942024-04-16 15:33:36341 days ago1713281616
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57115942024-04-16 15:33:36341 days ago1713281616
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57115922024-04-16 15:33:12341 days ago1713281592
0xAcAaaa98...64d90496b
0.0000001 ETH
Write Entry With...57115922024-04-16 15:33:12341 days ago1713281592
0xAcAaaa98...64d90496b
0.0000001 ETH
Request Batch Ve...57115902024-04-16 15:32:48341 days ago1713281568
0xAcAaaa98...64d90496b
0.0000001 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
InterchainDB

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 8 : InterchainDB.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {InterchainDBEvents} from "./events/InterchainDBEvents.sol";
import {IInterchainDB} from "./interfaces/IInterchainDB.sol";
import {IInterchainModule} from "./interfaces/IInterchainModule.sol";

import {InterchainBatch, InterchainBatchLib} from "./libs/InterchainBatch.sol";
import {InterchainEntry, InterchainEntryLib} from "./libs/InterchainEntry.sol";
import {VersionedPayloadLib} from "./libs/VersionedPayload.sol";

contract InterchainDB is InterchainDBEvents, IInterchainDB {
    using VersionedPayloadLib for bytes;

    uint16 public constant DB_VERSION = 1;

    bytes32[] internal _entryValues;
    mapping(address module => mapping(bytes32 batchKey => RemoteBatch batch)) internal _remoteBatches;

    modifier onlyRemoteChainId(uint256 chainId) {
        if (chainId == block.chainid) {
            revert InterchainDB__SameChainId(block.chainid);
        }
        _;
    }

    // ═══════════════════════════════════════════════ WRITER-FACING ═══════════════════════════════════════════════════

    /// @inheritdoc IInterchainDB
    function writeEntry(bytes32 dataHash) external returns (uint256 dbNonce, uint64 entryIndex) {
        InterchainEntry memory entry = _writeEntry(dataHash);
        (dbNonce, entryIndex) = (entry.dbNonce, entry.entryIndex);
    }

    /// @inheritdoc IInterchainDB
    function requestBatchVerification(
        uint256 dstChainId,
        uint256 dbNonce,
        address[] calldata srcModules
    )
        external
        payable
        onlyRemoteChainId(dstChainId)
    {
        InterchainBatch memory batch = getBatch(dbNonce);
        _requestVerification(dstChainId, batch, srcModules);
    }

    /// @inheritdoc IInterchainDB
    function writeEntryWithVerification(
        uint256 dstChainId,
        bytes32 dataHash,
        address[] calldata srcModules
    )
        external
        payable
        onlyRemoteChainId(dstChainId)
        returns (uint256 dbNonce, uint64 entryIndex)
    {
        InterchainEntry memory entry = _writeEntry(dataHash);
        (dbNonce, entryIndex) = (entry.dbNonce, entry.entryIndex);
        // In "no batching" mode: the batch root is the same as the entry value
        InterchainBatch memory batch = InterchainBatchLib.constructLocalBatch(dbNonce, entry.entryValue());
        _requestVerification(dstChainId, batch, srcModules);
    }

    // ═══════════════════════════════════════════════ MODULE-FACING ═══════════════════════════════════════════════════

    /// @inheritdoc IInterchainDB
    function verifyRemoteBatch(bytes calldata versionedBatch) external {
        uint16 dbVersion = versionedBatch.getVersion();
        if (dbVersion != DB_VERSION) {
            revert InterchainDB__InvalidBatchVersion(dbVersion);
        }
        InterchainBatch memory batch = InterchainBatchLib.decodeBatch(versionedBatch.getPayload());
        if (batch.srcChainId == block.chainid) {
            revert InterchainDB__SameChainId(batch.srcChainId);
        }
        bytes32 batchKey = InterchainBatchLib.batchKey(batch);
        RemoteBatch memory existingBatch = _remoteBatches[msg.sender][batchKey];
        // Check if that's the first time module verifies the batch
        if (existingBatch.verifiedAt == 0) {
            _remoteBatches[msg.sender][batchKey] =
                RemoteBatch({verifiedAt: block.timestamp, batchRoot: batch.batchRoot});
            emit InterchainBatchVerified(msg.sender, batch.srcChainId, batch.dbNonce, batch.batchRoot);
        } else {
            // If the module has already verified the batch, check that the batch root is the same
            if (existingBatch.batchRoot != batch.batchRoot) {
                revert InterchainDB__ConflictingBatches(msg.sender, existingBatch.batchRoot, batch);
            }
            // No-op if the batch root is the same
        }
    }

    // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════

    /// @inheritdoc IInterchainDB
    function getBatchLeafsPaginated(
        uint256 dbNonce,
        uint64 start,
        uint64 end
    )
        external
        view
        returns (bytes32[] memory leafs)
    {
        if (start != 0 || end != 1) {
            revert InterchainDB__InvalidEntryRange(dbNonce, start, end);
        }
        return getBatchLeafs(dbNonce);
    }

    /// @inheritdoc IInterchainDB
    function getEntryProof(uint256 dbNonce, uint64 entryIndex) external view returns (bytes32[] memory proof) {
        // In "no batching" mode: the batch root is the same as the entry value, hence the proof is empty
        _assertBatchFinalized(dbNonce);
        _assertEntryExists(dbNonce, entryIndex);
        return new bytes32[](0);
    }

    /// @inheritdoc IInterchainDB
    function getInterchainFee(uint256 dstChainId, address[] calldata srcModules) external view returns (uint256 fee) {
        (, fee) = _getModuleFees(dstChainId, getDBNonce(), srcModules);
    }

    /// @inheritdoc IInterchainDB
    function getNextEntryIndex() external view returns (uint256 dbNonce, uint64 entryIndex) {
        // In "no batching" mode: entry index is 0, batch size is 1
        dbNonce = getDBNonce();
        entryIndex = 0;
    }

    /// @inheritdoc IInterchainDB
    function checkVerification(
        address dstModule,
        InterchainEntry memory entry,
        bytes32[] calldata proof
    )
        external
        view
        onlyRemoteChainId(entry.srcChainId)
        returns (uint256 moduleVerifiedAt)
    {
        // In "no batching" mode: the batch root is the same as the entry value, hence the proof is empty
        if (proof.length != 0) {
            // If proof is not empty, the batch root is not verified
            return 0;
        }
        // In "no batching" mode: entry index is 0, batch size is 1
        if (entry.entryIndex != 0) {
            // If entry index is not 0, it does not belong to the batch
            return 0;
        }
        RemoteBatch memory remoteBatch = _remoteBatches[dstModule][InterchainEntryLib.batchKey(entry)];
        bytes32 entryValue = InterchainEntryLib.entryValue(entry);
        // Check entry value against the batch root verified by the module
        return remoteBatch.batchRoot == entryValue ? remoteBatch.verifiedAt : 0;
    }

    /// @inheritdoc IInterchainDB
    function getBatchLeafs(uint256 dbNonce) public view returns (bytes32[] memory leafs) {
        // In "no batching" mode: the finalized batch size is 1
        _assertBatchFinalized(dbNonce);
        leafs = new bytes32[](1);
        leafs[0] = getEntryValue(dbNonce, 0);
    }

    /// @inheritdoc IInterchainDB
    function getBatchSize(uint256 dbNonce) public view returns (uint64) {
        // In "no batching" mode: the finalized batch size is 1, the pending batch size is 0
        uint256 pendingNonce = _assertBatchExists(dbNonce);
        return dbNonce < pendingNonce ? 1 : 0;
    }

    /// @inheritdoc IInterchainDB
    function getBatch(uint256 dbNonce) public view returns (InterchainBatch memory) {
        _assertBatchFinalized(dbNonce);
        // In "no batching" mode: the batch root is the same as the entry hash
        return InterchainBatchLib.constructLocalBatch(dbNonce, getEntryValue(dbNonce, 0));
    }

    /// @inheritdoc IInterchainDB
    function getEntryValue(uint256 dbNonce, uint64 entryIndex) public view returns (bytes32) {
        _assertEntryExists(dbNonce, entryIndex);
        return _entryValues[dbNonce];
    }

    /// @inheritdoc IInterchainDB
    function getDBNonce() public view returns (uint256) {
        return _entryValues.length;
    }

    // ══════════════════════════════════════════════ INTERNAL LOGIC ═══════════════════════════════════════════════════

    /// @dev Write the entry to the database and emit the event.
    function _writeEntry(bytes32 dataHash) internal returns (InterchainEntry memory entry) {
        entry = InterchainEntryLib.constructLocalEntry({
            dbNonce: getDBNonce(),
            entryIndex: 0,
            writer: msg.sender,
            dataHash: dataHash
        });
        _entryValues.push(entry.entryValue());
        emit InterchainEntryWritten(block.chainid, entry.dbNonce, entry.srcWriter, dataHash);
    }

    /// @dev Request the verification of the entry by the modules, and emit the event.
    /// Note: the validity of the passed entry and chain id being remote is enforced in the calling function.
    function _requestVerification(
        uint256 dstChainId,
        InterchainBatch memory batch,
        address[] calldata srcModules
    )
        internal
    {
        (uint256[] memory fees, uint256 totalFee) = _getModuleFees(dstChainId, batch.dbNonce, srcModules);
        if (msg.value < totalFee) {
            revert InterchainDB__IncorrectFeeAmount(msg.value, totalFee);
        } else if (msg.value > totalFee) {
            // The exceeding amount goes to the first module
            fees[0] += msg.value - totalFee;
        }
        uint256 len = srcModules.length;
        bytes memory versionedBatch = VersionedPayloadLib.encodeVersionedPayload({
            version: DB_VERSION,
            payload: InterchainBatchLib.encodeBatch(batch)
        });
        for (uint256 i = 0; i < len; ++i) {
            IInterchainModule(srcModules[i]).requestBatchVerification{value: fees[i]}(dstChainId, versionedBatch);
        }
        emit InterchainBatchVerificationRequested(dstChainId, batch.dbNonce, batch.batchRoot, srcModules);
    }

    // ══════════════════════════════════════════════ INTERNAL VIEWS ═══════════════════════════════════════════════════

    /// @dev Check that the batch with the given nonce exists and return the pending nonce.
    function _assertBatchExists(uint256 dbNonce) internal view returns (uint256 pendingNonce) {
        pendingNonce = getDBNonce();
        if (dbNonce > pendingNonce) {
            revert InterchainDB__BatchDoesNotExist(dbNonce);
        }
    }

    /// @dev Check that the batch with the given nonce is finalized and return the pending nonce.
    function _assertBatchFinalized(uint256 dbNonce) internal view returns (uint256 pendingNonce) {
        pendingNonce = getDBNonce();
        if (dbNonce >= pendingNonce) {
            revert InterchainDB__BatchNotFinalized(dbNonce);
        }
    }

    /// @dev Check that the entry index is within the batch size. Also checks that the batch exists.
    function _assertEntryExists(uint256 dbNonce, uint64 entryIndex) internal view {
        // This will revert if the batch does not exist
        uint64 batchSize = getBatchSize(dbNonce);
        if (entryIndex >= batchSize) {
            revert InterchainDB__EntryIndexOutOfRange(dbNonce, entryIndex, batchSize);
        }
    }

    /// @dev Get the verification fees for the modules
    function _getModuleFees(
        uint256 dstChainId,
        uint256 dbNonce,
        address[] calldata srcModules
    )
        internal
        view
        returns (uint256[] memory fees, uint256 totalFee)
    {
        uint256 len = srcModules.length;
        if (len == 0) {
            revert InterchainDB__NoModulesSpecified();
        }
        fees = new uint256[](len);
        for (uint256 i = 0; i < len; ++i) {
            fees[i] = IInterchainModule(srcModules[i]).getModuleFee(dstChainId, dbNonce);
            totalFee += fees[i];
        }
    }
}

File 2 of 8 : InterchainDBEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract InterchainDBEvents {
    // TODO: figure out indexing
    event InterchainEntryWritten(uint256 srcChainId, uint256 dbNonce, bytes32 srcWriter, bytes32 dataHash);

    event InterchainBatchVerified(address module, uint256 srcChainId, uint256 dbNonce, bytes32 batchRoot);

    event InterchainBatchVerificationRequested(
        uint256 dstChainId, uint256 dbNonce, bytes32 batchRoot, address[] srcModules
    );
}

File 3 of 8 : IInterchainDB.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {InterchainEntry} from "../libs/InterchainEntry.sol";
import {InterchainBatch} from "../libs/InterchainBatch.sol";

interface IInterchainDB {
    /// @notice Struct representing a batch of entries from the remote Interchain DataBase,
    /// verified by the Interchain Module.
    /// @param verifiedAt   The block timestamp at which the entry was verified by the module
    /// @param batchRoot    The Merkle root of the batch
    struct RemoteBatch {
        uint256 verifiedAt;
        bytes32 batchRoot;
    }

    error InterchainDB__BatchDoesNotExist(uint256 dbNonce);
    error InterchainDB__BatchNotFinalized(uint256 dbNonce);
    error InterchainDB__ConflictingBatches(address module, bytes32 existingBatchRoot, InterchainBatch newBatch);
    error InterchainDB__EntryIndexOutOfRange(uint256 dbNonce, uint64 entryIndex, uint64 batchSize);
    error InterchainDB__IncorrectFeeAmount(uint256 actualFee, uint256 expectedFee);
    error InterchainDB__InvalidBatchVersion(uint16 version);
    error InterchainDB__InvalidEntryRange(uint256 dbNonce, uint64 start, uint64 end);
    error InterchainDB__NoModulesSpecified();
    error InterchainDB__SameChainId(uint256 chainId);

    /// @notice Write data to the Interchain DataBase as a new entry in the current batch.
    /// Note: there are no guarantees that this entry will be available for reading on any of the remote chains.
    /// Use `requestBatchVerification` to ensure that the entry is available for reading on the destination chain.
    /// @param dataHash     The hash of the data to be written to the Interchain DataBase as a new entry
    /// @return dbNonce     The database nonce of the batch containing the written entry
    /// @return entryIndex  The index of the written entry within the batch
    function writeEntry(bytes32 dataHash) external returns (uint256 dbNonce, uint64 entryIndex);

    /// @notice Request the given Interchain Modules to verify an existing batch.
    /// If the batch is not finalized, the module will verify it after finalization.
    /// For the finalized batch the batch root is already available, and the module can verify it immediately.
    /// Note: every module has a separate fee paid in the native gas token of the source chain,
    /// and `msg.value` must be equal to the sum of all fees.
    /// Note: this method is permissionless, and anyone can request verification for any batch.
    /// @dev Will revert if the batch with the given nonce does not exist.
    /// @param dstChainId    The chain id of the destination chain
    /// @param dbNonce       The database nonce of the existing batch
    /// @param srcModules    The source chain addresses of the Interchain Modules to use for verification
    function requestBatchVerification(
        uint256 dstChainId,
        uint256 dbNonce,
        address[] memory srcModules
    )
        external
        payable;

    /// @notice Write data to the Interchain DataBase as a new entry in the current batch.
    /// Then request the Interchain Modules to verify the batch containing the written entry on the destination chain.
    /// See `writeEntry` and `requestBatchVerification` for more details.
    /// @dev Will revert if the empty array of modules is provided.
    /// @param dstChainId   The chain id of the destination chain
    /// @param dataHash     The hash of the data to be written to the Interchain DataBase as a new entry
    /// @param srcModules   The source chain addresses of the Interchain Modules to use for verification
    /// @return dbNonce     The database nonce of the batch containing the written entry
    /// @return entryIndex  The index of the written entry within the batch
    function writeEntryWithVerification(
        uint256 dstChainId,
        bytes32 dataHash,
        address[] memory srcModules
    )
        external
        payable
        returns (uint256 dbNonce, uint64 entryIndex);

    /// @notice Allows the Interchain Module to verify the batch coming from the remote chain.
    /// Note: The DB will only accept the batch of the same version as the DB itself.
    /// @param versionedBatch   The versioned Interchain Batch to verify
    function verifyRemoteBatch(bytes memory versionedBatch) external;

    // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════

    /// @notice Get the fee for writing data to the Interchain DataBase, and verifying it on the destination chain
    /// using the provided Interchain Modules.
    /// @dev Will revert if the empty array of modules is provided.
    /// @param dstChainId   The chain id of the destination chain
    /// @param srcModules   The source chain addresses of the Interchain Modules to use for verification
    function getInterchainFee(uint256 dstChainId, address[] memory srcModules) external view returns (uint256);

    /// @notice Returns the list of leafs of the finalized batch with the given nonce.
    /// Note: the leafs are ordered by the index of the written entry in the current batch,
    /// and the leafs value match the value of the written entry (srcWriter + dataHash hashed together).
    /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized.
    /// @param dbNonce      The database nonce of the finalized batch
    function getBatchLeafs(uint256 dbNonce) external view returns (bytes32[] memory);

    /// @notice Returns the list of leafs of the finalized batch with the given nonce,
    /// paginated by the given start and end indexes. The end index is exclusive.
    /// Note: this is useful when the batch contains a large number of leafs, and calling `getBatchLeafs`
    /// would result in a gas limit exceeded error.
    /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized.
    /// Will revert if the provided range is invalid.
    /// @param dbNonce      The database nonce of the finalized batch
    /// @param start        The start index of the paginated leafs, inclusive
    /// @param end          The end index of the paginated leafs, exclusive
    function getBatchLeafsPaginated(
        uint256 dbNonce,
        uint64 start,
        uint64 end
    )
        external
        view
        returns (bytes32[] memory);

    /// @notice Returns the size of the finalized batch with the given nonce.
    /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized.
    /// @param dbNonce      The database nonce of the finalized batch
    function getBatchSize(uint256 dbNonce) external view returns (uint64);

    /// @notice Get the finalized Interchain Batch with the given nonce.
    /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized.
    /// @param dbNonce      The database nonce of the finalized batch
    function getBatch(uint256 dbNonce) external view returns (InterchainBatch memory);

    /// @notice Get the Interchain Entry's value written on the local chain with the given batch nonce and entry index.
    /// Entry value is calculated as the hash of the writer address and the written data hash.
    /// Note: the batch does not have to be finalized to fetch the entry value.
    /// @dev Will revert if the batch with the given nonce does not exist,
    /// or the entry with the given index does not exist within the batch.
    /// @param dbNonce      The database nonce of the existing batch
    /// @param entryIndex   The index of the written entry within the batch
    function getEntryValue(uint256 dbNonce, uint64 entryIndex) external view returns (bytes32);

    /// @notice Get the Merkle proof of inclusion for the entry with the given index
    /// in the finalized batch with the given nonce.
    /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized.
    /// Will revert if the entry with the given index does not exist within the batch.
    /// @param dbNonce      The database nonce of the finalized batch
    /// @param entryIndex   The index of the written entry within the batch
    /// @return proof       The Merkle proof of inclusion for the entry
    function getEntryProof(uint256 dbNonce, uint64 entryIndex) external view returns (bytes32[] memory proof);

    /// @notice Get the nonce of the database, which is incremented every time a new batch is finalized.
    /// This is the nonce of the current non-finalized batch.
    function getDBNonce() external view returns (uint256);

    /// @notice Get the index of the next entry to be written to the database.
    /// @return dbNonce      The database nonce of the batch including the next entry
    /// @return entryIndex   The index of the next entry within that batch
    function getNextEntryIndex() external view returns (uint256 dbNonce, uint64 entryIndex);

    /// @notice Read the data written on specific source chain by a specific writer,
    /// and verify it on the destination chain using the provided Interchain Module.
    /// Note: returned zero value indicates that the module has not verified the entry.
    /// @param entry        The Interchain Entry to read
    /// @param dstModule    The destination chain addresses of the Interchain Modules to use for verification
    /// @return moduleVerifiedAt   The block timestamp at which the entry was verified by the module,
    ///                             or ZERO if the module has not verified the entry.
    function checkVerification(
        address dstModule,
        InterchainEntry memory entry,
        bytes32[] memory proof
    )
        external
        view
        returns (uint256 moduleVerifiedAt);

    /// @notice Get the version of the Interchain DataBase.
    // solhint-disable-next-line func-name-mixedcase
    function DB_VERSION() external pure returns (uint16);
}

File 4 of 8 : IInterchainModule.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Every Module may opt a different method to confirm the verified entries on destination chain,
/// therefore this is not a part of a common interface.
interface IInterchainModule {
    error InterchainModule__NotInterchainDB(address caller);
    error InterchainModule__IncorrectSourceChainId(uint256 chainId);
    error InterchainModule__InsufficientFee(uint256 actual, uint256 required);
    error InterchainModule__SameChainId(uint256 chainId);

    /// @notice Request the verification of a batch from the Interchain DataBase by the module.
    /// If the batch is not yet finalized, the verification on destination chain will be delayed until
    /// the finalization is done and batch root is saved on the source chain.
    /// Note: a fee is paid to the module for verification, and could be retrieved by using `getModuleFee`.
    /// Note: this will eventually trigger `InterchainDB.verifyRemoteBatch(batch)` function on destination chain,
    /// with no guarantee of ordering.
    /// @dev Could be only called by the Interchain DataBase contract.
    /// @param dstChainId       The chain id of the destination chain
    /// @param versionedBatch   The versioned batch to verify
    function requestBatchVerification(uint256 dstChainId, bytes memory versionedBatch) external payable;

    /// @notice Get the Module fee for verifying a batch on the specified destination chain.
    /// @param dstChainId   The chain id of the destination chain
    /// @param dbNonce      The database nonce of the batch on the source chain
    function getModuleFee(uint256 dstChainId, uint256 dbNonce) external view returns (uint256);
}

File 5 of 8 : InterchainBatch.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {VersionedPayloadLib} from "./VersionedPayload.sol";

/// @notice Struct representing a batch of entries in the Interchain DataBase.
/// Batched entries are put together in a Merkle tree, which root is saved.
/// Batch has a globally unique identifier (key) and a value.
/// - key: srcChainId + dbNonce
/// - value: batchRoot
/// @param srcChainId   The chain id of the source chain
/// @param dbNonce      The database nonce of the batch
/// @param batchRoot    The root of the Merkle tree containing the batched entries
struct InterchainBatch {
    // TODO: can we use uint64 for chain id?
    uint256 srcChainId;
    uint256 dbNonce;
    bytes32 batchRoot;
}

library InterchainBatchLib {
    using VersionedPayloadLib for bytes;

    /// @notice Constructs an InterchainBatch struct to be saved on the local chain.
    /// @param dbNonce      The database nonce of the batch
    /// @param batchRoot    The root of the Merkle tree containing the batched entries
    /// @return batch       The constructed InterchainBatch struct
    function constructLocalBatch(
        uint256 dbNonce,
        bytes32 batchRoot
    )
        internal
        view
        returns (InterchainBatch memory batch)
    {
        return InterchainBatch({srcChainId: block.chainid, dbNonce: dbNonce, batchRoot: batchRoot});
    }

    /// @notice Encodes the InterchainBatch struct into a non-versioned batch payload.
    function encodeBatch(InterchainBatch memory batch) internal pure returns (bytes memory) {
        return abi.encode(batch);
    }

    /// @notice Decodes the InterchainBatch struct from a non-versioned batch payload in calldata.
    function decodeBatch(bytes calldata data) internal pure returns (InterchainBatch memory) {
        return abi.decode(data, (InterchainBatch));
    }

    /// @notice Decodes the InterchainBatch struct from a non-versioned batch payload in memory.
    function decodeBatchFromMemory(bytes memory data) internal pure returns (InterchainBatch memory) {
        return abi.decode(data, (InterchainBatch));
    }

    /// @notice Returns the globally unique identifier of the batch
    function batchKey(InterchainBatch memory batch) internal pure returns (bytes32) {
        return keccak256(abi.encode(batch.srcChainId, batch.dbNonce));
    }
}

File 6 of 8 : InterchainEntry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {TypeCasts} from "./TypeCasts.sol";

/// @notice Struct representing an entry in the Interchain DataBase.
/// Entry has a globally unique identifier (key) and a value.
/// - key: srcChainId + dbNonce + entryIndex
/// - value: srcWriter + dataHash
/// @param srcChainId   The chain id of the source chain
/// @param dbNonce      The database nonce of the batch containing the entry
/// @param entryIndex   The index of the entry in the batch
/// @param srcWriter    The address of the writer on the source chain
/// @param dataHash     The hash of the data written on the source chain
struct InterchainEntry {
    // TODO: can we use uint64 for chain id?
    uint256 srcChainId;
    uint256 dbNonce;
    uint64 entryIndex;
    bytes32 srcWriter;
    bytes32 dataHash;
}

using InterchainEntryLib for InterchainEntry global;

library InterchainEntryLib {
    /// @notice Constructs an InterchainEntry struct to be written on the local chain
    /// @param dbNonce      The database nonce of the entry on the source chain
    /// @param writer       The address of the writer on the local chain
    /// @param dataHash     The hash of the data written on the local chain
    /// @return entry       The constructed InterchainEntry struct
    function constructLocalEntry(
        uint256 dbNonce,
        uint64 entryIndex,
        address writer,
        bytes32 dataHash
    )
        internal
        view
        returns (InterchainEntry memory entry)
    {
        return InterchainEntry({
            srcChainId: block.chainid,
            dbNonce: dbNonce,
            entryIndex: entryIndex,
            srcWriter: TypeCasts.addressToBytes32(writer),
            dataHash: dataHash
        });
    }

    /// @notice Returns the globally unique identifier of the entry
    function entryKey(InterchainEntry memory entry) internal pure returns (bytes32) {
        return keccak256(abi.encode(entry.srcChainId, entry.dbNonce, entry.entryIndex));
    }

    /// @notice Returns the value of the entry: writer + dataHash hashed together
    function entryValue(InterchainEntry memory entry) internal pure returns (bytes32) {
        return keccak256(abi.encode(entry.srcWriter, entry.dataHash));
    }

    /// @notice Returns the globally unique identifier of the batch containing the entry
    function batchKey(InterchainEntry memory entry) internal pure returns (bytes32) {
        return keccak256(abi.encode(entry.srcChainId, entry.dbNonce));
    }
}

File 7 of 8 : VersionedPayload.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// solhint-disable no-inline-assembly
// solhint-disable ordering
library VersionedPayloadLib {
    /// @notice Amount of bytes reserved for the version (uint16) in the versioned payload
    uint256 internal constant VERSION_LENGTH = 2;

    error VersionedPayload__TooShort(bytes versionedPayload);
    error VersionedPayload__PrecompileFailed();

    /// @notice Encodes the versioned payload into a single bytes array.
    /// @param version  The payload's version.
    /// @param payload  The payload to encode.
    function encodeVersionedPayload(uint16 version, bytes memory payload) internal pure returns (bytes memory) {
        return abi.encodePacked(version, payload);
    }

    /// @notice Extracts the version from the versioned payload (calldata reference).
    /// @param versionedPayload     The versioned payload (calldata reference).
    function getVersion(bytes calldata versionedPayload) internal pure returns (uint16 version) {
        if (versionedPayload.length < VERSION_LENGTH) {
            revert VersionedPayload__TooShort(versionedPayload);
        }
        assembly {
            // We are only interested in the highest 16 bits of the loaded full 32 bytes word.
            version := shr(240, calldataload(versionedPayload.offset))
        }
    }

    /// @notice Extracts the payload from the versioned payload (calldata reference).
    /// @dev The extracted payload is also returned as a calldata reference.
    /// @param versionedPayload     The versioned payload.
    function getPayload(bytes calldata versionedPayload) internal pure returns (bytes calldata) {
        if (versionedPayload.length < VERSION_LENGTH) {
            revert VersionedPayload__TooShort(versionedPayload);
        }
        return versionedPayload[VERSION_LENGTH:];
    }

    /// @notice Extracts the version from the versioned payload (memory reference).
    /// @param versionedPayload     The versioned payload (memory reference).
    function getVersionFromMemory(bytes memory versionedPayload) internal pure returns (uint16 version) {
        if (versionedPayload.length < VERSION_LENGTH) {
            revert VersionedPayload__TooShort(versionedPayload);
        }
        assembly {
            // We are only interested in the highest 16 bits of the loaded full 32 bytes word.
            // We add 0x20 to skip the length of the bytes array.
            version := shr(240, mload(add(versionedPayload, 0x20)))
        }
    }

    /// @notice Extracts the payload from the versioned payload (memory reference).
    /// @dev The extracted payload is copied into a new memory location. Use `getPayload` when possible
    /// to avoid extra memory allocation.
    /// @param versionedPayload     The versioned payload (memory reference).
    function getPayloadFromMemory(bytes memory versionedPayload) internal view returns (bytes memory payload) {
        if (versionedPayload.length < VERSION_LENGTH) {
            revert VersionedPayload__TooShort(versionedPayload);
        }
        // Figure how many bytes to copy and allocate the memory for the extracted payload.
        uint256 toCopy;
        unchecked {
            toCopy = versionedPayload.length - VERSION_LENGTH;
        }
        payload = new bytes(toCopy);
        // Use identity precompile (0x04) to copy the payload. Unlike MCOPY, this is available on all EVM chains.
        bool res;
        assembly {
            // We add 0x20 to skip the length of the bytes array.
            // We add 0x02 to skip the 2 bytes reserved for the version.
            // Copy the payload to the previously allocated memory.
            res := staticcall(gas(), 0x04, add(versionedPayload, 0x22), toCopy, add(payload, 0x20), toCopy)
        }
        if (!res) {
            revert VersionedPayload__PrecompileFailed();
        }
    }
}

File 8 of 8 : TypeCasts.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library TypeCasts {
    function addressToBytes32(address addr) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(addr)));
    }

    function bytes32ToAddress(bytes32 b) internal pure returns (address) {
        return address(uint160(uint256(b)));
    }
}

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

Contract ABI

API
[{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"}],"name":"InterchainDB__BatchDoesNotExist","type":"error"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"}],"name":"InterchainDB__BatchNotFinalized","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"},{"internalType":"bytes32","name":"existingBatchRoot","type":"bytes32"},{"components":[{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"bytes32","name":"batchRoot","type":"bytes32"}],"internalType":"struct InterchainBatch","name":"newBatch","type":"tuple"}],"name":"InterchainDB__ConflictingBatches","type":"error"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"},{"internalType":"uint64","name":"batchSize","type":"uint64"}],"name":"InterchainDB__EntryIndexOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualFee","type":"uint256"},{"internalType":"uint256","name":"expectedFee","type":"uint256"}],"name":"InterchainDB__IncorrectFeeAmount","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"InterchainDB__InvalidBatchVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"start","type":"uint64"},{"internalType":"uint64","name":"end","type":"uint64"}],"name":"InterchainDB__InvalidEntryRange","type":"error"},{"inputs":[],"name":"InterchainDB__NoModulesSpecified","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"InterchainDB__SameChainId","type":"error"},{"inputs":[{"internalType":"bytes","name":"versionedPayload","type":"bytes"}],"name":"VersionedPayload__TooShort","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"dstChainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"batchRoot","type":"bytes32"},{"indexed":false,"internalType":"address[]","name":"srcModules","type":"address[]"}],"name":"InterchainBatchVerificationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"module","type":"address"},{"indexed":false,"internalType":"uint256","name":"srcChainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"batchRoot","type":"bytes32"}],"name":"InterchainBatchVerified","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"srcChainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"srcWriter","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"InterchainEntryWritten","type":"event"},{"inputs":[],"name":"DB_VERSION","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dstModule","type":"address"},{"components":[{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"},{"internalType":"bytes32","name":"srcWriter","type":"bytes32"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"internalType":"struct InterchainEntry","name":"entry","type":"tuple"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"checkVerification","outputs":[{"internalType":"uint256","name":"moduleVerifiedAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"}],"name":"getBatch","outputs":[{"components":[{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"bytes32","name":"batchRoot","type":"bytes32"}],"internalType":"struct InterchainBatch","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"}],"name":"getBatchLeafs","outputs":[{"internalType":"bytes32[]","name":"leafs","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"start","type":"uint64"},{"internalType":"uint64","name":"end","type":"uint64"}],"name":"getBatchLeafsPaginated","outputs":[{"internalType":"bytes32[]","name":"leafs","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"}],"name":"getBatchSize","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDBNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"name":"getEntryProof","outputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"name":"getEntryValue","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"address[]","name":"srcModules","type":"address[]"}],"name":"getInterchainFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextEntryIndex","outputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"address[]","name":"srcModules","type":"address[]"}],"name":"requestBatchVerification","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"versionedBatch","type":"bytes"}],"name":"verifyRemoteBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"name":"writeEntry","outputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"address[]","name":"srcModules","type":"address[]"}],"name":"writeEntryWithVerification","outputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"stateMutability":"payable","type":"function"}]

608060405234801561001057600080fd5b50611466806100206000396000f3fe6080604052600436106100e85760003560e01c806384b1c8b81161008a578063d63020bb11610059578063d63020bb14610294578063d961a48e146102b4578063f338140e146102d4578063fc7686ec146102e957600080fd5b806384b1c8b814610212578063aa2f06ae14610227578063afa250051461023c578063b955e9b91461025c57600080fd5b80634f84d040116100c65780634f84d040146101845780635ac44282146101a457806367b1f42e146101d157806367c769af146101ff57600080fd5b806315f53956146100ed57806325a1641d1461011a5780632ad8c70614610147575b600080fd5b3480156100f957600080fd5b50610102600181565b60405161ffff90911681526020015b60405180910390f35b34801561012657600080fd5b5061013a610135366004610e79565b610309565b6040516101119190610eb5565b34801561015357600080fd5b50610167610162366004610ef9565b61037a565b604080519283526001600160401b03909116602083015201610111565b34801561019057600080fd5b5061013a61019f366004610f12565b61039e565b3480156101b057600080fd5b506101c46101bf366004610ef9565b6103cb565b6040516101119190610f3e565b3480156101dd57600080fd5b506101f16101ec366004611006565b610434565b604051908152602001610111565b61016761020d3660046110ac565b610507565b6102256102203660046110ac565b610572565b005b34801561023357600080fd5b506101676105b6565b34801561024857600080fd5b506101f1610257366004610f12565b6105cb565b34801561026857600080fd5b5061027c610277366004610ef9565b6105fd565b6040516001600160401b039091168152602001610111565b3480156102a057600080fd5b5061013a6102af366004610ef9565b610626565b3480156102c057600080fd5b506102256102cf3660046110e6565b610681565b3480156102e057600080fd5b506000546101f1565b3480156102f557600080fd5b506101f1610304366004611157565b6107fa565b60606001600160401b03831615158061032c5750816001600160401b0316600114155b15610369576040516376e6dff560e11b8152600481018590526001600160401b038085166024830152831660448201526064015b60405180910390fd5b61037284610626565b949350505050565b600080600061038884610819565b6020810151604090910151909590945092505050565b60606103a9836108d1565b506103b483836108fc565b506040805160008152602081019091525b92915050565b60408051606081018252600080825260208201819052918101919091526103f1826108d1565b506103c5826104018460006105cb565b60408051606080820183526000808352602080840182905292840152825190810183524681529081019390935282015290565b825160009046810361045b57604051637e16f74d60e11b8152466004820152602401610360565b821561046a57600091506104fe565b60408501516001600160401b03161561048657600091506104fe565b6001600160a01b0386166000908152600160205260408120816104a88861095a565b815260200190815260200160002060405180604001604052908160008201548152602001600182015481525050905060006104e28761099d565b9050808260200151146104f65760006104f9565b81515b935050505b50949350505050565b6000808546810361052d57604051637e16f74d60e11b8152466004820152602401610360565b600061053887610819565b60208101516040820151909550935090506000610558856104018461099d565b9050610566898289896109c0565b50505094509492505050565b8346810361059557604051637e16f74d60e11b8152466004820152602401610360565b60006105a0856103cb565b90506105ae868286866109c0565b505050505050565b6000806105c260005490565b92600092509050565b60006105d783836108fc565b600083815481106105ea576105ea6111a2565b9060005260206000200154905092915050565b60008061060983610b64565b905080831061061957600061061c565b60015b60ff169392505050565b6060610631826108d1565b50604080516001808252818301909252906020808301908036833701905050905061065d8260006105cb565b81600081518110610670576106706111a2565b602002602001018181525050919050565b600061068d8383610b8b565b905061ffff81166001146106ba57604051630293290760e11b815261ffff82166004820152602401610360565b60006106ce6106c98585610bbc565b610bfe565b9050468160000151036106fa578051604051637e16f74d60e11b81526004810191909152602401610360565b60006107058261095a565b3360009081526001602081815260408084208585528252808420815180830190925280548083529301549181019190915292935090036107c9576040805180820182524281528482018051602080840191825233600081815260018084528782208a8352845290879020955186559251949092019390935586518388015192518551928352938201529283015260608201527fbdb1c58ad0991a7df73dd7d1e0c63ba29dd69af7d09838990eef8127de1a548c9060800160405180910390a16105ae565b82604001518160200151146105ae5760208101516040516327b8099d60e11b815261036091339186906004016111b8565b60006108108461080960005490565b8585610c2e565b95945050505050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810182905290546108529060003385610d9b565b9050600061085f8261099d565b81546001810183556000928352602092839020015581015160608201516040517f8adbf0953083a65c138963c649cd1eabd31fa900ecd1cd5d6b5b530fbfa41771926108c4924692879093845260208401929092526040830152606082015260800190565b60405180910390a1919050565b6000548082106108f757604051633e85a07b60e21b815260048101839052602401610360565b919050565b6000610907836105fd565b9050806001600160401b0316826001600160401b03161061095557604051633acda1b760e11b8152600481018490526001600160401b03808416602483015282166044820152606401610360565b505050565b600081600001518260200151604051602001610980929190918252602082015260400190565b604051602081830303815290604052805190602001209050919050565b606080820151608083015160408051602081019390935282015260009101610980565b6000806109d38686602001518686610c2e565b9150915080341015610a0157604051630fb7d66160e41b815234600482015260248101829052604401610360565b80341115610a3e57610a138134611206565b82600081518110610a2657610a266111a2565b60200260200101818151610a3a9190611219565b9052505b826000610a546001610a4f89610e0d565b610e36565b905060005b82811015610b1257868682818110610a7357610a736111a2565b9050602002016020810190610a88919061122c565b6001600160a01b0316634bd7e4dd868381518110610aa857610aa86111a2565b60200260200101518b856040518463ffffffff1660e01b8152600401610acf92919061126b565b6000604051808303818588803b158015610ae857600080fd5b505af1158015610afc573d6000803e3d6000fd5b505050505080610b0b906112a5565b9050610a59565b507f9f201dd0d5465cd198596655528d58e40b6ee2715d5e8bdab49f7e1b1dde771788886020015189604001518989604051610b529594939291906112be565b60405180910390a15050505050505050565b600054808211156108f757604051631de809a760e21b815260048101839052602401610360565b60006002821015610bb35782826040516332ce7cfd60e11b8152600401610360929190611325565b50503560f01c90565b3660006002831015610be55783836040516332ce7cfd60e11b8152600401610360929190611325565b610bf28360028187611354565b915091505b9250929050565b6040805160608101825260008082526020820181905291810191909152610c278284018461137e565b9392505050565b6060600082808203610c5357604051634c65249560e11b815260040160405180910390fd5b806001600160401b03811115610c6b57610c6b610f76565b604051908082528060200260200182016040528015610c94578160200160208202803683370190505b50925060005b81811015610d9057858582818110610cb457610cb46111a2565b9050602002016020810190610cc9919061122c565b604051632508a7b960e11b8152600481018a9052602481018990526001600160a01b039190911690634a114f7290604401602060405180830381865afa158015610d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3b91906113e7565b848281518110610d4d57610d4d6111a2565b602002602001018181525050838181518110610d6b57610d6b6111a2565b602002602001015183610d7e9190611219565b9250610d89816112a5565b9050610c9a565b505094509492505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040518060a00160405280468152602001868152602001856001600160401b03168152602001610dfc856001600160a01b031690565b815260200192909252509392505050565b606081604051602001610e209190610f3e565b6040516020818303038152906040529050919050565b60608282604051602001610e4b929190611400565b604051602081830303815290604052905092915050565b80356001600160401b03811681146108f757600080fd5b600080600060608486031215610e8e57600080fd5b83359250610e9e60208501610e62565b9150610eac60408501610e62565b90509250925092565b6020808252825182820181905260009190848201906040850190845b81811015610eed57835183529284019291840191600101610ed1565b50909695505050505050565b600060208284031215610f0b57600080fd5b5035919050565b60008060408385031215610f2557600080fd5b82359150610f3560208401610e62565b90509250929050565b815181526020808301519082015260408083015190820152606081016103c5565b80356001600160a01b03811681146108f757600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715610fbc57634e487b7160e01b600052604160045260246000fd5b60405290565b60008083601f840112610fd457600080fd5b5081356001600160401b03811115610feb57600080fd5b6020830191508360208260051b8501011115610bf757600080fd5b60008060008084860360e081121561101d57600080fd5b61102686610f5f565b945060a0601f198201121561103a57600080fd5b50611043610f8c565b602086013581526040860135602082015261106060608701610e62565b6040820152608086810135606083015260a087013590820152925060c08501356001600160401b0381111561109457600080fd5b6110a087828801610fc2565b95989497509550505050565b600080600080606085870312156110c257600080fd5b843593506020850135925060408501356001600160401b0381111561109457600080fd5b600080602083850312156110f957600080fd5b82356001600160401b038082111561111057600080fd5b818501915085601f83011261112457600080fd5b81358181111561113357600080fd5b86602082850101111561114557600080fd5b60209290920196919550909350505050565b60008060006040848603121561116c57600080fd5b8335925060208401356001600160401b0381111561118957600080fd5b61119586828701610fc2565b9497909650939450505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03841681526020810183905260a0810161037260408301848051825260208082015190830152604090810151910152565b634e487b7160e01b600052601160045260246000fd5b818103818111156103c5576103c56111f0565b808201808211156103c5576103c56111f0565b60006020828403121561123e57600080fd5b610c2782610f5f565b60005b8381101561126257818101518382015260200161124a565b50506000910152565b8281526040602082015260008251806040840152611290816060850160208701611247565b601f01601f1916919091016060019392505050565b6000600182016112b7576112b76111f0565b5060010190565b60006080820187835260208781850152866040850152608060608501528185835260a08501905086925060005b86811015611317576001600160a01b0361130485610f5f565b16825292820192908201906001016112eb565b509998505050505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6000808585111561136457600080fd5b8386111561137157600080fd5b5050820193919092039150565b60006060828403121561139057600080fd5b604051606081018181106001600160401b03821117156113c057634e487b7160e01b600052604160045260246000fd5b80604052508235815260208301356020820152604083013560408201528091505092915050565b6000602082840312156113f957600080fd5b5051919050565b61ffff60f01b8360f01b16815260008251611422816002850160208701611247565b91909101600201939250505056fea26469706673582212206f3c3ee0012a4583eaac79c3ca7542f5b8a697eb140d8a18de7c703dd0413fac64736f6c63430008140033

Deployed Bytecode

0x6080604052600436106100e85760003560e01c806384b1c8b81161008a578063d63020bb11610059578063d63020bb14610294578063d961a48e146102b4578063f338140e146102d4578063fc7686ec146102e957600080fd5b806384b1c8b814610212578063aa2f06ae14610227578063afa250051461023c578063b955e9b91461025c57600080fd5b80634f84d040116100c65780634f84d040146101845780635ac44282146101a457806367b1f42e146101d157806367c769af146101ff57600080fd5b806315f53956146100ed57806325a1641d1461011a5780632ad8c70614610147575b600080fd5b3480156100f957600080fd5b50610102600181565b60405161ffff90911681526020015b60405180910390f35b34801561012657600080fd5b5061013a610135366004610e79565b610309565b6040516101119190610eb5565b34801561015357600080fd5b50610167610162366004610ef9565b61037a565b604080519283526001600160401b03909116602083015201610111565b34801561019057600080fd5b5061013a61019f366004610f12565b61039e565b3480156101b057600080fd5b506101c46101bf366004610ef9565b6103cb565b6040516101119190610f3e565b3480156101dd57600080fd5b506101f16101ec366004611006565b610434565b604051908152602001610111565b61016761020d3660046110ac565b610507565b6102256102203660046110ac565b610572565b005b34801561023357600080fd5b506101676105b6565b34801561024857600080fd5b506101f1610257366004610f12565b6105cb565b34801561026857600080fd5b5061027c610277366004610ef9565b6105fd565b6040516001600160401b039091168152602001610111565b3480156102a057600080fd5b5061013a6102af366004610ef9565b610626565b3480156102c057600080fd5b506102256102cf3660046110e6565b610681565b3480156102e057600080fd5b506000546101f1565b3480156102f557600080fd5b506101f1610304366004611157565b6107fa565b60606001600160401b03831615158061032c5750816001600160401b0316600114155b15610369576040516376e6dff560e11b8152600481018590526001600160401b038085166024830152831660448201526064015b60405180910390fd5b61037284610626565b949350505050565b600080600061038884610819565b6020810151604090910151909590945092505050565b60606103a9836108d1565b506103b483836108fc565b506040805160008152602081019091525b92915050565b60408051606081018252600080825260208201819052918101919091526103f1826108d1565b506103c5826104018460006105cb565b60408051606080820183526000808352602080840182905292840152825190810183524681529081019390935282015290565b825160009046810361045b57604051637e16f74d60e11b8152466004820152602401610360565b821561046a57600091506104fe565b60408501516001600160401b03161561048657600091506104fe565b6001600160a01b0386166000908152600160205260408120816104a88861095a565b815260200190815260200160002060405180604001604052908160008201548152602001600182015481525050905060006104e28761099d565b9050808260200151146104f65760006104f9565b81515b935050505b50949350505050565b6000808546810361052d57604051637e16f74d60e11b8152466004820152602401610360565b600061053887610819565b60208101516040820151909550935090506000610558856104018461099d565b9050610566898289896109c0565b50505094509492505050565b8346810361059557604051637e16f74d60e11b8152466004820152602401610360565b60006105a0856103cb565b90506105ae868286866109c0565b505050505050565b6000806105c260005490565b92600092509050565b60006105d783836108fc565b600083815481106105ea576105ea6111a2565b9060005260206000200154905092915050565b60008061060983610b64565b905080831061061957600061061c565b60015b60ff169392505050565b6060610631826108d1565b50604080516001808252818301909252906020808301908036833701905050905061065d8260006105cb565b81600081518110610670576106706111a2565b602002602001018181525050919050565b600061068d8383610b8b565b905061ffff81166001146106ba57604051630293290760e11b815261ffff82166004820152602401610360565b60006106ce6106c98585610bbc565b610bfe565b9050468160000151036106fa578051604051637e16f74d60e11b81526004810191909152602401610360565b60006107058261095a565b3360009081526001602081815260408084208585528252808420815180830190925280548083529301549181019190915292935090036107c9576040805180820182524281528482018051602080840191825233600081815260018084528782208a8352845290879020955186559251949092019390935586518388015192518551928352938201529283015260608201527fbdb1c58ad0991a7df73dd7d1e0c63ba29dd69af7d09838990eef8127de1a548c9060800160405180910390a16105ae565b82604001518160200151146105ae5760208101516040516327b8099d60e11b815261036091339186906004016111b8565b60006108108461080960005490565b8585610c2e565b95945050505050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810182905290546108529060003385610d9b565b9050600061085f8261099d565b81546001810183556000928352602092839020015581015160608201516040517f8adbf0953083a65c138963c649cd1eabd31fa900ecd1cd5d6b5b530fbfa41771926108c4924692879093845260208401929092526040830152606082015260800190565b60405180910390a1919050565b6000548082106108f757604051633e85a07b60e21b815260048101839052602401610360565b919050565b6000610907836105fd565b9050806001600160401b0316826001600160401b03161061095557604051633acda1b760e11b8152600481018490526001600160401b03808416602483015282166044820152606401610360565b505050565b600081600001518260200151604051602001610980929190918252602082015260400190565b604051602081830303815290604052805190602001209050919050565b606080820151608083015160408051602081019390935282015260009101610980565b6000806109d38686602001518686610c2e565b9150915080341015610a0157604051630fb7d66160e41b815234600482015260248101829052604401610360565b80341115610a3e57610a138134611206565b82600081518110610a2657610a266111a2565b60200260200101818151610a3a9190611219565b9052505b826000610a546001610a4f89610e0d565b610e36565b905060005b82811015610b1257868682818110610a7357610a736111a2565b9050602002016020810190610a88919061122c565b6001600160a01b0316634bd7e4dd868381518110610aa857610aa86111a2565b60200260200101518b856040518463ffffffff1660e01b8152600401610acf92919061126b565b6000604051808303818588803b158015610ae857600080fd5b505af1158015610afc573d6000803e3d6000fd5b505050505080610b0b906112a5565b9050610a59565b507f9f201dd0d5465cd198596655528d58e40b6ee2715d5e8bdab49f7e1b1dde771788886020015189604001518989604051610b529594939291906112be565b60405180910390a15050505050505050565b600054808211156108f757604051631de809a760e21b815260048101839052602401610360565b60006002821015610bb35782826040516332ce7cfd60e11b8152600401610360929190611325565b50503560f01c90565b3660006002831015610be55783836040516332ce7cfd60e11b8152600401610360929190611325565b610bf28360028187611354565b915091505b9250929050565b6040805160608101825260008082526020820181905291810191909152610c278284018461137e565b9392505050565b6060600082808203610c5357604051634c65249560e11b815260040160405180910390fd5b806001600160401b03811115610c6b57610c6b610f76565b604051908082528060200260200182016040528015610c94578160200160208202803683370190505b50925060005b81811015610d9057858582818110610cb457610cb46111a2565b9050602002016020810190610cc9919061122c565b604051632508a7b960e11b8152600481018a9052602481018990526001600160a01b039190911690634a114f7290604401602060405180830381865afa158015610d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3b91906113e7565b848281518110610d4d57610d4d6111a2565b602002602001018181525050838181518110610d6b57610d6b6111a2565b602002602001015183610d7e9190611219565b9250610d89816112a5565b9050610c9a565b505094509492505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040518060a00160405280468152602001868152602001856001600160401b03168152602001610dfc856001600160a01b031690565b815260200192909252509392505050565b606081604051602001610e209190610f3e565b6040516020818303038152906040529050919050565b60608282604051602001610e4b929190611400565b604051602081830303815290604052905092915050565b80356001600160401b03811681146108f757600080fd5b600080600060608486031215610e8e57600080fd5b83359250610e9e60208501610e62565b9150610eac60408501610e62565b90509250925092565b6020808252825182820181905260009190848201906040850190845b81811015610eed57835183529284019291840191600101610ed1565b50909695505050505050565b600060208284031215610f0b57600080fd5b5035919050565b60008060408385031215610f2557600080fd5b82359150610f3560208401610e62565b90509250929050565b815181526020808301519082015260408083015190820152606081016103c5565b80356001600160a01b03811681146108f757600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715610fbc57634e487b7160e01b600052604160045260246000fd5b60405290565b60008083601f840112610fd457600080fd5b5081356001600160401b03811115610feb57600080fd5b6020830191508360208260051b8501011115610bf757600080fd5b60008060008084860360e081121561101d57600080fd5b61102686610f5f565b945060a0601f198201121561103a57600080fd5b50611043610f8c565b602086013581526040860135602082015261106060608701610e62565b6040820152608086810135606083015260a087013590820152925060c08501356001600160401b0381111561109457600080fd5b6110a087828801610fc2565b95989497509550505050565b600080600080606085870312156110c257600080fd5b843593506020850135925060408501356001600160401b0381111561109457600080fd5b600080602083850312156110f957600080fd5b82356001600160401b038082111561111057600080fd5b818501915085601f83011261112457600080fd5b81358181111561113357600080fd5b86602082850101111561114557600080fd5b60209290920196919550909350505050565b60008060006040848603121561116c57600080fd5b8335925060208401356001600160401b0381111561118957600080fd5b61119586828701610fc2565b9497909650939450505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03841681526020810183905260a0810161037260408301848051825260208082015190830152604090810151910152565b634e487b7160e01b600052601160045260246000fd5b818103818111156103c5576103c56111f0565b808201808211156103c5576103c56111f0565b60006020828403121561123e57600080fd5b610c2782610f5f565b60005b8381101561126257818101518382015260200161124a565b50506000910152565b8281526040602082015260008251806040840152611290816060850160208701611247565b601f01601f1916919091016060019392505050565b6000600182016112b7576112b76111f0565b5060010190565b60006080820187835260208781850152866040850152608060608501528185835260a08501905086925060005b86811015611317576001600160a01b0361130485610f5f565b16825292820192908201906001016112eb565b509998505050505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6000808585111561136457600080fd5b8386111561137157600080fd5b5050820193919092039150565b60006060828403121561139057600080fd5b604051606081018181106001600160401b03821117156113c057634e487b7160e01b600052604160045260246000fd5b80604052508235815260208301356020820152604083013560408201528091505092915050565b6000602082840312156113f957600080fd5b5051919050565b61ffff60f01b8360f01b16815260008251611422816002850160208701611247565b91909101600201939250505056fea26469706673582212206f3c3ee0012a4583eaac79c3ca7542f5b8a697eb140d8a18de7c703dd0413fac64736f6c63430008140033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

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