Sepolia Testnet

Contract

0x588c7Bda9366EEf83EdF67049a1C45f737aFFe0F

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Interchain Execu...64594272024-08-08 7:56:0034 days ago1723103760IN
0x588c7Bda...737aFFe0F
0 ETH0.0062041523.69788889
Interchain Execu...64593702024-08-08 7:43:3634 days ago1723103016IN
0x588c7Bda...737aFFe0F
0 ETH0.0050317918.23886874
Interchain Execu...64593652024-08-08 7:42:3634 days ago1723102956IN
0x588c7Bda...737aFFe0F
0 ETH0.0057810520.95381706
Interchain Execu...64593152024-08-08 7:30:4834 days ago1723102248IN
0x588c7Bda...737aFFe0F
0 ETH0.0057573721.99134451
Interchain Execu...64593112024-08-08 7:30:0034 days ago1723102200IN
0x588c7Bda...737aFFe0F
0 ETH0.0053056620.26593168
Interchain Execu...64592372024-08-08 7:10:2434 days ago1723101024IN
0x588c7Bda...737aFFe0F
0 ETH0.001698686.24756245
Interchain Execu...64592142024-08-08 7:05:4834 days ago1723100748IN
0x588c7Bda...737aFFe0F
0 ETH0.002165027.96306119
Interchain Execu...64592142024-08-08 7:05:4834 days ago1723100748IN
0x588c7Bda...737aFFe0F
0 ETH0.002086347.96916626
Interchain Execu...64592142024-08-08 7:05:4834 days ago1723100748IN
0x588c7Bda...737aFFe0F
0 ETH0.002086347.96916626
Interchain Execu...64591572024-08-08 6:53:2434 days ago1723100004IN
0x588c7Bda...737aFFe0F
0 ETH0.001813146.66884355
Interchain Execu...64591232024-08-08 6:46:0034 days ago1723099560IN
0x588c7Bda...737aFFe0F
0 ETH0.000962113.48738934
Interchain Execu...64590882024-08-08 6:38:4834 days ago1723099128IN
0x588c7Bda...737aFFe0F
0 ETH0.00157556.01791812
Interchain Execu...64590882024-08-08 6:38:4834 days ago1723099128IN
0x588c7Bda...737aFFe0F
0 ETH0.00157556.01791812
Interchain Execu...64590642024-08-08 6:32:4834 days ago1723098768IN
0x588c7Bda...737aFFe0F
0 ETH0.002061747.47292719
Interchain Execu...64590332024-08-08 6:26:0034 days ago1723098360IN
0x588c7Bda...737aFFe0F
0 ETH0.001613575.93454661
Interchain Execu...64589782024-08-08 6:13:2434 days ago1723097604IN
0x588c7Bda...737aFFe0F
0 ETH0.001862517.1142214
Interchain Execu...64589782024-08-08 6:13:2434 days ago1723097604IN
0x588c7Bda...737aFFe0F
0 ETH0.001862517.1142214
Interchain Execu...64589532024-08-08 6:07:1234 days ago1723097232IN
0x588c7Bda...737aFFe0F
0 ETH0.001926246.98211137
Interchain Execu...64589242024-08-08 6:00:4834 days ago1723096848IN
0x588c7Bda...737aFFe0F
0 ETH0.001117334.10943576
Interchain Execu...64588932024-08-08 5:54:0034 days ago1723096440IN
0x588c7Bda...737aFFe0F
0 ETH0.000431921.64981823
Interchain Execu...64588932024-08-08 5:54:0034 days ago1723096440IN
0x588c7Bda...737aFFe0F
0 ETH0.000431921.64981823
Interchain Execu...64588442024-08-08 5:42:4834 days ago1723095768IN
0x588c7Bda...737aFFe0F
0 ETH0.000880933.1931358
Interchain Execu...64588412024-08-08 5:42:0034 days ago1723095720IN
0x588c7Bda...737aFFe0F
0 ETH0.000832493.06194556
Interchain Execu...64587842024-08-08 5:29:2434 days ago1723094964IN
0x588c7Bda...737aFFe0F
0 ETH0.000913483.48921144
Interchain Execu...64587842024-08-08 5:29:2434 days ago1723094964IN
0x588c7Bda...737aFFe0F
0 ETH0.000913483.48921144
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
65891192024-08-28 18:42:0014 days ago1724870520
0x588c7Bda...737aFFe0F
0 ETH
65891192024-08-28 18:42:0014 days ago1724870520
0x588c7Bda...737aFFe0F
0 ETH
65891192024-08-28 18:42:0014 days ago1724870520
0x588c7Bda...737aFFe0F
0 ETH
64594272024-08-08 7:56:0034 days ago1723103760
0x588c7Bda...737aFFe0F
0 ETH
64594272024-08-08 7:56:0034 days ago1723103760
0x588c7Bda...737aFFe0F
0 ETH
64594272024-08-08 7:56:0034 days ago1723103760
0x588c7Bda...737aFFe0F
0 ETH
64593702024-08-08 7:43:3634 days ago1723103016
0x588c7Bda...737aFFe0F
0 ETH
64593702024-08-08 7:43:3634 days ago1723103016
0x588c7Bda...737aFFe0F
0 ETH
64593702024-08-08 7:43:3634 days ago1723103016
0x588c7Bda...737aFFe0F
0 ETH
64593652024-08-08 7:42:3634 days ago1723102956
0x588c7Bda...737aFFe0F
0 ETH
64593652024-08-08 7:42:3634 days ago1723102956
0x588c7Bda...737aFFe0F
0 ETH
64593652024-08-08 7:42:3634 days ago1723102956
0x588c7Bda...737aFFe0F
0 ETH
64593152024-08-08 7:30:4834 days ago1723102248
0x588c7Bda...737aFFe0F
0 ETH
64593152024-08-08 7:30:4834 days ago1723102248
0x588c7Bda...737aFFe0F
0 ETH
64593152024-08-08 7:30:4834 days ago1723102248
0x588c7Bda...737aFFe0F
0 ETH
64593112024-08-08 7:30:0034 days ago1723102200
0x588c7Bda...737aFFe0F
0 ETH
64593112024-08-08 7:30:0034 days ago1723102200
0x588c7Bda...737aFFe0F
0 ETH
64593112024-08-08 7:30:0034 days ago1723102200
0x588c7Bda...737aFFe0F
0 ETH
64592372024-08-08 7:10:2434 days ago1723101024
0x588c7Bda...737aFFe0F
0 ETH
64592372024-08-08 7:10:2434 days ago1723101024
0x588c7Bda...737aFFe0F
0 ETH
64592372024-08-08 7:10:2434 days ago1723101024
0x588c7Bda...737aFFe0F
0 ETH
64592142024-08-08 7:05:4834 days ago1723100748
0x588c7Bda...737aFFe0F
0 ETH
64592142024-08-08 7:05:4834 days ago1723100748
0x588c7Bda...737aFFe0F
0 ETH
64592142024-08-08 7:05:4834 days ago1723100748
0x588c7Bda...737aFFe0F
0 ETH
64592142024-08-08 7:05:4834 days ago1723100748
0x588c7Bda...737aFFe0F
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
InterchainClientV1

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 16 : InterchainClientV1.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {InterchainClientV1Events} from "./events/InterchainClientV1Events.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, APP_CONFIG_GUARD_DISABLED, APP_CONFIG_GUARD_DEFAULT} from "./libs/AppConfig.sol";
import {InterchainEntry, InterchainEntryLib, ENTRY_UNVERIFIED, ENTRY_CONFLICT} 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";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.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 TypeCasts for address;
    using TypeCasts for bytes32;
    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 Guard module used to verify the validity of entries.
    /// Note: entries marked as invalid by the Guard could not be used for message execution,
    /// if the app opts in to use the Guard.
    address public defaultGuard;

    /// @notice Address of the default module to use to verify the validity of entries.
    /// Note: this module will be used for the apps that define an empty module list in their config.
    address public defaultModule;

    /// @dev Address of the InterchainClient contract on the remote chain
    mapping(uint64 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;
    }

    /// @notice Allows the contract owner to set the address of the Guard module.
    /// Note: entries marked as invalid by the Guard could not be used for message execution,
    /// if the app opts in to use the Guard.
    /// @param guard            The address of the Guard module.
    function setDefaultGuard(address guard) external onlyOwner {
        if (guard == address(0)) {
            revert InterchainClientV1__GuardZeroAddress();
        }
        defaultGuard = guard;
        emit DefaultGuardSet(guard);
    }

    /// @notice Allows the contract owner to set the address of the default module.
    /// Note: this module will be used for the apps that define an empty module list in their config.
    /// @param module           The address of the default module.
    function setDefaultModule(address module) external onlyOwner {
        if (module == address(0)) {
            revert InterchainClientV1__ModuleZeroAddress();
        }
        defaultModule = module;
        emit DefaultModuleSet(module);
    }

    /// @notice Sets the linked client for a specific chain ID.
    /// Note: only Interchain Entries written by the linked client could be used for message execution.
    /// @param chainId          The chain ID for which the client is being set.
    /// @param client           The address of the client being linked.
    function setLinkedClient(uint64 chainId, bytes32 client) external onlyOwner {
        _linkedClient[chainId] = client;
        emit LinkedClientSet(chainId, client);
    }

    /// @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.
    /// @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 to be sent.
    /// @return desc                The descriptor of the sent transaction:
    /// - transactionId: the ID of the transaction that was sent.
    /// - dbNonce: the database nonce of the entry containing the transaction.
    function interchainSend(
        uint64 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);
    }

    /// @notice A thin wrapper around `interchainSend` that allows to specify the receiver address as an EVM address.
    function interchainSendEVM(
        uint64 dstChainId,
        address receiver,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        bytes calldata message
    )
        external
        payable
        returns (InterchainTxDescriptor memory desc)
    {
        bytes32 receiverBytes32 = receiver.addressToBytes32();
        return _interchainSend(dstChainId, receiverBytes32, srcExecutionService, srcModules, options, message);
    }

    /// @notice Executes a transaction that has been sent via the Interchain Communication Protocol.
    /// Note: The transaction must be proven to be included in one of the InterchainDB entries.
    /// Note: 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.
    function interchainExecute(uint256 gasLimit, bytes calldata transaction) external payable {
        InterchainTransaction memory icTx = _assertCorrectTransaction(transaction);
        bytes32 transactionId = keccak256(transaction);
        _assertExecutable(icTx, transactionId);
        _txExecutor[transactionId] = msg.sender;

        OptionsV1 memory decodedOptions = icTx.options.decodeOptionsV1();
        if (msg.value != decodedOptions.gasAirdrop) {
            revert InterchainClientV1__MsgValueMismatch(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.
        uint256 gasLeft = gasleft();
        if (gasLeft <= gasLimit) {
            revert InterchainClientV1__GasLeftBelowMin(gasLeft, gasLimit);
        }
        // Pass the full msg.value to the app: we have already checked that it matches the requested gas airdrop.
        IInterchainApp(icTx.dstReceiver.bytes32ToAddress()).appReceive{gas: gasLimit, value: msg.value}({
            srcChainId: icTx.srcChainId,
            sender: icTx.srcSender,
            dbNonce: icTx.dbNonce,
            message: icTx.message
        });
        emit InterchainTransactionReceived({
            transactionId: transactionId,
            dbNonce: icTx.dbNonce,
            srcChainId: icTx.srcChainId,
            srcSender: icTx.srcSender,
            dstReceiver: icTx.dstReceiver
        });
    }

    /// @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 entry containing the written proof for transaction.
    function writeExecutionProof(bytes32 transactionId) external returns (uint64 dbNonce) {
        address executor = _txExecutor[transactionId];
        if (executor == address(0)) {
            revert InterchainClientV1__TxNotExecuted(transactionId);
        }
        bytes memory proof = abi.encode(transactionId, executor);
        dbNonce = IInterchainDB(INTERCHAIN_DB).writeEntry(keccak256(proof));
        emit ExecutionProofWritten({transactionId: transactionId, dbNonce: dbNonce, executor: executor});
    }

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

    /// @notice Determines if a transaction meets the criteria to be executed based on:
    /// - If approved modules have verified the entry in the InterchainDB
    /// - If the threshold of approved modules have been met
    /// - If the optimistic window has passed for all modules
    /// - If the Guard module (if opted in) has not submitted an entry that conflicts with the approved modules
    /// @dev Will revert with a specific error message if the transaction is not executable.
    /// @param encodedTx        The encoded transaction to check for executable status.
    function isExecutable(bytes calldata encodedTx) external view returns (bool) {
        InterchainTransaction memory icTx = _assertCorrectTransaction(encodedTx);
        // Check that options could be decoded
        icTx.options.decodeOptionsV1();
        bytes32 transactionId = keccak256(encodedTx);
        _assertExecutable(icTx, transactionId);
        return true;
    }

    /// @notice Returns the readiness status of a transaction to be executed.
    /// @dev Some of the possible statuses have additional arguments that are returned:
    /// - Ready: the transaction is ready to be executed.
    /// - AlreadyExecuted: the transaction has already been executed.
    ///   - `firstArg` is the transaction ID.
    /// - EntryAwaitingResponses: not enough responses have been received for the transaction.
    ///   - `firstArg` is the number of responses received.
    ///   - `secondArg` is the number of responses required.
    /// - EntryConflict: one of the modules have submitted a conflicting entry.
    ///   - `firstArg` is the address of the module.
    ///   - This is either one of the modules that the app trusts, or the Guard module used by the app.
    /// - ReceiverNotICApp: the receiver is not an Interchain app.
    ///  - `firstArg` is the receiver address.
    /// - TxWrongDstChainId: the destination chain ID does not match the local chain ID.
    ///   - `firstArg` is the destination chain ID.
    /// - UndeterminedRevert: the transaction will revert for another reason.
    ///
    /// Note: the arguments are abi-encoded bytes32 values (as their types could be different).
    // solhint-disable-next-line code-complexity
    function getTxReadinessV1(InterchainTransaction memory icTx)
        external
        view
        returns (TxReadiness status, bytes32 firstArg, bytes32 secondArg)
    {
        bytes memory encodedTx = encodeTransaction(icTx);
        try this.isExecutable(encodedTx) returns (bool) {
            return (TxReadiness.Ready, 0, 0);
        } catch (bytes memory errorData) {
            bytes4 selector;
            (selector, firstArg, secondArg) = _decodeRevertData(errorData);
            if (selector == InterchainClientV1__TxAlreadyExecuted.selector) {
                status = TxReadiness.AlreadyExecuted;
            } else if (selector == InterchainClientV1__ResponsesAmountBelowMin.selector) {
                status = TxReadiness.EntryAwaitingResponses;
            } else if (selector == InterchainClientV1__EntryConflict.selector) {
                status = TxReadiness.EntryConflict;
            } else if (selector == InterchainClientV1__ReceiverNotICApp.selector) {
                status = TxReadiness.ReceiverNotICApp;
            } else if (selector == InterchainClientV1__DstChainIdNotLocal.selector) {
                status = TxReadiness.TxWrongDstChainId;
            } else {
                status = TxReadiness.UndeterminedRevert;
                firstArg = 0;
                secondArg = 0;
            }
        }
    }

    /// @notice Returns the address of the executor for a transaction that has been sent to the local chain.
    function getExecutor(bytes calldata encodedTx) external view returns (address) {
        return _txExecutor[keccak256(encodedTx)];
    }

    /// @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) {
        return _txExecutor[transactionId];
    }

    /// @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(
        uint64 dstChainId,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        uint256 messageLen
    )
        external
        view
        returns (uint256 fee)
    {
        _assertLinkedClient(dstChainId);
        if (srcExecutionService == address(0)) {
            revert InterchainClientV1__ExecutionServiceZeroAddress();
        }
        // 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 from ExecutionService
        uint256 payloadSize = InterchainTransactionLib.payloadSize(options.length, messageLen);
        fee += IExecutionService(srcExecutionService).getExecutionFee(dstChainId, payloadSize, options);
    }

    /// @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(uint64 chainId) external view returns (bytes32) {
        if (chainId == block.chainid) {
            revert InterchainClientV1__ChainIdNotRemote(chainId);
        }
        return _linkedClient[chainId];
    }

    /// @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(uint64 chainId) external view returns (address linkedClientEVM) {
        if (chainId == block.chainid) {
            revert InterchainClientV1__ChainIdNotRemote(chainId);
        }
        bytes32 linkedClient = _linkedClient[chainId];
        linkedClientEVM = linkedClient.bytes32ToAddress();
        // Check that the linked client address fits into the EVM address space
        if (linkedClientEVM.addressToBytes32() != linkedClient) {
            revert InterchainClientV1__LinkedClientNotEVM(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 Gets the V1 app config and trusted modules for the receiving app.
    function getAppReceivingConfigV1(address receiver)
        public
        view
        returns (AppConfigV1 memory config, address[] memory modules)
    {
        // First, check that receiver is a contract
        if (receiver.code.length == 0) {
            revert InterchainClientV1__ReceiverNotICApp(receiver);
        }
        // Then, use a low-level static call to get the config and modules
        (bool success, bytes memory returnData) =
            receiver.staticcall(abi.encodeCall(IInterchainApp.getReceivingConfig, ()));
        if (!success || returnData.length == 0) {
            revert InterchainClientV1__ReceiverNotICApp(receiver);
        }
        bytes memory encodedConfig;
        (encodedConfig, modules) = abi.decode(returnData, (bytes, address[]));
        config = encodedConfig.decodeAppConfigV1();
        // Fallback to the default module if the app has no modules
        if (modules.length == 0) {
            modules = new address[](1);
            modules[0] = defaultModule;
        }
        // Fallback to "all responses" if the app requires zero responses
        if (config.requiredResponses == 0) {
            config.requiredResponses = SafeCast.toUint8(modules.length);
        }
    }

    /// @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(
        uint64 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__ReceiverZeroAddress();
        }
        if (srcExecutionService == address(0)) {
            revert InterchainClientV1__ExecutionServiceZeroAddress();
        }
        // 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__FeeAmountBelowMin(msg.value, verificationFee);
        }
        desc.dbNonce = IInterchainDB(INTERCHAIN_DB).getDBNonce();
        InterchainTransaction memory icTx = InterchainTransactionLib.constructLocalTransaction({
            srcSender: msg.sender,
            dstReceiver: receiver,
            dstChainId: dstChainId,
            dbNonce: desc.dbNonce,
            options: options,
            message: message
        });
        desc.transactionId = keccak256(encodeTransaction(icTx));
        // Sanity check: nonce returned from DB should match the nonce used to construct the transaction
        {
            uint64 dbNonce = IInterchainDB(INTERCHAIN_DB).writeEntryRequestVerification{value: verificationFee}(
                icTx.dstChainId, desc.transactionId, srcModules
            );
            assert(dbNonce == desc.dbNonce);
        }
        uint256 executionFee;
        unchecked {
            executionFee = msg.value - verificationFee;
        }
        IExecutionService(srcExecutionService).requestTxExecution{value: executionFee}({
            dstChainId: icTx.dstChainId,
            txPayloadSize: InterchainTransactionLib.payloadSize(options.length, message.length),
            transactionId: desc.transactionId,
            options: options
        });
        emit InterchainTransactionSent({
            transactionId: desc.transactionId,
            dbNonce: desc.dbNonce,
            dstChainId: icTx.dstChainId,
            srcSender: icTx.srcSender,
            dstReceiver: icTx.dstReceiver,
            verificationFee: verificationFee,
            executionFee: executionFee,
            options: icTx.options,
            message: icTx.message
        });
    }

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

    /// @dev Asserts that the transaction is executable.
    function _assertExecutable(InterchainTransaction memory icTx, bytes32 transactionId) internal view {
        bytes32 linkedClient = _assertLinkedClient(icTx.srcChainId);
        if (_txExecutor[transactionId] != address(0)) {
            revert InterchainClientV1__TxAlreadyExecuted(transactionId);
        }
        // Construct expected entry based on interchain transaction data
        InterchainEntry memory entry = InterchainEntry({
            srcChainId: icTx.srcChainId,
            dbNonce: icTx.dbNonce,
            entryValue: InterchainEntryLib.getEntryValue({srcWriter: linkedClient, digest: transactionId})
        });
        address receiver = icTx.dstReceiver.bytes32ToAddress();
        (AppConfigV1 memory appConfig, address[] memory approvedModules) = getAppReceivingConfigV1(receiver);
        // Note: appConfig.requiredResponses is never zero at this point, see fallbacks in `getAppReceivingConfigV1`
        // Verify against the Guard if the app opts in to use it
        address guard = _getGuard(appConfig);
        _assertNoGuardConflict(guard, entry);
        // Optimistic period is not used if there's no Guard configured
        uint256 optimisticSeconds = guard == address(0) ? 0 : appConfig.optimisticSeconds;
        uint256 finalizedResponses = _getFinalizedResponsesCount(approvedModules, entry, optimisticSeconds);
        if (finalizedResponses < appConfig.requiredResponses) {
            revert InterchainClientV1__ResponsesAmountBelowMin(finalizedResponses, appConfig.requiredResponses);
        }
    }

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

    /// @dev Asserts that the Guard has not submitted a conflicting entry.
    function _assertNoGuardConflict(address guard, InterchainEntry memory entry) internal view {
        if (guard != address(0)) {
            uint256 confirmedAt = IInterchainDB(INTERCHAIN_DB).checkEntryVerification(guard, entry);
            if (confirmedAt == ENTRY_CONFLICT) {
                revert InterchainClientV1__EntryConflict(guard);
            }
        }
    }

    /// @dev Returns the Guard address to use for the given app config.
    function _getGuard(AppConfigV1 memory appConfig) internal view returns (address) {
        if (appConfig.guardFlag == APP_CONFIG_GUARD_DISABLED) {
            return address(0);
        }
        if (appConfig.guardFlag == APP_CONFIG_GUARD_DEFAULT) {
            return defaultGuard;
        }
        return appConfig.guard;
    }

    /// @dev Counts the number of finalized responses for the given entry.
    /// Note: Reverts if a conflicting entry has been verified by any of the approved modules.
    function _getFinalizedResponsesCount(
        address[] memory approvedModules,
        InterchainEntry memory entry,
        uint256 optimisticSeconds
    )
        internal
        view
        returns (uint256 finalizedResponses)
    {
        for (uint256 i = 0; i < approvedModules.length; ++i) {
            address module = approvedModules[i];
            uint256 confirmedAt = IInterchainDB(INTERCHAIN_DB).checkEntryVerification(module, entry);
            // No-op if the module has not verified anything with the same entry key
            if (confirmedAt == ENTRY_UNVERIFIED) {
                continue;
            }
            // Revert if the module has verified a conflicting entry with the same entry key
            if (confirmedAt == ENTRY_CONFLICT) {
                revert InterchainClientV1__EntryConflict(module);
            }
            // The module has verified this exact entry, check if optimistic period has passed
            if (confirmedAt + optimisticSeconds < block.timestamp) {
                unchecked {
                    ++finalizedResponses;
                }
            }
        }
    }

    /// @dev Asserts that the transaction version is correct and that the transaction is for the current chain.
    /// Note: returns the decoded transaction for chaining purposes.
    function _assertCorrectTransaction(bytes calldata versionedTx)
        internal
        view
        returns (InterchainTransaction memory icTx)
    {
        uint16 version = versionedTx.getVersion();
        if (version != CLIENT_VERSION) {
            revert InterchainClientV1__TxVersionMismatch(version, CLIENT_VERSION);
        }
        icTx = InterchainTransactionLib.decodeTransaction(versionedTx.getPayload());
        if (icTx.dstChainId != block.chainid) {
            revert InterchainClientV1__DstChainIdNotLocal(icTx.dstChainId);
        }
    }

    // solhint-disable no-inline-assembly
    /// @dev Decodes the revert data into a selector and two arguments.
    /// Zero values are returned if the revert data is not long enough.
    /// Note: this is only used in `getTxReadinessV1` to decode the revert data,
    /// so usage of assembly is not a security risk.
    function _decodeRevertData(bytes memory revertData)
        internal
        pure
        returns (bytes4 selector, bytes32 firstArg, bytes32 secondArg)
    {
        // The easiest way to load the bytes chunks onto the stack is to use assembly.
        // Each time we try to load a value, we check if the revert data is long enough.
        // We add 0x20 to skip the length field of the revert data.
        if (revertData.length >= 4) {
            // Load the first 32 bytes, then apply the mask that has only the 4 highest bytes set.
            // There is no need to shift, as `bytesN` variables are right-aligned.
            // https://github.com/ProjectOpenSea/seaport/blob/2ff6ea37/contracts/helpers/SeaportRouter.sol#L161-L175
            selector = bytes4(0xFFFFFFFF);
            assembly {
                selector := and(mload(add(revertData, 0x20)), selector)
            }
        }
        if (revertData.length >= 36) {
            // Skip the length field + selector to get the 32 bytes of the first argument.
            assembly {
                firstArg := mload(add(revertData, 0x24))
            }
        }
        if (revertData.length >= 68) {
            // Skip the length field + selector + first argument to get the 32 bytes of the second argument.
            assembly {
                secondArg := mload(add(revertData, 0x44))
            }
        }
    }
}

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

