Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 666 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Interchain Execu... | 5711637 | 341 days ago | IN | 0 ETH | 0.00009943 | ||||
Interchain Execu... | 5711635 | 341 days ago | IN | 0 ETH | 0.00009948 | ||||
Interchain Execu... | 5711633 | 341 days ago | IN | 0 ETH | 0.00009948 | ||||
Interchain Execu... | 5711631 | 341 days ago | IN | 0 ETH | 0.00009949 | ||||
Interchain Execu... | 5711629 | 341 days ago | IN | 0 ETH | 0.00009949 | ||||
Interchain Execu... | 5711627 | 341 days ago | IN | 0 ETH | 0.00009952 | ||||
Interchain Execu... | 5711625 | 341 days ago | IN | 0 ETH | 0.00009953 | ||||
Interchain Execu... | 5711622 | 341 days ago | IN | 0 ETH | 0.0000996 | ||||
Interchain Execu... | 5711621 | 341 days ago | IN | 0 ETH | 0.00009957 | ||||
Interchain Execu... | 5711619 | 341 days ago | IN | 0 ETH | 0.0000996 | ||||
Interchain Execu... | 5711617 | 341 days ago | IN | 0 ETH | 0.00009961 | ||||
Interchain Execu... | 5711615 | 341 days ago | IN | 0 ETH | 0.00009961 | ||||
Interchain Execu... | 5711614 | 341 days ago | IN | 0 ETH | 0.00036759 | ||||
Interchain Execu... | 5711612 | 341 days ago | IN | 0 ETH | 0.00036768 | ||||
Interchain Execu... | 5711610 | 341 days ago | IN | 0 ETH | 0.00036771 | ||||
Interchain Execu... | 5711608 | 341 days ago | IN | 0 ETH | 0.00036772 | ||||
Interchain Execu... | 5711606 | 341 days ago | IN | 0 ETH | 0.00036747 | ||||
Interchain Execu... | 5711604 | 341 days ago | IN | 0 ETH | 0.00036758 | ||||
Interchain Execu... | 5711602 | 341 days ago | IN | 0 ETH | 0.00036732 | ||||
Interchain Execu... | 5711600 | 341 days ago | IN | 0 ETH | 0.00036728 | ||||
Interchain Execu... | 5711598 | 341 days ago | IN | 0 ETH | 0.00036735 | ||||
Interchain Execu... | 5711596 | 341 days ago | IN | 0 ETH | 0.00036737 | ||||
Interchain Execu... | 5711594 | 341 days ago | IN | 0 ETH | 0.00036725 | ||||
Interchain Execu... | 5711592 | 341 days ago | IN | 0 ETH | 0.00036724 | ||||
Interchain Execu... | 5711590 | 341 days ago | IN | 0 ETH | 0.00036716 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Add Execution Fe... | 5711614 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711614 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711614 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711612 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711612 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711612 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711610 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711610 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711610 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711608 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711608 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711608 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711606 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711606 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711606 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711604 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711604 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711604 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711602 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711602 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711602 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711600 | 341 days ago | 0.0000005 ETH | ||||
Write Entry With... | 5711600 | 341 days ago | 0.0000001 ETH | ||||
Interchain Send | 5711600 | 341 days ago | 0.0000006 ETH | ||||
Add Execution Fe... | 5711598 | 341 days ago | 0.0000005 ETH |
Loading...
Loading
Contract Name:
InterchainClientV1
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {InterchainClientV1Events} from "./events/InterchainClientV1Events.sol"; import {IExecutionFees} from "./interfaces/IExecutionFees.sol"; import {IExecutionService} from "./interfaces/IExecutionService.sol"; import {IInterchainApp} from "./interfaces/IInterchainApp.sol"; import {IInterchainClientV1} from "./interfaces/IInterchainClientV1.sol"; import {IInterchainDB} from "./interfaces/IInterchainDB.sol"; import {AppConfigV1, AppConfigLib} from "./libs/AppConfig.sol"; import {InterchainEntry} from "./libs/InterchainEntry.sol"; import { InterchainTransaction, InterchainTxDescriptor, InterchainTransactionLib } from "./libs/InterchainTransaction.sol"; import {OptionsLib, OptionsV1} from "./libs/Options.sol"; import {TypeCasts} from "./libs/TypeCasts.sol"; import {VersionedPayloadLib} from "./libs/VersionedPayload.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; /** * @title InterchainClientV1 * @dev Implements the operations of the Interchain Execution Layer. */ contract InterchainClientV1 is Ownable, InterchainClientV1Events, IInterchainClientV1 { using AppConfigLib for bytes; using OptionsLib for bytes; using VersionedPayloadLib for bytes; /// @notice Version of the InterchainClient contract. Sent and received transactions must have the same version. uint16 public constant CLIENT_VERSION = 1; /// @notice Address of the InterchainDB contract, set at the time of deployment. address public immutable INTERCHAIN_DB; /// @notice Address of the contract that handles execution fees. Can be updated by the owner. address public executionFees; /// @dev Address of the InterchainClient contract on the remote chain mapping(uint256 chainId => bytes32 remoteClient) internal _linkedClient; /// @dev Executor address that completed the transaction. Address(0) if not executed yet. mapping(bytes32 transactionId => address executor) internal _txExecutor; constructor(address interchainDB, address owner_) Ownable(owner_) { INTERCHAIN_DB = interchainDB; } // @inheritdoc IInterchainClientV1 function setExecutionFees(address executionFees_) external onlyOwner { executionFees = executionFees_; emit ExecutionFeesSet(executionFees_); } // @inheritdoc IInterchainClientV1 function setLinkedClient(uint256 chainId, bytes32 client) external onlyOwner { _linkedClient[chainId] = client; emit LinkedClientSet(chainId, client); } // @inheritdoc IInterchainClientV1 function interchainSend( uint256 dstChainId, bytes32 receiver, address srcExecutionService, address[] calldata srcModules, bytes calldata options, bytes calldata message ) external payable returns (InterchainTxDescriptor memory desc) { return _interchainSend(dstChainId, receiver, srcExecutionService, srcModules, options, message); } // @inheritdoc IInterchainClientV1 function interchainSendEVM( uint256 dstChainId, address receiver, address srcExecutionService, address[] calldata srcModules, bytes calldata options, bytes calldata message ) external payable returns (InterchainTxDescriptor memory desc) { bytes32 receiverBytes32 = TypeCasts.addressToBytes32(receiver); return _interchainSend(dstChainId, receiverBytes32, srcExecutionService, srcModules, options, message); } // TODO: Handle the case where receiver does not implement the IInterchainApp interface (or does not exist at all) // @inheritdoc IInterchainClientV1 function interchainExecute( uint256 gasLimit, bytes calldata transaction, bytes32[] calldata proof ) external payable { InterchainTransaction memory icTx = _assertCorrectVersion(transaction); bytes32 transactionId = keccak256(transaction); _assertExecutable(icTx, transactionId, proof); _txExecutor[transactionId] = msg.sender; OptionsV1 memory decodedOptions = icTx.options.decodeOptionsV1(); if (msg.value != decodedOptions.gasAirdrop) { revert InterchainClientV1__IncorrectMsgValue(msg.value, decodedOptions.gasAirdrop); } // We should always use at least as much as the requested gas limit. // The executor can specify a higher gas limit if they wanted. if (decodedOptions.gasLimit > gasLimit) gasLimit = decodedOptions.gasLimit; // Check the the Executor has provided big enough gas limit for the whole transaction. if (gasleft() <= gasLimit) { revert InterchainClientV1__NotEnoughGasSupplied(); } // Pass the full msg.value to the app: we have already checked that it matches the requested gas airdrop. IInterchainApp(TypeCasts.bytes32ToAddress(icTx.dstReceiver)).appReceive{gas: gasLimit, value: msg.value}({ srcChainId: icTx.srcChainId, sender: icTx.srcSender, dbNonce: icTx.dbNonce, entryIndex: icTx.entryIndex, message: icTx.message }); emit InterchainTransactionReceived( transactionId, icTx.dbNonce, icTx.entryIndex, icTx.srcChainId, icTx.srcSender, icTx.dstReceiver ); } /// @inheritdoc IInterchainClientV1 function writeExecutionProof(bytes32 transactionId) external returns (uint256 dbNonce, uint64 entryIndex) { address executor = _txExecutor[transactionId]; if (executor == address(0)) { revert InterchainClientV1__TxNotExecuted(transactionId); } bytes memory proof = abi.encode(transactionId, executor); (dbNonce, entryIndex) = IInterchainDB(INTERCHAIN_DB).writeEntry(keccak256(proof)); emit ExecutionProofWritten(transactionId, dbNonce, entryIndex, executor); } // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════ // @inheritdoc IInterchainClientV1 function isExecutable(bytes calldata encodedTx, bytes32[] calldata proof) external view returns (bool) { InterchainTransaction memory icTx = _assertCorrectVersion(encodedTx); // Check that options could be decoded icTx.options.decodeOptionsV1(); bytes32 transactionId = keccak256(encodedTx); _assertExecutable(icTx, transactionId, proof); return true; } // @inheritdoc IInterchainClientV1 function getExecutor(bytes calldata encodedTx) external view returns (address) { return _txExecutor[keccak256(encodedTx)]; } // @inheritdoc IInterchainClientV1 function getExecutorById(bytes32 transactionId) external view returns (address) { return _txExecutor[transactionId]; } // @inheritdoc IInterchainClientV1 function getInterchainFee( uint256 dstChainId, address srcExecutionService, address[] calldata srcModules, bytes calldata options, uint256 messageLen ) external view returns (uint256 fee) { _assertLinkedClient(dstChainId); // Check that options could be decoded on destination chain options.decodeOptionsV1(); // Verification fee from InterchainDB fee = IInterchainDB(INTERCHAIN_DB).getInterchainFee(dstChainId, srcModules); // Add execution fee, if ExecutionService is provided if (srcExecutionService != address(0)) { uint256 payloadSize = InterchainTransactionLib.payloadSize(options.length, messageLen); fee += IExecutionService(srcExecutionService).getExecutionFee(dstChainId, payloadSize, options); } } /// @inheritdoc IInterchainClientV1 function getLinkedClient(uint256 chainId) external view returns (bytes32) { if (chainId == block.chainid) { revert InterchainClientV1__NotRemoteChainId(chainId); } return _linkedClient[chainId]; } /// @inheritdoc IInterchainClientV1 function getLinkedClientEVM(uint256 chainId) external view returns (address linkedClientEVM) { if (chainId == block.chainid) { revert InterchainClientV1__NotRemoteChainId(chainId); } bytes32 linkedClient = _linkedClient[chainId]; linkedClientEVM = TypeCasts.bytes32ToAddress(linkedClient); // Check that the linked client address fits into the EVM address space if (TypeCasts.addressToBytes32(linkedClientEVM) != linkedClient) { revert InterchainClientV1__NotEVMClient(linkedClient); } } /// @notice Decodes the encoded options data into a OptionsV1 struct. function decodeOptions(bytes memory encodedOptions) external view returns (OptionsV1 memory) { return encodedOptions.decodeOptionsV1(); } /// @notice Encodes the transaction data into a bytes format. function encodeTransaction(InterchainTransaction memory icTx) public pure returns (bytes memory) { return VersionedPayloadLib.encodeVersionedPayload({ version: CLIENT_VERSION, payload: InterchainTransactionLib.encodeTransaction(icTx) }); } // ═════════════════════════════════════════════════ INTERNAL ══════════════════════════════════════════════════════ /// @dev Internal logic for sending a message to another chain. function _interchainSend( uint256 dstChainId, bytes32 receiver, address srcExecutionService, address[] calldata srcModules, bytes calldata options, bytes calldata message ) internal returns (InterchainTxDescriptor memory desc) { _assertLinkedClient(dstChainId); if (receiver == 0) revert InterchainClientV1__ZeroReceiver(); // Check that options could be decoded on destination chain options.decodeOptionsV1(); uint256 verificationFee = IInterchainDB(INTERCHAIN_DB).getInterchainFee(dstChainId, srcModules); if (msg.value < verificationFee) { revert InterchainClientV1__FeeAmountTooLow(msg.value, verificationFee); } (desc.dbNonce, desc.entryIndex) = IInterchainDB(INTERCHAIN_DB).getNextEntryIndex(); InterchainTransaction memory icTx = InterchainTransactionLib.constructLocalTransaction({ srcSender: msg.sender, dstReceiver: receiver, dstChainId: dstChainId, dbNonce: desc.dbNonce, entryIndex: desc.entryIndex, options: options, message: message }); desc.transactionId = keccak256(encodeTransaction(icTx)); // Sanity check: nonce returned from DB should match the nonce used to construct the transaction { (uint256 dbNonce, uint64 entryIndex) = IInterchainDB(INTERCHAIN_DB).writeEntryWithVerification{ value: verificationFee }(icTx.dstChainId, desc.transactionId, srcModules); assert(dbNonce == desc.dbNonce && entryIndex == desc.entryIndex); } uint256 executionFee; unchecked { executionFee = msg.value - verificationFee; } if (executionFee > 0) { IExecutionFees(executionFees).addExecutionFee{value: executionFee}(icTx.dstChainId, desc.transactionId); } // TODO: consider disallowing the use of empty srcExecutionService if (srcExecutionService != address(0)) { IExecutionService(srcExecutionService).requestExecution({ dstChainId: dstChainId, txPayloadSize: InterchainTransactionLib.payloadSize(options.length, message.length), transactionId: desc.transactionId, executionFee: executionFee, options: options }); address srcExecutorEOA = IExecutionService(srcExecutionService).executorEOA(); IExecutionFees(executionFees).recordExecutor(icTx.dstChainId, desc.transactionId, srcExecutorEOA); } emit InterchainTransactionSent( desc.transactionId, icTx.dbNonce, icTx.entryIndex, icTx.dstChainId, icTx.srcSender, icTx.dstReceiver, verificationFee, executionFee, icTx.options, icTx.message ); } // ══════════════════════════════════════════════ INTERNAL VIEWS ═══════════════════════════════════════════════════ /// @dev Asserts that the transaction is executable. function _assertExecutable( InterchainTransaction memory icTx, bytes32 transactionId, bytes32[] calldata proof ) internal view { bytes32 linkedClient = _assertLinkedClient(icTx.srcChainId); if (icTx.dstChainId != block.chainid) { revert InterchainClientV1__IncorrectDstChainId(icTx.dstChainId); } if (_txExecutor[transactionId] != address(0)) { revert InterchainClientV1__TxAlreadyExecuted(transactionId); } // Construct expected entry based on icTransaction data InterchainEntry memory icEntry = InterchainEntry({ srcChainId: icTx.srcChainId, dbNonce: icTx.dbNonce, entryIndex: icTx.entryIndex, srcWriter: linkedClient, dataHash: transactionId }); (bytes memory encodedAppConfig, address[] memory approvedDstModules) = IInterchainApp(TypeCasts.bytes32ToAddress(icTx.dstReceiver)).getReceivingConfig(); AppConfigV1 memory appConfig = encodedAppConfig.decodeAppConfigV1(); if (appConfig.requiredResponses == 0) { revert InterchainClientV1__ZeroRequiredResponses(); } uint256 responses = _getFinalizedResponsesCount(approvedDstModules, icEntry, proof, appConfig.optimisticPeriod); if (responses < appConfig.requiredResponses) { revert InterchainClientV1__NotEnoughResponses(responses, appConfig.requiredResponses); } } /// @dev Asserts that the chain is linked and returns the linked client address. function _assertLinkedClient(uint256 chainId) internal view returns (bytes32 linkedClient) { if (chainId == block.chainid) { revert InterchainClientV1__NotRemoteChainId(chainId); } linkedClient = _linkedClient[chainId]; if (linkedClient == 0) { revert InterchainClientV1__NoLinkedClient(chainId); } } /** * @dev Calculates the number of responses that are considered finalized within the optimistic time period. * @param approvedModules Approved modules that could have confirmed the entry. * @param icEntry The InterchainEntry to confirm. * @param optimisticPeriod The time period in seconds within which a response is considered valid. * @return finalizedResponses The count of responses that are finalized within the optimistic time period. */ function _getFinalizedResponsesCount( address[] memory approvedModules, InterchainEntry memory icEntry, bytes32[] calldata proof, uint256 optimisticPeriod ) internal view returns (uint256 finalizedResponses) { for (uint256 i = 0; i < approvedModules.length; ++i) { uint256 confirmedAt = IInterchainDB(INTERCHAIN_DB).checkVerification(approvedModules[i], icEntry, proof); // checkVerification() returns 0 if entry hasn't been confirmed by the module, so we check for that as well if (confirmedAt != 0 && confirmedAt + optimisticPeriod < block.timestamp) { ++finalizedResponses; } } } /// @dev Asserts that the transaction version is correct. Returns the decoded transaction for chaining purposes. function _assertCorrectVersion(bytes calldata versionedTx) internal pure returns (InterchainTransaction memory icTx) { uint16 version = versionedTx.getVersion(); if (version != CLIENT_VERSION) { revert InterchainClientV1__InvalidTransactionVersion(version); } icTx = InterchainTransactionLib.decodeTransaction(versionedTx.getPayload()); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract InterchainClientV1Events { event ExecutionFeesSet(address executionFees); event LinkedClientSet(uint256 chainId, bytes32 client); // TODO: figure out indexing event InterchainTransactionSent( bytes32 indexed transactionId, uint256 indexed dbNonce, uint64 indexed entryIndex, uint256 dstChainId, bytes32 srcSender, bytes32 dstReceiver, uint256 verificationFee, uint256 executionFee, bytes options, bytes message ); event InterchainTransactionReceived( bytes32 indexed transactionId, uint256 indexed dbNonce, uint64 indexed entryIndex, uint256 srcChainId, bytes32 srcSender, bytes32 dstReceiver ); event ExecutionProofWritten( bytes32 indexed transactionId, uint256 indexed dbNonce, uint64 indexed entryIndex, address executor ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IExecutionFees { error ExecutionFees__AlreadyRecorded(uint256 dstChainId, bytes32 transactionId, address executor); error ExecutionFees__ZeroAddress(); error ExecutionFees__ZeroAmount(); /// @notice Add the execution fee for a transaction. The attached value will be added to the /// rewards for the executor completing the transaction. /// Note: this could be used to store the execution fee for a new transaction, or to add more /// funds to the execution fee of an existing transaction. Therefore this function is payable, /// and does not implement any caller restrictions. /// @dev Will revert if the executor is already recorded for the transaction. /// @param dstChainId The chain id of the destination chain. /// @param transactionId The id of the transaction to add the execution fee to. function addExecutionFee(uint256 dstChainId, bytes32 transactionId) external payable; /// @notice Record the executor (who completed the transaction) for a transaction, /// and update the accumulated rewards for the executor. /// @dev Could only be called by the Recorder. /// @param dstChainId The chain id of the destination chain. /// @param transactionId The id of the transaction to record the executor for. /// @param executor The address of the executor who completed the transaction. function recordExecutor(uint256 dstChainId, bytes32 transactionId, address executor) external; /// @notice Allows the executor to claim their unclaimed rewards. /// @dev Will revert if the executor has no unclaimed rewards. function claimExecutionFees(address executor) external; // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════ /// @notice Get the accumulated rewards for an executor. /// @param executor The address of the executor to get the rewards for. function accumulatedRewards(address executor) external view returns (uint256 accumulated); /// @notice Get the unclaimed rewards for an executor. /// @param executor The address of the executor to get the rewards for. function unclaimedRewards(address executor) external view returns (uint256 unclaimed); /// @notice Get the total execution fee for a transaction. /// @param dstChainId The chain id of the destination chain. /// @param transactionId The id of the transaction to get the execution fee for. function executionFee(uint256 dstChainId, bytes32 transactionId) external view returns (uint256 fee); /// @notice Get the address of the recorded executor for a transaction. /// @dev Will return address(0) if the executor is not recorded. /// @param dstChainId The chain id of the destination chain. /// @param transactionId The id of the transaction to get the recorded executor for. function recordedExecutor(uint256 dstChainId, bytes32 transactionId) external view returns (address executor); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IExecutionService { /// @notice Request the execution of an Interchain Transaction on a remote chain. /// Note: the off-chain actor needs to fetch the transaction payload from the InterchainClient /// event with the same transactionId, then execute the transaction on the remote chain: /// `dstInterchainClient.executeTransaction(transactionPayload)` /// Once the execution is confirmed on the source chain, the off-chain actor will be able /// to claim `executionFee` in the ExecutionFees contract. /// @dev Could only be called by `InterchainClient` contracts. /// Will revert if the execution fee is not big enough. /// @param dstChainId The chain id of the destination chain. /// @param txPayloadSize The size of the transaction payload to use for the execution. /// @param transactionId The id of the transaction to execute. /// @param executionFee The fee paid for the execution. /// @param options The options to use for the execution. function requestExecution( uint256 dstChainId, uint256 txPayloadSize, bytes32 transactionId, uint256 executionFee, bytes memory options ) external; /// @notice Get the address of the EOA account that will be used to execute transactions on the /// remote chains. function executorEOA() external view returns (address); /// @notice Get the execution fee for executing an Interchain Transaction on a remote chain. /// @param dstChainId The chain id of the destination chain. /// @param txPayloadSize The size of the transaction payload to use for the execution. /// @param options The options to use for the execution. function getExecutionFee( uint256 dstChainId, uint256 txPayloadSize, bytes memory options ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice Minimal interface for the Interchain App to work with the Interchain Client. interface IInterchainApp { /// @notice Allows the Interchain Client to pass the message to the Interchain App. /// @dev App is responsible for keeping track of interchain clients, and must verify the message sender. /// @param srcChainId Chain ID of the source chain, where the message was sent from. /// @param sender Sender address on the source chain, as a bytes32 value. /// @param dbNonce The Interchain DB nonce of the batch containing the message entry. /// @param entryIndex The index of the message entry within the batch. /// @param message The message being sent. function appReceive( uint256 srcChainId, bytes32 sender, uint256 dbNonce, uint64 entryIndex, bytes calldata message ) external payable; /// @notice Returns the verification configuration of the Interchain App. /// @dev This configuration is used by the Interchain Client to verify that message has been confirmed /// by the Interchain Modules on the destination chain. /// Note: V1 version of AppConfig includes the required responses count, and optimistic period after which /// the message is considered confirmed by the module. Following versions may include additional fields. /// @return appConfig The versioned configuration of the Interchain App, encoded as bytes. /// @return modules The list of Interchain Modules that app is trusting to confirm the messages. function getReceivingConfig() external view returns (bytes memory appConfig, address[] memory modules); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {InterchainTxDescriptor} from "../libs/InterchainTransaction.sol"; interface IInterchainClientV1 { error InterchainClientV1__FeeAmountTooLow(uint256 actual, uint256 required); error InterchainClientV1__IncorrectDstChainId(uint256 chainId); error InterchainClientV1__IncorrectMsgValue(uint256 actual, uint256 required); error InterchainClientV1__InvalidTransactionVersion(uint16 version); error InterchainClientV1__NoLinkedClient(uint256 chainId); error InterchainClientV1__NotEnoughGasSupplied(); error InterchainClientV1__NotEnoughResponses(uint256 actual, uint256 required); error InterchainClientV1__NotEVMClient(bytes32 client); error InterchainClientV1__NotRemoteChainId(uint256 chainId); error InterchainClientV1__TxAlreadyExecuted(bytes32 transactionId); error InterchainClientV1__TxNotExecuted(bytes32 transactionId); error InterchainClientV1__ZeroReceiver(); error InterchainClientV1__ZeroRequiredResponses(); /** * @notice Sets the address of the ExecutionFees contract. * @dev Only callable by the contract owner or an authorized account. * @param executionFees_ The address of the ExecutionFees contract. */ function setExecutionFees(address executionFees_) external; /** * @notice Sets the linked client for a specific chain ID. * @dev Stores the address of the linked client in a mapping with the chain ID as the key. * @param chainId The chain ID for which the client is being set. * @param client The address of the client being linked. */ function setLinkedClient(uint256 chainId, bytes32 client) external; /** * @notice Sends a message to another chain via the Interchain Communication Protocol. * @dev Charges a fee for the message, which is payable upon calling this function: * - Verification fees: paid to every module that verifies the message. * - Execution fee: paid to the executor that executes the message. * Note: while a specific execution service is specified to request the execution of the message, * any executor is able to execute the message on destination chain, earning the execution fee. * @param dstChainId The chain ID of the destination chain. * @param receiver The address of the receiver on the destination chain. * @param srcExecutionService The address of the execution service to use for the message. * @param srcModules The source modules involved in the message sending. * @param options Execution options for the message sent, encoded as bytes, currently gas limit + native gas drop. * @param message The message being sent. * @return desc The descriptor of the sent transaction: * - transactionId: the ID of the transaction that was sent. * - dbNonce: the database nonce of the batch containing the written entry for transaction. * - entryIndex: the index of the written entry for transaction within the batch. */ function interchainSend( uint256 dstChainId, bytes32 receiver, address srcExecutionService, address[] calldata srcModules, bytes calldata options, bytes calldata message ) external payable returns (InterchainTxDescriptor memory desc); function interchainSendEVM( uint256 dstChainId, address receiver, address srcExecutionService, address[] calldata srcModules, bytes calldata options, bytes calldata message ) external payable returns (InterchainTxDescriptor memory desc); /** * @notice Executes a transaction that has been sent via the Interchain. * @dev The transaction must have been previously sent and recorded. * Transaction data includes the requested gas limit, but the executors could specify a different gas limit. * If the specified gas limit is lower than requested, the requested gas limit will be used. * Otherwise, the specified gas limit will be used. * This allows to execute the transactions with requested gas limit set too low. * @param gasLimit The gas limit to use for the execution. * @param transaction The transaction data. * @param proof The Merkle proof for transaction execution, fetched from the source chain. */ function interchainExecute( uint256 gasLimit, bytes calldata transaction, bytes32[] calldata proof ) external payable; /// @notice Writes the proof of execution for a transaction into the InterchainDB. /// @dev Will revert if the transaction has not been executed. /// @param transactionId The ID of the transaction to write the proof for. /// @return dbNonce The database nonce of the batch containing the written proof for transaction. /// @return entryIndex The index of the written proof for transaction within the batch. function writeExecutionProof(bytes32 transactionId) external returns (uint256 dbNonce, uint64 entryIndex); /** * @notice Checks if a transaction is executable. * @dev Determines if a transaction meets the criteria to be executed based on: * - If approved modules have written to the InterchainDB * - If the threshold of approved modules have been met * - If the optimistic window has passed for all modules * @param transaction The InterchainTransaction struct to be checked. * @param proof The Merkle proof for transaction execution, fetched from the source chain. * @return bool Returns true if the transaction is executable, false otherwise. */ function isExecutable(bytes calldata transaction, bytes32[] calldata proof) external view returns (bool); /// @notice Returns the fee for sending an Interchain message. /// @param dstChainId The chain ID of the destination chain. /// @param srcExecutionService The address of the execution service to use for the message. /// @param srcModules The source modules involved in the message sending. /// @param options Execution options for the message sent, currently gas limit + native gas drop. /// @param messageLen The length of the message being sent. function getInterchainFee( uint256 dstChainId, address srcExecutionService, address[] calldata srcModules, bytes calldata options, uint256 messageLen ) external view returns (uint256); /// @notice Returns the address of the executor for a transaction that has been sent to the local chain. function getExecutor(bytes calldata transaction) external view returns (address); /// @notice Returns the address of the executor for a transaction that has been sent to the local chain. function getExecutorById(bytes32 transactionId) external view returns (address); /// @notice Returns the address of the linked client (as bytes32) for a specific chain ID. /// @dev Will return 0x0 if no client is linked for the chain ID. function getLinkedClient(uint256 chainId) external view returns (bytes32); /// @notice Returns the EVM address of the linked client for a specific chain ID. /// @dev Will return 0x0 if no client is linked for the chain ID. /// Will revert if the client is not an EVM client. function getLinkedClientEVM(uint256 chainId) external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {InterchainEntry} from "../libs/InterchainEntry.sol"; import {InterchainBatch} from "../libs/InterchainBatch.sol"; interface IInterchainDB { /// @notice Struct representing a batch of entries from the remote Interchain DataBase, /// verified by the Interchain Module. /// @param verifiedAt The block timestamp at which the entry was verified by the module /// @param batchRoot The Merkle root of the batch struct RemoteBatch { uint256 verifiedAt; bytes32 batchRoot; } error InterchainDB__BatchDoesNotExist(uint256 dbNonce); error InterchainDB__BatchNotFinalized(uint256 dbNonce); error InterchainDB__ConflictingBatches(address module, bytes32 existingBatchRoot, InterchainBatch newBatch); error InterchainDB__EntryIndexOutOfRange(uint256 dbNonce, uint64 entryIndex, uint64 batchSize); error InterchainDB__IncorrectFeeAmount(uint256 actualFee, uint256 expectedFee); error InterchainDB__InvalidBatchVersion(uint16 version); error InterchainDB__InvalidEntryRange(uint256 dbNonce, uint64 start, uint64 end); error InterchainDB__NoModulesSpecified(); error InterchainDB__SameChainId(uint256 chainId); /// @notice Write data to the Interchain DataBase as a new entry in the current batch. /// Note: there are no guarantees that this entry will be available for reading on any of the remote chains. /// Use `requestBatchVerification` to ensure that the entry is available for reading on the destination chain. /// @param dataHash The hash of the data to be written to the Interchain DataBase as a new entry /// @return dbNonce The database nonce of the batch containing the written entry /// @return entryIndex The index of the written entry within the batch function writeEntry(bytes32 dataHash) external returns (uint256 dbNonce, uint64 entryIndex); /// @notice Request the given Interchain Modules to verify an existing batch. /// If the batch is not finalized, the module will verify it after finalization. /// For the finalized batch the batch root is already available, and the module can verify it immediately. /// Note: every module has a separate fee paid in the native gas token of the source chain, /// and `msg.value` must be equal to the sum of all fees. /// Note: this method is permissionless, and anyone can request verification for any batch. /// @dev Will revert if the batch with the given nonce does not exist. /// @param dstChainId The chain id of the destination chain /// @param dbNonce The database nonce of the existing batch /// @param srcModules The source chain addresses of the Interchain Modules to use for verification function requestBatchVerification( uint256 dstChainId, uint256 dbNonce, address[] memory srcModules ) external payable; /// @notice Write data to the Interchain DataBase as a new entry in the current batch. /// Then request the Interchain Modules to verify the batch containing the written entry on the destination chain. /// See `writeEntry` and `requestBatchVerification` for more details. /// @dev Will revert if the empty array of modules is provided. /// @param dstChainId The chain id of the destination chain /// @param dataHash The hash of the data to be written to the Interchain DataBase as a new entry /// @param srcModules The source chain addresses of the Interchain Modules to use for verification /// @return dbNonce The database nonce of the batch containing the written entry /// @return entryIndex The index of the written entry within the batch function writeEntryWithVerification( uint256 dstChainId, bytes32 dataHash, address[] memory srcModules ) external payable returns (uint256 dbNonce, uint64 entryIndex); /// @notice Allows the Interchain Module to verify the batch coming from the remote chain. /// Note: The DB will only accept the batch of the same version as the DB itself. /// @param versionedBatch The versioned Interchain Batch to verify function verifyRemoteBatch(bytes memory versionedBatch) external; // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════ /// @notice Get the fee for writing data to the Interchain DataBase, and verifying it on the destination chain /// using the provided Interchain Modules. /// @dev Will revert if the empty array of modules is provided. /// @param dstChainId The chain id of the destination chain /// @param srcModules The source chain addresses of the Interchain Modules to use for verification function getInterchainFee(uint256 dstChainId, address[] memory srcModules) external view returns (uint256); /// @notice Returns the list of leafs of the finalized batch with the given nonce. /// Note: the leafs are ordered by the index of the written entry in the current batch, /// and the leafs value match the value of the written entry (srcWriter + dataHash hashed together). /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized. /// @param dbNonce The database nonce of the finalized batch function getBatchLeafs(uint256 dbNonce) external view returns (bytes32[] memory); /// @notice Returns the list of leafs of the finalized batch with the given nonce, /// paginated by the given start and end indexes. The end index is exclusive. /// Note: this is useful when the batch contains a large number of leafs, and calling `getBatchLeafs` /// would result in a gas limit exceeded error. /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized. /// Will revert if the provided range is invalid. /// @param dbNonce The database nonce of the finalized batch /// @param start The start index of the paginated leafs, inclusive /// @param end The end index of the paginated leafs, exclusive function getBatchLeafsPaginated( uint256 dbNonce, uint64 start, uint64 end ) external view returns (bytes32[] memory); /// @notice Returns the size of the finalized batch with the given nonce. /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized. /// @param dbNonce The database nonce of the finalized batch function getBatchSize(uint256 dbNonce) external view returns (uint64); /// @notice Get the finalized Interchain Batch with the given nonce. /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized. /// @param dbNonce The database nonce of the finalized batch function getBatch(uint256 dbNonce) external view returns (InterchainBatch memory); /// @notice Get the Interchain Entry's value written on the local chain with the given batch nonce and entry index. /// Entry value is calculated as the hash of the writer address and the written data hash. /// Note: the batch does not have to be finalized to fetch the entry value. /// @dev Will revert if the batch with the given nonce does not exist, /// or the entry with the given index does not exist within the batch. /// @param dbNonce The database nonce of the existing batch /// @param entryIndex The index of the written entry within the batch function getEntryValue(uint256 dbNonce, uint64 entryIndex) external view returns (bytes32); /// @notice Get the Merkle proof of inclusion for the entry with the given index /// in the finalized batch with the given nonce. /// @dev Will revert if the batch with the given nonce does not exist, or is not finalized. /// Will revert if the entry with the given index does not exist within the batch. /// @param dbNonce The database nonce of the finalized batch /// @param entryIndex The index of the written entry within the batch /// @return proof The Merkle proof of inclusion for the entry function getEntryProof(uint256 dbNonce, uint64 entryIndex) external view returns (bytes32[] memory proof); /// @notice Get the nonce of the database, which is incremented every time a new batch is finalized. /// This is the nonce of the current non-finalized batch. function getDBNonce() external view returns (uint256); /// @notice Get the index of the next entry to be written to the database. /// @return dbNonce The database nonce of the batch including the next entry /// @return entryIndex The index of the next entry within that batch function getNextEntryIndex() external view returns (uint256 dbNonce, uint64 entryIndex); /// @notice Read the data written on specific source chain by a specific writer, /// and verify it on the destination chain using the provided Interchain Module. /// Note: returned zero value indicates that the module has not verified the entry. /// @param entry The Interchain Entry to read /// @param dstModule The destination chain addresses of the Interchain Modules to use for verification /// @return moduleVerifiedAt The block timestamp at which the entry was verified by the module, /// or ZERO if the module has not verified the entry. function checkVerification( address dstModule, InterchainEntry memory entry, bytes32[] memory proof ) external view returns (uint256 moduleVerifiedAt); /// @notice Get the version of the Interchain DataBase. // solhint-disable-next-line func-name-mixedcase function DB_VERSION() external pure returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {VersionedPayloadLib} from "./VersionedPayload.sol"; struct AppConfigV1 { uint256 requiredResponses; uint256 optimisticPeriod; } using AppConfigLib for AppConfigV1 global; library AppConfigLib { using VersionedPayloadLib for bytes; uint16 internal constant APP_CONFIG_V1 = 1; error AppConfigLib__IncorrectVersion(uint16 version); /// @notice Decodes app config (V1 or higher) from a bytes format back into an AppConfigV1 struct. /// @param data The app config data in bytes format. function decodeAppConfigV1(bytes memory data) internal view returns (AppConfigV1 memory) { uint16 version = data.getVersionFromMemory(); if (version < APP_CONFIG_V1) { revert AppConfigLib__IncorrectVersion(version); } // Structs of the same version will always be decoded correctly. // Following versions will be decoded correctly if they have the same fields as the previous version, // and new fields at the end: abi.decode ignores the extra bytes in the decoded payload. return abi.decode(data.getPayloadFromMemory(), (AppConfigV1)); } /// @notice Encodes V1 app config into a bytes format. /// @param appConfig The AppConfigV1 to encode. function encodeAppConfigV1(AppConfigV1 memory appConfig) internal pure returns (bytes memory) { return VersionedPayloadLib.encodeVersionedPayload(APP_CONFIG_V1, abi.encode(appConfig)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {TypeCasts} from "./TypeCasts.sol"; /// @notice Struct representing an entry in the Interchain DataBase. /// Entry has a globally unique identifier (key) and a value. /// - key: srcChainId + dbNonce + entryIndex /// - value: srcWriter + dataHash /// @param srcChainId The chain id of the source chain /// @param dbNonce The database nonce of the batch containing the entry /// @param entryIndex The index of the entry in the batch /// @param srcWriter The address of the writer on the source chain /// @param dataHash The hash of the data written on the source chain struct InterchainEntry { // TODO: can we use uint64 for chain id? uint256 srcChainId; uint256 dbNonce; uint64 entryIndex; bytes32 srcWriter; bytes32 dataHash; } using InterchainEntryLib for InterchainEntry global; library InterchainEntryLib { /// @notice Constructs an InterchainEntry struct to be written on the local chain /// @param dbNonce The database nonce of the entry on the source chain /// @param writer The address of the writer on the local chain /// @param dataHash The hash of the data written on the local chain /// @return entry The constructed InterchainEntry struct function constructLocalEntry( uint256 dbNonce, uint64 entryIndex, address writer, bytes32 dataHash ) internal view returns (InterchainEntry memory entry) { return InterchainEntry({ srcChainId: block.chainid, dbNonce: dbNonce, entryIndex: entryIndex, srcWriter: TypeCasts.addressToBytes32(writer), dataHash: dataHash }); } /// @notice Returns the globally unique identifier of the entry function entryKey(InterchainEntry memory entry) internal pure returns (bytes32) { return keccak256(abi.encode(entry.srcChainId, entry.dbNonce, entry.entryIndex)); } /// @notice Returns the value of the entry: writer + dataHash hashed together function entryValue(InterchainEntry memory entry) internal pure returns (bytes32) { return keccak256(abi.encode(entry.srcWriter, entry.dataHash)); } /// @notice Returns the globally unique identifier of the batch containing the entry function batchKey(InterchainEntry memory entry) internal pure returns (bytes32) { return keccak256(abi.encode(entry.srcChainId, entry.dbNonce)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {MathLib} from "./Math.sol"; import {TypeCasts} from "./TypeCasts.sol"; import {VersionedPayloadLib} from "./VersionedPayload.sol"; struct InterchainTransaction { uint256 srcChainId; bytes32 srcSender; uint256 dstChainId; bytes32 dstReceiver; uint256 dbNonce; uint64 entryIndex; bytes options; bytes message; } struct InterchainTxDescriptor { bytes32 transactionId; uint256 dbNonce; uint64 entryIndex; } using InterchainTransactionLib for InterchainTransaction global; library InterchainTransactionLib { using MathLib for uint256; using VersionedPayloadLib for bytes; function constructLocalTransaction( address srcSender, uint256 dstChainId, bytes32 dstReceiver, uint256 dbNonce, uint64 entryIndex, bytes memory options, bytes memory message ) internal view returns (InterchainTransaction memory transaction) { return InterchainTransaction({ srcChainId: block.chainid, srcSender: TypeCasts.addressToBytes32(srcSender), dstChainId: dstChainId, dstReceiver: dstReceiver, dbNonce: dbNonce, entryIndex: entryIndex, options: options, message: message }); } function encodeTransaction(InterchainTransaction memory transaction) internal pure returns (bytes memory) { return abi.encode(transaction); } function decodeTransaction(bytes calldata transaction) internal pure returns (InterchainTransaction memory) { return abi.decode(transaction, (InterchainTransaction)); } function payloadSize(uint256 optionsLen, uint256 messageLen) internal pure returns (uint256) { // 2 bytes are reserved for the transaction version // + 8 fields * 32 bytes (6 values for static, 2 offsets for dynamic) + 2 * 32 bytes (lengths for dynamic) = 322 // abi.encode() also prepends the global offset (which is always 0x20) if there's a dynamic field, making it 354 // Both options and message are dynamic fields, which are padded up to 32 bytes return 354 + optionsLen.roundUpToWord() + messageLen.roundUpToWord(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {VersionedPayloadLib} from "./VersionedPayload.sol"; /// @notice Struct to hold V1 of options data. /// @dev Next versions have to use the fields from the previous version and add new fields at the end. /// @param gasLimit The gas limit for the transaction. /// @param gasAirdrop The amount of gas to airdrop. struct OptionsV1 { uint256 gasLimit; uint256 gasAirdrop; } using OptionsLib for OptionsV1 global; /// @title OptionsLib /// @notice A library for encoding and decoding Interchain options related to interchain messages. library OptionsLib { using VersionedPayloadLib for bytes; uint16 internal constant OPTIONS_V1 = 1; error OptionsLib__IncorrectVersion(uint16 version); /// @notice Decodes options (V1 or higher) from a bytes format back into an OptionsV1 struct. /// @param data The options data in bytes format. function decodeOptionsV1(bytes memory data) internal view returns (OptionsV1 memory) { uint16 version = data.getVersionFromMemory(); if (version < OPTIONS_V1) { revert OptionsLib__IncorrectVersion(version); } // Structs of the same version will always be decoded correctly. // Following versions will be decoded correctly if they have the same fields as the previous version, // and new fields at the end: abi.decode ignores the extra bytes in the decoded payload. return abi.decode(data.getPayloadFromMemory(), (OptionsV1)); } /// @notice Encodes V1 options into a bytes format. /// @param options The OptionsV1 to encode. function encodeOptionsV1(OptionsV1 memory options) internal pure returns (bytes memory) { return VersionedPayloadLib.encodeVersionedPayload(OPTIONS_V1, abi.encode(options)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library TypeCasts { function addressToBytes32(address addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(addr))); } function bytes32ToAddress(bytes32 b) internal pure returns (address) { return address(uint160(uint256(b))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // solhint-disable no-inline-assembly // solhint-disable ordering library VersionedPayloadLib { /// @notice Amount of bytes reserved for the version (uint16) in the versioned payload uint256 internal constant VERSION_LENGTH = 2; error VersionedPayload__TooShort(bytes versionedPayload); error VersionedPayload__PrecompileFailed(); /// @notice Encodes the versioned payload into a single bytes array. /// @param version The payload's version. /// @param payload The payload to encode. function encodeVersionedPayload(uint16 version, bytes memory payload) internal pure returns (bytes memory) { return abi.encodePacked(version, payload); } /// @notice Extracts the version from the versioned payload (calldata reference). /// @param versionedPayload The versioned payload (calldata reference). function getVersion(bytes calldata versionedPayload) internal pure returns (uint16 version) { if (versionedPayload.length < VERSION_LENGTH) { revert VersionedPayload__TooShort(versionedPayload); } assembly { // We are only interested in the highest 16 bits of the loaded full 32 bytes word. version := shr(240, calldataload(versionedPayload.offset)) } } /// @notice Extracts the payload from the versioned payload (calldata reference). /// @dev The extracted payload is also returned as a calldata reference. /// @param versionedPayload The versioned payload. function getPayload(bytes calldata versionedPayload) internal pure returns (bytes calldata) { if (versionedPayload.length < VERSION_LENGTH) { revert VersionedPayload__TooShort(versionedPayload); } return versionedPayload[VERSION_LENGTH:]; } /// @notice Extracts the version from the versioned payload (memory reference). /// @param versionedPayload The versioned payload (memory reference). function getVersionFromMemory(bytes memory versionedPayload) internal pure returns (uint16 version) { if (versionedPayload.length < VERSION_LENGTH) { revert VersionedPayload__TooShort(versionedPayload); } assembly { // We are only interested in the highest 16 bits of the loaded full 32 bytes word. // We add 0x20 to skip the length of the bytes array. version := shr(240, mload(add(versionedPayload, 0x20))) } } /// @notice Extracts the payload from the versioned payload (memory reference). /// @dev The extracted payload is copied into a new memory location. Use `getPayload` when possible /// to avoid extra memory allocation. /// @param versionedPayload The versioned payload (memory reference). function getPayloadFromMemory(bytes memory versionedPayload) internal view returns (bytes memory payload) { if (versionedPayload.length < VERSION_LENGTH) { revert VersionedPayload__TooShort(versionedPayload); } // Figure how many bytes to copy and allocate the memory for the extracted payload. uint256 toCopy; unchecked { toCopy = versionedPayload.length - VERSION_LENGTH; } payload = new bytes(toCopy); // Use identity precompile (0x04) to copy the payload. Unlike MCOPY, this is available on all EVM chains. bool res; assembly { // We add 0x20 to skip the length of the bytes array. // We add 0x02 to skip the 2 bytes reserved for the version. // Copy the payload to the previously allocated memory. res := staticcall(gas(), 0x04, add(versionedPayload, 0x22), toCopy, add(payload, 0x20), toCopy) } if (!res) { revert VersionedPayload__PrecompileFailed(); } } }
// 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); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {VersionedPayloadLib} from "./VersionedPayload.sol"; /// @notice Struct representing a batch of entries in the Interchain DataBase. /// Batched entries are put together in a Merkle tree, which root is saved. /// Batch has a globally unique identifier (key) and a value. /// - key: srcChainId + dbNonce /// - value: batchRoot /// @param srcChainId The chain id of the source chain /// @param dbNonce The database nonce of the batch /// @param batchRoot The root of the Merkle tree containing the batched entries struct InterchainBatch { // TODO: can we use uint64 for chain id? uint256 srcChainId; uint256 dbNonce; bytes32 batchRoot; } library InterchainBatchLib { using VersionedPayloadLib for bytes; /// @notice Constructs an InterchainBatch struct to be saved on the local chain. /// @param dbNonce The database nonce of the batch /// @param batchRoot The root of the Merkle tree containing the batched entries /// @return batch The constructed InterchainBatch struct function constructLocalBatch( uint256 dbNonce, bytes32 batchRoot ) internal view returns (InterchainBatch memory batch) { return InterchainBatch({srcChainId: block.chainid, dbNonce: dbNonce, batchRoot: batchRoot}); } /// @notice Encodes the InterchainBatch struct into a non-versioned batch payload. function encodeBatch(InterchainBatch memory batch) internal pure returns (bytes memory) { return abi.encode(batch); } /// @notice Decodes the InterchainBatch struct from a non-versioned batch payload in calldata. function decodeBatch(bytes calldata data) internal pure returns (InterchainBatch memory) { return abi.decode(data, (InterchainBatch)); } /// @notice Decodes the InterchainBatch struct from a non-versioned batch payload in memory. function decodeBatchFromMemory(bytes memory data) internal pure returns (InterchainBatch memory) { return abi.decode(data, (InterchainBatch)); } /// @notice Returns the globally unique identifier of the batch function batchKey(InterchainBatch memory batch) internal pure returns (bytes32) { return keccak256(abi.encode(batch.srcChainId, batch.dbNonce)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library MathLib { /// @notice Rounds up to the nearest multiple of 32. /// Note: Returns zero on overflows instead of reverting. This is fine for practical /// use cases, as this is used for determining the size of the payload in memory. function roundUpToWord(uint256 x) internal pure returns (uint256) { unchecked { return (x + 31) & ~uint256(31); } } }
// 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; } }
{ "remappings": [ "@openzeppelin/=node_modules/@openzeppelin/", "@synapsecns/=node_modules/@synapsecns/", "ds-test/=node_modules/ds-test/src/", "forge-std/=node_modules/forge-std/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"address","name":"interchainDB","type":"address"},{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"AppConfigLib__IncorrectVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InterchainClientV1__FeeAmountTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"InterchainClientV1__IncorrectDstChainId","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InterchainClientV1__IncorrectMsgValue","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"InterchainClientV1__InvalidTransactionVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"InterchainClientV1__NoLinkedClient","type":"error"},{"inputs":[{"internalType":"bytes32","name":"client","type":"bytes32"}],"name":"InterchainClientV1__NotEVMClient","type":"error"},{"inputs":[],"name":"InterchainClientV1__NotEnoughGasSupplied","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InterchainClientV1__NotEnoughResponses","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"InterchainClientV1__NotRemoteChainId","type":"error"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"InterchainClientV1__TxAlreadyExecuted","type":"error"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"InterchainClientV1__TxNotExecuted","type":"error"},{"inputs":[],"name":"InterchainClientV1__ZeroReceiver","type":"error"},{"inputs":[],"name":"InterchainClientV1__ZeroRequiredResponses","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"OptionsLib__IncorrectVersion","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"VersionedPayload__PrecompileFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"versionedPayload","type":"bytes"}],"name":"VersionedPayload__TooShort","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"executionFees","type":"address"}],"name":"ExecutionFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"entryIndex","type":"uint64"},{"indexed":false,"internalType":"address","name":"executor","type":"address"}],"name":"ExecutionProofWritten","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"entryIndex","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"srcChainId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"dstReceiver","type":"bytes32"}],"name":"InterchainTransactionReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"dbNonce","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"entryIndex","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"dstChainId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"dstReceiver","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"verificationFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"executionFee","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"options","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"InterchainTransactionSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"client","type":"bytes32"}],"name":"LinkedClientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"CLIENT_VERSION","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTERCHAIN_DB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedOptions","type":"bytes"}],"name":"decodeOptions","outputs":[{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasAirdrop","type":"uint256"}],"internalType":"struct OptionsV1","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"bytes32","name":"srcSender","type":"bytes32"},{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"bytes32","name":"dstReceiver","type":"bytes32"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"internalType":"struct InterchainTransaction","name":"icTx","type":"tuple"}],"name":"encodeTransaction","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"executionFees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"getExecutor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"getExecutorById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"address","name":"srcExecutionService","type":"address"},{"internalType":"address[]","name":"srcModules","type":"address[]"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"uint256","name":"messageLen","type":"uint256"}],"name":"getInterchainFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getLinkedClient","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getLinkedClientEVM","outputs":[{"internalType":"address","name":"linkedClientEVM","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"transaction","type":"bytes"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"interchainExecute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"bytes32","name":"receiver","type":"bytes32"},{"internalType":"address","name":"srcExecutionService","type":"address"},{"internalType":"address[]","name":"srcModules","type":"address[]"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"interchainSend","outputs":[{"components":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"internalType":"struct InterchainTxDescriptor","name":"desc","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"srcExecutionService","type":"address"},{"internalType":"address[]","name":"srcModules","type":"address[]"},{"internalType":"bytes","name":"options","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"interchainSendEVM","outputs":[{"components":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"internalType":"struct InterchainTxDescriptor","name":"desc","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"isExecutable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"executionFees_","type":"address"}],"name":"setExecutionFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"bytes32","name":"client","type":"bytes32"}],"name":"setLinkedClient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"writeExecutionProof","outputs":[{"internalType":"uint256","name":"dbNonce","type":"uint256"},{"internalType":"uint64","name":"entryIndex","type":"uint64"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b5060405162002622380380620026228339810160408190526200003491620000f0565b806001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f8162000083565b50506001600160a01b031660805262000128565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000eb57600080fd5b919050565b600080604083850312156200010457600080fd5b6200010f83620000d3565b91506200011f60208401620000d3565b90509250929050565b6080516124b46200016e600039600081816103970152818161079d015281816109b201528181611057015281816110ff01528181611255015261175101526124b46000f3fe60806040526004361061011f5760003560e01c80638da5cb5b116100a0578063e4c6124711610064578063e4c6124714610385578063f1a61fac146103b9578063f2fde38b146103ef578063f34234c81461040f578063f92a79ff1461042f57600080fd5b80638da5cb5b146102bc57806390e81077146102da57806398939d2814610317578063aa102ec41461032a578063d5e788a01461034a57600080fd5b80637341eaf9116100e75780637341eaf9146101db5780637813cd52146101fb5780637a1277db146102235780637c80a90f14610251578063827f940d1461027e57600080fd5b806302172a35146101245780631450c281146101615780633dc68b871461019157806353b67d74146101b3578063715018a6146101c6575b600080fd5b34801561013057600080fd5b5061014461013f3660046118fb565b61044f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561016d57600080fd5b5061018161017c366004611999565b6104bc565b6040519015158152602001610158565b34801561019d57600080fd5b506101b16101ac366004611a19565b61050e565b005b6101b16101c1366004611a36565b61056a565b3480156101d257600080fd5b506101b1610726565b3480156101e757600080fd5b50600154610144906001600160a01b031681565b34801561020757600080fd5b50610210600181565b60405161ffff9091168152602001610158565b34801561022f57600080fd5b5061024361023e366004611aaf565b61073a565b604051908152602001610158565b34801561025d57600080fd5b5061027161026c366004611c4f565b6108c3565b6040516101589190611d73565b61029161028c366004611d86565b6108de565b604080518251815260208084015190820152918101516001600160401b031690820152606001610158565b3480156102c857600080fd5b506000546001600160a01b0316610144565b3480156102e657600080fd5b506102fa6102f53660046118fb565b610925565b604080519283526001600160401b03909116602083015201610158565b610291610325366004611e50565b610a7d565b34801561033657600080fd5b506102436103453660046118fb565b610ab9565b34801561035657600080fd5b5061036a610365366004611e87565b610af1565b60408051825181526020928301519281019290925201610158565b34801561039157600080fd5b506101447f000000000000000000000000000000000000000000000000000000000000000081565b3480156103c557600080fd5b506101446103d43660046118fb565b6000908152600360205260409020546001600160a01b031690565b3480156103fb57600080fd5b506101b161040a366004611a19565b610b0e565b34801561041b57600080fd5b506101b161042a366004611ebb565b610b4c565b34801561043b57600080fd5b5061014461044a366004611edd565b610ba3565b6000468203610479576040516357516f6960e01b8152600481018390526024015b60405180910390fd5b50600081815260026020526040902054806001600160a01b03811681146104b657604051630a55a4eb60e01b815260048101829052602401610470565b50919050565b6000806104c98686610be3565b90506104d88160c00151610c3e565b50600086866040516104eb929190611f1e565b6040518091039020905061050182828787610cae565b5060019695505050505050565b610516610e5c565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527fec02f15d78cdfc4beeba45f31cfad25089004e5e3d72727168dd96a77d1f2f829060200160405180910390a150565b60006105768585610be3565b90506000858560405161058a929190611f1e565b604051809103902090506105a082828686610cae565b600081815260036020526040812080546001600160a01b0319163317905560c08301516105cc90610c3e565b905080602001513414610601576020810151604051632b36102560e01b81523460048201526024810191909152604401610470565b805188101561060f57805197505b875a1161062f576040516374dc18ab60e11b815260040160405180910390fd5b60608301516001600160a01b03166368a6984789348660000151876020015188608001518960a001518a60e001516040518863ffffffff1660e01b815260040161067d959493929190611f2e565b6000604051808303818589803b15801561069657600080fd5b5088f11580156106aa573d6000803e3d6000fd5b5050505050508260a001516001600160401b03168360800151837f9c887f38b8f2330ee9894137eb60cf6ab904c5d2063ddc0baa7a77bfd1880e8c866000015187602001518860600151604051610714939291909283526020830191909152604082015260600190565b60405180910390a45050505050505050565b61072e610e5c565b6107386000610e89565b565b600061074588610ed9565b5061078584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fc7686ec906107d6908b908a908a90600401611fab565b602060405180830381865afa1580156107f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108179190611fce565b90506001600160a01b038716156108b85760006108348484610f37565b60405163188e7cfd60e31b81529091506001600160a01b0389169063c473e7e890610869908c9085908a908a90600401612010565b602060405180830381865afa158015610886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190611fce565b6108b49083612050565b9150505b979650505050505050565b60606108d860016108d384610f5f565b610f88565b92915050565b60408051606081018252600080825260208201819052918101919091526001600160a01b0389166109168b828b8b8b8b8b8b8b610fb4565b9b9a5050505050505050505050565b60008181526003602052604081205481906001600160a01b0316806109605760405163e99eb48d60e01b815260048101859052602401610470565b600084826040516020016109879291909182526001600160a01b0316602082015260400190565b60408051808303601f19018152908290528051602082012063156c638360e11b8352600483015291507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632ad8c7069060240160408051808303816000875af1158015610a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a269190612063565b6040516001600160a01b038516815291955093506001600160401b03841690859087907f810ecf3e461a7f5c46c0bbbca8680cf65de59e78e521d58d569e03969d08648c9060200160405180910390a45050915091565b6040805160608101825260008082526020820181905291810191909152610aab8a8a8a8a8a8a8a8a8a610fb4565b9a9950505050505050505050565b6000468203610ade576040516357516f6960e01b815260048101839052602401610470565b5060009081526002602052604090205490565b60408051808201909152600080825260208201526108d882610c3e565b610b16610e5c565b6001600160a01b038116610b4057604051631e4fbdf760e01b815260006004820152602401610470565b610b4981610e89565b50565b610b54610e5c565b60008281526002602090815260409182902083905581518481529081018390527fb6b5dc04cc1c35fc7a8c8342e378dccc610c6589ef3bcfcd6eaf0304913f889a910160405180910390a15050565b6000600360008484604051610bb9929190611f1e565b60408051918290039091208252602082019290925201600020546001600160a01b03169392505050565b610beb6118a7565b6000610bf78484611591565b905061ffff8116600114610c2457604051630fda659b60e01b815261ffff82166004820152602401610470565b610c36610c3185856115c2565b611604565b949350505050565b60408051808201909152600080825260208201526000610c5d83611618565b9050600161ffff82161015610c8b5760405163b94fa72560e01b815261ffff82166004820152602401610470565b610c948361164a565b806020019051810190610ca791906120e1565b9392505050565b6000610cbd8560000151610ed9565b905046856040015114610ceb578460400151604051634b9929c160e11b815260040161047091815260200190565b6000848152600360205260409020546001600160a01b031615610d245760405163d80aeb9160e01b815260048101859052602401610470565b60006040518060a0016040528087600001518152602001876080015181526020018760a001516001600160401b03168152602001838152602001868152509050600080610d72886060015190565b6001600160a01b031663287bc0576040518163ffffffff1660e01b8152600401600060405180830381865afa158015610daf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd791908101906120fd565b915091506000610de6836116f3565b8051909150600003610e0b5760405163a09e214360e01b815260040160405180910390fd5b6000610e1e83868a8a8660200151611740565b8251909150811015610e50578151604051630bce4e8560e01b8152610470918391600401918252602082015260400190565b50505050505050505050565b6000546001600160a01b031633146107385760405163118cdaa760e01b8152336004820152602401610470565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000468203610efe576040516357516f6960e01b815260048101839052602401610470565b5060008181526002602052604081205490819003610f3257604051639a45110f60e01b815260048101839052602401610470565b919050565b6000601f19601f830116601f19601f850116610f5590610162612050565b610ca79190612050565b606081604051602001610f729190612211565b6040516020818303038152906040529050919050565b60608282604051602001610f9d929190612291565b604051602081830303815290604052905092915050565b6040805160608101825260008082526020820181905291810191909152610fda8a610ed9565b506000899003610ffd5760405163059f20d360e11b815260040160405180910390fd5b61103c85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fc7686ec90611090908e908c908c90600401611fab565b602060405180830381865afa1580156110ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d19190611fce565b9050803410156110fd57604051639557ee4960e01b815234600482015260248101829052604401610470565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663aa2f06ae6040518163ffffffff1660e01b81526004016040805180830381865afa15801561115a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117e9190612063565b8360200184604001826001600160401b03166001600160401b03168152508281525050506000611235338d8d866020015187604001518c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061184092505050565b9050611240816108c3565b805190602001208360000181815250506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166367c769af85856040015188600001518f8f6040518663ffffffff1660e01b81526004016112ae94939291906122c1565b604080518083038185885af11580156112cb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f09190612063565b9150915084602001518214801561131c575084604001516001600160401b0316816001600160401b0316145b611328576113286122e1565b5050348281039083146113ae57600154604080840151865191516001620989c160e11b031981526001600160a01b039093169263ffecec7e92859261137b92909190600401918252602082015260400190565b6000604051808303818588803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b50505050505b6001600160a01b038b1615611512576001600160a01b038b1663e4e065228e6113d78a89610f37565b87516040516001600160e01b031960e086901b1681526114029392919087908f908f906004016122f7565b600060405180830381600087803b15801561141c57600080fd5b505af1158015611430573d6000803e3d6000fd5b5050505060008b6001600160a01b03166362014bad6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611474573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611498919061232f565b6001546040858101518851915163033b5b8360e11b8152600481019190915260248101919091526001600160a01b038084166044830152929350911690630676b70690606401600060405180830381600087803b1580156114f857600080fd5b505af115801561150c573d6000803e3d6000fd5b50505050505b8160a001516001600160401b0316826080015185600001517f1b22d6c0b67f6f17a9004833bfb5afbaea4602457bd57e1d128cb997fb30161b85604001518660200151876060015189888a60c001518b60e00151604051611579979695949392919061234c565b60405180910390a45050509998505050505050505050565b600060028210156115b95782826040516332ce7cfd60e11b815260040161047092919061238f565b50503560f01c90565b36600060028310156115eb5783836040516332ce7cfd60e11b815260040161047092919061238f565b6115f883600281876123a3565b915091505b9250929050565b61160c6118a7565b610ca782840184611c4f565b600060028251101561163f57816040516332ce7cfd60e11b81526004016104709190611d73565b506020015160f01c90565b606060028251101561167157816040516332ce7cfd60e11b81526004016104709190611d73565b815160011901806001600160401b0381111561168f5761168f611b43565b6040519080825280601f01601f1916602001820160405280156116b9576020820181803683370190505b50915060008160208401836022870160045afa9050806116ec5760405163080f227d60e11b815260040160405180910390fd5b5050919050565b6040805180820190915260008082526020820152600061171283611618565b9050600161ffff82161015610c8b5760405163aac8bd2360e01b815261ffff82166004820152602401610470565b6000805b86518110156118365760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166367b1f42e898481518110611790576117906123cd565b60200260200101518989896040518563ffffffff1660e01b81526004016117ba94939291906123e3565b602060405180830381865afa1580156117d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fb9190611fce565b905080158015906118145750426118128583612050565b105b156118255761182283612465565b92505b5061182f81612465565b9050611744565b5095945050505050565b6118486118a7565b60405180610100016040528046815260200161186a8a6001600160a01b031690565b8152602001888152602001878152602001868152602001856001600160401b03168152602001848152602001838152509050979650505050505050565b604051806101000160405280600081526020016000801916815260200160008152602001600080191681526020016000815260200160006001600160401b0316815260200160608152602001606081525090565b60006020828403121561190d57600080fd5b5035919050565b60008083601f84011261192657600080fd5b5081356001600160401b0381111561193d57600080fd5b6020830191508360208285010111156115fd57600080fd5b60008083601f84011261196757600080fd5b5081356001600160401b0381111561197e57600080fd5b6020830191508360208260051b85010111156115fd57600080fd5b600080600080604085870312156119af57600080fd5b84356001600160401b03808211156119c657600080fd5b6119d288838901611914565b909650945060208701359150808211156119eb57600080fd5b506119f887828801611955565b95989497509550505050565b6001600160a01b0381168114610b4957600080fd5b600060208284031215611a2b57600080fd5b8135610ca781611a04565b600080600080600060608688031215611a4e57600080fd5b8535945060208601356001600160401b0380821115611a6c57600080fd5b611a7889838a01611914565b90965094506040880135915080821115611a9157600080fd5b50611a9e88828901611955565b969995985093965092949392505050565b600080600080600080600060a0888a031215611aca57600080fd5b873596506020880135611adc81611a04565b955060408801356001600160401b0380821115611af857600080fd5b611b048b838c01611955565b909750955060608a0135915080821115611b1d57600080fd5b50611b2a8a828b01611914565b989b979a50959894979596608090950135949350505050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b0381118282101715611b7c57611b7c611b43565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611baa57611baa611b43565b604052919050565b6001600160401b0381168114610b4957600080fd5b8035610f3281611bb2565b60006001600160401b03821115611beb57611beb611b43565b50601f01601f191660200190565b600082601f830112611c0a57600080fd5b8135611c1d611c1882611bd2565b611b82565b818152846020838601011115611c3257600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215611c6157600080fd5b81356001600160401b0380821115611c7857600080fd5b908301906101008286031215611c8d57600080fd5b611c95611b59565b8235815260208301356020820152604083013560408201526060830135606082015260808301356080820152611ccd60a08401611bc7565b60a082015260c083013582811115611ce457600080fd5b611cf087828601611bf9565b60c08301525060e083013582811115611d0857600080fd5b611d1487828601611bf9565b60e08301525095945050505050565b60005b83811015611d3e578181015183820152602001611d26565b50506000910152565b60008151808452611d5f816020860160208601611d23565b601f01601f19169290920160200192915050565b602081526000610ca76020830184611d47565b600080600080600080600080600060c08a8c031215611da457600080fd5b8935985060208a0135611db681611a04565b975060408a0135611dc681611a04565b965060608a01356001600160401b0380821115611de257600080fd5b611dee8d838e01611955565b909850965060808c0135915080821115611e0757600080fd5b611e138d838e01611914565b909650945060a08c0135915080821115611e2c57600080fd5b50611e398c828d01611914565b915080935050809150509295985092959850929598565b600080600080600080600080600060c08a8c031215611e6e57600080fd5b8935985060208a0135975060408a0135611dc681611a04565b600060208284031215611e9957600080fd5b81356001600160401b03811115611eaf57600080fd5b610c3684828501611bf9565b60008060408385031215611ece57600080fd5b50508035926020909101359150565b60008060208385031215611ef057600080fd5b82356001600160401b03811115611f0657600080fd5b611f1285828601611914565b90969095509350505050565b8183823760009101908152919050565b8581528460208201528360408201526001600160401b038316606082015260a0608082015260006108b860a0830184611d47565b8183526000602080850194508260005b85811015611fa0578135611f8581611a04565b6001600160a01b031687529582019590820190600101611f72565b509495945050505050565b838152604060208201526000611fc5604083018486611f62565b95945050505050565b600060208284031215611fe057600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201526000612030606083018486611fe7565b9695505050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156108d8576108d861203a565b6000806040838503121561207657600080fd5b82519150602083015161208881611bb2565b809150509250929050565b6000604082840312156120a557600080fd5b604051604081018181106001600160401b03821117156120c7576120c7611b43565b604052825181526020928301519281019290925250919050565b6000604082840312156120f357600080fd5b610ca78383612093565b6000806040838503121561211057600080fd5b82516001600160401b038082111561212757600080fd5b818501915085601f83011261213b57600080fd5b8151602061214b611c1883611bd2565b828152888284870101111561215f57600080fd5b61216e83838301848801611d23565b8782015190965093508284111561218457600080fd5b838701935087601f85011261219857600080fd5b83519150828211156121ac576121ac611b43565b8160051b92506121bd818401611b82565b82815292840181019281810190898511156121d757600080fd5b948201945b8486101561220157855193506121f184611a04565b83825294820194908201906121dc565b8096505050505050509250929050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a08201526001600160401b0360a08301511660c0820152600060c08301516101008060e0850152612275610120850183611d47565b915060e0850151601f1985840301828601526120308382611d47565b61ffff60f01b8360f01b168152600082516122b3816002850160208701611d23565b919091016002019392505050565b848152836020820152606060408201526000612030606083018486611f62565b634e487b7160e01b600052600160045260246000fd5b86815285602082015284604082015283606082015260a06080820152600061232360a083018486611fe7565b98975050505050505050565b60006020828403121561234157600080fd5b8151610ca781611a04565b87815286602082015285604082015284606082015283608082015260e060a0820152600061237d60e0830185611d47565b82810360c0840152610aab8185611d47565b602081526000610c36602083018486611fe7565b600080858511156123b357600080fd5b838611156123c057600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b60018060a01b038516815283516020820152602084015160408201526001600160401b03604085015116606082015260608401516080820152608084015160a082015260e060c08201528160e0820152600061010060018060fb1b0384111561244b57600080fd5b8360051b8086838601379290920190910195945050505050565b6000600182016124775761247761203a565b506001019056fea26469706673582212204b444d61c3a8c6d3b80f563e0c706f3505d59bc22df9f17a67e39b2c0967fb7464736f6c63430008140033000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4
Deployed Bytecode
0x60806040526004361061011f5760003560e01c80638da5cb5b116100a0578063e4c6124711610064578063e4c6124714610385578063f1a61fac146103b9578063f2fde38b146103ef578063f34234c81461040f578063f92a79ff1461042f57600080fd5b80638da5cb5b146102bc57806390e81077146102da57806398939d2814610317578063aa102ec41461032a578063d5e788a01461034a57600080fd5b80637341eaf9116100e75780637341eaf9146101db5780637813cd52146101fb5780637a1277db146102235780637c80a90f14610251578063827f940d1461027e57600080fd5b806302172a35146101245780631450c281146101615780633dc68b871461019157806353b67d74146101b3578063715018a6146101c6575b600080fd5b34801561013057600080fd5b5061014461013f3660046118fb565b61044f565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561016d57600080fd5b5061018161017c366004611999565b6104bc565b6040519015158152602001610158565b34801561019d57600080fd5b506101b16101ac366004611a19565b61050e565b005b6101b16101c1366004611a36565b61056a565b3480156101d257600080fd5b506101b1610726565b3480156101e757600080fd5b50600154610144906001600160a01b031681565b34801561020757600080fd5b50610210600181565b60405161ffff9091168152602001610158565b34801561022f57600080fd5b5061024361023e366004611aaf565b61073a565b604051908152602001610158565b34801561025d57600080fd5b5061027161026c366004611c4f565b6108c3565b6040516101589190611d73565b61029161028c366004611d86565b6108de565b604080518251815260208084015190820152918101516001600160401b031690820152606001610158565b3480156102c857600080fd5b506000546001600160a01b0316610144565b3480156102e657600080fd5b506102fa6102f53660046118fb565b610925565b604080519283526001600160401b03909116602083015201610158565b610291610325366004611e50565b610a7d565b34801561033657600080fd5b506102436103453660046118fb565b610ab9565b34801561035657600080fd5b5061036a610365366004611e87565b610af1565b60408051825181526020928301519281019290925201610158565b34801561039157600080fd5b506101447f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b81565b3480156103c557600080fd5b506101446103d43660046118fb565b6000908152600360205260409020546001600160a01b031690565b3480156103fb57600080fd5b506101b161040a366004611a19565b610b0e565b34801561041b57600080fd5b506101b161042a366004611ebb565b610b4c565b34801561043b57600080fd5b5061014461044a366004611edd565b610ba3565b6000468203610479576040516357516f6960e01b8152600481018390526024015b60405180910390fd5b50600081815260026020526040902054806001600160a01b03811681146104b657604051630a55a4eb60e01b815260048101829052602401610470565b50919050565b6000806104c98686610be3565b90506104d88160c00151610c3e565b50600086866040516104eb929190611f1e565b6040518091039020905061050182828787610cae565b5060019695505050505050565b610516610e5c565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527fec02f15d78cdfc4beeba45f31cfad25089004e5e3d72727168dd96a77d1f2f829060200160405180910390a150565b60006105768585610be3565b90506000858560405161058a929190611f1e565b604051809103902090506105a082828686610cae565b600081815260036020526040812080546001600160a01b0319163317905560c08301516105cc90610c3e565b905080602001513414610601576020810151604051632b36102560e01b81523460048201526024810191909152604401610470565b805188101561060f57805197505b875a1161062f576040516374dc18ab60e11b815260040160405180910390fd5b60608301516001600160a01b03166368a6984789348660000151876020015188608001518960a001518a60e001516040518863ffffffff1660e01b815260040161067d959493929190611f2e565b6000604051808303818589803b15801561069657600080fd5b5088f11580156106aa573d6000803e3d6000fd5b5050505050508260a001516001600160401b03168360800151837f9c887f38b8f2330ee9894137eb60cf6ab904c5d2063ddc0baa7a77bfd1880e8c866000015187602001518860600151604051610714939291909283526020830191909152604082015260600190565b60405180910390a45050505050505050565b61072e610e5c565b6107386000610e89565b565b600061074588610ed9565b5061078584848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526001600160a01b037f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b169063fc7686ec906107d6908b908a908a90600401611fab565b602060405180830381865afa1580156107f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108179190611fce565b90506001600160a01b038716156108b85760006108348484610f37565b60405163188e7cfd60e31b81529091506001600160a01b0389169063c473e7e890610869908c9085908a908a90600401612010565b602060405180830381865afa158015610886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190611fce565b6108b49083612050565b9150505b979650505050505050565b60606108d860016108d384610f5f565b610f88565b92915050565b60408051606081018252600080825260208201819052918101919091526001600160a01b0389166109168b828b8b8b8b8b8b8b610fb4565b9b9a5050505050505050505050565b60008181526003602052604081205481906001600160a01b0316806109605760405163e99eb48d60e01b815260048101859052602401610470565b600084826040516020016109879291909182526001600160a01b0316602082015260400190565b60408051808303601f19018152908290528051602082012063156c638360e11b8352600483015291507f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b031690632ad8c7069060240160408051808303816000875af1158015610a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a269190612063565b6040516001600160a01b038516815291955093506001600160401b03841690859087907f810ecf3e461a7f5c46c0bbbca8680cf65de59e78e521d58d569e03969d08648c9060200160405180910390a45050915091565b6040805160608101825260008082526020820181905291810191909152610aab8a8a8a8a8a8a8a8a8a610fb4565b9a9950505050505050505050565b6000468203610ade576040516357516f6960e01b815260048101839052602401610470565b5060009081526002602052604090205490565b60408051808201909152600080825260208201526108d882610c3e565b610b16610e5c565b6001600160a01b038116610b4057604051631e4fbdf760e01b815260006004820152602401610470565b610b4981610e89565b50565b610b54610e5c565b60008281526002602090815260409182902083905581518481529081018390527fb6b5dc04cc1c35fc7a8c8342e378dccc610c6589ef3bcfcd6eaf0304913f889a910160405180910390a15050565b6000600360008484604051610bb9929190611f1e565b60408051918290039091208252602082019290925201600020546001600160a01b03169392505050565b610beb6118a7565b6000610bf78484611591565b905061ffff8116600114610c2457604051630fda659b60e01b815261ffff82166004820152602401610470565b610c36610c3185856115c2565b611604565b949350505050565b60408051808201909152600080825260208201526000610c5d83611618565b9050600161ffff82161015610c8b5760405163b94fa72560e01b815261ffff82166004820152602401610470565b610c948361164a565b806020019051810190610ca791906120e1565b9392505050565b6000610cbd8560000151610ed9565b905046856040015114610ceb578460400151604051634b9929c160e11b815260040161047091815260200190565b6000848152600360205260409020546001600160a01b031615610d245760405163d80aeb9160e01b815260048101859052602401610470565b60006040518060a0016040528087600001518152602001876080015181526020018760a001516001600160401b03168152602001838152602001868152509050600080610d72886060015190565b6001600160a01b031663287bc0576040518163ffffffff1660e01b8152600401600060405180830381865afa158015610daf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd791908101906120fd565b915091506000610de6836116f3565b8051909150600003610e0b5760405163a09e214360e01b815260040160405180910390fd5b6000610e1e83868a8a8660200151611740565b8251909150811015610e50578151604051630bce4e8560e01b8152610470918391600401918252602082015260400190565b50505050505050505050565b6000546001600160a01b031633146107385760405163118cdaa760e01b8152336004820152602401610470565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000468203610efe576040516357516f6960e01b815260048101839052602401610470565b5060008181526002602052604081205490819003610f3257604051639a45110f60e01b815260048101839052602401610470565b919050565b6000601f19601f830116601f19601f850116610f5590610162612050565b610ca79190612050565b606081604051602001610f729190612211565b6040516020818303038152906040529050919050565b60608282604051602001610f9d929190612291565b604051602081830303815290604052905092915050565b6040805160608101825260008082526020820181905291810191909152610fda8a610ed9565b506000899003610ffd5760405163059f20d360e11b815260040160405180910390fd5b61103c85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c3e92505050565b50604051633f1da1bb60e21b81526000906001600160a01b037f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b169063fc7686ec90611090908e908c908c90600401611fab565b602060405180830381865afa1580156110ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d19190611fce565b9050803410156110fd57604051639557ee4960e01b815234600482015260248101829052604401610470565b7f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b031663aa2f06ae6040518163ffffffff1660e01b81526004016040805180830381865afa15801561115a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117e9190612063565b8360200184604001826001600160401b03166001600160401b03168152508281525050506000611235338d8d866020015187604001518c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061184092505050565b9050611240816108c3565b805190602001208360000181815250506000807f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b03166367c769af85856040015188600001518f8f6040518663ffffffff1660e01b81526004016112ae94939291906122c1565b604080518083038185885af11580156112cb573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f09190612063565b9150915084602001518214801561131c575084604001516001600160401b0316816001600160401b0316145b611328576113286122e1565b5050348281039083146113ae57600154604080840151865191516001620989c160e11b031981526001600160a01b039093169263ffecec7e92859261137b92909190600401918252602082015260400190565b6000604051808303818588803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b50505050505b6001600160a01b038b1615611512576001600160a01b038b1663e4e065228e6113d78a89610f37565b87516040516001600160e01b031960e086901b1681526114029392919087908f908f906004016122f7565b600060405180830381600087803b15801561141c57600080fd5b505af1158015611430573d6000803e3d6000fd5b5050505060008b6001600160a01b03166362014bad6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611474573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611498919061232f565b6001546040858101518851915163033b5b8360e11b8152600481019190915260248101919091526001600160a01b038084166044830152929350911690630676b70690606401600060405180830381600087803b1580156114f857600080fd5b505af115801561150c573d6000803e3d6000fd5b50505050505b8160a001516001600160401b0316826080015185600001517f1b22d6c0b67f6f17a9004833bfb5afbaea4602457bd57e1d128cb997fb30161b85604001518660200151876060015189888a60c001518b60e00151604051611579979695949392919061234c565b60405180910390a45050509998505050505050505050565b600060028210156115b95782826040516332ce7cfd60e11b815260040161047092919061238f565b50503560f01c90565b36600060028310156115eb5783836040516332ce7cfd60e11b815260040161047092919061238f565b6115f883600281876123a3565b915091505b9250929050565b61160c6118a7565b610ca782840184611c4f565b600060028251101561163f57816040516332ce7cfd60e11b81526004016104709190611d73565b506020015160f01c90565b606060028251101561167157816040516332ce7cfd60e11b81526004016104709190611d73565b815160011901806001600160401b0381111561168f5761168f611b43565b6040519080825280601f01601f1916602001820160405280156116b9576020820181803683370190505b50915060008160208401836022870160045afa9050806116ec5760405163080f227d60e11b815260040160405180910390fd5b5050919050565b6040805180820190915260008082526020820152600061171283611618565b9050600161ffff82161015610c8b5760405163aac8bd2360e01b815261ffff82166004820152602401610470565b6000805b86518110156118365760007f000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b6001600160a01b03166367b1f42e898481518110611790576117906123cd565b60200260200101518989896040518563ffffffff1660e01b81526004016117ba94939291906123e3565b602060405180830381865afa1580156117d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fb9190611fce565b905080158015906118145750426118128583612050565b105b156118255761182283612465565b92505b5061182f81612465565b9050611744565b5095945050505050565b6118486118a7565b60405180610100016040528046815260200161186a8a6001600160a01b031690565b8152602001888152602001878152602001868152602001856001600160401b03168152602001848152602001838152509050979650505050505050565b604051806101000160405280600081526020016000801916815260200160008152602001600080191681526020016000815260200160006001600160401b0316815260200160608152602001606081525090565b60006020828403121561190d57600080fd5b5035919050565b60008083601f84011261192657600080fd5b5081356001600160401b0381111561193d57600080fd5b6020830191508360208285010111156115fd57600080fd5b60008083601f84011261196757600080fd5b5081356001600160401b0381111561197e57600080fd5b6020830191508360208260051b85010111156115fd57600080fd5b600080600080604085870312156119af57600080fd5b84356001600160401b03808211156119c657600080fd5b6119d288838901611914565b909650945060208701359150808211156119eb57600080fd5b506119f887828801611955565b95989497509550505050565b6001600160a01b0381168114610b4957600080fd5b600060208284031215611a2b57600080fd5b8135610ca781611a04565b600080600080600060608688031215611a4e57600080fd5b8535945060208601356001600160401b0380821115611a6c57600080fd5b611a7889838a01611914565b90965094506040880135915080821115611a9157600080fd5b50611a9e88828901611955565b969995985093965092949392505050565b600080600080600080600060a0888a031215611aca57600080fd5b873596506020880135611adc81611a04565b955060408801356001600160401b0380821115611af857600080fd5b611b048b838c01611955565b909750955060608a0135915080821115611b1d57600080fd5b50611b2a8a828b01611914565b989b979a50959894979596608090950135949350505050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b0381118282101715611b7c57611b7c611b43565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611baa57611baa611b43565b604052919050565b6001600160401b0381168114610b4957600080fd5b8035610f3281611bb2565b60006001600160401b03821115611beb57611beb611b43565b50601f01601f191660200190565b600082601f830112611c0a57600080fd5b8135611c1d611c1882611bd2565b611b82565b818152846020838601011115611c3257600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215611c6157600080fd5b81356001600160401b0380821115611c7857600080fd5b908301906101008286031215611c8d57600080fd5b611c95611b59565b8235815260208301356020820152604083013560408201526060830135606082015260808301356080820152611ccd60a08401611bc7565b60a082015260c083013582811115611ce457600080fd5b611cf087828601611bf9565b60c08301525060e083013582811115611d0857600080fd5b611d1487828601611bf9565b60e08301525095945050505050565b60005b83811015611d3e578181015183820152602001611d26565b50506000910152565b60008151808452611d5f816020860160208601611d23565b601f01601f19169290920160200192915050565b602081526000610ca76020830184611d47565b600080600080600080600080600060c08a8c031215611da457600080fd5b8935985060208a0135611db681611a04565b975060408a0135611dc681611a04565b965060608a01356001600160401b0380821115611de257600080fd5b611dee8d838e01611955565b909850965060808c0135915080821115611e0757600080fd5b611e138d838e01611914565b909650945060a08c0135915080821115611e2c57600080fd5b50611e398c828d01611914565b915080935050809150509295985092959850929598565b600080600080600080600080600060c08a8c031215611e6e57600080fd5b8935985060208a0135975060408a0135611dc681611a04565b600060208284031215611e9957600080fd5b81356001600160401b03811115611eaf57600080fd5b610c3684828501611bf9565b60008060408385031215611ece57600080fd5b50508035926020909101359150565b60008060208385031215611ef057600080fd5b82356001600160401b03811115611f0657600080fd5b611f1285828601611914565b90969095509350505050565b8183823760009101908152919050565b8581528460208201528360408201526001600160401b038316606082015260a0608082015260006108b860a0830184611d47565b8183526000602080850194508260005b85811015611fa0578135611f8581611a04565b6001600160a01b031687529582019590820190600101611f72565b509495945050505050565b838152604060208201526000611fc5604083018486611f62565b95945050505050565b600060208284031215611fe057600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201526000612030606083018486611fe7565b9695505050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156108d8576108d861203a565b6000806040838503121561207657600080fd5b82519150602083015161208881611bb2565b809150509250929050565b6000604082840312156120a557600080fd5b604051604081018181106001600160401b03821117156120c7576120c7611b43565b604052825181526020928301519281019290925250919050565b6000604082840312156120f357600080fd5b610ca78383612093565b6000806040838503121561211057600080fd5b82516001600160401b038082111561212757600080fd5b818501915085601f83011261213b57600080fd5b8151602061214b611c1883611bd2565b828152888284870101111561215f57600080fd5b61216e83838301848801611d23565b8782015190965093508284111561218457600080fd5b838701935087601f85011261219857600080fd5b83519150828211156121ac576121ac611b43565b8160051b92506121bd818401611b82565b82815292840181019281810190898511156121d757600080fd5b948201945b8486101561220157855193506121f184611a04565b83825294820194908201906121dc565b8096505050505050509250929050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a08201526001600160401b0360a08301511660c0820152600060c08301516101008060e0850152612275610120850183611d47565b915060e0850151601f1985840301828601526120308382611d47565b61ffff60f01b8360f01b168152600082516122b3816002850160208701611d23565b919091016002019392505050565b848152836020820152606060408201526000612030606083018486611f62565b634e487b7160e01b600052600160045260246000fd5b86815285602082015284604082015283606082015260a06080820152600061232360a083018486611fe7565b98975050505050505050565b60006020828403121561234157600080fd5b8151610ca781611a04565b87815286602082015285604082015284606082015283608082015260e060a0820152600061237d60e0830185611d47565b82810360c0840152610aab8185611d47565b602081526000610c36602083018486611fe7565b600080858511156123b357600080fd5b838611156123c057600080fd5b5050820193919092039150565b634e487b7160e01b600052603260045260246000fd5b60018060a01b038516815283516020820152602084015160408201526001600160401b03604085015116606082015260608401516080820152608084015160a082015260e060c08201528160e0820152600061010060018060fb1b0384111561244b57600080fd5b8360051b8086838601379290920190910195945050505050565b6000600182016124775761247761203a565b506001019056fea26469706673582212204b444d61c3a8c6d3b80f563e0c706f3505d59bc22df9f17a67e39b2c0967fb7464736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4
-----Decoded View---------------
Arg [0] : interchainDB (address): 0xAcAaaa98b9E23725046edA88D371B4864d90496b
Arg [1] : owner_ (address): 0xE7353BEdc72D29f99D6cA5CDE69F807cCE5d57e4
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000acaaaa98b9e23725046eda88d371b4864d90496b
Arg [1] : 000000000000000000000000e7353bedc72d29f99d6ca5cde69f807cce5d57e4
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.