Sepolia Testnet

Contract

0x5a81Dfa5885058ED838fa750060C804B49F69991

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Interchain Execu...57116372024-04-16 15:42:12341 days ago1713282132IN
0x5a81Dfa5...B49F69991
0 ETH0.000099431.10333016
Interchain Execu...57116352024-04-16 15:41:48341 days ago1713282108IN
0x5a81Dfa5...B49F69991
0 ETH0.000099481.10384364
Interchain Execu...57116332024-04-16 15:41:24341 days ago1713282084IN
0x5a81Dfa5...B49F69991
0 ETH0.000099481.10391254
Interchain Execu...57116312024-04-16 15:41:00341 days ago1713282060IN
0x5a81Dfa5...B49F69991
0 ETH0.000099491.1039339
Interchain Execu...57116292024-04-16 15:40:36341 days ago1713282036IN
0x5a81Dfa5...B49F69991
0 ETH0.000099491.10399505
Interchain Execu...57116272024-04-16 15:40:12341 days ago1713282012IN
0x5a81Dfa5...B49F69991
0 ETH0.000099521.10433856
Interchain Execu...57116252024-04-16 15:39:48341 days ago1713281988IN
0x5a81Dfa5...B49F69991
0 ETH0.000099531.10436757
Interchain Execu...57116222024-04-16 15:39:12341 days ago1713281952IN
0x5a81Dfa5...B49F69991
0 ETH0.00009961.10522479
Interchain Execu...57116212024-04-16 15:39:00341 days ago1713281940IN
0x5a81Dfa5...B49F69991
0 ETH0.000099571.10489667
Interchain Execu...57116192024-04-16 15:38:36341 days ago1713281916IN
0x5a81Dfa5...B49F69991
0 ETH0.00009961.10524343
Interchain Execu...57116172024-04-16 15:38:12341 days ago1713281892IN
0x5a81Dfa5...B49F69991
0 ETH0.000099611.10529123
Interchain Execu...57116152024-04-16 15:37:48341 days ago1713281868IN
0x5a81Dfa5...B49F69991
0 ETH0.000099611.10533082
Interchain Execu...57116142024-04-16 15:37:36341 days ago1713281856IN
0x5a81Dfa5...B49F69991
0 ETH0.000367591.10541981
Interchain Execu...57116122024-04-16 15:37:12341 days ago1713281832IN
0x5a81Dfa5...B49F69991
0 ETH0.000367681.10568853
Interchain Execu...57116102024-04-16 15:36:48341 days ago1713281808IN
0x5a81Dfa5...B49F69991
0 ETH0.000367711.10575594
Interchain Execu...57116082024-04-16 15:36:24341 days ago1713281784IN
0x5a81Dfa5...B49F69991
0 ETH0.000367721.10580701
Interchain Execu...57116062024-04-16 15:36:00341 days ago1713281760IN
0x5a81Dfa5...B49F69991
0 ETH0.000367471.10505793
Interchain Execu...57116042024-04-16 15:35:36341 days ago1713281736IN
0x5a81Dfa5...B49F69991
0 ETH0.000367581.10536559
Interchain Execu...57116022024-04-16 15:35:12341 days ago1713281712IN
0x5a81Dfa5...B49F69991
0 ETH0.000367321.10459338
Interchain Execu...57116002024-04-16 15:34:48341 days ago1713281688IN
0x5a81Dfa5...B49F69991
0 ETH0.000367281.10448705
Interchain Execu...57115982024-04-16 15:34:24341 days ago1713281664IN
0x5a81Dfa5...B49F69991
0 ETH0.000367351.10468503
Interchain Execu...57115962024-04-16 15:34:00341 days ago1713281640IN
0x5a81Dfa5...B49F69991
0 ETH0.000367371.10473894
Interchain Execu...57115942024-04-16 15:33:36341 days ago1713281616IN
0x5a81Dfa5...B49F69991
0 ETH0.000367251.10437311
Interchain Execu...57115922024-04-16 15:33:12341 days ago1713281592IN
0x5a81Dfa5...B49F69991
0 ETH0.000367241.10436164
Interchain Execu...57115902024-04-16 15:32:48341 days ago1713281568IN
0x5a81Dfa5...B49F69991
0 ETH0.000367161.10412107
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Add Execution Fe...57116142024-04-16 15:37:36341 days ago1713281856
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116142024-04-16 15:37:36341 days ago1713281856
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116142024-04-16 15:37:36341 days ago1713281856
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57116122024-04-16 15:37:12341 days ago1713281832
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116122024-04-16 15:37:12341 days ago1713281832
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116122024-04-16 15:37:12341 days ago1713281832
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57116102024-04-16 15:36:48341 days ago1713281808
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116102024-04-16 15:36:48341 days ago1713281808
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116102024-04-16 15:36:48341 days ago1713281808
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57116082024-04-16 15:36:24341 days ago1713281784
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116082024-04-16 15:36:24341 days ago1713281784
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116082024-04-16 15:36:24341 days ago1713281784
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57116062024-04-16 15:36:00341 days ago1713281760
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116062024-04-16 15:36:00341 days ago1713281760
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116062024-04-16 15:36:00341 days ago1713281760
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57116042024-04-16 15:35:36341 days ago1713281736
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116042024-04-16 15:35:36341 days ago1713281736
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116042024-04-16 15:35:36341 days ago1713281736
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57116022024-04-16 15:35:12341 days ago1713281712
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116022024-04-16 15:35:12341 days ago1713281712
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116022024-04-16 15:35:12341 days ago1713281712
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57116002024-04-16 15:34:48341 days ago1713281688
0x5a81Dfa5...B49F69991
0.0000005 ETH
Write Entry With...57116002024-04-16 15:34:48341 days ago1713281688
0x5a81Dfa5...B49F69991
0.0000001 ETH
Interchain Send57116002024-04-16 15:34:48341 days ago1713281688
0x5a81Dfa5...B49F69991
0.0000006 ETH
Add Execution Fe...57115982024-04-16 15:34:24341 days ago1713281664
0x5a81Dfa5...B49F69991
0.0000005 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
InterchainClientV1

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 17 : InterchainClientV1.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {InterchainClientV1Events} from "./events/InterchainClientV1Events.sol";

import {IExecutionFees} from "./interfaces/IExecutionFees.sol";
import {IExecutionService} from "./interfaces/IExecutionService.sol";
import {IInterchainApp} from "./interfaces/IInterchainApp.sol";
import {IInterchainClientV1} from "./interfaces/IInterchainClientV1.sol";
import {IInterchainDB} from "./interfaces/IInterchainDB.sol";

import {AppConfigV1, AppConfigLib} from "./libs/AppConfig.sol";
import {InterchainEntry} from "./libs/InterchainEntry.sol";
import {
    InterchainTransaction, InterchainTxDescriptor, InterchainTransactionLib
} from "./libs/InterchainTransaction.sol";
import {OptionsLib, OptionsV1} from "./libs/Options.sol";
import {TypeCasts} from "./libs/TypeCasts.sol";
import {VersionedPayloadLib} from "./libs/VersionedPayload.sol";

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title InterchainClientV1
 * @dev Implements the operations of the Interchain Execution Layer.
 */