abstract contract InterchainClientV1Events {
    /// @notice Emitted when the default Guard module is set.
    /// @param guard    The address of the Guard module that will be used by default.
    event DefaultGuardSet(address guard);

    /// @notice Emitted when the default Module is set.
    /// @param module   The address of the Module that will be used by default.
    event DefaultModuleSet(address module);

    /// @notice Emitted when the InterchainClientV1 deployment on a remote chain is linked.
    /// @param chainId   The chain ID of the remote chain.
    /// @param client    The address of the InterchainClientV1 deployment on the remote chain.
    event LinkedClientSet(uint64 chainId, bytes32 client);

    /// @notice Emitted when a new interchain transaction is sent through the InterchainClientV1.
    /// The Receiver on the destination chain will receive the specified message once the transaction is executed.
    /// @param transactionId    The unique identifier of the interchain transaction.
    /// @param dbNonce          The nonce of entry containing the transaction.
    /// @param dstChainId       The chain ID of the destination chain.
    /// @param srcSender        The sender of the transaction on the source chain.
    /// @param dstReceiver      The receiver of the transaction on the destination chain.
    /// @param verificationFee  The fee paid to verify the entry on the destination chain.
    /// @param executionFee     The fee paid to execute the transaction on the destination chain.
    /// @param options          The execution options for the transaction.
    /// @param message          The payload of the message being sent.
    event InterchainTransactionSent(
        bytes32 indexed transactionId,
        uint64 dbNonce,
        uint64 dstChainId,
        bytes32 indexed srcSender,
        bytes32 indexed dstReceiver,
        uint256 verificationFee,
        uint256 executionFee,
        bytes options,
        bytes message
    );

    /// @notice Emitted when an interchain transaction is received by the InterchainClientV1.
    /// The Receiver on the destination chain has just received the message sent from the source chain.
    /// @param transactionId    The unique identifier of the interchain transaction.
    /// @param dbNonce          The nonce of entry containing the transaction.
    /// @param srcChainId       The chain ID of the source chain.
    /// @param srcSender        The sender of the transaction on the source chain.
    /// @param dstReceiver      The receiver of the transaction on the destination chain.
    event InterchainTransactionReceived(
        bytes32 indexed transactionId,
        uint64 dbNonce,
        uint64 srcChainId,
        bytes32 indexed srcSender,
        bytes32 indexed dstReceiver
    );

    /// @notice Emitted when the proof of execution is written to InterchainDB. This allows the source chain
    /// to verify that the transaction was executed by a specific executor, if necessary.
    /// @param transactionId    The unique identifier of the interchain transaction.
    /// @param dbNonce          The nonce of entry containing the transaction.
    /// @param executor         The address of the executor that completed the transaction.
    event ExecutionProofWritten(bytes32 indexed transactionId, uint64 dbNonce, address indexed executor);
}

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

interface IExecutionService {
    function requestTxExecution(
        uint64 dstChainId,
        uint256 txPayloadSize,
        bytes32 transactionId,
        bytes memory options
    )
        external
        payable;

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

    function executorEOA() external view returns (address);

    function getExecutionFee(
        uint64 dstChainId,
        uint256 txPayloadSize,
        bytes memory options
    )
        external
        view
        returns (uint256);
}

File 4 of 16 : 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 {
    function appReceive(uint64 srcChainId, bytes32 sender, uint64 dbNonce, bytes calldata message) external payable;

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

    function getReceivingConfig() external view returns (bytes memory appConfig, address[] memory modules);
}

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

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

interface IInterchainClientV1 {
    enum TxReadiness {
        Ready,
        AlreadyExecuted,
        EntryAwaitingResponses,
        EntryConflict,
        ReceiverNotICApp,
        TxWrongDstChainId,
        UndeterminedRevert
    }

    error InterchainClientV1__ChainIdNotLinked(uint64 chainId);
    error InterchainClientV1__ChainIdNotRemote(uint64 chainId);
    error InterchainClientV1__DstChainIdNotLocal(uint64 chainId);
    error InterchainClientV1__EntryConflict(address module);
    error InterchainClientV1__ExecutionServiceZeroAddress();
    error InterchainClientV1__FeeAmountBelowMin(uint256 feeAmount, uint256 minRequired);
    error InterchainClientV1__GasLeftBelowMin(uint256 gasLeft, uint256 minRequired);
    error InterchainClientV1__GuardZeroAddress();
    error InterchainClientV1__LinkedClientNotEVM(bytes32 client);
    error InterchainClientV1__ModuleZeroAddress();
    error InterchainClientV1__MsgValueMismatch(uint256 msgValue, uint256 required);
    error InterchainClientV1__ReceiverNotICApp(address receiver);
    error InterchainClientV1__ReceiverZeroAddress();
    error InterchainClientV1__ResponsesAmountBelowMin(uint256 responsesAmount, uint256 minRequired);
    error InterchainClientV1__TxAlreadyExecuted(bytes32 transactionId);
    error InterchainClientV1__TxNotExecuted(bytes32 transactionId);
    error InterchainClientV1__TxVersionMismatch(uint16 txVersion, uint16 required);

    function setDefaultGuard(address guard) external;
    function setDefaultModule(address module) external;
    function setLinkedClient(uint64 chainId, bytes32 client) external;

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

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

    function interchainExecute(uint256 gasLimit, bytes calldata transaction) external payable;

    function writeExecutionProof(bytes32 transactionId) external returns (uint64 dbNonce);

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

    function isExecutable(bytes calldata transaction) external view returns (bool);
    function getTxReadinessV1(InterchainTransaction memory icTx)
        external
        view
        returns (TxReadiness status, bytes32 firstArg, bytes32 secondArg);

    function getInterchainFee(
        uint64 dstChainId,
        address srcExecutionService,
        address[] calldata srcModules,
        bytes calldata options,
        uint256 messageLen
    )
        external
        view
        returns (uint256);

    function getExecutor(bytes calldata transaction) external view returns (address);
    function getExecutorById(bytes32 transactionId) external view returns (address);
    function getLinkedClient(uint64 chainId) external view returns (bytes32);
    function getLinkedClientEVM(uint64 chainId) external view returns (address);
}

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

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

interface IInterchainDB {
    error InterchainDB__ChainIdNotRemote(uint64 chainId);
    error InterchainDB__EntryConflict(address module, InterchainEntry newEntry);
    error InterchainDB__EntryVersionMismatch(uint16 version, uint16 required);
    error InterchainDB__FeeAmountBelowMin(uint256 feeAmount, uint256 minRequired);
    error InterchainDB__ModulesNotProvided();

    function writeEntry(bytes32 digest) external returns (uint64 dbNonce);

    function requestEntryVerification(
        uint64 dstChainId,
        uint64 dbNonce,
        address[] memory srcModules
    )
        external
        payable;

    function writeEntryRequestVerification(
        uint64 dstChainId,
        bytes32 digest,
        address[] memory srcModules
    )
        external
        payable
        returns (uint64 dbNonce);

    function verifyRemoteEntry(bytes memory encodedEntry) external;

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

    function getInterchainFee(uint64 dstChainId, address[] memory srcModules) external view returns (uint256);

    function getEncodedEntry(uint64 dbNonce) external view returns (bytes memory);
    function getEntry(uint64 dbNonce) external view returns (InterchainEntry memory);
    function getEntryValue(uint64 dbNonce) external view returns (bytes32);

    function getDBNonce() external view returns (uint64);

    function checkEntryVerification(
        address dstModule,
        InterchainEntry memory entry
    )
        external
        view
        returns (uint256 moduleVerifiedAt);