contract InterchainClientV1 is Ownable, InterchainClientV1Events, IInterchainClientV1 {
    using AppConfigLib for bytes;
    using OptionsLib for bytes;
    using VersionedPayloadLib for bytes;

    /// @notice Version of the InterchainClient contract. Sent and received transactions must have the same version.
    uint16 public constant CLIENT_VERSION = 1;

    /// @notice Address of the InterchainDB contract, set at the time of deployment.
    address public immutable INTERCHAIN_DB;

    /// @notice Address of the contract that handles execution fees. Can be updated by the owner.
    address public executionFees;

    /// @dev Address of the InterchainClient contract on the remote chain
    mapping(uint256 chainId => bytes32 remoteClient) internal _linkedClient;
    /// @dev Executor address that completed the transaction. Address(0) if not executed yet.
    mapping(bytes32 transactionId => address executor) internal _txExecutor;

    constructor(address interchainDB, address owner_) Ownable(owner_) {
        INTERCHAIN_DB = interchainDB;
    }

    // @inheritdoc IInterchainClientV1
    function setExecutionFees(address executionFees_) external onlyOwner {
        executionFees = executionFees_;
        emit ExecutionFeesSet(executionFees_);
    }

    // @inheritdoc IInterchainClientV1
    function setLinkedClient(uint256 chainId, bytes32 client) external onlyOwner {
        _linkedClient[chainId] = client;
        emit LinkedClientSet(chainId, client);
    }

    // @inheritdoc IInterchainClientV1
    function interchainSend(
        uint256 dstChainId,
        bytes32 receiver,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        bytes calldata message
    )
        external
        payable
        returns (InterchainTxDescriptor memory desc)
    {
        return _interchainSend(dstChainId, receiver, srcExecutionService, srcModules, options, message);
    }

    // @inheritdoc IInterchainClientV1
    function interchainSendEVM(
        uint256 dstChainId,
        address receiver,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        bytes calldata message
    )
        external
        payable
        returns (InterchainTxDescriptor memory desc)
    {
        bytes32 receiverBytes32 = TypeCasts.addressToBytes32(receiver);
        return _interchainSend(dstChainId, receiverBytes32, srcExecutionService, srcModules, options, message);
    }

    // TODO: Handle the case where receiver does not implement the IInterchainApp interface (or does not exist at all)
    // @inheritdoc IInterchainClientV1
    function interchainExecute(
        uint256 gasLimit,
        bytes calldata transaction,
        bytes32[] calldata proof
    )
        external
        payable
    {
        InterchainTransaction memory icTx = _assertCorrectVersion(transaction);
        bytes32 transactionId = keccak256(transaction);
        _assertExecutable(icTx, transactionId, proof);
        _txExecutor[transactionId] = msg.sender;

        OptionsV1 memory decodedOptions = icTx.options.decodeOptionsV1();
        if (msg.value != decodedOptions.gasAirdrop) {
            revert InterchainClientV1__IncorrectMsgValue(msg.value, decodedOptions.gasAirdrop);
        }
        // We should always use at least as much as the requested gas limit.
        // The executor can specify a higher gas limit if they wanted.
        if (decodedOptions.gasLimit > gasLimit) gasLimit = decodedOptions.gasLimit;
        // Check the the Executor has provided big enough gas limit for the whole transaction.
        if (gasleft() <= gasLimit) {
            revert InterchainClientV1__NotEnoughGasSupplied();
        }
        // Pass the full msg.value to the app: we have already checked that it matches the requested gas airdrop.
        IInterchainApp(TypeCasts.bytes32ToAddress(icTx.dstReceiver)).appReceive{gas: gasLimit, value: msg.value}({
            srcChainId: icTx.srcChainId,
            sender: icTx.srcSender,
            dbNonce: icTx.dbNonce,
            entryIndex: icTx.entryIndex,
            message: icTx.message
        });
        emit InterchainTransactionReceived(
            transactionId, icTx.dbNonce, icTx.entryIndex, icTx.srcChainId, icTx.srcSender, icTx.dstReceiver
        );
    }

    /// @inheritdoc IInterchainClientV1
    function writeExecutionProof(bytes32 transactionId) external returns (uint256 dbNonce, uint64 entryIndex) {
        address executor = _txExecutor[transactionId];
        if (executor == address(0)) {
            revert InterchainClientV1__TxNotExecuted(transactionId);
        }
        bytes memory proof = abi.encode(transactionId, executor);
        (dbNonce, entryIndex) = IInterchainDB(INTERCHAIN_DB).writeEntry(keccak256(proof));
        emit ExecutionProofWritten(transactionId, dbNonce, entryIndex, executor);
    }

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

    // @inheritdoc IInterchainClientV1
    function isExecutable(bytes calldata encodedTx, bytes32[] calldata proof) external view returns (bool) {
        InterchainTransaction memory icTx = _assertCorrectVersion(encodedTx);
        // Check that options could be decoded
        icTx.options.decodeOptionsV1();
        bytes32 transactionId = keccak256(encodedTx);
        _assertExecutable(icTx, transactionId, proof);
        return true;
    }

    // @inheritdoc IInterchainClientV1
    function getExecutor(bytes calldata encodedTx) external view returns (address) {
        return _txExecutor[keccak256(encodedTx)];
    }

    // @inheritdoc IInterchainClientV1
    function getExecutorById(bytes32 transactionId) external view returns (address) {
        return _txExecutor[transactionId];
    }

    // @inheritdoc IInterchainClientV1
    function getInterchainFee(
        uint256 dstChainId,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        uint256 messageLen
    )
        external
        view
        returns (uint256 fee)
    {
        _assertLinkedClient(dstChainId);
        // Check that options could be decoded on destination chain
        options.decodeOptionsV1();
        // Verification fee from InterchainDB
        fee = IInterchainDB(INTERCHAIN_DB).getInterchainFee(dstChainId, srcModules);
        // Add execution fee, if ExecutionService is provided
        if (srcExecutionService != address(0)) {
            uint256 payloadSize = InterchainTransactionLib.payloadSize(options.length, messageLen);
            fee += IExecutionService(srcExecutionService).getExecutionFee(dstChainId, payloadSize, options);
        }
    }

    /// @inheritdoc IInterchainClientV1
    function getLinkedClient(uint256 chainId) external view returns (bytes32) {
        if (chainId == block.chainid) {
            revert InterchainClientV1__NotRemoteChainId(chainId);
        }
        return _linkedClient[chainId];
    }

    /// @inheritdoc IInterchainClientV1
    function getLinkedClientEVM(uint256 chainId) external view returns (address linkedClientEVM) {
        if (chainId == block.chainid) {
            revert InterchainClientV1__NotRemoteChainId(chainId);
        }
        bytes32 linkedClient = _linkedClient[chainId];
        linkedClientEVM = TypeCasts.bytes32ToAddress(linkedClient);
        // Check that the linked client address fits into the EVM address space
        if (TypeCasts.addressToBytes32(linkedClientEVM) != linkedClient) {
            revert InterchainClientV1__NotEVMClient(linkedClient);
        }
    }

    /// @notice Decodes the encoded options data into a OptionsV1 struct.
    function decodeOptions(bytes memory encodedOptions) external view returns (OptionsV1 memory) {
        return encodedOptions.decodeOptionsV1();
    }

    /// @notice Encodes the transaction data into a bytes format.
    function encodeTransaction(InterchainTransaction memory icTx) public pure returns (bytes memory) {
        return VersionedPayloadLib.encodeVersionedPayload({
            version: CLIENT_VERSION,
            payload: InterchainTransactionLib.encodeTransaction(icTx)
        });
    }

    // ═════════════════════════════════════════════════ INTERNAL ══════════════════════════════════════════════════════

    /// @dev Internal logic for sending a message to another chain.
    function _interchainSend(
        uint256 dstChainId,
        bytes32 receiver,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        bytes calldata message
    )
        internal
        returns (InterchainTxDescriptor memory desc)
    {
        _assertLinkedClient(dstChainId);
        if (receiver == 0) revert InterchainClientV1__ZeroReceiver();
        // Check that options could be decoded on destination chain
        options.decodeOptionsV1();
        uint256 verificationFee = IInterchainDB(INTERCHAIN_DB).getInterchainFee(dstChainId, srcModules);
        if (msg.value < verificationFee) {
            revert InterchainClientV1__FeeAmountTooLow(msg.value, verificationFee);
        }
        (desc.dbNonce, desc.entryIndex) = IInterchainDB(INTERCHAIN_DB).getNextEntryIndex();
        InterchainTransaction memory icTx = InterchainTransactionLib.constructLocalTransaction({
            srcSender: msg.sender,
            dstReceiver: receiver,
            dstChainId: dstChainId,
            dbNonce: desc.dbNonce,
            entryIndex: desc.entryIndex,
            options: options,
            message: message
        });
        desc.transactionId = keccak256(encodeTransaction(icTx));
        // Sanity check: nonce returned from DB should match the nonce used to construct the transaction
        {
            (uint256 dbNonce, uint64 entryIndex) = IInterchainDB(INTERCHAIN_DB).writeEntryWithVerification{
                value: verificationFee
            }(icTx.dstChainId, desc.transactionId, srcModules);
            assert(dbNonce == desc.dbNonce && entryIndex == desc.entryIndex);
        }
        uint256 executionFee;
        unchecked {
            executionFee = msg.value - verificationFee;
        }
        if (executionFee > 0) {
            IExecutionFees(executionFees).addExecutionFee{value: executionFee}(icTx.dstChainId, desc.transactionId);
        }
        // TODO: consider disallowing the use of empty srcExecutionService
        if (srcExecutionService != address(0)) {
            IExecutionService(srcExecutionService).requestExecution({
                dstChainId: dstChainId,
                txPayloadSize: InterchainTransactionLib.payloadSize(options.length, message.length),
                transactionId: desc.transactionId,
                executionFee: executionFee,
                options: options
            });
            address srcExecutorEOA = IExecutionService(srcExecutionService).executorEOA();
            IExecutionFees(executionFees).recordExecutor(icTx.dstChainId, desc.transactionId, srcExecutorEOA);
        }
        emit InterchainTransactionSent(
            desc.transactionId,
            icTx.dbNonce,
            icTx.entryIndex,
            icTx.dstChainId,
            icTx.srcSender,
            icTx.dstReceiver,
            verificationFee,
            executionFee,
            icTx.options,
            icTx.message
        );
    }

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

    /// @dev Asserts that the transaction is executable.
    function _assertExecutable(
        InterchainTransaction memory icTx,
        bytes32 transactionId,
        bytes32[] calldata proof
    )
        internal
        view
    {
        bytes32 linkedClient = _assertLinkedClient(icTx.srcChainId);
        if (icTx.dstChainId != block.chainid) {
            revert InterchainClientV1__IncorrectDstChainId(icTx.dstChainId);
        }
        if (_txExecutor[transactionId] != address(0)) {
            revert InterchainClientV1__TxAlreadyExecuted(transactionId);
        }
        // Construct expected entry based on icTransaction data
        InterchainEntry memory icEntry = InterchainEntry({
            srcChainId: icTx.srcChainId,
            dbNonce: icTx.dbNonce,
            entryIndex: icTx.entryIndex,
            srcWriter: linkedClient,
            dataHash: transactionId
        });
        (bytes memory encodedAppConfig, address[] memory approvedDstModules) =
            IInterchainApp(TypeCasts.bytes32ToAddress(icTx.dstReceiver)).getReceivingConfig();
        AppConfigV1 memory appConfig = encodedAppConfig.decodeAppConfigV1();
        if (appConfig.requiredResponses == 0) {
            revert InterchainClientV1__ZeroRequiredResponses();
        }
        uint256 responses = _getFinalizedResponsesCount(approvedDstModules, icEntry, proof, appConfig.optimisticPeriod);
        if (responses < appConfig.requiredResponses) {
            revert InterchainClientV1__NotEnoughResponses(responses, appConfig.requiredResponses);
        }
    }

    /// @dev Asserts that the chain is linked and returns the linked client address.
    function _assertLinkedClient(uint256 chainId) internal view returns (bytes32 linkedClient) {
        if (chainId == block.chainid) {
            revert InterchainClientV1__NotRemoteChainId(chainId);
        }
        linkedClient = _linkedClient[chainId];
        if (linkedClient == 0) {
            revert InterchainClientV1__NoLinkedClient(chainId);
        }
    }

    /**
     * @dev Calculates the number of responses that are considered finalized within the optimistic time period.
     * @param approvedModules       Approved modules that could have confirmed the entry.
     * @param icEntry               The InterchainEntry to confirm.
     * @param optimisticPeriod      The time period in seconds within which a response is considered valid.
     * @return finalizedResponses   The count of responses that are finalized within the optimistic time period.
     */
    function _getFinalizedResponsesCount(
        address[] memory approvedModules,
        InterchainEntry memory icEntry,
        bytes32[] calldata proof,
        uint256 optimisticPeriod
    )
        internal
        view
        returns (uint256 finalizedResponses)
    {
        for (uint256 i = 0; i < approvedModules.length; ++i) {
            uint256 confirmedAt = IInterchainDB(INTERCHAIN_DB).checkVerification(approvedModules[i], icEntry, proof);
            // checkVerification() returns 0 if entry hasn't been confirmed by the module, so we check for that as well
            if (confirmedAt != 0 && confirmedAt + optimisticPeriod < block.timestamp) {
                ++finalizedResponses;
            }
        }
    }

    /// @dev Asserts that the transaction version is correct. Returns the decoded transaction for chaining purposes.
    function _assertCorrectVersion(bytes calldata versionedTx)
        internal
        pure
        returns (InterchainTransaction memory icTx)
    {
        uint16 version = versionedTx.getVersion();
        if (version != CLIENT_VERSION) {
            revert InterchainClientV1__InvalidTransactionVersion(version);
        }
        icTx = InterchainTransactionLib.decodeTransaction(versionedTx.getPayload());
    }
}

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