    // solhint-disable-next-line func-name-mixedcase
    function DB_VERSION() external pure returns (uint16);
}

File 7 of 16 : AppConfig.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

struct AppConfigV1 {
    uint8 requiredResponses;
    uint48 optimisticSeconds;
    uint8 guardFlag;
    address guard;
}

using AppConfigLib for AppConfigV1 global;

/// @dev Signals that the app opted out of using any Guard module.
uint8 constant APP_CONFIG_GUARD_DISABLED = 0;
/// @dev Signals that the app uses the default Guard module provided by InterchainClient contract.
uint8 constant APP_CONFIG_GUARD_DEFAULT = 1;
/// @dev Signals that the app uses a custom Guard module.
uint8 constant APP_CONFIG_GUARD_CUSTOM = 2;

library AppConfigLib {
    using VersionedPayloadLib for bytes;

    uint16 internal constant APP_CONFIG_V1 = 1;

    error AppConfigLib__VersionInvalid(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__VersionInvalid(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 8 of 16 : InterchainEntry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

/// @notice Struct representing an entry in the Interchain DataBase.
/// Entry has a globally unique identifier (key) and a value.
/// Assuming `srcWriter` has written data `digest` on the source chain:
/// - key: (srcChainId, dbNonce)
/// - entryValue = keccak256(srcWriter, digest)
/// @param srcChainId   The chain id of the source chain
/// @param dbNonce      The database nonce of the entry
/// @param entryValue   The entry value
struct InterchainEntry {
    uint64 srcChainId;
    uint64 dbNonce;
    bytes32 entryValue;
}

type EntryKey is uint128;

/// @dev Signals that the module has not verified any entry with the given key.
uint256 constant ENTRY_UNVERIFIED = 0;
/// @dev Signals that the module has verified a conflicting entry with the given key.
uint256 constant ENTRY_CONFLICT = type(uint256).max;

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 entryValue   The value of the entry
    /// @return entry       The constructed InterchainEntry struct
    function constructLocalEntry(
        uint64 dbNonce,
        bytes32 entryValue
    )
        internal
        view
        returns (InterchainEntry memory entry)
    {
        uint64 srcChainId = SafeCast.toUint64(block.chainid);
        return InterchainEntry({srcChainId: srcChainId, dbNonce: dbNonce, entryValue: entryValue});
    }

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

    /// @notice Returns the value of the entry: writer + digest hashed together.
    /// Note: this is exposed for convenience to avoid typecasts prior to abi-encoding.
    function getEntryValue(address srcWriter, bytes32 digest) internal pure returns (bytes32) {
        return keccak256(abi.encode(srcWriter, digest));
    }

    /// @notice Encodes the InterchainEntry struct into a non-versioned entry payload.
    function encodeEntry(InterchainEntry memory entry) internal pure returns (bytes memory) {
        return abi.encode(encodeEntryKey(entry.srcChainId, entry.dbNonce), entry.entryValue);
    }

    /// @notice Decodes the InterchainEntry struct from a non-versioned entry payload in calldata.
    function decodeEntry(bytes calldata data) internal pure returns (InterchainEntry memory entry) {
        EntryKey key;
        (key, entry.entryValue) = abi.decode(data, (EntryKey, bytes32));
        (entry.srcChainId, entry.dbNonce) = decodeEntryKey(key);
    }

    /// @notice Decodes the InterchainEntry struct from a non-versioned entry payload in memory.
    function decodeEntryFromMemory(bytes memory data) internal pure returns (InterchainEntry memory entry) {
        EntryKey key;
        (key, entry.entryValue) = abi.decode(data, (EntryKey, bytes32));
        (entry.srcChainId, entry.dbNonce) = decodeEntryKey(key);
    }

    /// @notice Encodes the uint128 key of the entry from uint64 srcChainId and uint64 dbNonce.
    function encodeEntryKey(uint64 srcChainId, uint64 dbNonce) internal pure returns (EntryKey) {
        return EntryKey.wrap((uint128(srcChainId) << 64) | dbNonce);
    }

    /// @notice Decodes the uint128 key of the entry into uint64 srcChainId and uint64 dbNonce.
    function decodeEntryKey(EntryKey key) internal pure returns (uint64 srcChainId, uint64 dbNonce) {
        srcChainId = uint64(EntryKey.unwrap(key) >> 64);
        dbNonce = uint64(EntryKey.unwrap(key));
    }
}

File 9 of 16 : 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";

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

type ICTxHeader is uint256;

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

struct InterchainTxDescriptor {
    bytes32 transactionId;
    uint64 dbNonce;
}

using InterchainTransactionLib for InterchainTransaction global;

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

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

    function encodeTransaction(InterchainTransaction memory transaction) internal pure returns (bytes memory) {
        return abi.encode(
            encodeTxHeader(transaction.srcChainId, transaction.dstChainId, transaction.dbNonce),
            transaction.srcSender,
            transaction.dstReceiver,
            transaction.options,
            transaction.message
        );
    }

    function decodeTransaction(bytes calldata transaction) internal pure returns (InterchainTransaction memory icTx) {
        ICTxHeader header;
        (header, icTx.srcSender, icTx.dstReceiver, icTx.options, icTx.message) =
            abi.decode(transaction, (ICTxHeader, bytes32, bytes32, bytes, bytes));
        (icTx.srcChainId, icTx.dstChainId, icTx.dbNonce) = decodeTxHeader(header);
    }

    function payloadSize(uint256 optionsLen, uint256 messageLen) internal pure returns (uint256) {
        // 2 bytes are reserved for the transaction version
        // + 5 fields * 32 bytes (3 values for static, 2 offsets for dynamic) + 2 * 32 bytes (lengths for dynamic) = 226
        // (srcChainId, dstChainId, dbNonce) are merged into a single 32 bytes field
        // Both options and message are dynamic fields, which are padded up to 32 bytes
        return 226 + optionsLen.roundUpToWord() + messageLen.roundUpToWord();
    }

    function encodeTxHeader(uint64 srcChainId, uint64 dstChainId, uint64 dbNonce) internal pure returns (ICTxHeader) {
        return ICTxHeader.wrap((uint256(srcChainId) << 128) | (uint256(dstChainId) << 64) | (uint256(dbNonce)));
    }

    function decodeTxHeader(ICTxHeader header)
        internal
        pure
        returns (uint64 srcChainId, uint64 dstChainId, uint64 dbNonce)
    {
        srcChainId = uint64(ICTxHeader.unwrap(header) >> 128);
        dstChainId = uint64(ICTxHeader.unwrap(header) >> 64);
        dbNonce = uint64(ICTxHeader.unwrap(header));
    }
}

File 10 of 16 : 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__VersionInvalid(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__VersionInvalid(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 11 of 16 : TypeCasts.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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 12 of 16 : VersionedPayload.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

// 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__PayloadTooShort(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__PayloadTooShort(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__PayloadTooShort(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__PayloadTooShort(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__PayloadTooShort(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 13 of 16 : 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 14 of 16 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }
}

File 15 of 16 : Math.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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 16 of 16 : 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/",
    "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

[{"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__VersionInvalid","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"}],"name":"InterchainClientV1__ChainIdNotLinked","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"}],"name":"InterchainClientV1__ChainIdNotRemote","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"}],"name":"InterchainClientV1__DstChainIdNotLocal","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"InterchainClientV1__EntryConflict","type":"error"},{"inputs":[],"name":"InterchainClientV1__ExecutionServiceZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"minRequired","type":"uint256"}],"name":"InterchainClientV1__FeeAmountBelowMin","type":"error"},{"inputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"internalType":"uint256","name":"minRequired","type":"uint256"}],"name":"InterchainClientV1__GasLeftBelowMin","type":"error"},{"inputs":[],"name":"InterchainClientV1__GuardZeroAddress","type":"error"},{"inputs":[{"internalType":"bytes32","name":"client","type":"bytes32"}],"name":"InterchainClientV1__LinkedClientNotEVM","type":"error"},{"inputs":[],"name":"InterchainClientV1__ModuleZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InterchainClientV1__MsgValueMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"InterchainClientV1__ReceiverNotICApp","type":"error"},{"inputs":[],"name":"InterchainClientV1__ReceiverZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"responsesAmount","type":"uint256"},{"internalType":"uint256","name":"minRequired","type":"uint256"}],"name":"InterchainClientV1__ResponsesAmountBelowMin","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":[{"internalType":"uint16","name":"txVersion","type":"uint16"},{"internalType":"uint16","name":"required","type":"uint16"}],"name":"InterchainClientV1__TxVersionMismatch","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"OptionsLib__VersionInvalid","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":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"bytes","name":"versionedPayload","type":"bytes"}],"name":"VersionedPayload__PayloadTooShort","type":"error"},{"inputs":[],"name":"VersionedPayload__PrecompileFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guard","type":"address"}],"name":"DefaultGuardSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"DefaultModuleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"dbNonce","type":"uint64"},{"indexed":true,"internalType":"address","name":"executor","type":"address"}],"name":"ExecutionProofWritten","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"dbNonce","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"srcChainId","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"dstReceiver","type":"bytes32"}],"name":"InterchainTransactionReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"dbNonce","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"dstChainId","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"indexed":true,"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":"uint64","name":"chainId","type":"uint64"},{"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":[],"name":"defaultGuard","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"uint64","name":"dstChainId","type":"uint64"},{"internalType":"uint64","name":"dbNonce","type":"uint64"},{"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"internalType":"bytes32","name":"dstReceiver","type":"bytes32"},{"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":[{"internalType":"address","name":"receiver","type":"address"}],"name":"getAppReceivingConfigV1","outputs":[{"components":[{"internalType":"uint8","name":"requiredResponses","type":"uint8"},{"internalType":"uint48","name":"optimisticSeconds","type":"uint48"},{"internalType":"uint8","name":"guardFlag","type":"uint8"},{"internalType":"address","name":"guard","type":"address"}],"internalType":"struct AppConfigV1","name":"config","type":"tuple"},{"internalType":"address[]","name":"modules","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":"uint64","name":"dstChainId","type":"uint64"},{"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":"uint64","name":"chainId","type":"uint64"}],"name":"getLinkedClient","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"}],"name":"getLinkedClientEVM","outputs":[{"internalType":"address","name":"linkedClientEVM","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"uint64","name":"dstChainId","type":"uint64"},{"internalType":"uint64","name":"dbNonce","type":"uint64"},{"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"internalType":"bytes32","name":"dstReceiver","type":"bytes32"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"internalType":"struct InterchainTransaction","name":"icTx","type":"tuple"}],"name":"getTxReadinessV1","outputs":[{"internalType":"enum IInterchainClientV1.TxReadiness","name":"status","type":"uint8"},{"internalType":"bytes32","name":"firstArg","type":"bytes32"},{"internalType":"bytes32","name":"secondArg","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"transaction","type":"bytes"}],"name":"interchainExecute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"dstChainId","type":"uint64"},{"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":"uint64","name":"dbNonce","type":"uint64"}],"internalType":"struct InterchainTxDescriptor","name":"desc","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"dstChainId","type":"uint64"},{"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":"uint64","name":"dbNonce","type":"uint64"}],"internalType":"struct InterchainTxDescriptor","name":"desc","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"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":"guard","type":"address"}],"name":"setDefaultGuard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"setDefaultModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"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":"uint64","name":"dbNonce","type":"uint64"}],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162002d3e38038062002d3e8339810160408190526200003491620000f0565b806001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f8162000083565b50506001600160a01b031660805262000128565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000eb57600080fd5b919050565b600080604083850312156200010457600080fd5b6200010f83620000d3565b91506200011f60208401620000d3565b90509250929050565b608051612bc9620001756000396000818161042b01528181610cd801528181610ea70152818161144f015281816114f70152818161163001528181611c510152611d2d0152612bc96000f3fe60806040526004361061014b5760003560e01c80638da5cb5b116100b6578063e4c612471161006f578063e4c6124714610419578063f06c79771461044d578063f1a61fac1461047a578063f2fde38b146104b0578063f3c66e2b146104d0578063f92a79ff146104f057600080fd5b80638da5cb5b1461032857806390e810771461034657806394bf49f41461037e578063cbb3c6311461039e578063d5e788a0146103be578063e4344069146103f957600080fd5b80633f34448e116101085780633f34448e14610260578063547efb8414610297578063695fd54f146102aa578063715018a6146102d85780637813cd52146102ed57806380efe7771461031557600080fd5b80630a24bb93146101505780632a20521e146101885780632e568739146101c057806331afa7de146101ee57806335c4a1911461021e5780633d677ed01461023e575b600080fd5b34801561015c57600080fd5b5061017061016b366004612018565b610510565b60405161017f939291906120ef565b60405180910390f35b34801561019457600080fd5b506001546101a8906001600160a01b031681565b6040516001600160a01b03909116815260200161017f565b3480156101cc57600080fd5b506101e06101db366004612125565b610697565b60405190815260200161017f565b3480156101fa57600080fd5b5061020e610209366004612183565b6106ee565b604051901515815260200161017f565b34801561022a57600080fd5b506101a8610239366004612125565b61073e565b34801561024a57600080fd5b5061025e6102593660046121d9565b6107c1565b005b61027361026e36600461223a565b610845565b60408051825181526020928301516001600160401b0316928101929092520161017f565b6102736102a536600461230d565b610883565b3480156102b657600080fd5b506102ca6102c53660046121d9565b6108b6565b60405161017f92919061234d565b3480156102e457600080fd5b5061025e610a82565b3480156102f957600080fd5b50610302600181565b60405161ffff909116815260200161017f565b61025e6103233660046123d9565b610a96565b34801561033457600080fd5b506000546001600160a01b03166101a8565b34801561035257600080fd5b50610366610361366004612424565b610c4d565b6040516001600160401b03909116815260200161017f565b34801561038a57600080fd5b5061025e6103993660046121d9565b610da0565b3480156103aa57600080fd5b506101e06103b936600461243d565b610e1d565b3480156103ca57600080fd5b506103de6103d93660046124da565b610fbc565b6040805182518152602092830151928101929092520161017f565b34801561040557600080fd5b506002546101a8906001600160a01b031681565b34801561042557600080fd5b506101a87f000000000000000000000000000000000000000000000000000000000000000081565b34801561045957600080fd5b5061046d610468366004612018565b610fd9565b60405161017f9190612566565b34801561048657600080fd5b506101a8610495366004612424565b6000908152600460205260409020546001600160a01b031690565b3480156104bc57600080fd5b5061025e6104cb3660046121d9565b610fee565b3480156104dc57600080fd5b5061025e6104eb366004612579565b61102c565b3480156104fc57600080fd5b506101a861050b366004612183565b61108c565b60008060008061051f85610fd9565b6040516318d7d3ef60e11b815290915030906331afa7de90610545908490600401612566565b602060405180830381865afa92505050801561057e575060408051601f3d908101601f1916820190925261057b918101906125a5565b60015b61067c573d8080156105ac576040519150601f19603f3d011682016040523d82523d6000602084013e6105b1565b606091505b5060006105bd826110cc565b909650945090506327f5146f60e01b6001600160e01b03198216016105e55760019550610675565b6357761ca160e11b6001600160e01b03198216016106065760029550610675565b631627ab1760e31b6001600160e01b03198216016106275760039550610675565b6305d6c00360e41b6001600160e01b03198216016106485760049550610675565b631515fcbb60e01b6001600160e01b03198216016106695760059550610675565b60069550600094508493505b505061068e565b50600093508392508291506106909050565b505b9193909250565b600046826001600160401b0316036106d257604051636b0dc00560e11b81526001600160401b03831660048201526024015b60405180910390fd5b506001600160401b031660009081526003602052604090205490565b6000806106fb8484611112565b905061070a8160a001516111b3565b506000848460405161071d9291906125c7565b604051809103902090506107318282611223565b6001925050505b92915050565b600046826001600160401b03160361077457604051636b0dc00560e11b81526001600160401b03831660048201526024016106c9565b506001600160401b038116600090815260036020526040902054806001600160a01b03811681146107bb5760405163ec3822b160e01b8152600481018290526024016106c9565b50919050565b6107c9611361565b6001600160a01b0381166107f057604051633bb893a160e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527ffa842b3692f81757c2420f55af6ab68a0a16f77c893dd8e2011c327d6c19ed49906020015b60405180910390a150565b60408051808201909152600080825260208201526001600160a01b0389166108748b828b8b8b8b8b8b8b61138e565b9b9a5050505050505050505050565b60408051808201909152600080825260208201526108a88a8a8a8a8a8a8a8a8a61138e565b9a9950505050505050505050565b6040805160808101825260008082526020820181905291810182905260608101919091526060826001600160a01b03163b60000361091257604051630a293ffd60e41b81526001600160a01b03841660048201526024016106c9565b60408051600481526024810182526020810180516001600160e01b031663287bc05760e01b179052905160009182916001600160a01b03871691610955916125d7565b600060405180830381855afa9150503d8060008114610990576040519150601f19603f3d011682016040523d82523d6000602084013e610995565b606091505b50915091508115806109a657508051155b156109cf57604051630a293ffd60e41b81526001600160a01b03861660048201526024016106c9565b6060818060200190518101906109e591906125f3565b945090506109f2816117e6565b94508351600003610a5e576040805160018082528183019092529060208083019080368337505060025482519296506001600160a01b031691869150600090610a3d57610a3d612707565b60200260200101906001600160a01b031690816001600160a01b0316815250505b845160ff16600003610a7a57610a74845161185d565b60ff1685525b505050915091565b610a8a611361565b610a94600061188f565b565b6000610aa28383611112565b905060008383604051610ab69291906125c7565b60405180910390209050610aca8282611223565b600081815260046020526040812080546001600160a01b0319163317905560a0830151610af6906111b3565b905080602001513414610b2b5760208101516040516366f7ba5d60e01b815234600482015260248101919091526044016106c9565b8051861015610b3957805195505b60005a9050868111610b685760405163176b11a760e21b815260048101829052602481018890526044016106c9565b60808401516001600160a01b0316630421a1f088348760000151886060015189604001518a60c001516040518763ffffffff1660e01b8152600401610bb0949392919061271d565b6000604051808303818589803b158015610bc957600080fd5b5088f1158015610bdd573d6000803e3d6000fd5b50505050505083608001518460600151847f6bca840947c9cad2cc8a66e663c1ca33d73c416b8a8d7e74345a1106b74a81fb87604001518860000151604051610c3c9291906001600160401b0392831681529116602082015260400190565b60405180910390a450505050505050565b6000818152600460205260408120546001600160a01b031680610c865760405163e99eb48d60e01b8152600481018490526024016106c9565b60008382604051602001610cad9291909182526001600160a01b0316602082015260400190565b60408051808303601f19018152908290528051602082012063156c638360e11b8352600483015291507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632ad8c706906024016020604051808303816000875af1158015610d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4d9190612759565b6040516001600160401b03821681529093506001600160a01b0383169085907fab644d167c2c65a7ca17d6920e7681356b90f09279e2b7dc4c714b826ea4fbcc9060200160405180910390a35050919050565b610da8611361565b6001600160a01b038116610dcf57604051633184f16960e21b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527fa42a6dc10e430cab5d4ba037ea6d7eee30240c6b6d7dd5b12a3d2acf41e7264f9060200161083a565b6000610e28886118df565b506001600160a01b038716610e505760405163146fd3c560e21b815260040160405180910390fd5b610e8f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111b392505050565b5060405163b8ba4ba160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b8ba4ba190610ee0908b908a908a906004016127bf565b602060405180830381865afa158015610efd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2191906127eb565b90506000610f2f8484611960565b604051634b7ed26d60e11b81529091506001600160a01b038916906396fda4da90610f64908c9085908a908a9060040161282d565b602060405180830381865afa158015610f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa591906127eb565b610faf9083612856565b9998505050505050505050565b6040805180820190915260008082526020820152610738826111b3565b60606107386001610fe984611987565b611a0b565b610ff6611361565b6001600160a01b03811661102057604051631e4fbdf760e01b8152600060048201526024016106c9565b6110298161188f565b50565b611034611361565b6001600160401b038216600081815260036020908152604091829020849055815192835282018390527ffdc2498138df0de25c8fc9bd75bb8e856dac69aaf28d3dd5e0fc48e5e9f6e93f910160405180910390a15050565b60006004600084846040516110a29291906125c7565b60408051918290039091208252602082019290925201600020546001600160a01b03169392505050565b600080600060048451106110ec5760208401516001600160e01b03191692505b60248451106110fd57602484015191505b60448451106106905750604492909201519092565b61111a611ecf565b60006111268484611a37565b905061ffff811660011461115a576040516316d8807d60e11b815261ffff82166004820152600160248201526044016106c9565b61116c6111678585611a68565b611aaa565b91504682602001516001600160401b0316146111ac57602082015160405163eaea034560e01b81526001600160401b0390911660048201526024016106c9565b5092915050565b604080518082019091526000808252602082015260006111d283611b0b565b9050600161ffff8216101561120057604051632b346f3760e01b815261ffff821660048201526024016106c9565b61120983611b3d565b80602001905181019061121c9190612877565b9392505050565b600061123283600001516118df565b6000838152600460205260409020549091506001600160a01b03161561126e5760405163d80aeb9160e01b8152600481018390526024016106c9565b604080516060808201835285516001600160401b039081168352868401511660208084019190915283518082018690528085018790528451808203860181529201845281519101209181019190915260808401516000806112ce836108b6565b9150915060006112dd83611be6565b90506112e98186611c28565b60006001600160a01b03821615611304578360200151611307565b60005b65ffffffffffff169050600061131e848884611cfe565b855190915060ff16811015611355578451604051632889e35f60e11b81526004810183905260ff90911660248201526044016106c9565b50505050505050505050565b6000546001600160a01b03163314610a945760405163118cdaa760e01b81523360048201526024016106c9565b60408051808201909152600080825260208201526113ab8a6118df565b5060008990036113ce576040516330014e4760e21b815260040160405180910390fd5b6001600160a01b0388166113f55760405163146fd3c560e21b815260040160405180910390fd5b61143485858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111b392505050565b5060405163b8ba4ba160e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b8ba4ba190611488908e908c908c906004016127bf565b602060405180830381865afa1580156114a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c991906127eb565b9050803410156114f55760405163457bf1e160e11b8152346004820152602481018290526044016106c9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f338140e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611553573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115779190612759565b82602001906001600160401b031690816001600160401b0316815250506000611611338d8d86602001518b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250611e2092505050565b905061161c81610fd9565b8051906020012083600001818152505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fecf58d84846020015187600001518e8e6040518663ffffffff1660e01b815260040161168994939291906128c5565b60206040518083038185885af11580156116a7573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906116cc9190612759565b905083602001516001600160401b0316816001600160401b0316146116f3576116f36128ee565b50602081015134839003906001600160a01b038c16906358efb47d90839061171b8b8a611960565b88516040516001600160e01b031960e087901b168152611744939291908f908f90600401612904565b6000604051808303818588803b15801561175d57600080fd5b505af1158015611771573d6000803e3d6000fd5b50505050508160800151826060015185600001517f4085591259df9982b703db65d112e8413b755dc4e74984fc5132fe4220fede268760200151866020015188878960a001518a60c001516040516117ce9695949392919061293e565b60405180910390a45050509998505050505050505050565b60408051608081018252600080825260208201819052918101829052606081018290529061181383611b0b565b9050600161ffff8216101561184157604051635b72a46360e11b815261ffff821660048201526024016106c9565b61184a83611b3d565b80602001905181019061121c9190612999565b600060ff82111561188b576040516306dfcc6560e41b815260086004820152602481018390526044016106c9565b5090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600046826001600160401b03160361191557604051636b0dc00560e11b81526001600160401b03831660048201526024016106c9565b506001600160401b0381166000908152600360205260408120549081900361195b57604051632e3a383760e21b81526001600160401b03831660048201526024016106c9565b919050565b6000601f19601f830116601f19601f85011661197d9060e2612856565b61121c9190612856565b805160208201516040808401516060936001600160401b039091169290911b6fffffffffffffffff00000000000000001660809190911b67ffffffffffffffff60801b161717826060015183608001518460a001518560c001516040516020016119f5959493929190612a24565b6040516020818303038152906040529050919050565b60608282604051602001611a20929190612a67565b604051602081830303815290604052905092915050565b60006002821015611a5f578282604051635840c5b160e11b81526004016106c9929190612a97565b50503560f01c90565b3660006002831015611a91578383604051635840c5b160e11b81526004016106c9929190612a97565b611a9e8360028187612aab565b915091505b9250929050565b611ab2611ecf565b6000611ac083850185612ad5565b60c087015260a0860152608085015260608401529050611ae981608081901c91604082901c9190565b6001600160401b03908116604086015290811660208501521682525092915050565b6000600282511015611b325781604051635840c5b160e11b81526004016106c99190612566565b506020015160f01c90565b6060600282511015611b645781604051635840c5b160e11b81526004016106c99190612566565b815160011901806001600160401b03811115611b8257611b82611f0d565b6040519080825280601f01601f191660200182016040528015611bac576020820181803683370190505b50915060008160208401836022870160045afa905080611bdf5760405163080f227d60e11b815260040160405180910390fd5b5050919050565b604081015160009060ff16611bfd57506000919050565b600160ff16826040015160ff1603611c205750506001546001600160a01b031690565b506060015190565b6001600160a01b03821615611cfa576040516387c59c6f60e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906387c59c6f90611c889086908690600401612b55565b602060405180830381865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc991906127eb565b90506000198103611cf8576040516309d854e960e31b81526001600160a01b03841660048201526024016106c9565b505b5050565b6000805b8451811015611e18576000858281518110611d1f57611d1f612707565b6020026020010151905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166387c59c6f83886040518363ffffffff1660e01b8152600401611d79929190612b55565b602060405180830381865afa158015611d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dba91906127eb565b905080611dc8575050611e10565b6000198103611df5576040516309d854e960e31b81526001600160a01b03831660048201526024016106c9565b42611e008683612856565b1015611e0d578360010193505b50505b600101611d02565b509392505050565b611e28611ecf565b6040518060e00160405280611e3c46611e99565b6001600160401b03168152602001876001600160401b03168152602001856001600160401b03168152602001611e78896001600160a01b031690565b81526020018681526020018481526020018381525090509695505050505050565b60006001600160401b0382111561188b57604080516306dfcc6560e41b81526004810191909152602481018390526044016106c9565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082019290925260a0810182905260c081019190915290565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715611f4557611f45611f0d565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611f7357611f73611f0d565b604052919050565b6001600160401b038116811461102957600080fd5b803561195b81611f7b565b60006001600160401b03821115611fb457611fb4611f0d565b50601f01601f191660200190565b600082601f830112611fd357600080fd5b8135611fe6611fe182611f9b565b611f4b565b818152846020838601011115611ffb57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561202a57600080fd5b81356001600160401b038082111561204157600080fd5b9083019060e0828603121561205557600080fd5b61205d611f23565b61206683611f90565b815261207460208401611f90565b602082015261208560408401611f90565b6040820152606083013560608201526080830135608082015260a0830135828111156120b057600080fd5b6120bc87828601611fc2565b60a08301525060c0830135828111156120d457600080fd5b6120e087828601611fc2565b60c08301525095945050505050565b606081016007851061211157634e487b7160e01b600052602160045260246000fd5b938152602081019290925260409091015290565b60006020828403121561213757600080fd5b813561121c81611f7b565b60008083601f84011261215457600080fd5b5081356001600160401b0381111561216b57600080fd5b602083019150836020828501011115611aa357600080fd5b6000806020838503121561219657600080fd5b82356001600160401b038111156121ac57600080fd5b6121b885828601612142565b90969095509350505050565b6001600160a01b038116811461102957600080fd5b6000602082840312156121eb57600080fd5b813561121c816121c4565b60008083601f84011261220857600080fd5b5081356001600160401b0381111561221f57600080fd5b6020830191508360208260051b8501011115611aa357600080fd5b600080600080600080600080600060c08a8c03121561225857600080fd5b893561226381611f7b565b985060208a0135612273816121c4565b975060408a0135612283816121c4565b965060608a01356001600160401b038082111561229f57600080fd5b6122ab8d838e016121f6565b909850965060808c01359150808211156122c457600080fd5b6122d08d838e01612142565b909650945060a08c01359150808211156122e957600080fd5b506122f68c828d01612142565b915080935050809150509295985092959850929598565b600080600080600080600080600060c08a8c03121561232b57600080fd5b893561233681611f7b565b985060208a0135975060408a0135612283816121c4565b600060a0820160ff8551168352602065ffffffffffff602087015116602085015260ff6040870151166040850152606086015160018060a01b03808216606087015260a06080870152839150865180855260c08701925060208801945060005b818110156123cb5785518316845294840194928401926001016123ad565b509198975050505050505050565b6000806000604084860312156123ee57600080fd5b8335925060208401356001600160401b0381111561240b57600080fd5b61241786828701612142565b9497909650939450505050565b60006020828403121561243657600080fd5b5035919050565b600080600080600080600060a0888a03121561245857600080fd5b873561246381611f7b565b96506020880135612473816121c4565b955060408801356001600160401b038082111561248f57600080fd5b61249b8b838c016121f6565b909750955060608a01359150808211156124b457600080fd5b506124c18a828b01612142565b989b979a50959894979596608090950135949350505050565b6000602082840312156124ec57600080fd5b81356001600160401b0381111561250257600080fd5b61250e84828501611fc2565b949350505050565b60005b83811015612531578181015183820152602001612519565b50506000910152565b60008151808452612552816020860160208601612516565b601f01601f19169290920160200192915050565b60208152600061121c602083018461253a565b6000806040838503121561258c57600080fd5b823561259781611f7b565b946020939093013593505050565b6000602082840312156125b757600080fd5b8151801515811461121c57600080fd5b8183823760009101908152919050565b600082516125e9818460208701612516565b9190910192915050565b6000806040838503121561260657600080fd5b82516001600160401b038082111561261d57600080fd5b818501915085601f83011261263157600080fd5b81516020612641611fe183611f9b565b828152888284870101111561265557600080fd5b61266483838301848801612516565b8782015190965093508284111561267a57600080fd5b838701935087601f85011261268e57600080fd5b83519150828211156126a2576126a2611f0d565b8160051b92506126b3818401611f4b565b82815292840181019281810190898511156126cd57600080fd5b948201945b848610156126f757855193506126e7846121c4565b83825294820194908201906126d2565b8096505050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b60006001600160401b0380871683528560208401528085166040840152506080606083015261274f608083018461253a565b9695505050505050565b60006020828403121561276b57600080fd5b815161121c81611f7b565b8183526000602080850194508260005b858110156127b4578135612799816121c4565b6001600160a01b031687529582019590820190600101612786565b509495945050505050565b6001600160401b03841681526040602082015260006127e2604083018486612776565b95945050505050565b6000602082840312156127fd57600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160401b038516815283602082015260606040820152600061274f606083018486612804565b8082018082111561073857634e487b7160e01b600052601160045260246000fd5b60006040828403121561288957600080fd5b604051604081018181106001600160401b03821117156128ab576128ab611f0d565b604052825181526020928301519281019290925250919050565b6001600160401b038516815283602082015260606040820152600061274f606083018486612776565b634e487b7160e01b600052600160045260246000fd5b6001600160401b0386168152846020820152836040820152608060608201526000612933608083018486612804565b979650505050505050565b60006001600160401b03808916835280881660208401525085604083015284606083015260c0608083015261297660c083018561253a565b82810360a0840152610faf818561253a565b805160ff8116811461195b57600080fd5b6000608082840312156129ab57600080fd5b604051608081018181106001600160401b03821117156129cd576129cd611f0d565b6040526129d983612988565b8152602083015165ffffffffffff811681146129f457600080fd5b6020820152612a0560408401612988565b60408201526060830151612a18816121c4565b60608201529392505050565b85815284602082015283604082015260a060608201526000612a4960a083018561253a565b8281036080840152612a5b818561253a565b98975050505050505050565b61ffff60f01b8360f01b16815260008251612a89816002850160208701612516565b919091016002019392505050565b60208152600061250e602083018486612804565b60008085851115612abb57600080fd5b83861115612ac857600080fd5b5050820193919092039150565b600080600080600060a08688031215612aed57600080fd5b85359450602086013593506040860135925060608601356001600160401b0380821115612b1957600080fd5b612b2589838a01611fc2565b93506080880135915080821115612b3b57600080fd5b50612b4888828901611fc2565b9150509295509295909350565b6001600160a01b0392909216825280516001600160401b0390811660208085019190915282015116604080840191909152015160608201526080019056fea264697066735822122075b5d045844692116640851ae4ef6651244619dbe89fbafc50cdf3322fcd0c8b64736f6c634300081800330000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a11000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4