abstract contract InterchainClientV1Events {
    event ExecutionFeesSet(address executionFees);
    event LinkedClientSet(uint256 chainId, bytes32 client);

    // TODO: figure out indexing

    event InterchainTransactionSent(
        bytes32 indexed transactionId,
        uint256 indexed dbNonce,
        uint64 indexed entryIndex,
        uint256 dstChainId,
        bytes32 srcSender,
        bytes32 dstReceiver,
        uint256 verificationFee,
        uint256 executionFee,
        bytes options,
        bytes message
    );

    event InterchainTransactionReceived(
        bytes32 indexed transactionId,
        uint256 indexed dbNonce,
        uint64 indexed entryIndex,
        uint256 srcChainId,
        bytes32 srcSender,
        bytes32 dstReceiver
    );

    event ExecutionProofWritten(
        bytes32 indexed transactionId, uint256 indexed dbNonce, uint64 indexed entryIndex, address executor
    );
}

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

interface IExecutionFees {
    error ExecutionFees__AlreadyRecorded(uint256 dstChainId, bytes32 transactionId, address executor);
    error ExecutionFees__ZeroAddress();
    error ExecutionFees__ZeroAmount();

    /// @notice Add the execution fee for a transaction. The attached value will be added to the
    /// rewards for the executor completing the transaction.
    /// Note: this could be used to store the execution fee for a new transaction, or to add more
    /// funds to the execution fee of an existing transaction. Therefore this function is payable,
    /// and does not implement any caller restrictions.
    /// @dev Will revert if the executor is already recorded for the transaction.
    /// @param dstChainId           The chain id of the destination chain.
    /// @param transactionId        The id of the transaction to add the execution fee to.
    function addExecutionFee(uint256 dstChainId, bytes32 transactionId) external payable;

    /// @notice Record the executor (who completed the transaction) for a transaction,
    /// and update the accumulated rewards for the executor.
    /// @dev Could only be called by the Recorder.
    /// @param dstChainId           The chain id of the destination chain.
    /// @param transactionId        The id of the transaction to record the executor for.
    /// @param executor             The address of the executor who completed the transaction.
    function recordExecutor(uint256 dstChainId, bytes32 transactionId, address executor) external;

    /// @notice Allows the executor to claim their unclaimed rewards.
    /// @dev Will revert if the executor has no unclaimed rewards.
    function claimExecutionFees(address executor) external;

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

    /// @notice Get the accumulated rewards for an executor.
    /// @param executor             The address of the executor to get the rewards for.
    function accumulatedRewards(address executor) external view returns (uint256 accumulated);

    /// @notice Get the unclaimed rewards for an executor.
    /// @param executor             The address of the executor to get the rewards for.
    function unclaimedRewards(address executor) external view returns (uint256 unclaimed);

    /// @notice Get the total execution fee for a transaction.
    /// @param dstChainId           The chain id of the destination chain.
    /// @param transactionId        The id of the transaction to get the execution fee for.
    function executionFee(uint256 dstChainId, bytes32 transactionId) external view returns (uint256 fee);

    /// @notice Get the address of the recorded executor for a transaction.
    /// @dev Will return address(0) if the executor is not recorded.
    /// @param dstChainId           The chain id of the destination chain.
    /// @param transactionId        The id of the transaction to get the recorded executor for.
    function recordedExecutor(uint256 dstChainId, bytes32 transactionId) external view returns (address executor);
}

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

interface IExecutionService {
    /// @notice Request the execution of an Interchain Transaction on a remote chain.
    /// Note: the off-chain actor needs to fetch the transaction payload from the InterchainClient
    /// event with the same transactionId, then execute the transaction on the remote chain:
    /// `dstInterchainClient.executeTransaction(transactionPayload)`
    /// Once the execution is confirmed on the source chain, the off-chain actor will be able
    /// to claim `executionFee` in the ExecutionFees contract.
    /// @dev Could only be called by `InterchainClient` contracts.
    /// Will revert if the execution fee is not big enough.
    /// @param dstChainId           The chain id of the destination chain.
    /// @param txPayloadSize        The size of the transaction payload to use for the execution.
    /// @param transactionId        The id of the transaction to execute.
    /// @param executionFee         The fee paid for the execution.
    /// @param options              The options to use for the execution.
    function requestExecution(
        uint256 dstChainId,
        uint256 txPayloadSize,
        bytes32 transactionId,
        uint256 executionFee,
        bytes memory options
    )
        external;

    /// @notice Get the address of the EOA account that will be used to execute transactions on the
    /// remote chains.
    function executorEOA() external view returns (address);

    /// @notice Get the execution fee for executing an Interchain Transaction on a remote chain.
    /// @param dstChainId           The chain id of the destination chain.
    /// @param txPayloadSize        The size of the transaction payload to use for the execution.
    /// @param options              The options to use for the execution.
    function getExecutionFee(
        uint256 dstChainId,
        uint256 txPayloadSize,
        bytes memory options
    )
        external
        view
        returns (uint256);
}

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

/// @notice Minimal interface for the Interchain App to work with the Interchain Client.
interface IInterchainApp {
    /// @notice Allows the Interchain Client to pass the message to the Interchain App.
    /// @dev App is responsible for keeping track of interchain clients, and must verify the message sender.
    /// @param srcChainId   Chain ID of the source chain, where the message was sent from.
    /// @param sender       Sender address on the source chain, as a bytes32 value.
    /// @param dbNonce      The Interchain DB nonce of the batch containing the message entry.
    /// @param entryIndex   The index of the message entry within the batch.
    /// @param message      The message being sent.
    function appReceive(
        uint256 srcChainId,
        bytes32 sender,
        uint256 dbNonce,
        uint64 entryIndex,
        bytes calldata message
    )
        external
        payable;

    /// @notice Returns the verification configuration of the Interchain App.
    /// @dev This configuration is used by the Interchain Client to verify that message has been confirmed
    /// by the Interchain Modules on the destination chain.
    /// Note: V1 version of AppConfig includes the required responses count, and optimistic period after which
    /// the message is considered confirmed by the module. Following versions may include additional fields.
    /// @return appConfig    The versioned configuration of the Interchain App, encoded as bytes.
    /// @return modules      The list of Interchain Modules that app is trusting to confirm the messages.
    function getReceivingConfig() external view returns (bytes memory appConfig, address[] memory modules);
}

File 6 of 17 : IInterchainClientV1.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {InterchainTxDescriptor} from "../libs/InterchainTransaction.sol";

interface IInterchainClientV1 {
    error InterchainClientV1__FeeAmountTooLow(uint256 actual, uint256 required);
    error InterchainClientV1__IncorrectDstChainId(uint256 chainId);
    error InterchainClientV1__IncorrectMsgValue(uint256 actual, uint256 required);
    error InterchainClientV1__InvalidTransactionVersion(uint16 version);
    error InterchainClientV1__NoLinkedClient(uint256 chainId);
    error InterchainClientV1__NotEnoughGasSupplied();
    error InterchainClientV1__NotEnoughResponses(uint256 actual, uint256 required);
    error InterchainClientV1__NotEVMClient(bytes32 client);
    error InterchainClientV1__NotRemoteChainId(uint256 chainId);
    error InterchainClientV1__TxAlreadyExecuted(bytes32 transactionId);
    error InterchainClientV1__TxNotExecuted(bytes32 transactionId);
    error InterchainClientV1__ZeroReceiver();
    error InterchainClientV1__ZeroRequiredResponses();

    /**
     * @notice Sets the address of the ExecutionFees contract.
     * @dev Only callable by the contract owner or an authorized account.
     * @param executionFees_ The address of the ExecutionFees contract.
     */
    function setExecutionFees(address executionFees_) external;

    /**
     * @notice Sets the linked client for a specific chain ID.
     * @dev Stores the address of the linked client in a mapping with the chain ID as the key.
     * @param chainId The chain ID for which the client is being set.
     * @param client The address of the client being linked.
     */
    function setLinkedClient(uint256 chainId, bytes32 client) external;