Deployed Bytecode

0x60806040526004361061014b5760003560e01c80638da5cb5b116100b6578063e4c612471161006f578063e4c6124714610419578063f06c79771461044d578063f1a61fac1461047a578063f2fde38b146104b0578063f3c66e2b146104d0578063f92a79ff146104f057600080fd5b80638da5cb5b1461032857806390e810771461034657806394bf49f41461037e578063cbb3c6311461039e578063d5e788a0146103be578063e4344069146103f957600080fd5b80633f34448e116101085780633f34448e14610260578063547efb8414610297578063695fd54f146102aa578063715018a6146102d85780637813cd52146102ed57806380efe7771461031557600080fd5b80630a24bb93146101505780632a20521e146101885780632e568739146101c057806331afa7de146101ee57806335c4a1911461021e5780633d677ed01461023e575b600080fd5b34801561015c57600080fd5b5061017061016b366004612018565b610510565b60405161017f939291906120ef565b60405180910390f35b34801561019457600080fd5b506001546101a8906001600160a01b031681565b6040516001600160a01b03909116815260200161017f565b3480156101cc57600080fd5b506101e06101db366004612125565b610697565b60405190815260200161017f565b3480156101fa57600080fd5b5061020e610209366004612183565b6106ee565b604051901515815260200161017f565b34801561022a57600080fd5b506101a8610239366004612125565b61073e565b34801561024a57600080fd5b5061025e6102593660046121d9565b6107c1565b005b61027361026e36600461223a565b610845565b60408051825181526020928301516001600160401b0316928101929092520161017f565b6102736102a536600461230d565b610883565b3480156102b657600080fd5b506102ca6102c53660046121d9565b6108b6565b60405161017f92919061234d565b3480156102e457600080fd5b5061025e610a82565b3480156102f957600080fd5b50610302600181565b60405161ffff909116815260200161017f565b61025e6103233660046123d9565b610a96565b34801561033457600080fd5b506000546001600160a01b03166101a8565b34801561035257600080fd5b50610366610361366004612424565b610c4d565b6040516001600160401b03909116815260200161017f565b34801561038a57600080fd5b5061025e6103993660046121d9565b610da0565b3480156103aa57600080fd5b506101e06103b936600461243d565b610e1d565b3480156103ca57600080fd5b506103de6103d93660046124da565b610fbc565b6040805182518152602092830151928101929092520161017f565b34801561040557600080fd5b506002546101a8906001600160a01b031681565b34801561042557600080fd5b506101a87f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a1181565b34801561045957600080fd5b5061046d610468366004612018565b610fd9565b60405161017f9190612566565b34801561048657600080fd5b506101a8610495366004612424565b6000908152600460205260409020546001600160a01b031690565b3480156104bc57600080fd5b5061025e6104cb3660046121d9565b610fee565b3480156104dc57600080fd5b5061025e6104eb366004612579565b61102c565b3480156104fc57600080fd5b506101a861050b366004612183565b61108c565b60008060008061051f85610fd9565b6040516318d7d3ef60e11b815290915030906331afa7de90610545908490600401612566565b602060405180830381865afa92505050801561057e575060408051601f3d908101601f1916820190925261057b918101906125a5565b60015b61067c573d8080156105ac576040519150601f19603f3d011682016040523d82523d6000602084013e6105b1565b606091505b5060006105bd826110cc565b909650945090506327f5146f60e01b6001600160e01b03198216016105e55760019550610675565b6357761ca160e11b6001600160e01b03198216016106065760029550610675565b631627ab1760e31b6001600160e01b03198216016106275760039550610675565b6305d6c00360e41b6001600160e01b03198216016106485760049550610675565b631515fcbb60e01b6001600160e01b03198216016106695760059550610675565b60069550600094508493505b505061068e565b50600093508392508291506106909050565b505b9193909250565b600046826001600160401b0316036106d257604051636b0dc00560e11b81526001600160401b03831660048201526024015b60405180910390fd5b506001600160401b031660009081526003602052604090205490565b6000806106fb8484611112565b905061070a8160a001516111b3565b506000848460405161071d9291906125c7565b604051809103902090506107318282611223565b6001925050505b92915050565b600046826001600160401b03160361077457604051636b0dc00560e11b81526001600160401b03831660048201526024016106c9565b506001600160401b038116600090815260036020526040902054806001600160a01b03811681146107bb5760405163ec3822b160e01b8152600481018290526024016106c9565b50919050565b6107c9611361565b6001600160a01b0381166107f057604051633bb893a160e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527ffa842b3692f81757c2420f55af6ab68a0a16f77c893dd8e2011c327d6c19ed49906020015b60405180910390a150565b60408051808201909152600080825260208201526001600160a01b0389166108748b828b8b8b8b8b8b8b61138e565b9b9a5050505050505050505050565b60408051808201909152600080825260208201526108a88a8a8a8a8a8a8a8a8a61138e565b9a9950505050505050505050565b6040805160808101825260008082526020820181905291810182905260608101919091526060826001600160a01b03163b60000361091257604051630a293ffd60e41b81526001600160a01b03841660048201526024016106c9565b60408051600481526024810182526020810180516001600160e01b031663287bc05760e01b179052905160009182916001600160a01b03871691610955916125d7565b600060405180830381855afa9150503d8060008114610990576040519150601f19603f3d011682016040523d82523d6000602084013e610995565b606091505b50915091508115806109a657508051155b156109cf57604051630a293ffd60e41b81526001600160a01b03861660048201526024016106c9565b6060818060200190518101906109e591906125f3565b945090506109f2816117e6565b94508351600003610a5e576040805160018082528183019092529060208083019080368337505060025482519296506001600160a01b031691869150600090610a3d57610a3d612707565b60200260200101906001600160a01b031690816001600160a01b0316815250505b845160ff16600003610a7a57610a74845161185d565b60ff1685525b505050915091565b610a8a611361565b610a94600061188f565b565b6000610aa28383611112565b905060008383604051610ab69291906125c7565b60405180910390209050610aca8282611223565b600081815260046020526040812080546001600160a01b0319163317905560a0830151610af6906111b3565b905080602001513414610b2b5760208101516040516366f7ba5d60e01b815234600482015260248101919091526044016106c9565b8051861015610b3957805195505b60005a9050868111610b685760405163176b11a760e21b815260048101829052602481018890526044016106c9565b60808401516001600160a01b0316630421a1f088348760000151886060015189604001518a60c001516040518763ffffffff1660e01b8152600401610bb0949392919061271d565b6000604051808303818589803b158015610bc957600080fd5b5088f1158015610bdd573d6000803e3d6000fd5b50505050505083608001518460600151847f6bca840947c9cad2cc8a66e663c1ca33d73c416b8a8d7e74345a1106b74a81fb87604001518860000151604051610c3c9291906001600160401b0392831681529116602082015260400190565b60405180910390a450505050505050565b6000818152600460205260408120546001600160a01b031680610c865760405163e99eb48d60e01b8152600481018490526024016106c9565b60008382604051602001610cad9291909182526001600160a01b0316602082015260400190565b60408051808303601f19018152908290528051602082012063156c638360e11b8352600483015291507f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a116001600160a01b031690632ad8c706906024016020604051808303816000875af1158015610d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4d9190612759565b6040516001600160401b03821681529093506001600160a01b0383169085907fab644d167c2c65a7ca17d6920e7681356b90f09279e2b7dc4c714b826ea4fbcc9060200160405180910390a35050919050565b610da8611361565b6001600160a01b038116610dcf57604051633184f16960e21b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527fa42a6dc10e430cab5d4ba037ea6d7eee30240c6b6d7dd5b12a3d2acf41e7264f9060200161083a565b6000610e28886118df565b506001600160a01b038716610e505760405163146fd3c560e21b815260040160405180910390fd5b610e8f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111b392505050565b5060405163b8ba4ba160e01b81526001600160a01b037f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a11169063b8ba4ba190610ee0908b908a908a906004016127bf565b602060405180830381865afa158015610efd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2191906127eb565b90506000610f2f8484611960565b604051634b7ed26d60e11b81529091506001600160a01b038916906396fda4da90610f64908c9085908a908a9060040161282d565b602060405180830381865afa158015610f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa591906127eb565b610faf9083612856565b9998505050505050505050565b6040805180820190915260008082526020820152610738826111b3565b60606107386001610fe984611987565b611a0b565b610ff6611361565b6001600160a01b03811661102057604051631e4fbdf760e01b8152600060048201526024016106c9565b6110298161188f565b50565b611034611361565b6001600160401b038216600081815260036020908152604091829020849055815192835282018390527ffdc2498138df0de25c8fc9bd75bb8e856dac69aaf28d3dd5e0fc48e5e9f6e93f910160405180910390a15050565b60006004600084846040516110a29291906125c7565b60408051918290039091208252602082019290925201600020546001600160a01b03169392505050565b600080600060048451106110ec5760208401516001600160e01b03191692505b60248451106110fd57602484015191505b60448451106106905750604492909201519092565b61111a611ecf565b60006111268484611a37565b905061ffff811660011461115a576040516316d8807d60e11b815261ffff82166004820152600160248201526044016106c9565b61116c6111678585611a68565b611aaa565b91504682602001516001600160401b0316146111ac57602082015160405163eaea034560e01b81526001600160401b0390911660048201526024016106c9565b5092915050565b604080518082019091526000808252602082015260006111d283611b0b565b9050600161ffff8216101561120057604051632b346f3760e01b815261ffff821660048201526024016106c9565b61120983611b3d565b80602001905181019061121c9190612877565b9392505050565b600061123283600001516118df565b6000838152600460205260409020549091506001600160a01b03161561126e5760405163d80aeb9160e01b8152600481018390526024016106c9565b604080516060808201835285516001600160401b039081168352868401511660208084019190915283518082018690528085018790528451808203860181529201845281519101209181019190915260808401516000806112ce836108b6565b9150915060006112dd83611be6565b90506112e98186611c28565b60006001600160a01b03821615611304578360200151611307565b60005b65ffffffffffff169050600061131e848884611cfe565b855190915060ff16811015611355578451604051632889e35f60e11b81526004810183905260ff90911660248201526044016106c9565b50505050505050505050565b6000546001600160a01b03163314610a945760405163118cdaa760e01b81523360048201526024016106c9565b60408051808201909152600080825260208201526113ab8a6118df565b5060008990036113ce576040516330014e4760e21b815260040160405180910390fd5b6001600160a01b0388166113f55760405163146fd3c560e21b815260040160405180910390fd5b61143485858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111b392505050565b5060405163b8ba4ba160e01b81526000906001600160a01b037f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a11169063b8ba4ba190611488908e908c908c906004016127bf565b602060405180830381865afa1580156114a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c991906127eb565b9050803410156114f55760405163457bf1e160e11b8152346004820152602481018290526044016106c9565b7f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a116001600160a01b031663f338140e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611553573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115779190612759565b82602001906001600160401b031690816001600160401b0316815250506000611611338d8d86602001518b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c9081908401838280828437600092019190915250611e2092505050565b905061161c81610fd9565b8051906020012083600001818152505060007f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a116001600160a01b0316635fecf58d84846020015187600001518e8e6040518663ffffffff1660e01b815260040161168994939291906128c5565b60206040518083038185885af11580156116a7573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906116cc9190612759565b905083602001516001600160401b0316816001600160401b0316146116f3576116f36128ee565b50602081015134839003906001600160a01b038c16906358efb47d90839061171b8b8a611960565b88516040516001600160e01b031960e087901b168152611744939291908f908f90600401612904565b6000604051808303818588803b15801561175d57600080fd5b505af1158015611771573d6000803e3d6000fd5b50505050508160800151826060015185600001517f4085591259df9982b703db65d112e8413b755dc4e74984fc5132fe4220fede268760200151866020015188878960a001518a60c001516040516117ce9695949392919061293e565b60405180910390a45050509998505050505050505050565b60408051608081018252600080825260208201819052918101829052606081018290529061181383611b0b565b9050600161ffff8216101561184157604051635b72a46360e11b815261ffff821660048201526024016106c9565b61184a83611b3d565b80602001905181019061121c9190612999565b600060ff82111561188b576040516306dfcc6560e41b815260086004820152602481018390526044016106c9565b5090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600046826001600160401b03160361191557604051636b0dc00560e11b81526001600160401b03831660048201526024016106c9565b506001600160401b0381166000908152600360205260408120549081900361195b57604051632e3a383760e21b81526001600160401b03831660048201526024016106c9565b919050565b6000601f19601f830116601f19601f85011661197d9060e2612856565b61121c9190612856565b805160208201516040808401516060936001600160401b039091169290911b6fffffffffffffffff00000000000000001660809190911b67ffffffffffffffff60801b161717826060015183608001518460a001518560c001516040516020016119f5959493929190612a24565b6040516020818303038152906040529050919050565b60608282604051602001611a20929190612a67565b604051602081830303815290604052905092915050565b60006002821015611a5f578282604051635840c5b160e11b81526004016106c9929190612a97565b50503560f01c90565b3660006002831015611a91578383604051635840c5b160e11b81526004016106c9929190612a97565b611a9e8360028187612aab565b915091505b9250929050565b611ab2611ecf565b6000611ac083850185612ad5565b60c087015260a0860152608085015260608401529050611ae981608081901c91604082901c9190565b6001600160401b03908116604086015290811660208501521682525092915050565b6000600282511015611b325781604051635840c5b160e11b81526004016106c99190612566565b506020015160f01c90565b6060600282511015611b645781604051635840c5b160e11b81526004016106c99190612566565b815160011901806001600160401b03811115611b8257611b82611f0d565b6040519080825280601f01601f191660200182016040528015611bac576020820181803683370190505b50915060008160208401836022870160045afa905080611bdf5760405163080f227d60e11b815260040160405180910390fd5b5050919050565b604081015160009060ff16611bfd57506000919050565b600160ff16826040015160ff1603611c205750506001546001600160a01b031690565b506060015190565b6001600160a01b03821615611cfa576040516387c59c6f60e01b81526000906001600160a01b037f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a1116906387c59c6f90611c889086908690600401612b55565b602060405180830381865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc991906127eb565b90506000198103611cf8576040516309d854e960e31b81526001600160a01b03841660048201526024016106c9565b505b5050565b6000805b8451811015611e18576000858281518110611d1f57611d1f612707565b6020026020010151905060007f0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a116001600160a01b03166387c59c6f83886040518363ffffffff1660e01b8152600401611d79929190612b55565b602060405180830381865afa158015611d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dba91906127eb565b905080611dc8575050611e10565b6000198103611df5576040516309d854e960e31b81526001600160a01b03831660048201526024016106c9565b42611e008683612856565b1015611e0d578360010193505b50505b600101611d02565b509392505050565b611e28611ecf565b6040518060e00160405280611e3c46611e99565b6001600160401b03168152602001876001600160401b03168152602001856001600160401b03168152602001611e78896001600160a01b031690565b81526020018681526020018481526020018381525090509695505050505050565b60006001600160401b0382111561188b57604080516306dfcc6560e41b81526004810191909152602481018390526044016106c9565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082019290925260a0810182905260c081019190915290565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715611f4557611f45611f0d565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611f7357611f73611f0d565b604052919050565b6001600160401b038116811461102957600080fd5b803561195b81611f7b565b60006001600160401b03821115611fb457611fb4611f0d565b50601f01601f191660200190565b600082601f830112611fd357600080fd5b8135611fe6611fe182611f9b565b611f4b565b818152846020838601011115611ffb57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561202a57600080fd5b81356001600160401b038082111561204157600080fd5b9083019060e0828603121561205557600080fd5b61205d611f23565b61206683611f90565b815261207460208401611f90565b602082015261208560408401611f90565b6040820152606083013560608201526080830135608082015260a0830135828111156120b057600080fd5b6120bc87828601611fc2565b60a08301525060c0830135828111156120d457600080fd5b6120e087828601611fc2565b60c08301525095945050505050565b606081016007851061211157634e487b7160e01b600052602160045260246000fd5b938152602081019290925260409091015290565b60006020828403121561213757600080fd5b813561121c81611f7b565b60008083601f84011261215457600080fd5b5081356001600160401b0381111561216b57600080fd5b602083019150836020828501011115611aa357600080fd5b6000806020838503121561219657600080fd5b82356001600160401b038111156121ac57600080fd5b6121b885828601612142565b90969095509350505050565b6001600160a01b038116811461102957600080fd5b6000602082840312156121eb57600080fd5b813561121c816121c4565b60008083601f84011261220857600080fd5b5081356001600160401b0381111561221f57600080fd5b6020830191508360208260051b8501011115611aa357600080fd5b600080600080600080600080600060c08a8c03121561225857600080fd5b893561226381611f7b565b985060208a0135612273816121c4565b975060408a0135612283816121c4565b965060608a01356001600160401b038082111561229f57600080fd5b6122ab8d838e016121f6565b909850965060808c01359150808211156122c457600080fd5b6122d08d838e01612142565b909650945060a08c01359150808211156122e957600080fd5b506122f68c828d01612142565b915080935050809150509295985092959850929598565b600080600080600080600080600060c08a8c03121561232b57600080fd5b893561233681611f7b565b985060208a0135975060408a0135612283816121c4565b600060a0820160ff8551168352602065ffffffffffff602087015116602085015260ff6040870151166040850152606086015160018060a01b03808216606087015260a06080870152839150865180855260c08701925060208801945060005b818110156123cb5785518316845294840194928401926001016123ad565b509198975050505050505050565b6000806000604084860312156123ee57600080fd5b8335925060208401356001600160401b0381111561240b57600080fd5b61241786828701612142565b9497909650939450505050565b60006020828403121561243657600080fd5b5035919050565b600080600080600080600060a0888a03121561245857600080fd5b873561246381611f7b565b96506020880135612473816121c4565b955060408801356001600160401b038082111561248f57600080fd5b61249b8b838c016121f6565b909750955060608a01359150808211156124b457600080fd5b506124c18a828b01612142565b989b979a50959894979596608090950135949350505050565b6000602082840312156124ec57600080fd5b81356001600160401b0381111561250257600080fd5b61250e84828501611fc2565b949350505050565b60005b83811015612531578181015183820152602001612519565b50506000910152565b60008151808452612552816020860160208601612516565b601f01601f19169290920160200192915050565b60208152600061121c602083018461253a565b6000806040838503121561258c57600080fd5b823561259781611f7b565b946020939093013593505050565b6000602082840312156125b757600080fd5b8151801515811461121c57600080fd5b8183823760009101908152919050565b600082516125e9818460208701612516565b9190910192915050565b6000806040838503121561260657600080fd5b82516001600160401b038082111561261d57600080fd5b818501915085601f83011261263157600080fd5b81516020612641611fe183611f9b565b828152888284870101111561265557600080fd5b61266483838301848801612516565b8782015190965093508284111561267a57600080fd5b838701935087601f85011261268e57600080fd5b83519150828211156126a2576126a2611f0d565b8160051b92506126b3818401611f4b565b82815292840181019281810190898511156126cd57600080fd5b948201945b848610156126f757855193506126e7846121c4565b83825294820194908201906126d2565b8096505050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b60006001600160401b0380871683528560208401528085166040840152506080606083015261274f608083018461253a565b9695505050505050565b60006020828403121561276b57600080fd5b815161121c81611f7b565b8183526000602080850194508260005b858110156127b4578135612799816121c4565b6001600160a01b031687529582019590820190600101612786565b509495945050505050565b6001600160401b03841681526040602082015260006127e2604083018486612776565b95945050505050565b6000602082840312156127fd57600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160401b038516815283602082015260606040820152600061274f606083018486612804565b8082018082111561073857634e487b7160e01b600052601160045260246000fd5b60006040828403121561288957600080fd5b604051604081018181106001600160401b03821117156128ab576128ab611f0d565b604052825181526020928301519281019290925250919050565b6001600160401b038516815283602082015260606040820152600061274f606083018486612776565b634e487b7160e01b600052600160045260246000fd5b6001600160401b0386168152846020820152836040820152608060608201526000612933608083018486612804565b979650505050505050565b60006001600160401b03808916835280881660208401525085604083015284606083015260c0608083015261297660c083018561253a565b82810360a0840152610faf818561253a565b805160ff8116811461195b57600080fd5b6000608082840312156129ab57600080fd5b604051608081018181106001600160401b03821117156129cd576129cd611f0d565b6040526129d983612988565b8152602083015165ffffffffffff811681146129f457600080fd5b6020820152612a0560408401612988565b60408201526060830151612a18816121c4565b60608201529392505050565b85815284602082015283604082015260a060608201526000612a4960a083018561253a565b8281036080840152612a5b818561253a565b98975050505050505050565b61ffff60f01b8360f01b16815260008251612a89816002850160208701612516565b919091016002019392505050565b60208152600061250e602083018486612804565b60008085851115612abb57600080fd5b83861115612ac857600080fd5b5050820193919092039150565b600080600080600060a08688031215612aed57600080fd5b85359450602086013593506040860135925060608601356001600160401b0380821115612b1957600080fd5b612b2589838a01611fc2565b93506080880135915080821115612b3b57600080fd5b50612b4888828901611fc2565b9150509295509295909350565b6001600160a01b0392909216825280516001600160401b0390811660208085019190915282015116604080840191909152015160608201526080019056fea264697066735822122075b5d045844692116640851ae4ef6651244619dbe89fbafc50cdf3322fcd0c8b64736f6c63430008180033

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

0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a11000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4

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

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002def303ea27a3674bb3a5d017e60b2ef43312a11
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
[ 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.