    /**
     * @notice Sends a message to another chain via the Interchain Communication Protocol.
     * @dev Charges a fee for the message, which is payable upon calling this function:
     * - Verification fees: paid to every module that verifies the message.
     * - Execution fee: paid to the executor that executes the message.
     * Note: while a specific execution service is specified to request the execution of the message,
     * any executor is able to execute the message on destination chain, earning the execution fee.
     * @param dstChainId The chain ID of the destination chain.
     * @param receiver The address of the receiver on the destination chain.
     * @param srcExecutionService The address of the execution service to use for the message.
     * @param srcModules The source modules involved in the message sending.
     * @param options Execution options for the message sent, encoded as bytes, currently gas limit + native gas drop.
     * @param message The message being sent.
     * @return desc The descriptor of the sent transaction:
     * - transactionId: the ID of the transaction that was sent.
     * - dbNonce: the database nonce of the batch containing the written entry for transaction.
     * - entryIndex: the index of the written entry for transaction within the batch.
     */
    function interchainSend(
        uint256 dstChainId,
        bytes32 receiver,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        bytes calldata message
    )
        external
        payable
        returns (InterchainTxDescriptor memory desc);

    function interchainSendEVM(
        uint256 dstChainId,
        address receiver,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        bytes calldata message
    )
        external
        payable
        returns (InterchainTxDescriptor memory desc);

    /**
     * @notice Executes a transaction that has been sent via the Interchain.
     * @dev The transaction must have been previously sent and recorded.
     * Transaction data includes the requested gas limit, but the executors could specify a different gas limit.
     * If the specified gas limit is lower than requested, the requested gas limit will be used.
     * Otherwise, the specified gas limit will be used.
     * This allows to execute the transactions with requested gas limit set too low.
     * @param gasLimit          The gas limit to use for the execution.
     * @param transaction       The transaction data.
     * @param proof             The Merkle proof for transaction execution, fetched from the source chain.
     */
    function interchainExecute(
        uint256 gasLimit,
        bytes calldata transaction,
        bytes32[] calldata proof
    )
        external
        payable;

    /// @notice Writes the proof of execution for a transaction into the InterchainDB.
    /// @dev Will revert if the transaction has not been executed.
    /// @param transactionId    The ID of the transaction to write the proof for.
    /// @return dbNonce         The database nonce of the batch containing the written proof for transaction.
    /// @return entryIndex      The index of the written proof for transaction within the batch.
    function writeExecutionProof(bytes32 transactionId) external returns (uint256 dbNonce, uint64 entryIndex);

    /**
     * @notice Checks if a transaction is executable.
     * @dev Determines if a transaction meets the criteria to be executed based on:
     * - If approved modules have written to the InterchainDB
     * - If the threshold of approved modules have been met
     * - If the optimistic window has passed for all modules
     * @param transaction       The InterchainTransaction struct to be checked.
     * @param proof             The Merkle proof for transaction execution, fetched from the source chain.
     * @return bool Returns true if the transaction is executable, false otherwise.
     */
    function isExecutable(bytes calldata transaction, bytes32[] calldata proof) external view returns (bool);

    /// @notice Returns the fee for sending an Interchain message.
    /// @param dstChainId           The chain ID of the destination chain.
    /// @param srcExecutionService  The address of the execution service to use for the message.
    /// @param srcModules           The source modules involved in the message sending.
    /// @param options              Execution options for the message sent, currently gas limit + native gas drop.
    /// @param messageLen           The length of the message being sent.
    function getInterchainFee(
        uint256 dstChainId,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        uint256 messageLen
    )
        external
        view
        returns (uint256);

    /// @notice Returns the address of the executor for a transaction that has been sent to the local chain.
    function getExecutor(bytes calldata transaction) external view returns (address);

    /// @notice Returns the address of the executor for a transaction that has been sent to the local chain.
    function getExecutorById(bytes32 transactionId) external view returns (address);

    /// @notice Returns the address of the linked client (as bytes32) for a specific chain ID.
    /// @dev Will return 0x0 if no client is linked for the chain ID.
    function getLinkedClient(uint256 chainId) external view returns (bytes32);

    /// @notice Returns the EVM address of the linked client for a specific chain ID.
    /// @dev Will return 0x0 if no client is linked for the chain ID.
    /// Will revert if the client is not an EVM client.
    function getLinkedClientEVM(uint256 chainId) external view returns (address);
}

File 7 of 17 : 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 8 of 17 : AppConfig.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

struct AppConfigV1 {
    uint256 requiredResponses;
    uint256 optimisticPeriod;
}

using AppConfigLib for AppConfigV1 global;

library AppConfigLib {
    using VersionedPayloadLib for bytes;

    uint16 internal constant APP_CONFIG_V1 = 1;

    error AppConfigLib__IncorrectVersion(uint16 version);

    /// @notice Decodes app config (V1 or higher) from a bytes format back into an AppConfigV1 struct.
    /// @param data         The app config data in bytes format.
    function decodeAppConfigV1(bytes memory data) internal view returns (AppConfigV1 memory) {
        uint16 version = data.getVersionFromMemory();
        if (version < APP_CONFIG_V1) {
            revert AppConfigLib__IncorrectVersion(version);
        }
        // Structs of the same version will always be decoded correctly.
        // Following versions will be decoded correctly if they have the same fields as the previous version,
        // and new fields at the end: abi.decode ignores the extra bytes in the decoded payload.
        return abi.decode(data.getPayloadFromMemory(), (AppConfigV1));
    }

    /// @notice Encodes V1 app config into a bytes format.
    /// @param appConfig    The AppConfigV1 to encode.
    function encodeAppConfigV1(AppConfigV1 memory appConfig) internal pure returns (bytes memory) {
        return VersionedPayloadLib.encodeVersionedPayload(APP_CONFIG_V1, abi.encode(appConfig));
    }
}

File 9 of 17 : 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 10 of 17 : InterchainTransaction.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {MathLib} from "./Math.sol";
import {TypeCasts} from "./TypeCasts.sol";
import {VersionedPayloadLib} from "./VersionedPayload.sol";

struct InterchainTransaction {
    uint256 srcChainId;
    bytes32 srcSender;
    uint256 dstChainId;
    bytes32 dstReceiver;
    uint256 dbNonce;
    uint64 entryIndex;
    bytes options;
    bytes message;
}

struct InterchainTxDescriptor {
    bytes32 transactionId;
    uint256 dbNonce;
    uint64 entryIndex;
}

using InterchainTransactionLib for InterchainTransaction global;

library InterchainTransactionLib {
    using MathLib for uint256;
    using VersionedPayloadLib for bytes;

    function constructLocalTransaction(
        address srcSender,
        uint256 dstChainId,
        bytes32 dstReceiver,
        uint256 dbNonce,
        uint64 entryIndex,
        bytes memory options,
        bytes memory message
    )
        internal
        view
        returns (InterchainTransaction memory transaction)
    {
        return InterchainTransaction({
            srcChainId: block.chainid,
            srcSender: TypeCasts.addressToBytes32(srcSender),
            dstChainId: dstChainId,
            dstReceiver: dstReceiver,
            dbNonce: dbNonce,
            entryIndex: entryIndex,
            options: options,
            message: message
        });
    }

    function encodeTransaction(InterchainTransaction memory transaction) internal pure returns (bytes memory) {
        return abi.encode(transaction);
    }

    function decodeTransaction(bytes calldata transaction) internal pure returns (InterchainTransaction memory) {
        return abi.decode(transaction, (InterchainTransaction));
    }

    function payloadSize(uint256 optionsLen, uint256 messageLen) internal pure returns (uint256) {
        // 2 bytes are reserved for the transaction version
        // + 8 fields * 32 bytes (6 values for static, 2 offsets for dynamic) + 2 * 32 bytes (lengths for dynamic) = 322
        // abi.encode() also prepends the global offset (which is always 0x20) if there's a dynamic field, making it 354
        // Both options and message are dynamic fields, which are padded up to 32 bytes
        return 354 + optionsLen.roundUpToWord() + messageLen.roundUpToWord();
    }
}

File 11 of 17 : Options.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

/// @notice Struct to hold V1 of options data.
/// @dev Next versions have to use the fields from the previous version and add new fields at the end.
/// @param gasLimit The gas limit for the transaction.
/// @param gasAirdrop The amount of gas to airdrop.
struct OptionsV1 {
    uint256 gasLimit;
    uint256 gasAirdrop;
}

using OptionsLib for OptionsV1 global;

/// @title OptionsLib
/// @notice A library for encoding and decoding Interchain options related to interchain messages.
library OptionsLib {
    using VersionedPayloadLib for bytes;

    uint16 internal constant OPTIONS_V1 = 1;

    error OptionsLib__IncorrectVersion(uint16 version);

    /// @notice Decodes options (V1 or higher) from a bytes format back into an OptionsV1 struct.
    /// @param data         The options data in bytes format.
    function decodeOptionsV1(bytes memory data) internal view returns (OptionsV1 memory) {
        uint16 version = data.getVersionFromMemory();
        if (version < OPTIONS_V1) {
            revert OptionsLib__IncorrectVersion(version);
        }
        // Structs of the same version will always be decoded correctly.
        // Following versions will be decoded correctly if they have the same fields as the previous version,
        // and new fields at the end: abi.decode ignores the extra bytes in the decoded payload.
        return abi.decode(data.getPayloadFromMemory(), (OptionsV1));
    }

    /// @notice Encodes V1 options into a bytes format.
    /// @param options      The OptionsV1 to encode.
    function encodeOptionsV1(OptionsV1 memory options) internal pure returns (bytes memory) {
        return VersionedPayloadLib.encodeVersionedPayload(OPTIONS_V1, abi.encode(options));
    }
}

File 12 of 17 : 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)));
    }
}

File 13 of 17 : 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 14 of 17 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _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 15 of 17 : 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 16 of 17 : Math.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library MathLib {
    /// @notice Rounds up to the nearest multiple of 32.
    /// Note: Returns zero on overflows instead of reverting. This is fine for practical
    /// use cases, as this is used for determining the size of the payload in memory.
    function roundUpToWord(uint256 x) internal pure returns (uint256) {
        unchecked {
            return (x + 31) & ~uint256(31);
        }
    }
}

File 17 of 17 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

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":"address","name":"interchainDB","type":"address"},{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"AppConfigLib__IncorrectVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InterchainClientV1__FeeAmountTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"InterchainClientV1__IncorrectDstChainId","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InterchainClientV1__IncorrectMsgValue","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"InterchainClientV1__InvalidTransactionVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"InterchainClientV1__NoLinkedClient","type":"error"},{"inputs":[{"internalType":"bytes32","name":"client","type":"bytes32"}],"name":"InterchainClientV1__NotEVMClient","type":"error"},{"inputs":[],"name":"InterchainClientV1__NotEnoughGasSupplied","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InterchainClientV1__NotEnoughResponses","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"InterchainClientV1__NotRemoteChainId","type":"error"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"InterchainClientV1__TxAlreadyExecuted","type":"error"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"InterchainClientV1__TxNotExecuted","type":"error"},{"inputs":[],"name":"InterchainClientV1__ZeroReceiver","type":"error"},{"inputs":[],"name":"InterchainClientV1__ZeroRequiredResponses","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"OptionsLib__IncorrectVersion","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"VersionedPayload__PrecompileFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"versionedPayload","type":"bytes"}],"name":"VersionedPayload__TooShort","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"executionFees","type":"address"}],"name":"ExecutionFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"entryIndex","type":"uint64"},{"indexed":false,"internalType":"address","name":"executor","type":"address"}],"name":"ExecutionProofWritten","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"entryIndex","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"srcChainId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"dstReceiver","type":"bytes32"}],"name":"InterchainTransactionReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"entryIndex","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"dstChainId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"dstReceiver","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"verificationFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"executionFee","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"options","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"InterchainTransactionSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"client","type":"bytes32"}],"name":"LinkedClientSet","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":"CLIENT_VERSION","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTERCHAIN_DB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedOptions","type":"bytes"}],"name":"decodeOptions","outputs":[{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasAirdrop","type":"uint256"}],"internalType":"struct OptionsV1","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"bytes32","name":"dstReceiver","type":"bytes32"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"internalType":"struct InterchainTransaction","name":"icTx","type":"tuple"}],"name":"encodeTransaction","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"executionFees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"getExecutor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"getExecutorById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"address","name":"srcExecutionService","type":"address"},{"internalType":"address[]","name":"srcModules","type":"address[]"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"uint256","name":"messageLen","type":"uint256"}],"name":"getInterchainFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getLinkedClient","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getLinkedClientEVM","outputs":[{"internalType":"address","name":"linkedClientEVM","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"transaction","type":"bytes"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"interchainExecute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"bytes32","name":"receiver","type":"bytes32"},{"internalType":"address","name":"srcExecutionService","type":"address"},{"internalType":"address[]","name":"srcModules","type":"address[]"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"interchainSend","outputs":[{"components":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"internalType":"struct InterchainTxDescriptor","name":"desc","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"srcExecutionService","type":"address"},{"internalType":"address[]","name":"srcModules","type":"address[]"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"interchainSendEVM","outputs":[{"components":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"internalType":"struct InterchainTxDescriptor","name":"desc","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"isExecutable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"executionFees_","type":"address"}],"name":"setExecutionFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"bytes32","name":"client","type":"bytes32"}],"name":"setLinkedClient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"writeExecutionProof","outputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162002622380380620026228339810160408190526200003491620000f0565b806001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f8162000083565b50506001600160a01b031660805262000128565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000eb57600080fd5b919050565b600080604083850312156200010457600080fd5b6200010f83620000d3565b91506200011f60208401620000d3565b90509250929050565b6080516124b46200016e600039600081816103970152818161079d015281816109b201528181611057015281816110ff01528181611255015261175101526124b46000f3fe60806040526004361061011f5760003560e01c80638da5cb5b116100a0578063e4c6124711610064578063e4c6124714610385578063f1a61fac146103b9578063f2fde38b146103ef578063f34234c81461040f578063f92a79ff1461042f57600080fd5b80638da5cb5b146102bc57806390e81077146102da57806398939d2814610317578063aa102ec41461032a578063d5e788a01461034a57600080fd5b80637341eaf9116100e75780637341eaf9146101db5780637813cd52146101fb5780637a1277db146102235780637c80a90f14610251578063827f940d1461027e57600080fd5b806302172a35146101245780631450c281146101615780633dc68b871461019157806353b67d74146101b3578063715018a6146101c6575b600080fd5b34801561013057600080fd5b5061014461013f3660046118fb565b61044f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561016d57600080fd5b5061018161017c366004611999565b6104bc565b6040519015158152602001610158565b34801561019d57600080fd5b506101b16101ac366004611a19565b61050e565b005b6101b16101c1366004611a36565b61056a565b3480156101d257600080fd5b506101b1610726565b3480156101e757600080fd5b50600154610144906001600160a01b031681565b34801561020757600080fd5b50610210600181565b60405161ffff9091168152602001610158565b34801561022f57600080fd5b5061024361023e366004611aaf565b61073a565b604051908152602001610158565b34801561025d57600080fd5b5061027161026c366004611c4f565b6108c3565b6040516101589190611d73565b61029161028c366004611d86565b6108de565b604080518251815260208084015190820152918101516001600160401b031690820152606001610158565b3480156102c857600080fd5b506000546001600160a01b0316610144565b3480156102e657600080fd5b506102fa6102f53660046118fb565b610925565b604080519283526001600160401b03909116602083015201610158565b610291610325366004611e50565b610a7d565b34801561033657600080fd5b506102436103453660046118fb565b610ab9565b34801561035657600080fd5b5061036a610365366004611e87565b610af1565b60408051825181526020928301519281019290925201610158565b34801561039157600080fd5b506101447f000000000000000000000000000000000000000000000000000000000000000081565b3480156103c557600080fd5b506101446103d43660046118fb565b6000908152600360205260409020546001600160a01b031690565b3480156103fb57600080fd5b506101b161040a366004611a19565b610b0e565b34801561041b57600080fd5b506101b161042a366004611ebb565b610b4c565b34801561043b57600080fd5b5061014461044a366004611edd565b610ba3565b6000468203610479576040516357516f6960e01b8152600481018390526024015b60405180910390fd5b50600081815260026020526040902054806001600160a01b03811681146104b657604051630a55a4eb60e01b815260048101829052602401610470565b50919050565b6000806104c98686610be3565b90506104d88160c00151610c3e565b50600086866040516104eb929190611f1e565b6040518091039020905061050182828787610cae565b5060019695505050505050565b610516610e5c565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527fec02f15d78cdfc4beeba45f31cfad25089004e5e3d72727168dd96a77d1f2f829060200160405180910390a150565b60006105768585610be3565b90506000858560405161058a929190611f1e565b604051809103902090506105a082828686610cae565b600081815260036020526040812080546001600160a01b0319163317905560c08301516105cc90610c3e565b905080602001513414610601576020810151604051632b36102560e01b81523460048201526024810191909152604401610470565b805188101561060f57805197505b875a1161062f576040516374dc18ab60e11b815260040160405180910390fd5b60608301516001600160a01b03166368a6984789348660000151876020015188608001518960a001518a60e001516040518863ffffffff1660e01b815260040161067d959493929190611f2e565b6000604051808303818589803b15801561069657600080fd5b5088f11580156106aa573d6000803e3d6000fd5b5050505050508260a001516001600160401b03168360800151837f9c887f38b8f2330ee9894137eb60cf6ab904c5d2063ddc0baa7a77bfd1880e8c866000015187602001518860600151604051610714939291909283526020830191909152604082015260600190565b60405180910390a45050505050505050565b61072e610e5c565b6107386000610e89565b565b600061074588610ed9565b5061078584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fc7686ec906107d6908b908a908a90600401611fab565b602060405180830381865afa1580156107f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108179190611fce565b90506001600160a01b038716156108b85760006108348484610f37565b60405163188e7cfd60e31b81529091506001600160a01b0389169063c473e7e890610869908c9085908a908a90600401612010565b602060405180830381865afa158015610886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190611fce565b6108b49083612050565b9150505b979650505050505050565b60606108d860016108d384610f5f565b610f88565b92915050565b60408051606081018252600080825260208201819052918101919091526001600160a01b0389166109168b828b8b8b8b8b8b8b610fb4565b9b9a5050505050505050505050565b60008181526003602052604081205481906001600160a01b0316806109605760405163e99eb48d60e01b815260048101859052602401610470565b600084826040516020016109879291909182526001600160a01b0316602082015260400190565b60408051808303601f19018152908290528051602082012063156c638360e11b8352600483015291507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632ad8c7069060240160408051808303816000875af1158015610a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a269190612063565b6040516001600160a01b038516815291955093506001600160401b03841690859087907f810ecf3e461a7f5c46c0bbbca8680cf65de59e78e521d58d569e03969d08648c9060200160405180910390a45050915091565b6040805160608101825260008082526020820181905291810191909152610aab8a8a8a8a8a8a8a8a8a610fb4565b9a9950505050505050505050565b6000468203610ade576040516357516f6960e01b815260048101839052602401610470565b5060009081526002602052604090205490565b60408051808201909152600080825260208201526108d882610c3e565b610b16610e5c565b6001600160a01b038116610b4057604051631e4fbdf760e01b815260006004820152602401610470565b610b4981610e89565b50565b610b54610e5c565b60008281526002602090815260409182902083905581518481529081018390527fb6b5dc04cc1c35fc7a8c8342e378dccc610c6589ef3bcfcd6eaf0304913f889a910160405180910390a15050565b6000600360008484604051610bb9929190611f1e565b60408051918290039091208252602082019290925201600020546001600160a01b03169392505050565b610beb6118a7565b6000610bf78484611591565b905061ffff8116600114610c2457604051630fda659b60e01b815261ffff82166004820152602401610470565b610c36610c3185856115c2565b611604565b949350505050565b60408051808201909152600080825260208201526000610c5d83611618565b9050600161ffff82161015610c8b5760405163b94fa72560e01b815261ffff82166004820152602401610470565b610c948361164a565b806020019051810190610ca791906120e1565b9392505050565b6000610cbd8560000151610ed9565b905046856040015114610ceb578460400151604051634b9929c160e11b815260040161047091815260200190565b6000848152600360205260409020546001600160a01b031615610d245760405163d80aeb9160e01b815260048101859052602401610470565b60006040518060a0016040528087600001518152602001876080015181526020018760a001516001600160401b03168152602001838152602001868152509050600080610d72886060015190565b6001600160a01b031663287bc0576040518163ffffffff1660e01b8152600401600060405180830381865afa158015610daf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd791908101906120fd565b915091506000610de6836116f3565b8051909150600003610e0b5760405163a09e214360e01b815260040160405180910390fd5b6000610e1e83868a8a8660200151611740565b8251909150811015610e50578151604051630bce4e8560e01b8152610470918391600401918252602082015260400190565b50505050505050505050565b6000546001600160a01b031633146107385760405163118cdaa760e01b8152336004820152602401610470565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000468203610efe576040516357516f6960e01b815260048101839052602401610470565b5060008181526002602052604081205490819003610f3257604051639a45110f60e01b815260048101839052602401610470565b919050565b6000601f19601f830116601f19601f850116610f5590610162612050565b610ca79190612050565b606081604051602001610f729190612211565b6040516020818303038152906040529050919050565b60608282604051602001610f9d929190612291565b604051602081830303815290604052905092915050565b6040805160608101825260008082526020820181905291810191909152610fda8a610ed9565b506000899003610ffd5760405163059f20d360e11b815260040160405180910390fd5b61103c85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fc7686ec90611090908e908c908c90600401611fab565b602060405180830381865afa1580156110ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d19190611fce565b9050803410156110fd57604051639557ee4960e01b815234600482015260248101829052604401610470565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663aa2f06ae6040518163ffffffff1660e01b81526004016040805180830381865afa15801561115a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117e9190612063565b8360200184604001826001600160401b03166001600160401b03168152508281525050506000611235338d8d866020015187604001518c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061184092505050565b9050611240816108c3565b805190602001208360000181815250506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166367c769af85856040015188600001518f8f6040518663ffffffff1660e01b81526004016112ae94939291906122c1565b604080518083038185885af11580156112cb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f09190612063565b9150915084602001518214801561131c575084604001516001600160401b0316816001600160401b0316145b611328576113286122e1565b5050348281039083146113ae57600154604080840151865191516001620989c160e11b031981526001600160a01b039093169263ffecec7e92859261137b92909190600401918252602082015260400190565b6000604051808303818588803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b50505050505b6001600160a01b038b1615611512576001600160a01b038b1663e4e065228e6113d78a89610f37565b87516040516001600160e01b031960e086901b1681526114029392919087908f908f906004016122f7565b600060405180830381600087803b15801561141c57600080fd5b505af1158015611430573d6000803e3d6000fd5b5050505060008b6001600160a01b03166362014bad6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611474573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611498919061232f565b6001546040858101518851915163033b5b8360e11b8152600481019190915260248101919091526001600160a01b038084166044830152929350911690630676b70690606401600060405180830381600087803b1580156114f857600080fd5b505af115801561150c573d6000803e3d6000fd5b50505050505b8160a001516001600160401b0316826080015185600001517f1b22d6c0b67f6f17a9004833bfb5afbaea4602457bd57e1d128cb997fb30161b85604001518660200151876060015189888a60c001518b60e00151604051611579979695949392919061234c565b60405180910390a45050509998505050505050505050565b600060028210156115b95782826040516332ce7cfd60e11b815260040161047092919061238f565b50503560f01c90565b36600060028310156115eb5783836040516332ce7cfd60e11b815260040161047092919061238f565b6115f883600281876123a3565b915091505b9250929050565b61160c6118a7565b610ca782840184611c4f565b600060028251101561163f57816040516332ce7cfd60e11b81526004016104709190611d73565b506020015160f01c90565b606060028251101561167157816040516332ce7cfd60e11b81526004016104709190611d73565b815160011901806001600160401b0381111561168f5761168f611b43565b6040519080825280601f01601f1916602001820160405280156116b9576020820181803683370190505b50915060008160208401836022870160045afa9050806116ec5760405163080f227d60e11b815260040160405180910390fd5b5050919050565b6040805180820190915260008082526020820152600061171283611618565b9050600161ffff82161015610c8b5760405163aac8bd2360e01b815261ffff82166004820152602401610470565b6000805b86518110156118365760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166367b1f42e898481518110611790576117906123cd565b60200260200101518989896040518563ffffffff1660e01b81526004016117ba94939291906123e3565b602060405180830381865afa1580156117d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fb9190611fce565b905080158015906118145750426118128583612050565b105b156118255761182283612465565b92505b5061182f81612465565b9050611744565b5095945050505050565b6118486118a7565b60405180610100016040528046815260200161186a8a6001600160a01b031690565b8152602001888152602001878152602001868152602001856001600160401b03168152602001848152602001838152509050979650505050505050565b604051806101000160405280600081526020016000801916815260200160008152602001600080191681526020016000815260200160006001600160401b0316815260200160608152602001606081525090565b60006020828403121561190d57600080fd5b5035919050565b60008083601f84011261192657600080fd5b5081356001600160401b0381111561193d57600080fd5b6020830191508360208285010111156115fd57600080fd5b60008083601f84011261196757600080fd5b5081356001600160401b0381111561197e57600080fd5b6020830191508360208260051b85010111156115fd57600080fd5b600080600080604085870312156119af57600080fd5b84356001600160401b03808211156119c657600080fd5b6119d288838901611914565b909650945060208701359150808211156119eb57600080fd5b506119f887828801611955565b95989497509550505050565b6001600160a01b0381168114610b4957600080fd5b600060208284031215611a2b57600080fd5b8135610ca781611a04565b600080600080600060608688031215611a4e57600080fd5b8535945060208601356001600160401b0380821115611a6c57600080fd5b611a7889838a01611914565b90965094506040880135915080821115611a9157600080fd5b50611a9e88828901611955565b969995985093965092949392505050565b600080600080600080600060a0888a031215611aca57600080fd5b873596506020880135611adc81611a04565b955060408801356001600160401b0380821115611af857600080fd5b611b048b838c01611955565b909750955060608a0135915080821115611b1d57600080fd5b50611b2a8a828b01611914565b989b979a50959894979596608090950135949350505050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b0381118282101715611b7c57611b7c611b43565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611baa57611baa611b43565b604052919050565b6001600160401b0381168114610b4957600080fd5b8035610f3281611bb2565b60006001600160401b03821115611beb57611beb611b43565b50601f01601f191660200190565b600082601f830112611c0a57600080fd5b8135611c1d611c1882611bd2565b611b82565b818152846020838601011115611c3257600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215611c6157600080fd5b81356001600160401b0380821115611c7857600080fd5b908301906101008286031215611c8d57600080fd5b611c95611b59565b8235815260208301356020820152604083013560408201526060830135606082015260808301356080820152611ccd60a08401611bc7565b60a082015260c083013582811115611ce457600080fd5b611cf087828601611bf9565b60c08301525060e083013582811115611d0857600080fd5b611d1487828601611bf9565b60e08301525095945050505050565b60005b83811015611d3e578181015183820152602001611d26565b50506000910152565b60008151808452611d5f816020860160208601611d23565b601f01601f19169290920160200192915050565b602081526000610ca76020830184611d47565b600080600080600080600080600060c08a8c031215611da457600080fd5b8935985060208a0135611db681611a04565b975060408a0135611dc681611a04565b965060608a01356001600160401b0380821115611de257600080fd5b611dee8d838e01611955565b909850965060808c0135915080821115611e0757600080fd5b611e138d838e01611914565b909650945060a08c0135915080821115611e2c57600080fd5b50611e398c828d01611914565b915080935050809150509295985092959850929598565b600080600080600080600080600060c08a8c031215611e6e57600080fd5b8935985060208a0135975060408a0135611dc681611a04565b600060208284031215611e9957600080fd5b81356001600160401b03811115611eaf57600080fd5b610c3684828501611bf9565b60008060408385031215611ece57600080fd5b50508035926020909101359150565b60008060208385031215611ef057600080fd5b82356001600160401b03811115611f0657600080fd5b611f1285828601611914565b90969095509350505050565b8183823760009101908152919050565b8581528460208201528360408201526001600160401b038316606082015260a0608082015260006108b860a0830184611d47565b8183526000602080850194508260005b85811015611fa0578135611f8581611a04565b6001600160a01b031687529582019590820190600101611f72565b509495945050505050565b838152604060208201526000611fc5604083018486611f62565b95945050505050565b600060208284031215611fe057600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201526000612030606083018486611fe7565b9695505050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156108d8576108d861203a565b6000806040838503121561207657600080fd5b82519150602083015161208881611bb2565b809150509250929050565b6000604082840312156120a557600080fd5b604051604081018181106001600160401b03821117156120c7576120c7611b43565b604052825181526020928301519281019290925250919050565b6000604082840312156120f357600080fd5b610ca78383612093565b6000806040838503121561211057600080fd5b82516001600160401b038082111561212757600080fd5b818501915085601f83011261213b57600080fd5b8151602061214b611c1883611bd2565b828152888284870101111561215f57600080fd5b61216e83838301848801611d23565b8782015190965093508284111561218457600080fd5b838701935087601f85011261219857600080fd5b83519150828211156121ac576121ac611b43565b8160051b92506121bd818401611b82565b82815292840181019281810190898511156121d757600080fd5b948201945b8486101561220157855193506121f184611a04565b83825294820194908201906121dc565b8096505050505050509250929050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a08201526001600160401b0360a08301511660c0820152600060c08301516101008060e0850152612275610120850183611d47565b915060e0850151601f1985840301828601526120308382611d47565b61ffff60f01b8360f01b168152600082516122b3816002850160208701611d23565b919091016002019392505050565b848152836020820152606060408201526000612030606083018486611f62565b634e487b7160e01b600052600160045260246000fd5b86815285602082015284604082015283606082015260a06080820152600061232360a083018486611fe7565b98975050505050505050565b60006020828403121561234157600080fd5b8151610ca781611a04565b87815286602082015285604082015284606082015283608082015260e060a0820152600061237d60e0830185611d47565b82810360c0840152610aab8185611d47565b602081526000610c36602083018486611fe7565b600080858511156123b357600080fd5b838611156123c057600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b60018060a01b038516815283516020820152602084015160408201526001600160401b03604085015116606082015260608401516080820152608084015160a082015260e060c08201528160e0820152600061010060018060fb1b0384111561244b57600080fd5b8360051b8086838601379290920190910195945050505050565b6000600182016124775761247761203a565b506001019056fea26469706673582212204b444d61c3a8c6d3b80f563e0c706f3505d59bc22df9f17a67e39b2c0967fb7464736f6c63430008140033000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4

Deployed Bytecode

0x60806040526004361061011f5760003560e01c80638da5cb5b116100a0578063e4c6124711610064578063e4c6124714610385578063f1a61fac146103b9578063f2fde38b146103ef578063f34234c81461040f578063f92a79ff1461042f57600080fd5b80638da5cb5b146102bc57806390e81077146102da57806398939d2814610317578063aa102ec41461032a578063d5e788a01461034a57600080fd5b80637341eaf9116100e75780637341eaf9146101db5780637813cd52146101fb5780637a1277db146102235780637c80a90f14610251578063827f940d1461027e57600080fd5b806302172a35146101245780631450c281146101615780633dc68b871461019157806353b67d74146101b3578063715018a6146101c6575b600080fd5b34801561013057600080fd5b5061014461013f3660046118fb565b61044f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561016d57600080fd5b5061018161017c366004611999565b6104bc565b6040519015158152602001610158565b34801561019d57600080fd5b506101b16101ac366004611a19565b61050e565b005b6101b16101c1366004611a36565b61056a565b3480156101d257600080fd5b506101b1610726565b3480156101e757600080fd5b50600154610144906001600160a01b031681565b34801561020757600080fd5b50610210600181565b60405161ffff9091168152602001610158565b34801561022f57600080fd5b5061024361023e366004611aaf565b61073a565b604051908152602001610158565b34801561025d57600080fd5b5061027161026c366004611c4f565b6108c3565b6040516101589190611d73565b61029161028c366004611d86565b6108de565b604080518251815260208084015190820152918101516001600160401b031690820152606001610158565b3480156102c857600080fd5b506000546001600160a01b0316610144565b3480156102e657600080fd5b506102fa6102f53660046118fb565b610925565b604080519283526001600160401b03909116602083015201610158565b610291610325366004611e50565b610a7d565b34801561033657600080fd5b506102436103453660046118fb565b610ab9565b34801561035657600080fd5b5061036a610365366004611e87565b610af1565b60408051825181526020928301519281019290925201610158565b34801561039157600080fd5b506101447f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b81565b3480156103c557600080fd5b506101446103d43660046118fb565b6000908152600360205260409020546001600160a01b031690565b3480156103fb57600080fd5b506101b161040a366004611a19565b610b0e565b34801561041b57600080fd5b506101b161042a366004611ebb565b610b4c565b34801561043b57600080fd5b5061014461044a366004611edd565b610ba3565b6000468203610479576040516357516f6960e01b8152600481018390526024015b60405180910390fd5b50600081815260026020526040902054806001600160a01b03811681146104b657604051630a55a4eb60e01b815260048101829052602401610470565b50919050565b6000806104c98686610be3565b90506104d88160c00151610c3e565b50600086866040516104eb929190611f1e565b6040518091039020905061050182828787610cae565b5060019695505050505050565b610516610e5c565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527fec02f15d78cdfc4beeba45f31cfad25089004e5e3d72727168dd96a77d1f2f829060200160405180910390a150565b60006105768585610be3565b90506000858560405161058a929190611f1e565b604051809103902090506105a082828686610cae565b600081815260036020526040812080546001600160a01b0319163317905560c08301516105cc90610c3e565b905080602001513414610601576020810151604051632b36102560e01b81523460048201526024810191909152604401610470565b805188101561060f57805197505b875a1161062f576040516374dc18ab60e11b815260040160405180910390fd5b60608301516001600160a01b03166368a6984789348660000151876020015188608001518960a001518a60e001516040518863ffffffff1660e01b815260040161067d959493929190611f2e565b6000604051808303818589803b15801561069657600080fd5b5088f11580156106aa573d6000803e3d6000fd5b5050505050508260a001516001600160401b03168360800151837f9c887f38b8f2330ee9894137eb60cf6ab904c5d2063ddc0baa7a77bfd1880e8c866000015187602001518860600151604051610714939291909283526020830191909152604082015260600190565b60405180910390a45050505050505050565b61072e610e5c565b6107386000610e89565b565b600061074588610ed9565b5061078584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526001600160a01b037f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b169063fc7686ec906107d6908b908a908a90600401611fab565b602060405180830381865afa1580156107f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108179190611fce565b90506001600160a01b038716156108b85760006108348484610f37565b60405163188e7cfd60e31b81529091506001600160a01b0389169063c473e7e890610869908c9085908a908a90600401612010565b602060405180830381865afa158015610886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190611fce565b6108b49083612050565b9150505b979650505050505050565b60606108d860016108d384610f5f565b610f88565b92915050565b60408051606081018252600080825260208201819052918101919091526001600160a01b0389166109168b828b8b8b8b8b8b8b610fb4565b9b9a5050505050505050505050565b60008181526003602052604081205481906001600160a01b0316806109605760405163e99eb48d60e01b815260048101859052602401610470565b600084826040516020016109879291909182526001600160a01b0316602082015260400190565b60408051808303601f19018152908290528051602082012063156c638360e11b8352600483015291507f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b031690632ad8c7069060240160408051808303816000875af1158015610a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a269190612063565b6040516001600160a01b038516815291955093506001600160401b03841690859087907f810ecf3e461a7f5c46c0bbbca8680cf65de59e78e521d58d569e03969d08648c9060200160405180910390a45050915091565b6040805160608101825260008082526020820181905291810191909152610aab8a8a8a8a8a8a8a8a8a610fb4565b9a9950505050505050505050565b6000468203610ade576040516357516f6960e01b815260048101839052602401610470565b5060009081526002602052604090205490565b60408051808201909152600080825260208201526108d882610c3e565b610b16610e5c565b6001600160a01b038116610b4057604051631e4fbdf760e01b815260006004820152602401610470565b610b4981610e89565b50565b610b54610e5c565b60008281526002602090815260409182902083905581518481529081018390527fb6b5dc04cc1c35fc7a8c8342e378dccc610c6589ef3bcfcd6eaf0304913f889a910160405180910390a15050565b6000600360008484604051610bb9929190611f1e565b60408051918290039091208252602082019290925201600020546001600160a01b03169392505050565b610beb6118a7565b6000610bf78484611591565b905061ffff8116600114610c2457604051630fda659b60e01b815261ffff82166004820152602401610470565b610c36610c3185856115c2565b611604565b949350505050565b60408051808201909152600080825260208201526000610c5d83611618565b9050600161ffff82161015610c8b5760405163b94fa72560e01b815261ffff82166004820152602401610470565b610c948361164a565b806020019051810190610ca791906120e1565b9392505050565b6000610cbd8560000151610ed9565b905046856040015114610ceb578460400151604051634b9929c160e11b815260040161047091815260200190565b6000848152600360205260409020546001600160a01b031615610d245760405163d80aeb9160e01b815260048101859052602401610470565b60006040518060a0016040528087600001518152602001876080015181526020018760a001516001600160401b03168152602001838152602001868152509050600080610d72886060015190565b6001600160a01b031663287bc0576040518163ffffffff1660e01b8152600401600060405180830381865afa158015610daf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd791908101906120fd565b915091506000610de6836116f3565b8051909150600003610e0b5760405163a09e214360e01b815260040160405180910390fd5b6000610e1e83868a8a8660200151611740565b8251909150811015610e50578151604051630bce4e8560e01b8152610470918391600401918252602082015260400190565b50505050505050505050565b6000546001600160a01b031633146107385760405163118cdaa760e01b8152336004820152602401610470565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000468203610efe576040516357516f6960e01b815260048101839052602401610470565b5060008181526002602052604081205490819003610f3257604051639a45110f60e01b815260048101839052602401610470565b919050565b6000601f19601f830116601f19601f850116610f5590610162612050565b610ca79190612050565b606081604051602001610f729190612211565b6040516020818303038152906040529050919050565b60608282604051602001610f9d929190612291565b604051602081830303815290604052905092915050565b6040805160608101825260008082526020820181905291810191909152610fda8a610ed9565b506000899003610ffd5760405163059f20d360e11b815260040160405180910390fd5b61103c85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526000906001600160a01b037f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b169063fc7686ec90611090908e908c908c90600401611fab565b602060405180830381865afa1580156110ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d19190611fce565b9050803410156110fd57604051639557ee4960e01b815234600482015260248101829052604401610470565b7f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b031663aa2f06ae6040518163ffffffff1660e01b81526004016040805180830381865afa15801561115a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117e9190612063565b8360200184604001826001600160401b03166001600160401b03168152508281525050506000611235338d8d866020015187604001518c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061184092505050565b9050611240816108c3565b805190602001208360000181815250506000807f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b03166367c769af85856040015188600001518f8f6040518663ffffffff1660e01b81526004016112ae94939291906122c1565b604080518083038185885af11580156112cb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f09190612063565b9150915084602001518214801561131c575084604001516001600160401b0316816001600160401b0316145b611328576113286122e1565b5050348281039083146113ae57600154604080840151865191516001620989c160e11b031981526001600160a01b039093169263ffecec7e92859261137b92909190600401918252602082015260400190565b6000604051808303818588803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b50505050505b6001600160a01b038b1615611512576001600160a01b038b1663e4e065228e6113d78a89610f37565b87516040516001600160e01b031960e086901b1681526114029392919087908f908f906004016122f7565b600060405180830381600087803b15801561141c57600080fd5b505af1158015611430573d6000803e3d6000fd5b5050505060008b6001600160a01b03166362014bad6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611474573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611498919061232f565b6001546040858101518851915163033b5b8360e11b8152600481019190915260248101919091526001600160a01b038084166044830152929350911690630676b70690606401600060405180830381600087803b1580156114f857600080fd5b505af115801561150c573d6000803e3d6000fd5b50505050505b8160a001516001600160401b0316826080015185600001517f1b22d6c0b67f6f17a9004833bfb5afbaea4602457bd57e1d128cb997fb30161b85604001518660200151876060015189888a60c001518b60e00151604051611579979695949392919061234c565b60405180910390a45050509998505050505050505050565b600060028210156115b95782826040516332ce7cfd60e11b815260040161047092919061238f565b50503560f01c90565b36600060028310156115eb5783836040516332ce7cfd60e11b815260040161047092919061238f565b6115f883600281876123a3565b915091505b9250929050565b61160c6118a7565b610ca782840184611c4f565b600060028251101561163f57816040516332ce7cfd60e11b81526004016104709190611d73565b506020015160f01c90565b606060028251101561167157816040516332ce7cfd60e11b81526004016104709190611d73565b815160011901806001600160401b0381111561168f5761168f611b43565b6040519080825280601f01601f1916602001820160405280156116b9576020820181803683370190505b50915060008160208401836022870160045afa9050806116ec5760405163080f227d60e11b815260040160405180910390fd5b5050919050565b6040805180820190915260008082526020820152600061171283611618565b9050600161ffff82161015610c8b5760405163aac8bd2360e01b815261ffff82166004820152602401610470565b6000805b86518110156118365760007f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b03166367b1f42e898481518110611790576117906123cd565b60200260200101518989896040518563ffffffff1660e01b81526004016117ba94939291906123e3565b602060405180830381865afa1580156117d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fb9190611fce565b905080158015906118145750426118128583612050565b105b156118255761182283612465565b92505b5061182f81612465565b9050611744565b5095945050505050565b6118486118a7565b60405180610100016040528046815260200161186a8a6001600160a01b031690565b8152602001888152602001878152602001868152602001856001600160401b03168152602001848152602001838152509050979650505050505050565b604051806101000160405280600081526020016000801916815260200160008152602001600080191681526020016000815260200160006001600160401b0316815260200160608152602001606081525090565b60006020828403121561190d57600080fd5b5035919050565b60008083601f84011261192657600080fd5b5081356001600160401b0381111561193d57600080fd5b6020830191508360208285010111156115fd57600080fd5b60008083601f84011261196757600080fd5b5081356001600160401b0381111561197e57600080fd5b6020830191508360208260051b85010111156115fd57600080fd5b600080600080604085870312156119af57600080fd5b84356001600160401b03808211156119c657600080fd5b6119d288838901611914565b909650945060208701359150808211156119eb57600080fd5b506119f887828801611955565b95989497509550505050565b6001600160a01b0381168114610b4957600080fd5b600060208284031215611a2b57600080fd5b8135610ca781611a04565b600080600080600060608688031215611a4e57600080fd5b8535945060208601356001600160401b0380821115611a6c57600080fd5b611a7889838a01611914565b90965094506040880135915080821115611a9157600080fd5b50611a9e88828901611955565b969995985093965092949392505050565b600080600080600080600060a0888a031215611aca57600080fd5b873596506020880135611adc81611a04565b955060408801356001600160401b0380821115611af857600080fd5b611b048b838c01611955565b909750955060608a0135915080821115611b1d57600080fd5b50611b2a8a828b01611914565b989b979a50959894979596608090950135949350505050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b0381118282101715611b7c57611b7c611b43565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611baa57611baa611b43565b604052919050565b6001600160401b0381168114610b4957600080fd5b8035610f3281611bb2565b60006001600160401b03821115611beb57611beb611b43565b50601f01601f191660200190565b600082601f830112611c0a57600080fd5b8135611c1d611c1882611bd2565b611b82565b818152846020838601011115611c3257600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215611c6157600080fd5b81356001600160401b0380821115611c7857600080fd5b908301906101008286031215611c8d57600080fd5b611c95611b59565b8235815260208301356020820152604083013560408201526060830135606082015260808301356080820152611ccd60a08401611bc7565b60a082015260c083013582811115611ce457600080fd5b611cf087828601611bf9565b60c08301525060e083013582811115611d0857600080fd5b611d1487828601611bf9565b60e08301525095945050505050565b60005b83811015611d3e578181015183820152602001611d26565b50506000910152565b60008151808452611d5f816020860160208601611d23565b601f01601f19169290920160200192915050565b602081526000610ca76020830184611d47565b600080600080600080600080600060c08a8c031215611da457600080fd5b8935985060208a0135611db681611a04565b975060408a0135611dc681611a04565b965060608a01356001600160401b0380821115611de257600080fd5b611dee8d838e01611955565b909850965060808c0135915080821115611e0757600080fd5b611e138d838e01611914565b909650945060a08c0135915080821115611e2c57600080fd5b50611e398c828d01611914565b915080935050809150509295985092959850929598565b600080600080600080600080600060c08a8c031215611e6e57600080fd5b8935985060208a0135975060408a0135611dc681611a04565b600060208284031215611e9957600080fd5b81356001600160401b03811115611eaf57600080fd5b610c3684828501611bf9565b60008060408385031215611ece57600080fd5b50508035926020909101359150565b60008060208385031215611ef057600080fd5b82356001600160401b03811115611f0657600080fd5b611f1285828601611914565b90969095509350505050565b8183823760009101908152919050565b8581528460208201528360408201526001600160401b038316606082015260a0608082015260006108b860a0830184611d47565b8183526000602080850194508260005b85811015611fa0578135611f8581611a04565b6001600160a01b031687529582019590820190600101611f72565b509495945050505050565b838152604060208201526000611fc5604083018486611f62565b95945050505050565b600060208284031215611fe057600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201526000612030606083018486611fe7565b9695505050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156108d8576108d861203a565b6000806040838503121561207657600080fd5b82519150602083015161208881611bb2565b809150509250929050565b6000604082840312156120a557600080fd5b604051604081018181106001600160401b03821117156120c7576120c7611b43565b604052825181526020928301519281019290925250919050565b6000604082840312156120f357600080fd5b610ca78383612093565b6000806040838503121561211057600080fd5b82516001600160401b038082111561212757600080fd5b818501915085601f83011261213b57600080fd5b8151602061214b611c1883611bd2565b828152888284870101111561215f57600080fd5b61216e83838301848801611d23565b8782015190965093508284111561218457600080fd5b838701935087601f85011261219857600080fd5b83519150828211156121ac576121ac611b43565b8160051b92506121bd818401611b82565b82815292840181019281810190898511156121d757600080fd5b948201945b8486101561220157855193506121f184611a04565b83825294820194908201906121dc565b8096505050505050509250929050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a08201526001600160401b0360a08301511660c0820152600060c08301516101008060e0850152612275610120850183611d47565b915060e0850151601f1985840301828601526120308382611d47565b61ffff60f01b8360f01b168152600082516122b3816002850160208701611d23565b919091016002019392505050565b848152836020820152606060408201526000612030606083018486611f62565b634e487b7160e01b600052600160045260246000fd5b86815285602082015284604082015283606082015260a06080820152600061232360a083018486611fe7565b98975050505050505050565b60006020828403121561234157600080fd5b8151610ca781611a04565b87815286602082015285604082015284606082015283608082015260e060a0820152600061237d60e0830185611d47565b82810360c0840152610aab8185611d47565b602081526000610c36602083018486611fe7565b600080858511156123b357600080fd5b838611156123c057600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b60018060a01b038516815283516020820152602084015160408201526001600160401b03604085015116606082015260608401516080820152608084015160a082015260e060c08201528160e0820152600061010060018060fb1b0384111561244b57600080fd5b8360051b8086838601379290920190910195945050505050565b6000600182016124775761247761203a565b506001019056fea26469706673582212204b444d61c3a8c6d3b80f563e0c706f3505d59bc22df9f17a67e39b2c0967fb7464736f6c63430008140033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4

-----Decoded View---------------
Arg [0] : interchainDB (address): 0xAcAaaa98b9E23725046edA88D371B4864d90496b
Arg [1] : owner_ (address): 0xE7353BEdc72D29f99D6cA5CDE69F807cCE5d57e4

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b
Arg [1] : 000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4


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  ]
[ 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.