Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Consensus St... | 12200139 | 167 days ago | IN | 0 ETH | 0.000863577221 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12199718 | 167 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xAFcD4F16...06E4b8324 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
OptimismHost
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// Copyright (C) Polytope Labs Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma solidity 0.8.17; import "./EvmHost.sol"; import "ismp/StateMachine.sol"; contract OptimismHost is EvmHost { constructor(HostParams memory params) EvmHost(params) {} /// chainId for the optimism mainnet uint256 public constant CHAIN_ID = 10; function chainId() public pure override returns (uint256) { return CHAIN_ID; } function host() public pure override returns (bytes memory) { return StateMachine.optimism(); } }
// Copyright (C) Polytope Labs Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma solidity 0.8.17; import {Context} from "openzeppelin/utils/Context.sol"; import {Math} from "openzeppelin/utils/math/Math.sol"; import {Strings} from "openzeppelin/utils/Strings.sol"; import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol"; import {Bytes} from "solidity-merkle-trees/trie/Bytes.sol"; import {IIsmpModule, IncomingPostRequest, IncomingPostResponse, IncomingGetResponse} from "ismp/IIsmpModule.sol"; import {DispatchPost, DispatchPostResponse, DispatchGet} from "ismp/IDispatcher.sol"; import {IIsmpHost, FeeMetadata, ResponseReceipt} from "ismp/IIsmpHost.sol"; import {StateCommitment, StateMachineHeight} from "ismp/IConsensusClient.sol"; import {IHandler} from "ismp/IHandler.sol"; import {PostRequest, PostResponse, GetRequest, GetResponse, PostTimeout, Message} from "ismp/Message.sol"; // The IsmpHost parameters struct HostParams { // default timeout in seconds for requests. uint256 defaultTimeout; // cost of cross-chain requests in the fee token per byte uint256 perByteFee; // The fee token contract. This will typically be DAI. // but we allow it to be configurable to prevent future regrets. address feeToken; // admin account, this only has the rights to freeze, or unfreeze the bridge address admin; // Ismp request/response handler address handler; // the authorized host manager contract address hostManager; // unstaking period uint256 unStakingPeriod; // minimum challenge period in seconds; uint256 challengePeriod; // consensus client contract address consensusClient; // whitelisted state machines uint256[] stateMachineWhitelist; // white list of fishermen accounts address[] fishermen; // state machine identifier for hyperbridge bytes hyperbridge; } // The host manager interface. This provides methods for modifying the host's params or withdrawing bridge revenue. // Can only be called used by the HostManager module. interface IHostManager { /** * @dev Updates IsmpHost params * @param params new IsmpHost params */ function updateHostParams(HostParams memory params) external; /** * @dev withdraws bridge revenue to the given address * @param params, the parameters for withdrawal */ function withdraw(WithdrawParams memory params) external; } // Withdraw parameters struct WithdrawParams { // The beneficiary address address beneficiary; // the amount to be disbursed uint256 amount; } /// IsmpHost implementation for Evm hosts. Refer to the official ISMP specification. /// https://docs.hyperbridge.network/protocol/ismp abstract contract EvmHost is IIsmpHost, IHostManager, Context { using Bytes for bytes; using Message for PostResponse; using Message for PostRequest; using Message for GetRequest; // commitment of all outgoing requests and amount put up for relayers. mapping(bytes32 => FeeMetadata) private _requestCommitments; // commitment of all outgoing responses and amount put up for relayers. mapping(bytes32 => FeeMetadata) private _responseCommitments; // commitment of all incoming requests and who delivered them. mapping(bytes32 => address) private _requestReceipts; // commitment of all incoming responses and who delivered them. // maps the request commitment to a receipt object mapping(bytes32 => ResponseReceipt) private _responseReceipts; // commitment of all incoming requests that have been responded to mapping(bytes32 => bool) private _responded; // mapping of state machine identifier to latest known height to state commitment // (stateMachineId => (blockHeight => StateCommitment)) mapping(uint256 => mapping(uint256 => StateCommitment)) private _stateCommitments; // mapping of state machine identifier to latest known height to update time // (stateMachineId => (blockHeight => timestamp)) mapping(uint256 => mapping(uint256 => uint256)) private _stateCommitmentsUpdateTime; // mapping of state machine identifier to latest known height // (stateMachineId => blockHeight) mapping(uint256 => uint256) private _latestStateMachineHeight; // mapping of all known fishermen accounts mapping(address => bool) private _fishermen; // mapping of state machine identifier to height vetoed to fisherman // useful for rewarding fishermen on hyperbridge // (stateMachineId => (blockHeight => fisherman)) mapping(uint256 => mapping(uint256 => address)) private _vetoes; // Parameters for the host HostParams private _hostParams; // monotonically increasing nonce for outgoing requests uint256 private _nonce; // emergency shutdown button, only the admin can do this bool private _frozen; // current verified state of the consensus client; bytes private _consensusState; // timestamp for when the consensus was most recently updated uint256 private _consensusUpdateTimestamp; // Emitted when an incoming POST request is handled event PostRequestHandled(bytes32 commitment, address relayer); // Emitted when an outgoing POST request timeout is handled, `dest` refers // to the destination for the request event PostRequestTimeoutHandled(bytes32 commitment, bytes dest); // Emitted when an incoming POST response is handled event PostResponseHandled(bytes32 commitment, address relayer); // Emitted when an outgoing POST response timeout is handled, `dest` refers // to the destination for the response event PostResponseTimeoutHandled(bytes32 commitment, bytes dest); // Emitted when an outgoing GET request is handled event GetRequestHandled(bytes32 commitment, address relayer); // Emitted when an outgoing GET request timeout is handled, `dest` refers // to the destination for the request event GetRequestTimeoutHandled(bytes32 commitment, bytes dest); // Emitted when new heights are finalized event StateMachineUpdated(bytes stateMachineId, uint256 height); // Emitted when a state commitment is vetoed by a fisherman event StateCommitmentVetoed( bytes stateMachineId, uint256 height, StateCommitment stateCommitment, address fisherman ); // Emitted when a new POST request is dispatched event PostRequestEvent( bytes source, bytes dest, bytes from, bytes to, uint256 indexed nonce, uint256 timeoutTimestamp, bytes data, uint256 fee ); // Emitted when a new POST response is dispatched event PostResponseEvent( bytes source, bytes dest, bytes from, bytes to, uint256 indexed nonce, uint256 timeoutTimestamp, bytes data, bytes response, uint256 resTimeoutTimestamp, uint256 fee ); // Emitted when a new GET request is dispatched event GetRequestEvent( bytes source, bytes dest, bytes from, bytes[] keys, uint256 indexed nonce, uint256 height, uint256 timeoutTimestamp ); // only permits fishermen modifier onlyFishermen() { require(_fishermen[_msgSender()], "EvmHost: Account is not in the fishermen set"); _; } // only permits the admin modifier onlyAdmin() { require(_msgSender() == _hostParams.admin, "EvmHost: Account is not the admin"); _; } // only permits the IHandler contract modifier onlyHandler() { require(_msgSender() == address(_hostParams.handler), "EvmHost: Account is not the handler"); _; } // only permits the HostManager contract modifier onlyManager() { require(_msgSender() == _hostParams.hostManager, "EvmHost: Account is not the Manager contract"); _; } constructor(HostParams memory params) { updateHostParamsInternal(params); _consensusUpdateTimestamp = block.timestamp; } /** * @return the host admin */ function admin() external view returns (address) { return _hostParams.admin; } /** * @return the host state machine id */ function host() public view virtual returns (bytes memory); /** * @return the mainnet evm chainId for this host */ function chainId() public virtual returns (uint256); /** * @return the address of the fee token ERC-20 contract on this state machine */ function feeToken() public view returns (address) { return _hostParams.feeToken; } /** * @return the per-byte fee for outgoing requests. */ function perByteFee() external view returns (uint256) { return _hostParams.perByteFee; } /** * @return the host timestamp */ function timestamp() external view returns (uint256) { return block.timestamp; } /** * @return the `frozen` status */ function frozen() external view returns (bool) { return _frozen; } /** * @return the `HostParams` */ function hostParams() external view returns (HostParams memory) { return _hostParams; } /** * @return the state machine identifier for the connected hyperbridge instance */ function hyperbridge() external view returns (bytes memory) { return _hostParams.hyperbridge; } /** * @param height - state machine height * @return the state commitment at `height` */ function stateMachineCommitment(StateMachineHeight memory height) external view returns (StateCommitment memory) { return _stateCommitments[height.stateMachineId][height.height]; } /** * @param height - state machine height * @return the state machine update time at `height` */ function stateMachineCommitmentUpdateTime(StateMachineHeight memory height) external view returns (uint256) { return _stateCommitmentsUpdateTime[height.stateMachineId][height.height]; } /** * @dev Should return a handle to the consensus client based on the id * @return the consensus client contract */ function consensusClient() external view returns (address) { return _hostParams.consensusClient; } /** * @return the last updated time of the consensus client */ function consensusUpdateTime() external view returns (uint256) { return _consensusUpdateTimestamp; } /** * @return the state of the consensus client */ function consensusState() external view returns (bytes memory) { return _consensusState; } /** * @return the challenge period */ function challengePeriod() external view returns (uint256) { return _hostParams.challengePeriod; } /** * @return the latest state machine height for the given stateMachineId. If it returns 0, the state machine is unsupported. */ function latestStateMachineHeight(uint256 id) external view returns (uint256) { return _latestStateMachineHeight[id]; } /** * @return the unstaking period */ function unStakingPeriod() external view returns (uint256) { return _hostParams.unStakingPeriod; } /** * @param commitment - commitment to the request * @return existence status of an incoming request commitment */ function requestReceipts(bytes32 commitment) external view returns (address) { return _requestReceipts[commitment]; } /** * @param commitment - commitment to the response * @return existence status of an incoming response commitment */ function responseReceipts(bytes32 commitment) external view returns (ResponseReceipt memory) { return _responseReceipts[commitment]; } /** * @param commitment - commitment to the request * @return existence status of an outgoing request commitment */ function requestCommitments(bytes32 commitment) external view returns (FeeMetadata memory) { return _requestCommitments[commitment]; } /** * @param commitment - commitment to the response * @return existence status of an outgoing response commitment */ function responseCommitments(bytes32 commitment) external view returns (FeeMetadata memory) { return _responseCommitments[commitment]; } /** * @dev Updates the HostParams, can only be called by cross-chain governance * @param params, the new host params. */ function updateHostParams(HostParams memory params) external onlyManager { updateHostParamsInternal(params); } /** * @dev Updates the HostParams * @param params, the new host params. Can only be called by admin on testnets. */ function setHostParamsAdmin(HostParams memory params) public onlyAdmin { require(chainId() != block.chainid, "Cannot set params on mainnet"); uint256 whitelistLength = params.stateMachineWhitelist.length; for (uint256 i = 0; i < whitelistLength; i++) { delete _latestStateMachineHeight[params.stateMachineWhitelist[i]]; } updateHostParamsInternal(params); } /** * @dev Updates the HostParams * @param params, the new host params. */ function updateHostParamsInternal(HostParams memory params) private { // delete old fishermen uint256 fishermenLength = _hostParams.fishermen.length; for (uint256 i = 0; i < fishermenLength; i++) { delete _fishermen[_hostParams.fishermen[i]]; } _hostParams = params; // add new fishermen if any uint256 newFishermenLength = params.fishermen.length; for (uint256 i = 0; i < newFishermenLength; i++) { _fishermen[params.fishermen[i]] = true; } // add whitelisted state machines uint256 whitelistLength = params.stateMachineWhitelist.length; for (uint256 i = 0; i < whitelistLength; i++) { // create if it doesn't already exist if (_latestStateMachineHeight[params.stateMachineWhitelist[i]] == 0) { _latestStateMachineHeight[params.stateMachineWhitelist[i]] = 1; } } } /** * @dev withdraws host revenue to the given address, can only be called by cross-chain governance * @param params, the parameters for withdrawal */ function withdraw(WithdrawParams memory params) external onlyManager { require(IERC20(feeToken()).transfer(params.beneficiary, params.amount), "Host has an insufficient balance"); } /** * @dev Store the serialized consensus state, alongside relevant metadata */ function storeConsensusState(bytes memory state) external onlyHandler { _consensusState = state; _consensusUpdateTimestamp = block.timestamp; } /** * @dev Store the state commitment at given state height alongside relevant metadata. Assumes the state commitment is of the latest height. */ function storeStateMachineCommitment(StateMachineHeight memory height, StateCommitment memory commitment) external onlyHandler { _stateCommitments[height.stateMachineId][height.height] = commitment; _stateCommitmentsUpdateTime[height.stateMachineId][height.height] = block.timestamp; _latestStateMachineHeight[height.stateMachineId] = height.height; emit StateMachineUpdated({stateMachineId: stateMachineId(height.stateMachineId), height: height.height}); } /** * @dev Delete the state commitment at given state height. */ function deleteStateMachineCommitment(StateMachineHeight memory height, address fisherman) external onlyHandler { deleteStateMachineCommitmentInternal(height, fisherman); } /** * @dev A fisherman has determined that some [`StateCommitment`] * (which is ideally still in it's challenge period) * is infact fraudulent and misrepresentative of the state * changes at the provided height. This allows them to veto the state commitment. * At the moment, they aren't required to provide any proofs for this. */ function vetoStateCommitment(StateMachineHeight memory height) public onlyFishermen { deleteStateMachineCommitmentInternal(height, _msgSender()); } /** * @dev Delete the state commitment at given state height. */ function deleteStateMachineCommitmentInternal(StateMachineHeight memory height, address fisherman) private { StateCommitment memory stateCommitment = _stateCommitments[height.stateMachineId][height.height]; delete _stateCommitments[height.stateMachineId][height.height]; delete _stateCommitmentsUpdateTime[height.stateMachineId][height.height]; // technically any state commitment can be vetoed, safety check that it's the latest before resetting it. if (_latestStateMachineHeight[height.stateMachineId] == height.height) { _latestStateMachineHeight[height.stateMachineId] = 1; } // track the fisherman responsible for rewards on hyperbridge through state proofs _vetoes[height.stateMachineId][height.height] = fisherman; emit StateCommitmentVetoed({ stateMachineId: stateMachineId(height.stateMachineId), stateCommitment: stateCommitment, height: height.height, fisherman: fisherman }); } /** * @dev Get the state machine id for a parachain */ function stateMachineId(uint256 id) public view returns (bytes memory) { bytes memory hyperbridgeId = _hostParams.hyperbridge; uint256 offset = hyperbridgeId.length - 4; return bytes.concat(hyperbridgeId.substr(0, offset), bytes(Strings.toString(id))); } /** * @dev set the new state of the bridge * @param newState new state */ function setFrozenState(bool newState) public onlyAdmin { _frozen = newState; } /** * @dev sets the initial consensus state * @param state initial consensus state */ function setConsensusState(bytes memory state, StateMachineHeight memory height, StateCommitment memory commitment) public onlyAdmin { // if we're on mainnet, then consensus state can only be initialized once. // and updated subsequently by either consensus proofs or cross-chain governance require(chainId() == block.chainid ? _consensusState.equals(new bytes(0)) : true, "Unauthorized action"); _consensusState = state; _consensusUpdateTimestamp = block.timestamp; _stateCommitments[height.stateMachineId][height.height] = commitment; _stateCommitmentsUpdateTime[height.stateMachineId][height.height] = block.timestamp; _latestStateMachineHeight[height.stateMachineId] = height.height; } /** * @dev Dispatch an incoming POST request to destination module * @param request - post request */ function dispatchIncoming(PostRequest memory request, address relayer) external onlyHandler { address destination = _bytesToAddress(request.to); uint256 size; assembly { size := extcodesize(destination) } if (size == 0) { // instead of reverting the entire batch, early return here. return; } // replay protection bytes32 commitment = request.hash(); _requestReceipts[commitment] = relayer; (bool success,) = address(destination).call( abi.encodeWithSelector(IIsmpModule.onAccept.selector, IncomingPostRequest(request, relayer)) ); if (!success) { // so that it can be retried delete _requestReceipts[commitment]; return; } emit PostRequestHandled({commitment: commitment, relayer: relayer}); } /** * @dev Dispatch an incoming POST response to source module * @param response - post response */ function dispatchIncoming(PostResponse memory response, address relayer) external onlyHandler { address origin = _bytesToAddress(response.request.from); // replay protection bytes32 requestCommitment = response.request.hash(); bytes32 responseCommitment = response.hash(); _responseReceipts[requestCommitment] = ResponseReceipt({relayer: relayer, responseCommitment: responseCommitment}); (bool success,) = address(origin).call( abi.encodeWithSelector(IIsmpModule.onPostResponse.selector, IncomingPostResponse(response, relayer)) ); if (!success) { // so that it can be retried delete _responseReceipts[requestCommitment]; return; } emit PostResponseHandled({commitment: responseCommitment, relayer: relayer}); } /** * @dev Dispatch an incoming GET response to source module * @param response - get response */ function dispatchIncoming(GetResponse memory response, address relayer) external onlyHandler { address origin = _bytesToAddress(response.request.from); // replay protection bytes32 commitment = response.request.hash(); // don't commit the full response object, it's unused. _responseReceipts[commitment] = ResponseReceipt({relayer: relayer, responseCommitment: bytes32(0)}); (bool success,) = address(origin).call( abi.encodeWithSelector(IIsmpModule.onGetResponse.selector, IncomingGetResponse(response, relayer)) ); if (!success) { // so that it can be retried delete _responseReceipts[commitment]; return; } emit PostResponseHandled({commitment: commitment, relayer: relayer}); } /** * @dev Dispatch an incoming GET timeout to the source module * @param request - get request */ function dispatchIncoming(GetRequest memory request, FeeMetadata memory meta, bytes32 commitment) external onlyHandler { address origin = _bytesToAddress(request.from); // replay protection, delete memory of this request delete _requestCommitments[commitment]; (bool success,) = address(origin).call(abi.encodeWithSelector(IIsmpModule.onGetTimeout.selector, request)); if (!success) { // so that it can be retried _requestCommitments[commitment] = meta; return; } emit GetRequestTimeoutHandled({commitment: commitment, dest: request.dest}); } /** * @dev Dispatch an incoming POST timeout to the source module * @param request - post timeout */ function dispatchIncoming(PostRequest memory request, FeeMetadata memory meta, bytes32 commitment) external onlyHandler { address origin = _bytesToAddress(request.from); // replay protection, delete memory of this request delete _requestCommitments[commitment]; (bool success,) = address(origin).call(abi.encodeWithSelector(IIsmpModule.onPostRequestTimeout.selector, request)); if (!success) { // so that it can be retried _requestCommitments[commitment] = meta; return; } if (meta.fee > 0) { // refund relayer fee IERC20(feeToken()).transfer(meta.sender, meta.fee); } emit PostRequestTimeoutHandled({commitment: commitment, dest: request.dest}); } /** * @dev Dispatch an incoming POST response timeout to the source module * @param response - timed-out post response */ function dispatchIncoming(PostResponse memory response, FeeMetadata memory meta, bytes32 commitment) external onlyHandler { address origin = _bytesToAddress(response.request.to); // replay protection, delete memory of this response bytes32 reqCommitment = response.request.hash(); delete _responseCommitments[commitment]; delete _responded[reqCommitment]; (bool success,) = address(origin).call(abi.encodeWithSelector(IIsmpModule.onPostResponseTimeout.selector, response)); if (!success) { // so that it can be retried _responseCommitments[commitment] = meta; _responded[reqCommitment] = true; return; } if (meta.fee > 0) { // refund relayer fee IERC20(feeToken()).transfer(meta.sender, meta.fee); } emit PostResponseTimeoutHandled({commitment: commitment, dest: response.request.source}); } /** * @dev Dispatch a POST request to the hyperbridge * @param post - post request */ function dispatch(DispatchPost memory post) external returns (bytes32 commitment) { uint256 fee = (_hostParams.perByteFee * post.body.length) + post.fee; IERC20(feeToken()).transferFrom(_msgSender(), address(this), fee); // adjust the timeout uint64 timeout = post.timeout == 0 ? 0 : uint64(this.timestamp()) + uint64(Math.max(_hostParams.defaultTimeout, post.timeout)); PostRequest memory request = PostRequest({ source: host(), dest: post.dest, nonce: uint64(_nextNonce()), from: abi.encodePacked(_msgSender()), to: post.to, timeoutTimestamp: timeout, body: post.body }); // make the commitment commitment = request.hash(); _requestCommitments[commitment] = FeeMetadata({sender: post.payer, fee: post.fee}); emit PostRequestEvent( request.source, request.dest, request.from, abi.encodePacked(request.to), request.nonce, request.timeoutTimestamp, request.body, post.fee ); } /** * @dev Dispatch a GET request to the hyperbridge * @param get - get request */ function dispatch(DispatchGet memory get) external returns (bytes32 commitment) { if (get.fee > 0) { IERC20(feeToken()).transferFrom(_msgSender(), address(this), get.fee); } // adjust the timeout uint64 timeout = get.timeout == 0 ? 0 : uint64(this.timestamp()) + uint64(Math.max(_hostParams.defaultTimeout, get.timeout)); GetRequest memory request = GetRequest({ source: host(), dest: get.dest, nonce: uint64(_nextNonce()), from: abi.encodePacked(_msgSender()), timeoutTimestamp: timeout, keys: get.keys, height: get.height }); // make the commitment commitment = request.hash(); _requestCommitments[commitment] = FeeMetadata({sender: get.sender, fee: get.fee}); emit GetRequestEvent( request.source, request.dest, request.from, request.keys, request.nonce, request.height, request.timeoutTimestamp ); } /** * @dev Dispatch a POST response to the hyperbridge * @param post - post response */ function dispatch(DispatchPostResponse memory post) external returns (bytes32 commitment) { bytes32 receipt = post.request.hash(); // known request? require(_requestReceipts[receipt] != address(0), "EvmHost: Unknown request"); // check that the authorized application is issuing this response require(_bytesToAddress(post.request.to) == _msgSender(), "EvmHost: Unauthorized Response"); // check that request has not already been responed to require(!_responded[receipt], "EvmHost: Duplicate Response"); // collect fees uint256 fee = (_hostParams.perByteFee * post.response.length) + post.fee; IERC20(feeToken()).transferFrom(_msgSender(), address(this), fee); // adjust the timeout uint64 timeout = post.timeout == 0 ? 0 : uint64(this.timestamp()) + uint64(Math.max(_hostParams.defaultTimeout, post.timeout)); PostResponse memory response = PostResponse({request: post.request, response: post.response, timeoutTimestamp: timeout}); commitment = response.hash(); FeeMetadata memory meta = FeeMetadata({fee: post.fee, sender: post.payer}); _responseCommitments[commitment] = meta; _responded[receipt] = true; emit PostResponseEvent( response.request.source, response.request.dest, response.request.from, abi.encodePacked(response.request.to), response.request.nonce, response.request.timeoutTimestamp, response.request.body, response.response, response.timeoutTimestamp, meta.fee // sigh solidity ); } /** * @dev Increase the relayer fee for a previously dispatched request. * This is provided for use only on pending requests, such that when they timeout, * the user can recover the entire relayer fee. * * If called on an already delivered request, these funds will be seen as a donation to the hyperbridge protocol. * @param commitment - The request commitment */ function fundRequest(bytes32 commitment, uint256 amount) public { FeeMetadata memory metadata = _requestCommitments[commitment]; require(metadata.sender != address(0), "Unknown request"); IERC20(feeToken()).transferFrom(_msgSender(), address(this), amount); metadata.fee += amount; _requestCommitments[commitment] = metadata; } /** * @dev Increase the relayer fee for a previously dispatched response. * This is provided for use only on pending responses, such that when they timeout, * the user can recover the entire relayer fee. * * If called on an already delivered response, these funds will be seen as a donation to the hyperbridge protocol. * @param commitment - The response commitment */ function fundResponse(bytes32 commitment, uint256 amount) public { FeeMetadata memory metadata = _responseCommitments[commitment]; require(metadata.sender != address(0), "Unknown request"); IERC20(feeToken()).transferFrom(_msgSender(), address(this), amount); metadata.fee += amount; _responseCommitments[commitment] = metadata; } /** * @dev Get next available nonce for outgoing requests. */ function _nextNonce() private returns (uint256) { uint256 _nonce_copy = _nonce; unchecked { ++_nonce; } return _nonce_copy; } /** * @dev Converts bytes to address. * @param _bytes bytes value to be converted * @return addr returns the address */ function _bytesToAddress(bytes memory _bytes) private pure returns (address addr) { require(_bytes.length >= 20, "Invalid address length"); assembly { addr := mload(add(_bytes, 20)) } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {Strings} from "openzeppelin/utils/Strings.sol"; library StateMachine { /// The identifier for the relay chain. uint256 public constant RELAY_CHAIN = 0; // Address a state machine on the polkadot relay chain function polkadot(uint256 id) internal pure returns (bytes memory) { return bytes(string.concat("POLKADOT-", Strings.toString(id))); } // Address a state machine on the kusama relay chain function kusama(uint256 id) internal pure returns (bytes memory) { return bytes(string.concat("KUSAMA-", Strings.toString(id))); } // Address the ethereum "execution layer" function ethereum() internal pure returns (bytes memory) { return bytes("ETHE"); } // Address the Arbitrum state machine function arbitrum() internal pure returns (bytes memory) { return bytes("ARBI"); } // Address the Optimism state machine function optimism() internal pure returns (bytes memory) { return bytes("OPTI"); } // Address the Base state machine function base() internal pure returns (bytes memory) { return bytes("BASE"); } // Address the Polygon POS state machine function polygon() internal pure returns (bytes memory) { return bytes("POLY"); } // Address the Binance smart chain state machine function bsc() internal pure returns (bytes memory) { return bytes("BSC"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 import {Memory} from "./Memory.sol"; struct ByteSlice { bytes data; uint256 offset; } library Bytes { uint256 internal constant BYTES_HEADER_SIZE = 32; // Checks if two `bytes memory` variables are equal. This is done using hashing, // which is much more gas efficient then comparing each byte individually. // Equality means that: // - 'self.length == other.length' // - For 'n' in '[0, self.length)', 'self[n] == other[n]' function equals(bytes memory self, bytes memory other) internal pure returns (bool equal) { if (self.length != other.length) { return false; } uint256 addr; uint256 addr2; assembly { addr := add(self, /*BYTES_HEADER_SIZE*/ 32) addr2 := add(other, /*BYTES_HEADER_SIZE*/ 32) } equal = Memory.equals(addr, addr2, self.length); } function readByte(ByteSlice memory self) internal pure returns (uint8) { if (self.offset + 1 > self.data.length) { revert("Out of range"); } uint8 b = uint8(self.data[self.offset]); self.offset += 1; return b; } // Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'. // Returns the new copy. // Requires that: // - 'startIndex + len <= self.length' // The length of the substring is: 'len' function read(ByteSlice memory self, uint256 len) internal pure returns (bytes memory) { require(self.offset + len <= self.data.length); if (len == 0) { return ""; } uint256 addr = Memory.dataPtr(self.data); bytes memory slice = Memory.toBytes(addr + self.offset, len); self.offset += len; return slice; } // Copies a section of 'self' into a new array, starting at the provided 'startIndex'. // Returns the new copy. // Requires that 'startIndex <= self.length' // The length of the substring is: 'self.length - startIndex' function substr(bytes memory self, uint256 startIndex) internal pure returns (bytes memory) { require(startIndex <= self.length); uint256 len = self.length - startIndex; uint256 addr = Memory.dataPtr(self); return Memory.toBytes(addr + startIndex, len); } // Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'. // Returns the new copy. // Requires that: // - 'startIndex + len <= self.length' // The length of the substring is: 'len' function substr(bytes memory self, uint256 startIndex, uint256 len) internal pure returns (bytes memory) { require(startIndex + len <= self.length); if (len == 0) { return ""; } uint256 addr = Memory.dataPtr(self); return Memory.toBytes(addr + startIndex, len); } // Combines 'self' and 'other' into a single array. // Returns the concatenated arrays: // [self[0], self[1], ... , self[self.length - 1], other[0], other[1], ... , other[other.length - 1]] // The length of the new array is 'self.length + other.length' function concat(bytes memory self, bytes memory other) internal pure returns (bytes memory) { bytes memory ret = new bytes(self.length + other.length); uint256 src; uint256 srcLen; (src, srcLen) = Memory.fromBytes(self); uint256 src2; uint256 src2Len; (src2, src2Len) = Memory.fromBytes(other); uint256 dest; (dest,) = Memory.fromBytes(ret); uint256 dest2 = dest + srcLen; Memory.copy(src, dest, srcLen); Memory.copy(src2, dest2, src2Len); return ret; } function toBytes32(bytes memory self) internal pure returns (bytes32 out) { require(self.length >= 32, "Bytes:: toBytes32: data is to short."); assembly { out := mload(add(self, 32)) } } function toBytes16(bytes memory self, uint256 offset) internal pure returns (bytes16 out) { for (uint256 i = 0; i < 16; i++) { out |= bytes16(bytes1(self[offset + i]) & 0xFF) >> (i * 8); } } function toBytes8(bytes memory self, uint256 offset) internal pure returns (bytes8 out) { for (uint256 i = 0; i < 8; i++) { out |= bytes8(bytes1(self[offset + i]) & 0xFF) >> (i * 8); } } function toBytes4(bytes memory self, uint256 offset) internal pure returns (bytes4) { bytes4 out; for (uint256 i = 0; i < 4; i++) { out |= bytes4(self[offset + i] & 0xFF) >> (i * 8); } return out; } function toBytes2(bytes memory self, uint256 offset) internal pure returns (bytes2) { bytes2 out; for (uint256 i = 0; i < 2; i++) { out |= bytes2(self[offset + i] & 0xFF) >> (i * 8); } return out; } function removeLeadingZero(bytes memory data) internal pure returns (bytes memory) { uint256 length = data.length; uint256 startIndex = 0; for (uint256 i = 0; i < length; i++) { if (data[i] != 0) { startIndex = i; break; } } return substr(data, startIndex); } function removeEndingZero(bytes memory data) internal pure returns (bytes memory) { uint256 length = data.length; uint256 endIndex = 0; for (uint256 i = length - 1; i >= 0; i--) { if (data[i] != 0) { endIndex = i; break; } } return substr(data, 0, endIndex + 1); } function reverse(bytes memory inbytes) internal pure returns (bytes memory) { uint256 inlength = inbytes.length; bytes memory outbytes = new bytes(inlength); for (uint256 i = 0; i <= inlength - 1; i++) { outbytes[i] = inbytes[inlength - i - 1]; } return outbytes; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {PostRequest, PostResponse, GetResponse, GetRequest} from "./Message.sol"; struct IncomingPostRequest { // The Post request PostRequest request; // Relayer responsible for delivering the request address relayer; } struct IncomingPostResponse { // The Post response PostResponse response; // Relayer responsible for delivering the response address relayer; } struct IncomingGetResponse { // The Get response GetResponse response; // Relayer responsible for delivering the response address relayer; } interface IIsmpModule { /** * @dev Called by the IsmpHost to notify a module of a new request the module may choose to respond immediately, or in a later block * @param incoming post request */ function onAccept(IncomingPostRequest memory incoming) external; /** * @dev Called by the IsmpHost to notify a module of a post response to a previously sent out request * @param incoming post response */ function onPostResponse(IncomingPostResponse memory incoming) external; /** * @dev Called by the IsmpHost to notify a module of a get response to a previously sent out request * @param incoming get response */ function onGetResponse(IncomingGetResponse memory incoming) external; /** * @dev Called by the IsmpHost to notify a module of post requests that were previously sent but have now timed-out * @param request post request */ function onPostRequestTimeout(PostRequest memory request) external; /** * @dev Called by the IsmpHost to notify a module of post requests that were previously sent but have now timed-out * @param request post request */ function onPostResponseTimeout(PostResponse memory request) external; /** * @dev Called by the IsmpHost to notify a module of get requests that were previously sent but have now timed-out * @param request get request */ function onGetTimeout(GetRequest memory request) external; } /// Abstract contract to make implementing `IIsmpModule` easier. abstract contract BaseIsmpModule is IIsmpModule { function onAccept(IncomingPostRequest calldata) external virtual { revert("IsmpModule doesn't expect Post requests"); } function onPostRequestTimeout(PostRequest memory) external virtual { revert("IsmpModule doesn't emit Post requests"); } function onPostResponse(IncomingPostResponse memory) external virtual { revert("IsmpModule doesn't emit Post responses"); } function onPostResponseTimeout(PostResponse memory) external virtual { revert("IsmpModule doesn't emit Post responses"); } function onGetResponse(IncomingGetResponse memory) external virtual { revert("IsmpModule doesn't emit Get requests"); } function onGetTimeout(GetRequest memory) external virtual { revert("IsmpModule doesn't emit Get requests"); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateMachineHeight} from "./IConsensusClient.sol"; import {PostRequest} from "./Message.sol"; // An object for dispatching post requests to the IsmpDispatcher struct DispatchPost { // bytes representation of the destination state machine bytes dest; // the destination module bytes to; // the request body bytes body; // timeout for this request in seconds uint64 timeout; // the amount put up to be paid to the relayer, this is in $DAI and charged to tx.origin uint256 fee; // who pays for this request? address payer; } // An object for dispatching get requests to the IsmpDispatcher struct DispatchGet { // bytes representation of the destination state machine bytes dest; // height at which to read the state machine uint64 height; // Storage keys to read bytes[] keys; // timeout for this request in seconds uint64 timeout; // The initiator of this request address sender; // Hyperbridge protocol fees for processing this request. uint256 fee; } struct DispatchPostResponse { // The request that initiated this response PostRequest request; // bytes for post response bytes response; // timeout for this response in seconds uint64 timeout; // the amount put up to be paid to the relayer, this is in $DAI and charged to tx.origin uint256 fee; // who pays for this request? address payer; } // The core ISMP API, IIsmpModules use this interface to send outgoing get/post requests & responses interface IDispatcher { /** * @dev Dispatch a post request to the ISMP router. * @param request - post request * @return commitment - the request commitment */ function dispatch(DispatchPost memory request) external returns (bytes32 commitment); /** * @dev Dispatch a GET request to the ISMP router. * @param request - get request * @return commitment - the request commitment */ function dispatch(DispatchGet memory request) external returns (bytes32 commitment); /** * @dev Provide a response to a previously received request. * @param response - post response * @return commitment - the request commitment */ function dispatch(DispatchPostResponse memory response) external returns (bytes32 commitment); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateCommitment, StateMachineHeight} from "./IConsensusClient.sol"; import {IDispatcher} from "./IDispatcher.sol"; import {PostRequest, PostResponse, GetResponse, PostTimeout, GetRequest} from "./Message.sol"; // Some metadata about the request fee struct FeeMetadata { // the relayer fee uint256 fee; // user who initiated the request address sender; } struct ResponseReceipt { // commitment of the response object bytes32 responseCommitment; // address of the relayer responsible for this response delivery address relayer; } // The IsmpHost is the core of the interoperable state machine protocol which encapsulates the interfaces // required for handlers and modules. interface IIsmpHost is IDispatcher { /** * @return the host admin */ function admin() external returns (address); /** * @return the address of the fee token ERC-20 contract on this state machine */ function feeToken() external view returns (address); /** * @return the per-byte fee for outgoing requests. */ function perByteFee() external view returns (uint256); /** * @return the host state machine id */ function host() external view returns (bytes memory); /** * @return the state machine identifier for the connected hyperbridge instance */ function hyperbridge() external view returns (bytes memory); /** * @return the host timestamp */ function timestamp() external view returns (uint256); /** * @return the `frozen` status */ function frozen() external view returns (bool); /** * @param height - state machine height * @return the state commitment at `height` */ function stateMachineCommitment(StateMachineHeight memory height) external returns (StateCommitment memory); /** * @param height - state machine height * @return the state machine commitment update time at `height` */ function stateMachineCommitmentUpdateTime(StateMachineHeight memory height) external returns (uint256); /** * @dev Should return a handle to the consensus client based on the id * @return the consensus client contract */ function consensusClient() external view returns (address); /** * @return the last updated time of the consensus client */ function consensusUpdateTime() external view returns (uint256); /** * @return the latest state machine height for the given stateMachineId. If it returns 0, the state machine is unsupported. */ function latestStateMachineHeight(uint256 stateMachineId) external view returns (uint256); /** * @return the state of the consensus client */ function consensusState() external view returns (bytes memory); /** * @param commitment - commitment to the request * @return relayer address */ function requestReceipts(bytes32 commitment) external view returns (address); /** * @param commitment - commitment to the request of the response * @return response receipt */ function responseReceipts(bytes32 commitment) external view returns (ResponseReceipt memory); /** * @param commitment - commitment to the request * @return existence status of an outgoing request commitment */ function requestCommitments(bytes32 commitment) external view returns (FeeMetadata memory); /** * @param commitment - commitment to the response * @return existence status of an outgoing response commitment */ function responseCommitments(bytes32 commitment) external view returns (FeeMetadata memory); /** * @return the challenge period */ function challengePeriod() external view returns (uint256); /** * @return the unstaking period */ function unStakingPeriod() external view returns (uint256); /** * @dev Store an encoded consensus state * @param state new consensus state */ function storeConsensusState(bytes memory state) external; /** * @dev Store the commitment at `state height` * @param height state machine height * @param commitment state commitment */ function storeStateMachineCommitment(StateMachineHeight memory height, StateCommitment memory commitment) external; /** * @dev Delete the state commitment at given state height. */ function deleteStateMachineCommitment(StateMachineHeight memory height, address fisherman) external; /** * @dev Dispatch an incoming request to destination module * @param request - post request */ function dispatchIncoming(PostRequest memory request, address relayer) external; /** * @dev Dispatch an incoming post response to source module * @param response - post response */ function dispatchIncoming(PostResponse memory response, address relayer) external; /** * @dev Dispatch an incoming get response to source module * @param response - get response */ function dispatchIncoming(GetResponse memory response, address relayer) external; /** * @dev Dispatch an incoming get timeout to source module * @param timeout - timed-out get request */ function dispatchIncoming(GetRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external; /** * @dev Dispatch an incoming post timeout to source module * @param timeout - timed-out post request */ function dispatchIncoming(PostRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external; /** * @dev Dispatch an incoming post response timeout to source module * @param timeout - timed-out post response */ function dispatchIncoming(PostResponse memory timeout, FeeMetadata memory meta, bytes32 commitment) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; // The state commiment identifies a commiment to some intermediate state in the state machine. // This contains some metadata about the state machine like it's own timestamp at the time of this commitment. struct StateCommitment { // This timestamp is useful for handling request timeouts. uint256 timestamp; // Overlay trie commitment to all ismp requests & response. bytes32 overlayRoot; // State trie commitment at the given block height bytes32 stateRoot; } // Identifies some state machine height. We allow for a state machine identifier here // as some consensus clients may track multiple, concurrent state machines. struct StateMachineHeight { // the state machine identifier uint256 stateMachineId; // height of this state machine uint256 height; } // An intermediate state in the series of state transitions undergone by a given state machine. struct IntermediateState { // the state machine identifier uint256 stateMachineId; // height of this state machine uint256 height; // state commitment StateCommitment commitment; } // The consensus client interface responsible for the verification of consensus datagrams. // It's internals is opaque to the ISMP framework allowing it to evolve as needed. interface IConsensusClient { /// Verify the consensus proof and return the new trusted consensus state and any intermediate states finalized /// by this consensus proof. function verifyConsensus(bytes memory trustedState, bytes memory proof) external returns (bytes memory, IntermediateState memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {IIsmpHost} from "./IIsmpHost.sol"; import { PostRequestMessage, PostResponseMessage, GetResponseMessage, PostRequestTimeoutMessage, PostResponseTimeoutMessage, GetTimeoutMessage } from "./Message.sol"; /* The IHandler interface serves as the entry point for ISMP datagrams, i.e consensus, requests & response messages. The handler is decoupled from the IsmpHost as it allows for easy upgrading through the cross-chain governor contract. This way more efficient cryptographic schemes can be employed without cumbersome contract migrations. */ interface IHandler { /** * @dev Handle an incoming consensus message. This uses the IConsensusClient contract registered on the host to perform the consensus message verification. * @param host - Ismp host * @param proof - consensus proof */ function handleConsensus(IIsmpHost host, bytes memory proof) external; /** * @dev Handles incoming POST requests, check request proofs, message delay and timeouts, then dispatch POST requests to the apropriate contracts. * @param host - Ismp host * @param request - batch post requests */ function handlePostRequests(IIsmpHost host, PostRequestMessage memory request) external; /** * @dev Handles incoming POST responses, check response proofs, message delay and timeouts, then dispatch POST responses to the apropriate contracts. * @param host - Ismp host * @param response - batch post responses */ function handlePostResponses(IIsmpHost host, PostResponseMessage memory response) external; /** * @dev check response proofs, message delay and timeouts, then dispatch get responses to modules * @param host - Ismp host * @param message - batch get responses */ function handleGetResponses(IIsmpHost host, GetResponseMessage memory message) external; /** * @dev check timeout proofs then dispatch to modules * @param host - Ismp host * @param message - batch post request timeouts */ function handlePostRequestTimeouts(IIsmpHost host, PostRequestTimeoutMessage memory message) external; /** * @dev check timeout proofs then dispatch to modules * @param host - Ismp host * @param message - batch post response timeouts */ function handlePostResponseTimeouts(IIsmpHost host, PostResponseTimeoutMessage memory message) external; /** * @dev dispatch to modules * @param host - Ismp host * @param message - batch get request timeouts */ function handleGetRequestTimeouts(IIsmpHost host, GetTimeoutMessage memory message) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateMachineHeight} from "./IConsensusClient.sol"; import {StorageValue} from "solidity-merkle-trees/MerklePatricia.sol"; struct PostRequest { // the source state machine of this request bytes source; // the destination state machine of this request bytes dest; // request nonce uint64 nonce; // Module Id of this request origin bytes from; // destination module id bytes to; // timestamp by which this request times out. uint64 timeoutTimestamp; // request body bytes body; } struct GetRequest { // the source state machine of this request bytes source; // the destination state machine of this request bytes dest; // request nonce uint64 nonce; // Module Id of this request origin bytes from; // timestamp by which this request times out. uint64 timeoutTimestamp; // Storage keys to read. bytes[] keys; // height at which to read destination state machine uint64 height; } struct GetResponse { // The request that initiated this response GetRequest request; // storage values for get response StorageValue[] values; } struct PostResponse { // The request that initiated this response PostRequest request; // bytes for post response bytes response; // timestamp by which this response times out. uint64 timeoutTimestamp; } // A post request as a leaf in a merkle tree struct PostRequestLeaf { // The request PostRequest request; // It's index in the mmr leaves uint256 index; // it's k-index uint256 kIndex; } // A post response as a leaf in a merkle tree struct PostResponseLeaf { // The response PostResponse response; // It's index in the mmr leaves uint256 index; // it's k-index uint256 kIndex; } // A merkle mountain range proof. struct Proof { // height of the state machine StateMachineHeight height; // the multi-proof bytes32[] multiproof; // The total number of leaves in the mmr for this proof. uint256 leafCount; } // A message for handling incoming requests struct PostRequestMessage { // proof for the requests Proof proof; // the requests, contained in a merkle tree leaf PostRequestLeaf[] requests; } // A message for handling incoming GET responses struct GetResponseMessage { // the state (merkle-patricia) proof of the get request keys bytes[] proof; // the height of the state machine proof StateMachineHeight height; // The requests that initiated this response GetRequest[] requests; } struct GetTimeoutMessage { // requests which have timed-out GetRequest[] timeouts; } struct PostTimeout { PostRequest request; } struct PostRequestTimeoutMessage { // requests which have timed-out PostRequest[] timeouts; // the height of the state machine proof StateMachineHeight height; // non-membership proof of the requests bytes[] proof; } struct PostResponseTimeoutMessage { // responses which have timed-out PostResponse[] timeouts; // the height of the state machine proof StateMachineHeight height; // non-membership proof of the requests bytes[] proof; } // A message for handling incoming responses struct PostResponseMessage { // proof for the responses Proof proof; // the responses, contained in a merkle tree leaf PostResponseLeaf[] responses; } library Message { function timeout(PostRequest memory req) internal pure returns (uint64) { if (req.timeoutTimestamp == 0) { return type(uint64).max; } else { return req.timeoutTimestamp; } } function timeout(GetRequest memory req) internal pure returns (uint64) { if (req.timeoutTimestamp == 0) { return type(uint64).max; } else { return req.timeoutTimestamp; } } function timeout(PostResponse memory res) internal pure returns (uint64) { if (res.timeoutTimestamp == 0) { return type(uint64).max; } else { return res.timeoutTimestamp; } } function encodeRequest(PostRequest memory req) internal pure returns (bytes memory) { return abi.encodePacked(req.source, req.dest, req.nonce, req.timeoutTimestamp, req.from, req.to, req.body); } function hash(PostResponse memory res) internal pure returns (bytes32) { return keccak256(bytes.concat(encodeRequest(res.request), abi.encodePacked(res.response, res.timeoutTimestamp))); } function hash(PostRequest memory req) internal pure returns (bytes32) { return keccak256(encodeRequest(req)); } function hash(GetRequest memory req) internal pure returns (bytes32) { bytes memory keysEncoding = bytes(""); uint256 len = req.keys.length; for (uint256 i = 0; i < len; i++) { keysEncoding = bytes.concat(keysEncoding, req.keys[i]); } return keccak256( abi.encodePacked(req.source, req.dest, req.nonce, req.height, req.timeoutTimestamp, req.from, keysEncoding) ); } function hash(GetResponse memory res) internal pure returns (bytes32) { return hash(res.request); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 library Memory { uint256 internal constant WORD_SIZE = 32; // Compares the 'len' bytes starting at address 'addr' in memory with the 'len' // bytes starting at 'addr2'. // Returns 'true' if the bytes are the same, otherwise 'false'. function equals(uint256 addr, uint256 addr2, uint256 len) internal pure returns (bool equal) { assembly { equal := eq(keccak256(addr, len), keccak256(addr2, len)) } } // Compares the 'len' bytes starting at address 'addr' in memory with the bytes stored in // 'bts'. It is allowed to set 'len' to a lower value then 'bts.length', in which case only // the first 'len' bytes will be compared. // Requires that 'bts.length >= len' function equals(uint256 addr, uint256 len, bytes memory bts) internal pure returns (bool equal) { require(bts.length >= len); uint256 addr2; assembly { addr2 := add(bts, /*BYTES_HEADER_SIZE*/ 32) } return equals(addr, addr2, len); } // Returns a memory pointer to the data portion of the provided bytes array. function dataPtr(bytes memory bts) internal pure returns (uint256 addr) { assembly { addr := add(bts, /*BYTES_HEADER_SIZE*/ 32) } } // Creates a 'bytes memory' variable from the memory address 'addr', with the // length 'len'. The function will allocate new memory for the bytes array, and // the 'len bytes starting at 'addr' will be copied into that new memory. function toBytes(uint256 addr, uint256 len) internal pure returns (bytes memory bts) { bts = new bytes(len); uint256 btsptr; assembly { btsptr := add(bts, /*BYTES_HEADER_SIZE*/ 32) } copy(addr, btsptr, len); } // Copies 'self' into a new 'bytes memory'. // Returns the newly created 'bytes memory' // The returned bytes will be of length '32'. function toBytes(bytes32 self) internal pure returns (bytes memory bts) { bts = new bytes(32); assembly { mstore(add(bts, /*BYTES_HEADER_SIZE*/ 32), self) } } // Copy 'len' bytes from memory address 'src', to address 'dest'. // This function does not check the or destination, it only copies // the bytes. function copy(uint256 src, uint256 dest, uint256 len) internal pure { // Copy word-length chunks while possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } dest += WORD_SIZE; src += WORD_SIZE; } // Copy remaining bytes uint256 mask = len == 0 ? 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff : 256 ** (WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } // This function does the same as 'dataPtr(bytes memory)', but will also return the // length of the provided bytes array. function fromBytes(bytes memory bts) internal pure returns (uint256 addr, uint256 len) { len = bts.length; assembly { addr := add(bts, /*BYTES_HEADER_SIZE*/ 32) } } }
pragma solidity 0.8.17; import "./trie/Node.sol"; import "./trie/Option.sol"; import "./trie/NibbleSlice.sol"; import "./trie/TrieDB.sol"; import "./trie/substrate/SubstrateTrieDB.sol"; import "./trie/ethereum/EthereumTrieDB.sol"; // SPDX-License-Identifier: Apache2 // Outcome of a successfully verified merkle-patricia proof struct StorageValue { // the storage key bytes key; // the encoded value bytes value; } /** * @title A Merkle Patricia library * @author Polytope Labs * @dev Use this library to verify merkle patricia proofs * @dev refer to research for more info. https://research.polytope.technology/state-(machine)-proofs */ library MerklePatricia { /** * @notice Verifies substrate specific merkle patricia proofs. * @param root hash of the merkle patricia trie * @param proof a list of proof nodes * @param keys a list of keys to verify * @return bytes[] a list of values corresponding to the supplied keys. */ function VerifySubstrateProof(bytes32 root, bytes[] memory proof, bytes[] memory keys) public pure returns (StorageValue[] memory) { StorageValue[] memory values = new StorageValue[](keys.length); TrieNode[] memory nodes = new TrieNode[](proof.length); for (uint256 i = 0; i < proof.length; i++) { nodes[i] = TrieNode(keccak256(proof[i]), proof[i]); } for (uint256 i = 0; i < keys.length; i++) { values[i].key = keys[i]; NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0); NodeKind memory node = SubstrateTrieDB.decodeNodeKind(TrieDB.get(nodes, root)); // This loop is unbounded so that an adversary cannot insert a deeply nested key in the trie // and successfully convince us of it's non-existence, if we consume the block gas limit while // traversing the trie, then the transaction should revert. for (uint256 j = 1; j > 0; j++) { NodeHandle memory nextNode; if (TrieDB.isLeaf(node)) { Leaf memory leaf = SubstrateTrieDB.decodeLeaf(node); if (NibbleSliceOps.eq(leaf.key, keyNibbles)) { values[i].value = TrieDB.load(nodes, leaf.value); } break; } else if (TrieDB.isNibbledBranch(node)) { NibbledBranch memory nibbled = SubstrateTrieDB.decodeNibbledBranch(node); uint256 nibbledBranchKeyLength = NibbleSliceOps.len(nibbled.key); if (!NibbleSliceOps.startsWith(keyNibbles, nibbled.key)) { break; } if (NibbleSliceOps.len(keyNibbles) == nibbledBranchKeyLength) { if (Option.isSome(nibbled.value)) { values[i].value = TrieDB.load(nodes, nibbled.value.value); } break; } else { uint256 index = NibbleSliceOps.at(keyNibbles, nibbledBranchKeyLength); NodeHandleOption memory handle = nibbled.children[index]; if (Option.isSome(handle)) { keyNibbles = NibbleSliceOps.mid(keyNibbles, nibbledBranchKeyLength + 1); nextNode = handle.value; } else { break; } } } else if (TrieDB.isEmpty(node)) { break; } node = SubstrateTrieDB.decodeNodeKind(TrieDB.load(nodes, nextNode)); } } return values; } /** * @notice Verify child trie keys * @dev substrate specific method in order to verify keys in the child trie. * @param root hash of the merkle root * @param proof a list of proof nodes * @param keys a list of keys to verify * @param childInfo data that can be used to compute the root of the child trie * @return bytes[], a list of values corresponding to the supplied keys. */ function ReadChildProofCheck(bytes32 root, bytes[] memory proof, bytes[] memory keys, bytes memory childInfo) public pure returns (StorageValue[] memory) { // fetch the child trie root hash; bytes memory prefix = bytes(":child_storage:default:"); bytes memory key = bytes.concat(prefix, childInfo); bytes[] memory _keys = new bytes[](1); _keys[0] = key; StorageValue[] memory values = VerifySubstrateProof(root, proof, _keys); bytes32 childRoot = bytes32(values[0].value); require(childRoot != bytes32(0), "Invalid child trie proof"); return VerifySubstrateProof(childRoot, proof, keys); } /** * @notice Verifies ethereum specific merkle patricia proofs as described by EIP-1188. * @param root hash of the merkle patricia trie * @param proof a list of proof nodes * @param keys a list of keys to verify * @return bytes[] a list of values corresponding to the supplied keys. */ function VerifyEthereumProof(bytes32 root, bytes[] memory proof, bytes[] memory keys) public pure returns (StorageValue[] memory) { StorageValue[] memory values = new StorageValue[](keys.length); TrieNode[] memory nodes = new TrieNode[](proof.length); for (uint256 i = 0; i < proof.length; i++) { nodes[i] = TrieNode(keccak256(proof[i]), proof[i]); } for (uint256 i = 0; i < keys.length; i++) { values[i].key = keys[i]; NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0); NodeKind memory node = EthereumTrieDB.decodeNodeKind(TrieDB.get(nodes, root)); // This loop is unbounded so that an adversary cannot insert a deeply nested key in the trie // and successfully convince us of it's non-existence, if we consume the block gas limit while // traversing the trie, then the transaction should revert. for (uint256 j = 1; j > 0; j++) { NodeHandle memory nextNode; if (TrieDB.isLeaf(node)) { Leaf memory leaf = EthereumTrieDB.decodeLeaf(node); // Let's retrieve the offset to be used uint256 offset = keyNibbles.offset % 2 == 0 ? keyNibbles.offset / 2 : keyNibbles.offset / 2 + 1; // Let's cut the key passed as input keyNibbles = NibbleSlice(NibbleSliceOps.bytesSlice(keyNibbles.data, offset), 0); if (NibbleSliceOps.eq(leaf.key, keyNibbles)) { values[i].value = TrieDB.load(nodes, leaf.value); } break; } else if (TrieDB.isExtension(node)) { Extension memory extension = EthereumTrieDB.decodeExtension(node); if (NibbleSliceOps.startsWith(keyNibbles, extension.key)) { // Let's cut the key passed as input uint256 cutNibble = keyNibbles.offset + NibbleSliceOps.len(extension.key); keyNibbles = NibbleSlice( NibbleSliceOps.bytesSlice(keyNibbles.data, cutNibble / 2), cutNibble % 2 ); nextNode = extension.node; } else { break; } } else if (TrieDB.isBranch(node)) { Branch memory branch = EthereumTrieDB.decodeBranch(node); if (NibbleSliceOps.isEmpty(keyNibbles)) { if (Option.isSome(branch.value)) { values[i].value = TrieDB.load(nodes, branch.value.value); } break; } else { NodeHandleOption memory handle = branch.children[NibbleSliceOps.at(keyNibbles, 0)]; if (Option.isSome(handle)) { keyNibbles = NibbleSliceOps.mid(keyNibbles, 1); nextNode = handle.value; } else { break; } } } else if (TrieDB.isEmpty(node)) { break; } node = EthereumTrieDB.decodeNodeKind(TrieDB.load(nodes, nextNode)); } } return values; } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 import "./NibbleSlice.sol"; import "./Bytes.sol"; /// This is an enum for the different node types. struct NodeKind { bool isEmpty; bool isLeaf; bool isHashedLeaf; bool isNibbledValueBranch; bool isNibbledHashedValueBranch; bool isNibbledBranch; bool isExtension; bool isBranch; uint256 nibbleSize; ByteSlice data; } struct NodeHandle { bool isHash; bytes32 hash; bool isInline; bytes inLine; } struct Extension { NibbleSlice key; NodeHandle node; } struct Branch { NodeHandleOption value; NodeHandleOption[16] children; } struct NibbledBranch { NibbleSlice key; NodeHandleOption value; NodeHandleOption[16] children; } struct ValueOption { bool isSome; bytes value; } struct NodeHandleOption { bool isSome; NodeHandle value; } struct Leaf { NibbleSlice key; NodeHandle value; } struct TrieNode { bytes32 hash; bytes node; }
pragma solidity 0.8.17; import "./Node.sol"; // SPDX-License-Identifier: Apache2 library Option { function isSome(ValueOption memory val) internal pure returns (bool) { return val.isSome == true; } function isSome(NodeHandleOption memory val) internal pure returns (bool) { return val.isSome == true; } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 struct NibbleSlice { bytes data; uint256 offset; } library NibbleSliceOps { uint256 internal constant NIBBLE_PER_BYTE = 2; uint256 internal constant BITS_PER_NIBBLE = 4; function len(NibbleSlice memory nibble) internal pure returns (uint256) { return nibble.data.length * NIBBLE_PER_BYTE - nibble.offset; } function mid(NibbleSlice memory self, uint256 i) internal pure returns (NibbleSlice memory) { return NibbleSlice(self.data, self.offset + i); } function isEmpty(NibbleSlice memory self) internal pure returns (bool) { return len(self) == 0; } function eq(NibbleSlice memory self, NibbleSlice memory other) internal pure returns (bool) { return len(self) == len(other) && startsWith(self, other); } function at(NibbleSlice memory self, uint256 i) internal pure returns (uint256) { uint256 ix = (self.offset + i) / NIBBLE_PER_BYTE; uint256 pad = (self.offset + i) % NIBBLE_PER_BYTE; uint8 data = uint8(self.data[ix]); return (pad == 1) ? data & 0x0F : data >> BITS_PER_NIBBLE; } function startsWith(NibbleSlice memory self, NibbleSlice memory other) internal pure returns (bool) { return commonPrefix(self, other) == len(other); } function commonPrefix(NibbleSlice memory self, NibbleSlice memory other) internal pure returns (uint256) { uint256 self_align = self.offset % NIBBLE_PER_BYTE; uint256 other_align = other.offset % NIBBLE_PER_BYTE; if (self_align == other_align) { uint256 self_start = self.offset / NIBBLE_PER_BYTE; uint256 other_start = other.offset / NIBBLE_PER_BYTE; uint256 first = 0; if (self_align != 0) { if ((self.data[self_start] & 0x0F) != (other.data[other_start] & 0x0F)) { return 0; } ++self_start; ++other_start; ++first; } bytes memory selfSlice = bytesSlice(self.data, self_start); bytes memory otherSlice = bytesSlice(other.data, other_start); return biggestDepth(selfSlice, otherSlice) + first; } else { uint256 s = min(len(self), len(other)); uint256 i = 0; while (i < s) { if (at(self, i) != at(other, i)) { break; } ++i; } return i; } } function biggestDepth(bytes memory a, bytes memory b) internal pure returns (uint256) { uint256 upperBound = min(a.length, b.length); uint256 i = 0; while (i < upperBound) { if (a[i] != b[i]) { return i * NIBBLE_PER_BYTE + leftCommon(a[i], b[i]); } ++i; } return i * NIBBLE_PER_BYTE; } function leftCommon(bytes1 a, bytes1 b) internal pure returns (uint256) { if (a == b) { return 2; } else if (uint8(a) & 0xF0 == uint8(b) & 0xF0) { return 1; } else { return 0; } } function bytesSlice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) { uint256 bytesLength = _bytes.length; uint256 _length = bytesLength - _start; require(bytesLength >= _start, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { tempBytes := mload(0x40) // load free memory pointer let lengthmod := and(_length, 31) let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) mstore(0x40, and(add(mc, 31), not(31))) } default { tempBytes := mload(0x40) mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function min(uint256 a, uint256 b) private pure returns (uint256) { return (a < b) ? a : b; } }
// SPDX-License-Identifier: Apache2 pragma solidity 0.8.17; import "./Node.sol"; library TrieDB { function get(TrieNode[] memory nodes, bytes32 hash) internal pure returns (bytes memory) { for (uint256 i = 0; i < nodes.length; i++) { if (nodes[i].hash == hash) { return nodes[i].node; } } revert("Incomplete Proof!"); } function load(TrieNode[] memory nodes, NodeHandle memory node) internal pure returns (bytes memory) { if (node.isInline) { return node.inLine; } else if (node.isHash) { return get(nodes, node.hash); } return bytes(""); } function isNibbledBranch(NodeKind memory node) internal pure returns (bool) { return (node.isNibbledBranch || node.isNibbledHashedValueBranch || node.isNibbledValueBranch); } function isExtension(NodeKind memory node) internal pure returns (bool) { return node.isExtension; } function isBranch(NodeKind memory node) internal pure returns (bool) { return node.isBranch; } function isLeaf(NodeKind memory node) internal pure returns (bool) { return (node.isLeaf || node.isHashedLeaf); } function isEmpty(NodeKind memory node) internal pure returns (bool) { return node.isEmpty; } function isHash(NodeHandle memory node) internal pure returns (bool) { return node.isHash; } function isInline(NodeHandle memory node) internal pure returns (bool) { return node.isInline; } }
pragma solidity 0.8.17; import "../Node.sol"; import "../Bytes.sol"; import {NibbleSliceOps} from "../NibbleSlice.sol"; import {ScaleCodec} from "./ScaleCodec.sol"; import "openzeppelin/utils/Strings.sol"; // SPDX-License-Identifier: Apache2 library SubstrateTrieDB { uint8 public constant FIRST_PREFIX = 0x00 << 6; uint8 public constant PADDING_BITMASK = 0x0F; uint8 public constant EMPTY_TRIE = FIRST_PREFIX | (0x00 << 4); uint8 public constant LEAF_PREFIX_MASK = 0x01 << 6; uint8 public constant BRANCH_WITH_MASK = 0x03 << 6; uint8 public constant BRANCH_WITHOUT_MASK = 0x02 << 6; uint8 public constant ALT_HASHING_LEAF_PREFIX_MASK = FIRST_PREFIX | (0x01 << 5); uint8 public constant ALT_HASHING_BRANCH_WITH_MASK = FIRST_PREFIX | (0x01 << 4); uint8 public constant NIBBLE_PER_BYTE = 2; uint256 public constant NIBBLE_SIZE_BOUND = uint256(type(uint16).max); uint256 public constant BITMAP_LENGTH = 2; uint256 public constant HASH_lENGTH = 32; function decodeNodeKind(bytes memory encoded) internal pure returns (NodeKind memory) { NodeKind memory node; ByteSlice memory input = ByteSlice(encoded, 0); uint8 i = Bytes.readByte(input); if (i == EMPTY_TRIE) { node.isEmpty = true; return node; } uint8 mask = i & (0x03 << 6); if (mask == LEAF_PREFIX_MASK) { node.nibbleSize = decodeSize(i, input, 2); node.isLeaf = true; } else if (mask == BRANCH_WITH_MASK) { node.nibbleSize = decodeSize(i, input, 2); node.isNibbledValueBranch = true; } else if (mask == BRANCH_WITHOUT_MASK) { node.nibbleSize = decodeSize(i, input, 2); node.isNibbledBranch = true; } else if (mask == EMPTY_TRIE) { if (i & (0x07 << 5) == ALT_HASHING_LEAF_PREFIX_MASK) { node.nibbleSize = decodeSize(i, input, 3); node.isHashedLeaf = true; } else if (i & (0x0F << 4) == ALT_HASHING_BRANCH_WITH_MASK) { node.nibbleSize = decodeSize(i, input, 4); node.isNibbledHashedValueBranch = true; } else { // do not allow any special encoding revert("Unallowed encoding"); } } node.data = input; return node; } function decodeNibbledBranch(NodeKind memory node) internal pure returns (NibbledBranch memory) { NibbledBranch memory nibbledBranch; ByteSlice memory input = node.data; bool padding = node.nibbleSize % NIBBLE_PER_BYTE != 0; if (padding && (padLeft(uint8(input.data[input.offset])) != 0)) { revert("Bad Format!"); } uint256 nibbleLen = ((node.nibbleSize + (NibbleSliceOps.NIBBLE_PER_BYTE - 1)) / NibbleSliceOps.NIBBLE_PER_BYTE); nibbledBranch.key = NibbleSlice(Bytes.read(input, nibbleLen), node.nibbleSize % NIBBLE_PER_BYTE); bytes memory bitmapBytes = Bytes.read(input, BITMAP_LENGTH); uint16 bitmap = uint16(ScaleCodec.decodeUint256(bitmapBytes)); NodeHandleOption memory valueHandle; if (node.isNibbledHashedValueBranch) { valueHandle.isSome = true; valueHandle.value.isHash = true; valueHandle.value.hash = Bytes.toBytes32(Bytes.read(input, HASH_lENGTH)); } else if (node.isNibbledValueBranch) { uint256 len = ScaleCodec.decodeUintCompact(input); valueHandle.isSome = true; valueHandle.value.isInline = true; valueHandle.value.inLine = Bytes.read(input, len); } nibbledBranch.value = valueHandle; for (uint256 i = 0; i < 16; i++) { NodeHandleOption memory childHandle; if (valueAt(bitmap, i)) { childHandle.isSome = true; uint256 len = ScaleCodec.decodeUintCompact(input); // revert(string.concat("node index: ", Strings.toString(len))); if (len == HASH_lENGTH) { childHandle.value.isHash = true; childHandle.value.hash = Bytes.toBytes32(Bytes.read(input, HASH_lENGTH)); } else { childHandle.value.isInline = true; childHandle.value.inLine = Bytes.read(input, len); } } nibbledBranch.children[i] = childHandle; } return nibbledBranch; } function decodeLeaf(NodeKind memory node) internal pure returns (Leaf memory) { Leaf memory leaf; ByteSlice memory input = node.data; bool padding = node.nibbleSize % NIBBLE_PER_BYTE != 0; if (padding && padLeft(uint8(input.data[input.offset])) != 0) { revert("Bad Format!"); } uint256 nibbleLen = (node.nibbleSize + (NibbleSliceOps.NIBBLE_PER_BYTE - 1)) / NibbleSliceOps.NIBBLE_PER_BYTE; bytes memory nibbleBytes = Bytes.read(input, nibbleLen); leaf.key = NibbleSlice(nibbleBytes, node.nibbleSize % NIBBLE_PER_BYTE); NodeHandle memory handle; if (node.isHashedLeaf) { handle.isHash = true; handle.hash = Bytes.toBytes32(Bytes.read(input, HASH_lENGTH)); } else { uint256 len = ScaleCodec.decodeUintCompact(input); handle.isInline = true; handle.inLine = Bytes.read(input, len); } leaf.value = handle; return leaf; } function decodeSize(uint8 first, ByteSlice memory encoded, uint8 prefixMask) internal pure returns (uint256) { uint8 maxValue = uint8(255 >> prefixMask); uint256 result = uint256(first & maxValue); if (result < maxValue) { return result; } result -= 1; while (result <= NIBBLE_SIZE_BOUND) { uint256 n = uint256(Bytes.readByte(encoded)); if (n < 255) { return result + n + 1; } result += 255; } return NIBBLE_SIZE_BOUND; } function padLeft(uint8 b) internal pure returns (uint8) { return b & ~PADDING_BITMASK; } function valueAt(uint16 bitmap, uint256 i) internal pure returns (bool) { return bitmap & (uint16(1) << uint16(i)) != 0; } }
pragma solidity 0.8.17; import "../Node.sol"; import "../Bytes.sol"; import {NibbleSliceOps} from "../NibbleSlice.sol"; import "./RLPReader.sol"; // SPDX-License-Identifier: Apache2 library EthereumTrieDB { using RLPReader for bytes; using RLPReader for RLPReader.RLPItem; using RLPReader for RLPReader.Iterator; bytes constant HASHED_NULL_NODE = hex"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"; function decodeNodeKind(bytes memory encoded) external pure returns (NodeKind memory) { NodeKind memory node; ByteSlice memory input = ByteSlice(encoded, 0); if (Bytes.equals(encoded, HASHED_NULL_NODE)) { node.isEmpty = true; return node; } RLPReader.RLPItem[] memory itemList = encoded.toRlpItem().toList(); uint256 numItems = itemList.length; if (numItems == 0) { node.isEmpty = true; return node; } else if (numItems == 2) { //It may be a leaf or extension bytes memory key = itemList[0].toBytes(); uint256 prefix; assembly { let first := shr(248, mload(add(key, 32))) prefix := shr(4, first) } if (prefix == 2 || prefix == 3) { node.isLeaf = true; } else { node.isExtension = true; } } else if (numItems == 17) { node.isBranch = true; } else { revert("Invalid data"); } node.data = input; return node; } function decodeLeaf(NodeKind memory node) external pure returns (Leaf memory) { Leaf memory leaf; RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList(); bytes memory data = decoded[1].toBytes(); //Remove the first byte, which is the prefix and not present in the user provided key leaf.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), 1), 0); leaf.value = NodeHandle(false, bytes32(0), true, data); return leaf; } function decodeExtension(NodeKind memory node) external pure returns (Extension memory) { Extension memory extension; RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList(); bytes memory data = decoded[1].toBytes(); uint8 isOdd = uint8(decoded[0].toBytes()[0] >> 4) & 0x01; //Remove the first byte, which is the prefix and not present in the user provided key extension.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), (isOdd + 1) % 2), isOdd); extension.node = NodeHandle(true, Bytes.toBytes32(data), false, new bytes(0)); return extension; } function decodeBranch(NodeKind memory node) external pure returns (Branch memory) { Branch memory branch; RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList(); NodeHandleOption[16] memory childrens; for (uint256 i = 0; i < 16; i++) { bytes memory dataAsBytes = decoded[i].toBytes(); if (dataAsBytes.length != 32) { childrens[i] = NodeHandleOption(false, NodeHandle(false, bytes32(0), false, new bytes(0))); } else { bytes32 data = Bytes.toBytes32(dataAsBytes); childrens[i] = NodeHandleOption(true, NodeHandle(true, data, false, new bytes(0))); } } if (isEmpty(decoded[16].toBytes())) { branch.value = NodeHandleOption(false, NodeHandle(false, bytes32(0), false, new bytes(0))); } else { branch.value = NodeHandleOption(true, NodeHandle(false, bytes32(0), true, decoded[16].toBytes())); } branch.children = childrens; return branch; } function isEmpty(bytes memory item) internal pure returns (bool) { return item.length > 0 && (item[0] == 0xc0 || item[0] == 0x80); } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 import {Bytes, ByteSlice} from "../Bytes.sol"; library ScaleCodec { // Decodes a SCALE encoded uint256 by converting bytes (bid endian) to little endian format function decodeUint256(bytes memory data) internal pure returns (uint256) { uint256 number; for (uint256 i = data.length; i > 0; i--) { number = number + uint256(uint8(data[i - 1])) * (2 ** (8 * (i - 1))); } return number; } // Decodes a SCALE encoded compact unsigned integer function decodeUintCompact(ByteSlice memory data) internal pure returns (uint256 v) { uint8 b = Bytes.readByte(data); // read the first byte uint8 mode = b % 4; // bitwise operation uint256 value; if (mode == 0) { // [0, 63] value = b >> 2; // right shift to remove mode bits } else if (mode == 1) { // [64, 16383] uint8 bb = Bytes.readByte(data); // read the second byte uint64 r = bb; // convert to uint64 r <<= 6; // multiply by * 2^6 r += b >> 2; // right shift to remove mode bits value = r; } else if (mode == 2) { // [16384, 1073741823] uint8 b2 = Bytes.readByte(data); // read the next 3 bytes uint8 b3 = Bytes.readByte(data); uint8 b4 = Bytes.readByte(data); uint32 x1 = uint32(b) | (uint32(b2) << 8); // convert to little endian uint32 x2 = x1 | (uint32(b3) << 16); uint32 x3 = x2 | (uint32(b4) << 24); x3 >>= 2; // remove the last 2 mode bits value = uint256(x3); } else if (mode == 3) { // [1073741824, 4503599627370496] uint8 l = (b >> 2) + 4; // remove mode bits require(l <= 8, "unexpected prefix decoding Compact<Uint>"); return decodeUint256(Bytes.read(data, l)); } else { revert("Code should be unreachable"); } return value; } // Decodes a SCALE encoded compact unsigned integer function decodeUintCompact(bytes memory data) internal pure returns (uint256 v, uint8 m) { uint8 b = readByteAtIndex(data, 0); // read the first byte uint8 mode = b & 3; // bitwise operation uint256 value; if (mode == 0) { // [0, 63] value = b >> 2; // right shift to remove mode bits } else if (mode == 1) { // [64, 16383] uint8 bb = readByteAtIndex(data, 1); // read the second byte uint64 r = bb; // convert to uint64 r <<= 6; // multiply by * 2^6 r += b >> 2; // right shift to remove mode bits value = r; } else if (mode == 2) { // [16384, 1073741823] uint8 b2 = readByteAtIndex(data, 1); // read the next 3 bytes uint8 b3 = readByteAtIndex(data, 2); uint8 b4 = readByteAtIndex(data, 3); uint32 x1 = uint32(b) | (uint32(b2) << 8); // convert to little endian uint32 x2 = x1 | (uint32(b3) << 16); uint32 x3 = x2 | (uint32(b4) << 24); x3 >>= 2; // remove the last 2 mode bits value = uint256(x3); } else if (mode == 3) { // [1073741824, 4503599627370496] uint8 l = b >> 2; // remove mode bits require(l > 32, "Not supported: number cannot be greater than 32 bytes"); } else { revert("Code should be unreachable"); } return (value, mode); } // The biggest compact supported uint is 2 ** 536 - 1. // But the biggest value supported by this method is 2 ** 256 - 1(max of uint256) function encodeUintCompact(uint256 v) internal pure returns (bytes memory) { if (v < 64) { return abi.encodePacked(uint8(v << 2)); } else if (v < 2 ** 14) { return abi.encodePacked(reverse16(uint16(((v << 2) + 1)))); } else if (v < 2 ** 30) { return abi.encodePacked(reverse32(uint32(((v << 2) + 2)))); } else { bytes memory valueBytes = Bytes.removeEndingZero(abi.encodePacked(reverse256(v))); uint256 length = valueBytes.length; uint8 prefix = uint8(((length - 4) << 2) + 3); return abi.encodePacked(prefix, valueBytes); } } // Read a byte at a specific index and return it as type uint8 function readByteAtIndex(bytes memory data, uint8 index) internal pure returns (uint8) { return uint8(data[index]); } // Sources: // * https://ethereum.stackexchange.com/questions/15350/how-to-convert-an-bytes-to-address-in-solidity/50528 // * https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel function reverse256(uint256 input) internal pure returns (uint256 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); // swap 8-byte long pairs v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); // swap 16-byte long pairs v = (v >> 128) | (v << 128); } function reverse128(uint128 input) internal pure returns (uint128 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF) << 32); // swap 8-byte long pairs v = (v >> 64) | (v << 64); } function reverse64(uint64 input) internal pure returns (uint64 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = (v >> 32) | (v << 32); } function reverse32(uint32 input) internal pure returns (uint32 v) { v = input; // swap bytes v = ((v & 0xFF00FF00) >> 8) | ((v & 0x00FF00FF) << 8); // swap 2-byte long pairs v = (v >> 16) | (v << 16); } function reverse16(uint16 input) internal pure returns (uint16 v) { v = input; // swap bytes v = (v >> 8) | (v << 8); } function encode256(uint256 input) internal pure returns (bytes32) { return bytes32(reverse256(input)); } function encode128(uint128 input) internal pure returns (bytes16) { return bytes16(reverse128(input)); } function encode64(uint64 input) internal pure returns (bytes8) { return bytes8(reverse64(input)); } function encode32(uint32 input) internal pure returns (bytes4) { return bytes4(reverse32(input)); } function encode16(uint16 input) internal pure returns (bytes2) { return bytes2(reverse16(input)); } function encodeBytes(bytes memory input) internal pure returns (bytes memory) { return abi.encodePacked(encodeUintCompact(input.length), input); } }
// SPDX-License-Identifier: Apache-2.0 /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity >=0.5.10 <0.9.0; library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint256 len; uint256 memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint256 nextPtr; // Position of the next item in the list. } /* * @dev Returns the next element in the iteration. Reverts if it has not next element. * @param self The iterator. * @return The next element in the iteration. */ function next(Iterator memory self) internal pure returns (RLPItem memory) { require(hasNext(self)); uint256 ptr = self.nextPtr; uint256 itemLength = _itemLength(ptr); self.nextPtr = ptr + itemLength; return RLPItem(itemLength, ptr); } /* * @dev Returns true if the iteration has more elements. * @param self The iterator. * @return true if the iteration has more elements. */ function hasNext(Iterator memory self) internal pure returns (bool) { RLPItem memory item = self.item; return self.nextPtr < item.memPtr + item.len; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint256 memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @dev Create an iterator. Reverts if item is not a list. * @param self The RLP item. * @return An 'Iterator' over the item. */ function iterator(RLPItem memory self) internal pure returns (Iterator memory) { require(isList(self)); uint256 ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param the RLP item. */ function rlpLen(RLPItem memory item) internal pure returns (uint256) { return item.len; } /* * @param the RLP item. * @return (memPtr, len) pair: location of the item's payload in memory. */ function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) { uint256 offset = _payloadOffset(item.memPtr); uint256 memPtr = item.memPtr + offset; uint256 len = item.len - offset; // data length return (memPtr, len); } /* * @param the RLP item. */ function payloadLen(RLPItem memory item) internal pure returns (uint256) { (, uint256 len) = payloadLocation(item); return len; } /* * @param the RLP item containing the encoded list. */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint256 items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 dataLen; for (uint256 i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /* * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory. * @return keccak256 hash of RLP encoded bytes. */ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) { uint256 ptr = item.memPtr; uint256 len = item.len; bytes32 result; assembly { result := keccak256(ptr, len) } return result; } /* * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory. * @return keccak256 hash of the item payload. */ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) { (uint256 memPtr, uint256 len) = payloadLocation(item); bytes32 result; assembly { result := keccak256(memPtr, len) } return result; } /** * RLPItem conversions into data types * */ // @returns raw rlp encoding in bytes function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) { bytes memory result = new bytes(item.len); if (result.length == 0) return result; uint256 ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte except "0x80" is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint256 result; uint256 memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } // SEE Github Issue #5. // Summary: Most commonly used RLP libraries (i.e Geth) will encode // "0" as "0x80" instead of as "0". We handle this edge case explicitly // here. if (result == 0 || result == STRING_SHORT_START) { return false; } else { return true; } } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(uint160(toUint(item))); } function toUint(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33); (uint256 memPtr, uint256 len) = payloadLocation(item); uint256 result; assembly { result := mload(memPtr) // shift to the correct location if neccesary if lt(len, 32) { result := div(result, exp(256, sub(32, len))) } } return result; } // enforces 32 byte length function toUintStrict(RLPItem memory item) internal pure returns (uint256) { // one byte prefix require(item.len == 33); uint256 result; uint256 memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); (uint256 memPtr, uint256 len) = payloadLocation(item); bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(0x20, result) } copy(memPtr, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint256 memPtr) private pure returns (uint256) { uint256 itemLen; uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { itemLen = 1; } else if (byte0 < STRING_LONG_START) { itemLen = byte0 - STRING_SHORT_START + 1; } else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint256 memPtr) private pure returns (uint256) { uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { return 0; } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) { return 1; } else if (byte0 < LIST_SHORT_START) { // being explicit return byte0 - (STRING_LONG_START - 1) + 1; } else { return byte0 - (LIST_LONG_START - 1) + 1; } } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy(uint256 src, uint256 dest, uint256 len) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } if (len > 0) { // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256 ** (WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } } }
{ "remappings": [ "ismp/=lib/ismp-solidity/src/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "solidity-merkle-trees/=lib/solidity-merkle-trees/src/", "ERC6160/=lib/ERC6160/src/", "stringutils/=lib/solidity-stringutils/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "ismp-solidity/=lib/ismp-solidity/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solidity-stringutils/=lib/solidity-stringutils/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": { "lib/solidity-merkle-trees/src/MerklePatricia.sol": { "MerklePatricia": "0x396c6d5a9ede7868201384f02eda0370d3cc88d2" }, "lib/solidity-merkle-trees/src/trie/ethereum/EthereumTrieDB.sol": { "EthereumTrieDB": "0xc4cf25de85f8f610c170e3aefb16d80220baf864" }, "src/consensus/Header.sol": { "HeaderImpl": "0xc57ef6c88e4fc6b5484e984b3eb1fe44b321a8da" } } }
[{"inputs":[{"components":[{"internalType":"uint256","name":"defaultTimeout","type":"uint256"},{"internalType":"uint256","name":"perByteFee","type":"uint256"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"handler","type":"address"},{"internalType":"address","name":"hostManager","type":"address"},{"internalType":"uint256","name":"unStakingPeriod","type":"uint256"},{"internalType":"uint256","name":"challengePeriod","type":"uint256"},{"internalType":"address","name":"consensusClient","type":"address"},{"internalType":"uint256[]","name":"stateMachineWhitelist","type":"uint256[]"},{"internalType":"address[]","name":"fishermen","type":"address[]"},{"internalType":"bytes","name":"hyperbridge","type":"bytes"}],"internalType":"struct HostParams","name":"params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"source","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"dest","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"from","type":"bytes"},{"indexed":false,"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"height","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timeoutTimestamp","type":"uint256"}],"name":"GetRequestEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":false,"internalType":"address","name":"relayer","type":"address"}],"name":"GetRequestHandled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"dest","type":"bytes"}],"name":"GetRequestTimeoutHandled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"source","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"dest","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"from","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"to","type":"bytes"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timeoutTimestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PostRequestEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":false,"internalType":"address","name":"relayer","type":"address"}],"name":"PostRequestHandled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"dest","type":"bytes"}],"name":"PostRequestTimeoutHandled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"source","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"dest","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"from","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"to","type":"bytes"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timeoutTimestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"response","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"resTimeoutTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PostResponseEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":false,"internalType":"address","name":"relayer","type":"address"}],"name":"PostResponseHandled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"dest","type":"bytes"}],"name":"PostResponseTimeoutHandled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"stateMachineId","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"height","type":"uint256"},{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}],"indexed":false,"internalType":"struct StateCommitment","name":"stateCommitment","type":"tuple"},{"indexed":false,"internalType":"address","name":"fisherman","type":"address"}],"name":"StateCommitmentVetoed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"stateMachineId","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"height","type":"uint256"}],"name":"StateMachineUpdated","type":"event"},{"inputs":[],"name":"CHAIN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"challengePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"consensusClient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"consensusState","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"consensusUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"address","name":"fisherman","type":"address"}],"name":"deleteStateMachineCommitment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeout","type":"uint64"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"payer","type":"address"}],"internalType":"struct DispatchPostResponse","name":"post","type":"tuple"}],"name":"dispatch","outputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"bytes","name":"body","type":"bytes"},{"internalType":"uint64","name":"timeout","type":"uint64"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"payer","type":"address"}],"internalType":"struct DispatchPost","name":"post","type":"tuple"}],"name":"dispatch","outputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"timeout","type":"uint64"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"}],"internalType":"struct DispatchGet","name":"get","type":"tuple"}],"name":"dispatch","outputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse","name":"response","type":"tuple"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"internalType":"struct FeeMetadata","name":"meta","type":"tuple"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"dispatchIncoming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"internalType":"struct FeeMetadata","name":"meta","type":"tuple"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"dispatchIncoming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse","name":"response","type":"tuple"},{"internalType":"address","name":"relayer","type":"address"}],"name":"dispatchIncoming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"address","name":"relayer","type":"address"}],"name":"dispatchIncoming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct GetRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"internalType":"struct FeeMetadata","name":"meta","type":"tuple"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"dispatchIncoming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct GetRequest","name":"request","type":"tuple"},{"components":[{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"bytes","name":"value","type":"bytes"}],"internalType":"struct StorageValue[]","name":"values","type":"tuple[]"}],"internalType":"struct GetResponse","name":"response","type":"tuple"},{"internalType":"address","name":"relayer","type":"address"}],"name":"dispatchIncoming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"fundRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"fundResponse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"host","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"hostParams","outputs":[{"components":[{"internalType":"uint256","name":"defaultTimeout","type":"uint256"},{"internalType":"uint256","name":"perByteFee","type":"uint256"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"handler","type":"address"},{"internalType":"address","name":"hostManager","type":"address"},{"internalType":"uint256","name":"unStakingPeriod","type":"uint256"},{"internalType":"uint256","name":"challengePeriod","type":"uint256"},{"internalType":"address","name":"consensusClient","type":"address"},{"internalType":"uint256[]","name":"stateMachineWhitelist","type":"uint256[]"},{"internalType":"address[]","name":"fishermen","type":"address[]"},{"internalType":"bytes","name":"hyperbridge","type":"bytes"}],"internalType":"struct HostParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hyperbridge","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"latestStateMachineHeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"perByteFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"requestCommitments","outputs":[{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"internalType":"struct FeeMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"requestReceipts","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"responseCommitments","outputs":[{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"internalType":"struct FeeMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"responseReceipts","outputs":[{"components":[{"internalType":"bytes32","name":"responseCommitment","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"internalType":"struct ResponseReceipt","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"state","type":"bytes"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}],"internalType":"struct StateCommitment","name":"commitment","type":"tuple"}],"name":"setConsensusState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"newState","type":"bool"}],"name":"setFrozenState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"defaultTimeout","type":"uint256"},{"internalType":"uint256","name":"perByteFee","type":"uint256"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"handler","type":"address"},{"internalType":"address","name":"hostManager","type":"address"},{"internalType":"uint256","name":"unStakingPeriod","type":"uint256"},{"internalType":"uint256","name":"challengePeriod","type":"uint256"},{"internalType":"address","name":"consensusClient","type":"address"},{"internalType":"uint256[]","name":"stateMachineWhitelist","type":"uint256[]"},{"internalType":"address[]","name":"fishermen","type":"address[]"},{"internalType":"bytes","name":"hyperbridge","type":"bytes"}],"internalType":"struct HostParams","name":"params","type":"tuple"}],"name":"setHostParamsAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"}],"name":"stateMachineCommitment","outputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}],"internalType":"struct StateCommitment","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"}],"name":"stateMachineCommitmentUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"stateMachineId","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"state","type":"bytes"}],"name":"storeConsensusState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}],"internalType":"struct StateCommitment","name":"commitment","type":"tuple"}],"name":"storeStateMachineCommitment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unStakingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"defaultTimeout","type":"uint256"},{"internalType":"uint256","name":"perByteFee","type":"uint256"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"handler","type":"address"},{"internalType":"address","name":"hostManager","type":"address"},{"internalType":"uint256","name":"unStakingPeriod","type":"uint256"},{"internalType":"uint256","name":"challengePeriod","type":"uint256"},{"internalType":"address","name":"consensusClient","type":"address"},{"internalType":"uint256[]","name":"stateMachineWhitelist","type":"uint256[]"},{"internalType":"address[]","name":"fishermen","type":"address[]"},{"internalType":"bytes","name":"hyperbridge","type":"bytes"}],"internalType":"struct HostParams","name":"params","type":"tuple"}],"name":"updateHostParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"}],"name":"vetoStateCommitment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct WithdrawParams","name":"params","type":"tuple"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102685760003560e01c80638d48f3c711610151578063b9ea3289116100c3578063f3f480d911610087578063f3f480d914610697578063f437bc591461069f578063f851a440146106a7578063f8ddf259146106b8578063fadce3c7146106cb578063fc17f340146106de57600080fd5b8063b9ea32891461064e578063bbad99d414610661578063d0f9fcc214610669578063d40784c71461067c578063dab0feae1461068457600080fd5b8063a70a8c4711610115578063a70a8c4714610589578063ab013de1146105fc578063b4974cf01461060f578063b80777ea14610622578063b85e6fbb14610628578063b8f3e8f51461063b57600080fd5b80638d48f3c71461053457806394480805146105475780639a8425bc1461055a5780639a8a0592146105625780639c095f861461056957600080fd5b80632476132b116101ea578063641d729d116101ae578063641d729d14610498578063647846a5146104a05780637686a06a146104b157806385e1f4d0146104c45780638856337e146104cc57806388f92ca01461052157600080fd5b80632476132b146103fb578063368bf4641461040c5780633c5654171461045f5780634e9b74ec14610472578063559efe9e1461048557600080fd5b806319667a3e1161023157806319667a3e146102dc57806319e8faf11461031d5780631a880a93146103305780632211f1dd1461036d5780632215364d146103e657600080fd5b80625e763e1461026d57806303cb07f51461028b578063054f7d9c146102a05780630a4fe5c0146102b65780630b49e04c146102c9575b600080fd5b6102756106f1565b6040516102829190613172565b60405180910390f35b61029e610299366004613419565b610786565b005b60175460ff166040519015158152602001610282565b61029e6102c4366004613584565b6107ce565b6102756102d73660046135a0565b61084c565b6103056102ea3660046135a0565b6000908152600260205260409020546001600160a01b031690565b6040516001600160a01b039091168152602001610282565b61029e61032b3660046135c7565b610930565b61035f61033e366004613584565b80516000908152600660209081526040808320938201518352929052205490565b604051908152602001610282565b6103c261037b3660046135a0565b604080518082019091526000808252602082015250600090815260016020818152604092839020835180850190945280548452909101546001600160a01b03169082015290565b60408051825181526020928301516001600160a01b03169281019290925201610282565b6103ee610976565b6040516102829190613658565b6012546001600160a01b0316610305565b6103c261041a3660046135a0565b60408051808201909152600080825260208201525060009081526020818152604091829020825180840190935280548352600101546001600160a01b03169082015290565b61029e61046d366004613765565b610bbd565b61029e61048036600461396a565b610cc3565b61029e6104933660046139fb565b610f2d565b600b5461035f565b600c546001600160a01b0316610305565b61029e6104bf366004613a30565b611008565b61035f600a81565b6103c26104da3660046135a0565b604080518082019091526000808252602082015250600090815260036020908152604091829020825180840190935280548352600101546001600160a01b03169082015290565b61029e61052f366004613419565b61122e565b61029e610542366004613a67565b611319565b61035f610555366004613ac6565b6114c1565b60195461035f565b600a61035f565b61035f6105773660046135a0565b60009081526007602052604090205490565b6105ef610597366004613584565b6040805160608082018352600080835260208084018290529284018190528451815260058352838120948301518152938252928290208251938401835280548452600181015491840191909152600201549082015290565b6040516102829190613b82565b61029e61060a366004613ba3565b611899565b61029e61061d366004613be7565b611a6b565b4261035f565b61029e610636366004613c23565b611ab2565b61035f610649366004613c58565b611c5a565b61029e61065c366004613d38565b611f42565b610275612078565b61029e610677366004613ec4565b612087565b60105461035f565b61035f610692366004613efb565b61220e565b60115461035f565b6102756124b6565b600d546001600160a01b0316610305565b61029e6106c6366004613fcb565b6124de565b61029e6106d9366004613d38565b61251b565b61029e6106ec366004613ff6565b612654565b6060600a600b01805461070390614165565b80601f016020809104026020016040519081016040528092919081815260200182805461072f90614165565b801561077c5780601f106107515761010080835404028352916020019161077c565b820191906000526020600020905b81548152906001019060200180831161075f57829003601f168201915b5050505050905090565b600f546001600160a01b0316336001600160a01b0316146107c25760405162461bcd60e51b81526004016107b99061419f565b60405180910390fd5b6107cb81612812565b50565b3360009081526008602052604090205460ff166108425760405162461bcd60e51b815260206004820152602c60248201527f45766d486f73743a204163636f756e74206973206e6f7420696e20746865206660448201526b1a5cda195c9b595b881cd95d60a21b60648201526084016107b9565b6107cb8133612a6d565b60606000600a600b01805461086090614165565b80601f016020809104026020016040519081016040528092919081815260200182805461088c90614165565b80156108d95780601f106108ae576101008083540402835291602001916108d9565b820191906000526020600020905b8154815290600101906020018083116108bc57829003601f168201915b505050505090506000600482516108f09190614201565b90506108fe82600083612b98565b61090785612bf1565b604051602001610918929190614214565b60405160208183030381529060405292505050919050565b600d546001600160a01b0316336001600160a01b0316146109635760405162461bcd60e51b81526004016107b990614243565b6017805460ff1916911515919091179055565b610a07604051806101800160405280600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b031681526020016060815260200160608152602001606081525090565b6040805161018081018252600a80548252600b54602080840191909152600c546001600160a01b0390811684860152600d5481166060850152600e5481166080850152600f54811660a085015260105460c085015260115460e085015260125416610100840152601380548551818402810184019096528086529394929361012086019392830182828015610abb57602002820191906000526020600020905b815481526020019060010190808311610aa7575b50505050508152602001600a8201805480602002602001604051908101604052809291908181526020018280548015610b1d57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610aff575b50505050508152602001600b82018054610b3690614165565b80601f0160208091040260200160405190810160405280929190818152602001828054610b6290614165565b8015610baf5780601f10610b8457610100808354040283529160200191610baf565b820191906000526020600020905b815481529060010190602001808311610b9257829003601f168201915b505050505081525050905090565b600f546001600160a01b0316336001600160a01b031614610bf05760405162461bcd60e51b81526004016107b99061419f565b600c546001600160a01b03168151602083015160405163a9059cbb60e01b81526001600160a01b039283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015610c53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c779190614284565b6107cb5760405162461bcd60e51b815260206004820181905260248201527f486f73742068617320616e20696e73756666696369656e742062616c616e636560448201526064016107b9565b600e546001600160a01b0316336001600160a01b031614610cf65760405162461bcd60e51b81526004016107b9906142a1565b6000610d09846000015160800151612c83565b90506000610d1a8560000151612cd8565b600084815260016020818152604080842084815590920180546001600160a01b031916905583835260049052808220805460ff1916905551919250906001600160a01b03841690630bc37bab60e01b90610d789089906024016143d3565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610db691906143e6565b6000604051808303816000865af19150503d8060008114610df3576040519150601f19603f3d011682016040523d82523d6000602084013e610df8565b606091505b5050905080610e5857506000838152600160208181526040808420885181558289015190840180546001600160a01b039092166001600160a01b031990921691909117905593835260049052919020805460ff1916909117905550505050565b845115610ee857600c546001600160a01b03166020860151865160405163a9059cbb60e01b81526001600160a01b039283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af1158015610ec2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee69190614284565b505b8551516040517f1d3e1be35c5b0af16180a3e39997dbde26c1a2fe7add7aff91ffcbb1ca201f1f91610f1c91879190614402565b60405180910390a15050505b505050565b600e546001600160a01b0316336001600160a01b031614610f605760405162461bcd60e51b81526004016107b9906142a1565b815160009081526005602090815260408083208286018051855290835281842085518155838601516001820155828601516002909101558551845260068352818420815185528352818420429055518551845260079092529091205581517fbad502301abccc61a2489c48cee4c09e95c1b8ae9a2f2428f8bfb363a5b8fe8090610fe99061084c565b8360200151604051610ffc92919061441b565b60405180910390a15050565b600e546001600160a01b0316336001600160a01b03161461103b5760405162461bcd60e51b81526004016107b9906142a1565b600061104a8460600151612c83565b60008381526020819052604080822082815560010180546001600160a01b031916905551919250906001600160a01b0383169063bc0dd44760e01b9061109490889060240161443d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516110d291906143e6565b6000604051808303816000865af19150503d806000811461110f576040519150601f19603f3d011682016040523d82523d6000602084013e611114565b606091505b505090508061115a57505060009081526020818152604090912082518155910151600190910180546001600160a01b0319166001600160a01b0390921691909117905550565b8351156111ea57600c546001600160a01b03166020850151855160405163a9059cbb60e01b81526001600160a01b039283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af11580156111c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e89190614284565b505b7f439e4187994d5667f39994679045fee67901b31acde0ca21b2d5aa8eb877373183866020015160405161121f929190614402565b60405180910390a15050505050565b600d546001600160a01b0316336001600160a01b0316146112615760405162461bcd60e51b81526004016107b990614243565b46600a036112b15760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742073657420706172616d73206f6e206d61696e6e65740000000060448201526064016107b9565b6101208101515160005b8181101561130b576007600084610120015183815181106112de576112de614450565b6020026020010151815260200190815260200160002060009055808061130390614466565b9150506112bb565b5061131582612812565b5050565b600d546001600160a01b0316336001600160a01b03161461134c5760405162461bcd60e51b81526004016107b990614243565b46600a1461135b576001611409565b6040805160008082526020820190925261140991506018805461137d90614165565b80601f01602080910402602001604051908101604052809291908181526020018280546113a990614165565b80156113f65780601f106113cb576101008083540402835291602001916113f6565b820191906000526020600020905b8154815290600101906020018083116113d957829003601f168201915b5050505050612cf190919063ffffffff16565b61144b5760405162461bcd60e51b81526020600482015260136024820152722ab730baba3437b934bd32b21030b1ba34b7b760691b60448201526064016107b9565b601861145784826144cd565b5042601981905582516000908152600560209081526040808320828701805185529083528184208651815583870151600182015595820151600290960195909555855183526006825280832085518452825280832093909355925193518152600790925290205550565b6000806114d18360000151612cd8565b6000818152600260205260409020549091506001600160a01b03166115385760405162461bcd60e51b815260206004820152601860248201527f45766d486f73743a20556e6b6e6f776e2072657175657374000000000000000060448201526064016107b9565b825160800151339061154990612c83565b6001600160a01b03161461159f5760405162461bcd60e51b815260206004820152601e60248201527f45766d486f73743a20556e617574686f72697a656420526573706f6e7365000060448201526064016107b9565b60008181526004602052604090205460ff16156115fe5760405162461bcd60e51b815260206004820152601b60248201527f45766d486f73743a204475706c696361746520526573706f6e7365000000000060448201526064016107b9565b6060830151602084015151600b54600092916116199161458c565b61162391906145a3565b9050611637600c546001600160a01b031690565b6001600160a01b03166323b872dd3330846040518463ffffffff1660e01b8152600401611666939291906145b6565b6020604051808303816000875af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a99190614284565b50600084604001516001600160401b031660001461174e576116dd600a6000015486604001516001600160401b0316612d23565b306001600160a01b031663b80777ea6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561171b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173f91906145da565b61174991906145f3565b611751565b60005b6040805160608101825287518152602080890151908201526001600160401b0383169181019190915290915061178681612d39565b60408051808201825260608981015182526080808b01516001600160a01b0390811660208086019182526000888152600180835288822088518155935193810180546001600160a01b03191694909516939093179093558b83526004815291869020805460ff191690911790558651808601518151828401519583015192909401519651979c5094966001600160401b03909516957f08a1a7506fcfc6d2b25b0280f39edcb82f27ed423de283e69890eb4109b6142b95939493919261184c92016143e6565b60408051601f19818403018152828252895160a081015160c09091015160208c0151938c01518b516118879998979694959394929392614613565b60405180910390a25050505050919050565b600e546001600160a01b0316336001600160a01b0316146118cc5760405162461bcd60e51b81526004016107b9906142a1565b60006118df836000015160600151612c83565b905060006118f08460000151612cd8565b905060006118fd85612d39565b6040805180820182528281526001600160a01b038781166020808401828152600089815260038352868120955186559051600190950180546001600160a01b03191695851695909517909455845180860186528b815290810191909152925193945090929086169163b2a01bf560e01b9161197b91906024016146b4565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516119b991906143e6565b6000604051808303816000865af19150503d80600081146119f6576040519150601f19603f3d011682016040523d82523d6000602084013e6119fb565b606091505b5050905080611a2d575050600090815260036020526040812090815560010180546001600160a01b0319169055505050565b604080518381526001600160a01b03871660208201527fee00e116b272a1610063bf2a37255152212aeea2d088118e22add5cbe3e9f4189101610f1c565b600e546001600160a01b0316336001600160a01b031614611a9e5760405162461bcd60e51b81526004016107b9906142a1565b6018611aaa82826144cd565b505042601955565b600e546001600160a01b0316336001600160a01b031614611ae55760405162461bcd60e51b81526004016107b9906142a1565b6000611af48360800151612c83565b9050803b6000819003611b075750505050565b6000611b1285612cd8565b600081815260026020908152604080832080546001600160a01b0319166001600160a01b038a8116918217909255825180840184528b81529384015290519394509192918616916307f7196760e11b91611b6e916024016146f1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611bac91906143e6565b6000604051808303816000865af19150503d8060008114611be9576040519150601f19603f3d011682016040523d82523d6000602084013e611bee565b606091505b5050905080611c1c5750600090815260026020526040902080546001600160a01b0319169055506113159050565b604080518381526001600160a01b03871660208201527fa73d58a0fd0647075f9f6b1d18358fcb27c8f8f164fd05c4f9d3e9d5c4f3b64d9101610f1c565b6000808260800151836040015151600a60010154611c78919061458c565b611c8291906145a3565b9050611c96600c546001600160a01b031690565b6001600160a01b03166323b872dd3330846040518463ffffffff1660e01b8152600401611cc5939291906145b6565b6020604051808303816000875af1158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190614284565b50600083606001516001600160401b0316600014611dad57611d3c600a6000015485606001516001600160401b0316612d23565b306001600160a01b031663b80777ea6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9e91906145da565b611da891906145f3565b611db0565b60005b905060006040518060e00160405280611dc76124b6565b815286516020820152604001611de4601680546001810190915590565b6001600160401b0316815260200133604051602001611e1b919060609190911b6bffffffffffffffffffffffff1916815260140190565b604051602081830303815290604052815260200186602001518152602001836001600160401b0316815260200186604001518152509050611e5b81612cd8565b604080518082018252608088810151825260a08901516001600160a01b0390811660208085019182526000878152808252869020945185559051600190940180546001600160a01b03191694909216939093179055848301518551868401516060880151938801519551969a506001600160401b03909216957fcd4e29fd03db898bc8c88805cb5b0a1a99ff9ac7299b57f2b4dcca8ea40d708f959194929392611f069291016143e6565b60408051601f198184030181529082905260a088015160c089015160808e0151611f329796959461470d565b60405180910390a2505050919050565b60008281526020818152604091829020825180840190935280548352600101546001600160a01b0316908201819052611faf5760405162461bcd60e51b815260206004820152600f60248201526e155b9adb9bdddb881c995c5d595cdd608a1b60448201526064016107b9565b600c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90611fe3903390309087906004016145b6565b6020604051808303816000875af1158015612002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120269190614284565b50818160000181815161203991906145a3565b90525060009283526020838152604090932081518155920151600190920180546001600160a01b0319166001600160a01b039093169290921790915550565b60606018805461070390614165565b600e546001600160a01b0316336001600160a01b0316146120ba5760405162461bcd60e51b81526004016107b9906142a1565b60006120c98460600151612c83565b60008381526020819052604080822082815560010180546001600160a01b031916905551919250906001600160a01b03831690636249721360e11b90612113908890602401614887565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161215191906143e6565b6000604051808303816000865af19150503d806000811461218e576040519150601f19603f3d011682016040523d82523d6000602084013e612193565b606091505b50509050806121d957505060009081526020818152604090912082518155910151600190910180546001600160a01b0319166001600160a01b0390921691909117905550565b7f06d27f93060b13f7353c3593e7f4397164e53ea6841ac9296f6ba90fe456023183866020015160405161121f929190614402565b60a08101516000901561229757600c5460a08301516040516323b872dd60e01b81526001600160a01b03909216916323b872dd9161225291339130916004016145b6565b6020604051808303816000875af1158015612271573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122959190614284565b505b600082606001516001600160401b031660001461233b576122ca600a6000015484606001516001600160401b0316612d23565b306001600160a01b031663b80777ea6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612308573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232c91906145da565b61233691906145f3565b61233e565b60005b905060006040518060e001604052806123556124b6565b815285516020820152604001612372601680546001810190915590565b6001600160401b03168152602001336040516020016123a9919060609190911b6bffffffffffffffffffffffff1916815260140190565b6040516020818303038152906040528152602001836001600160401b031681526020018560400151815260200185602001516001600160401b031681525090506123f281612d9b565b60408051808201825260a08781015182526080808901516001600160a01b0390811660208086019182526000888152808252879020955186559051600190950180546001600160a01b031916959092169490941790558584015186519387015160608801519388015160c0890151938901519651979a506001600160401b03909216967fba3633af10c29adfd83887c45d38a18c134770a3173bb9e966a99bcfffa5d9ba966124a7969592949293929161489a565b60405180910390a25050919050565b60606124d96040805180820190915260048152634f50544960e01b602082015290565b905090565b600e546001600160a01b0316336001600160a01b0316146125115760405162461bcd60e51b81526004016107b9906142a1565b6113158282612a6d565b600082815260016020818152604092839020835180850190945280548452909101546001600160a01b031690820181905261258a5760405162461bcd60e51b815260206004820152600f60248201526e155b9adb9bdddb881c995c5d595cdd608a1b60448201526064016107b9565b600c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906125be903390309087906004016145b6565b6020604051808303816000875af11580156125dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126019190614284565b50818160000181815161261491906145a3565b9052506000928352600160208181526040909420825181559190930151920180546001600160a01b0319166001600160a01b039093169290921790915550565b600e546001600160a01b0316336001600160a01b0316146126875760405162461bcd60e51b81526004016107b9906142a1565b600061269a836000015160600151612c83565b905060006126ab8460000151612d9b565b60408051808201825260008082526001600160a01b038781166020808501828152878552600382528685209551865551600190950180546001600160a01b03191695841695909517909455845180860186528a8152938401529251939450929185169163b5a9824b60e01b916127239160240161490e565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161276191906143e6565b6000604051808303816000865af19150503d806000811461279e576040519150601f19603f3d011682016040523d82523d6000602084013e6127a3565b606091505b50509050806127d45750600090815260036020526040812090815560010180546001600160a01b0319169055505050565b604080518381526001600160a01b03861660208201527fee00e116b272a1610063bf2a37255152212aeea2d088118e22add5cbe3e9f418910161121f565b60145460005b818110156128775760086000600a8001838154811061283957612839614450565b60009182526020808320909101546001600160a01b031683528201929092526040019020805460ff191690558061286f81614466565b915050612818565b508151600a908155602080840151600b556040840151600c80546001600160a01b03199081166001600160a01b03938416179091556060860151600d805483169184169190911790556080860151600e8054831691841691909117905560a0860151600f8054831691841691909117905560c086015160105560e086015160115561010086015160128054909216921691909117905561012084015180518593926129279260139291019061306d565b50610140820151805161294491600a8401916020909101906130b8565b50610160820151600b82019061295a90826144cd565b5050506101408201515160005b818110156129d057600160086000866101400151848151811061298c5761298c614450565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806129c881614466565b915050612967565b506101208301515160005b81811015612a66576007600086610120015183815181106129fe576129fe614450565b6020026020010151815260200190815260200160002054600003612a54576001600760008761012001518481518110612a3957612a39614450565b60200260200101518152602001908152602001600020819055505b80612a5e81614466565b9150506129db565b5050505050565b815160009081526005602081815260408084208287018051865290835281852082516060810184528154815260018083015482870152600292830154828601528951885295855283872083518852855283872087815595860187905594018590558651855260068352818520815186528352818520859055518651855260079092529092205490919003612b105782516000908152600760205260409020600190555b82516000908152600960209081526040808320828701518452909152902080546001600160a01b0319166001600160a01b03841617905582517f54c345965d0120f275a9a4dc5e6143ce64e485ed1338f1f989a9804e06feee9990612b749061084c565b84602001518385604051612b8b94939291906149cf565b60405180910390a1505050565b8251606090612ba783856145a3565b1115612bb257600080fd5b81600003612bcf5750604080516020810190915260008152612bea565b60208401612be6612be085836145a3565b84612e67565b9150505b9392505050565b60606000612bfe83612ec4565b60010190506000816001600160401b03811115612c1d57612c1d613185565b6040519080825280601f01601f191660200182016040528015612c47576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612c5157509392505050565b6000601482511015612cd05760405162461bcd60e51b8152602060048201526016602482015275092dcecc2d8d2c840c2c8c8e4cae6e640d8cadccee8d60531b60448201526064016107b9565b506014015190565b6000612ce382612f9c565b805190602001209050919050565b60008151835114612d0457506000612d1d565b825160208381018281209186019283209091145b925050505b92915050565b6000818311612d325781612bea565b5090919050565b6000612d488260000151612f9c565b6020808401516040808601519051612d609301614a25565b60408051601f1981840301815290829052612d7e9291602001614214565b604051602081830303815290604052805190602001209050919050565b6040805160208101909152600080825260a083015151909190825b81811015612e1257828560a001518281518110612dd557612dd5614450565b6020026020010151604051602001612dee929190614214565b60405160208183030381529060405292508080612e0a90614466565b915050612db6565b508360000151846020015185604001518660c001518760800151886060015187604051602001612e489796959493929190614a57565b6040516020818303038152906040528051906020012092505050919050565b6060816001600160401b03811115612e8157612e81613185565b6040519080825280601f01601f191660200182016040528015612eab576020820181803683370190505b50905060208101612ebd848285612fed565b5092915050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310612f035772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612f2f576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310612f4d57662386f26fc10000830492506010015b6305f5e1008310612f65576305f5e100830492506008015b6127108310612f7957612710830492506004015b60648310612f8b576064830492506002015b600a8310612d1d5760010192915050565b60608160000151826020015183604001518460a00151856060015186608001518760c00151604051602001612fd79796959493929190614ae2565b6040516020818303038152906040529050919050565b6020811061302557825182526130046020836145a3565b91506130116020846145a3565b925061301e602082614201565b9050612fed565b6000811561305557600161303a836020614201565b61304690610100614c5d565b6130509190614201565b613059565b6000195b935183518516941916939093179091525050565b8280548282559060005260206000209081019282156130a8579160200282015b828111156130a857825182559160200191906001019061308d565b506130b492915061310d565b5090565b8280548282559060005260206000209081019282156130a8579160200282015b828111156130a857825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906130d8565b5b808211156130b4576000815560010161310e565b60005b8381101561313d578181015183820152602001613125565b50506000910152565b6000815180845261315e816020860160208601613122565b601f01601f19169290920160200192915050565b602081526000612bea6020830184613146565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b03811182821017156131be576131be613185565b60405290565b604080519081016001600160401b03811182821017156131be576131be613185565b60405160e081016001600160401b03811182821017156131be576131be613185565b604051606081016001600160401b03811182821017156131be576131be613185565b60405160a081016001600160401b03811182821017156131be576131be613185565b60405160c081016001600160401b03811182821017156131be576131be613185565b604051601f8201601f191681016001600160401b038111828210171561329657613296613185565b604052919050565b80356001600160a01b03811681146132b557600080fd5b919050565b60006001600160401b038211156132d3576132d3613185565b5060051b60200190565b600082601f8301126132ee57600080fd5b813560206133036132fe836132ba565b61326e565b82815260059290921b8401810191818101908684111561332257600080fd5b8286015b8481101561333d5780358352918301918301613326565b509695505050505050565b600082601f83011261335957600080fd5b813560206133696132fe836132ba565b82815260059290921b8401810191818101908684111561338857600080fd5b8286015b8481101561333d5761339d8161329e565b835291830191830161338c565b600082601f8301126133bb57600080fd5b81356001600160401b038111156133d4576133d4613185565b6133e7601f8201601f191660200161326e565b8181528460208386010111156133fc57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561342b57600080fd5b81356001600160401b038082111561344257600080fd5b90830190610180828603121561345757600080fd5b61345f61319b565b82358152602083013560208201526134796040840161329e565b604082015261348a6060840161329e565b606082015261349b6080840161329e565b60808201526134ac60a0840161329e565b60a082015260c083013560c082015260e083013560e08201526101006134d381850161329e565b9082015261012083810135838111156134eb57600080fd5b6134f7888287016132dd565b828401525050610140808401358381111561351157600080fd5b61351d88828701613348565b828401525050610160808401358381111561353757600080fd5b613543888287016133aa565b918301919091525095945050505050565b60006040828403121561356657600080fd5b61356e6131c4565b9050813581526020820135602082015292915050565b60006040828403121561359657600080fd5b612bea8383613554565b6000602082840312156135b257600080fd5b5035919050565b80151581146107cb57600080fd5b6000602082840312156135d957600080fd5b8135612bea816135b9565b600081518084526020808501945080840160005b83811015613614578151875295820195908201906001016135f8565b509495945050505050565b600081518084526020808501945080840160005b838110156136145781516001600160a01b031687529582019590820190600101613633565b6020815281516020820152602082015160408201526000604083015161368960608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e083015260e08301516101008181850152808501519150506101206136fe818501836001600160a01b03169052565b80850151915050610180610140818186015261371e6101a08601846135e4565b9250808601519050601f1961016081878603018188015261373f858461361f565b90880151878203909201848801529350905061375b8382613146565b9695505050505050565b60006040828403121561377757600080fd5b61377f6131c4565b6137888361329e565b8152602083013560208201528091505092915050565b80356001600160401b03811681146132b557600080fd5b600060e082840312156137c757600080fd5b6137cf6131e6565b905081356001600160401b03808211156137e857600080fd5b6137f4858386016133aa565b8352602084013591508082111561380a57600080fd5b613816858386016133aa565b60208401526138276040850161379e565b6040840152606084013591508082111561384057600080fd5b61384c858386016133aa565b6060840152608084013591508082111561386557600080fd5b613871858386016133aa565b608084015261388260a0850161379e565b60a084015260c084013591508082111561389b57600080fd5b506138a8848285016133aa565b60c08301525092915050565b6000606082840312156138c657600080fd5b6138ce613208565b905081356001600160401b03808211156138e757600080fd5b6138f3858386016137b5565b8352602084013591508082111561390957600080fd5b50613916848285016133aa565b6020830152506139286040830161379e565b604082015292915050565b60006040828403121561394557600080fd5b61394d6131c4565b90508135815261395f6020830161329e565b602082015292915050565b60008060006080848603121561397f57600080fd5b83356001600160401b0381111561399557600080fd5b6139a1868287016138b4565b9350506139b18560208601613933565b9150606084013590509250925092565b6000606082840312156139d357600080fd5b6139db613208565b905081358152602082013560208201526040820135604082015292915050565b60008060a08385031215613a0e57600080fd5b613a188484613554565b9150613a2784604085016139c1565b90509250929050565b600080600060808486031215613a4557600080fd5b83356001600160401b03811115613a5b57600080fd5b6139a1868287016137b5565b600080600060c08486031215613a7c57600080fd5b83356001600160401b03811115613a9257600080fd5b613a9e868287016133aa565b935050613aae8560208601613554565b9150613abd85606086016139c1565b90509250925092565b600060208284031215613ad857600080fd5b81356001600160401b0380821115613aef57600080fd5b9083019060a08286031215613b0357600080fd5b613b0b61322a565b823582811115613b1a57600080fd5b613b26878286016137b5565b825250602083013582811115613b3b57600080fd5b613b47878286016133aa565b602083015250613b596040840161379e565b604082015260608301356060820152613b746080840161329e565b608082015295945050505050565b81518152602080830151908201526040808301519082015260608101612d1d565b60008060408385031215613bb657600080fd5b82356001600160401b03811115613bcc57600080fd5b613bd8858286016138b4565b925050613a276020840161329e565b600060208284031215613bf957600080fd5b81356001600160401b03811115613c0f57600080fd5b613c1b848285016133aa565b949350505050565b60008060408385031215613c3657600080fd5b82356001600160401b03811115613c4c57600080fd5b613bd8858286016137b5565b600060208284031215613c6a57600080fd5b81356001600160401b0380821115613c8157600080fd5b9083019060c08286031215613c9557600080fd5b613c9d61324c565b823582811115613cac57600080fd5b613cb8878286016133aa565b825250602083013582811115613ccd57600080fd5b613cd9878286016133aa565b602083015250604083013582811115613cf157600080fd5b613cfd878286016133aa565b604083015250613d0f6060840161379e565b606082015260808301356080820152613d2a60a0840161329e565b60a082015295945050505050565b60008060408385031215613d4b57600080fd5b50508035926020909101359150565b600082601f830112613d6b57600080fd5b81356020613d7b6132fe836132ba565b82815260059290921b84018101918181019086841115613d9a57600080fd5b8286015b8481101561333d5780356001600160401b03811115613dbd5760008081fd5b613dcb8986838b01016133aa565b845250918301918301613d9e565b600060e08284031215613deb57600080fd5b613df36131e6565b905081356001600160401b0380821115613e0c57600080fd5b613e18858386016133aa565b83526020840135915080821115613e2e57600080fd5b613e3a858386016133aa565b6020840152613e4b6040850161379e565b60408401526060840135915080821115613e6457600080fd5b613e70858386016133aa565b6060840152613e816080850161379e565b608084015260a0840135915080821115613e9a57600080fd5b50613ea784828501613d5a565b60a083015250613eb960c0830161379e565b60c082015292915050565b600080600060808486031215613ed957600080fd5b83356001600160401b03811115613eef57600080fd5b6139a186828701613dd9565b600060208284031215613f0d57600080fd5b81356001600160401b0380821115613f2457600080fd5b9083019060c08286031215613f3857600080fd5b613f4061324c565b823582811115613f4f57600080fd5b613f5b878286016133aa565b825250613f6a6020840161379e565b6020820152604083013582811115613f8157600080fd5b613f8d87828601613d5a565b604083015250613f9f6060840161379e565b6060820152613fb06080840161329e565b608082015260a083013560a082015280935050505092915050565b60008060608385031215613fde57600080fd5b613fe88484613554565b9150613a276040840161329e565b6000806040838503121561400957600080fd5b82356001600160401b038082111561402057600080fd5b908401906040828703121561403457600080fd5b61403c6131c4565b82358281111561404b57600080fd5b61405788828601613dd9565b8252506020808401358381111561406d57600080fd5b80850194505087601f85011261408257600080fd5b83356140906132fe826132ba565b81815260059190911b8501820190828101908a8311156140af57600080fd5b8387015b83811015614141578035878111156140cb5760008081fd5b88016040818e03601f190112156140e25760008081fd5b6140ea6131c4565b86820135898111156140fc5760008081fd5b61410a8f89838601016133aa565b8252506040820135898111156141205760008081fd5b61412e8f89838601016133aa565b82890152508452509184019184016140b3565b50808486015250505081955061415881880161329e565b9450505050509250929050565b600181811c9082168061417957607f821691505b60208210810361419957634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602c908201527f45766d486f73743a204163636f756e74206973206e6f7420746865204d616e6160408201526b19d95c8818dbdb9d1c9858dd60a21b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b81810381811115612d1d57612d1d6141eb565b60008351614226818460208801613122565b83519083019061423a818360208801613122565b01949350505050565b60208082526021908201527f45766d486f73743a204163636f756e74206973206e6f74207468652061646d696040820152603760f91b606082015260800190565b60006020828403121561429657600080fd5b8151612bea816135b9565b60208082526023908201527f45766d486f73743a204163636f756e74206973206e6f74207468652068616e646040820152623632b960e91b606082015260800190565b6000815160e084526142f960e0850182613146565b9050602083015184820360208601526143128282613146565b91505060408301516001600160401b0380821660408701526060850151915085830360608701526143438383613146565b925060808501519150858303608087015261435e8383613146565b92508060a08601511660a0870152505060c083015184820360c0860152612d188282613146565b600081516060845261439a60608501826142e4565b9050602083015184820360208601526143b38282613146565b9150506001600160401b0360408401511660408501528091505092915050565b602081526000612bea6020830184614385565b600082516143f8818460208701613122565b9190910192915050565b828152604060208201526000613c1b6040830184613146565b60408152600061442e6040830185613146565b90508260208301529392505050565b602081526000612bea60208301846142e4565b634e487b7160e01b600052603260045260246000fd5b600060018201614478576144786141eb565b5060010190565b601f821115610f2857600081815260208120601f850160051c810160208610156144a65750805b601f850160051c820191505b818110156144c5578281556001016144b2565b505050505050565b81516001600160401b038111156144e6576144e6613185565b6144fa816144f48454614165565b8461447f565b602080601f83116001811461452f57600084156145175750858301515b600019600386901b1c1916600185901b1785556144c5565b600085815260208120601f198616915b8281101561455e5788860151825594840194600190910190840161453f565b508582101561457c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082028115828204841417612d1d57612d1d6141eb565b80820180821115612d1d57612d1d6141eb565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000602082840312156145ec57600080fd5b5051919050565b6001600160401b03818116838216019080821115612ebd57612ebd6141eb565b60006101208083526146278184018d613146565b9050828103602084015261463b818c613146565b9050828103604084015261464f818b613146565b90508281036060840152614663818a613146565b90506001600160401b03808916608085015283820360a08501526146878289613146565b915083820360c085015261469b8288613146565b951660e084015250506101000152979650505050505050565b6020815260008251604060208401526146d06060840182614385565b602094909401516001600160a01b0316604093909301929092525090919050565b6020815260008251604060208401526146d060608401826142e4565b60e08152600061472060e083018a613146565b8281036020840152614732818a613146565b905082810360408401526147468189613146565b9050828103606084015261475a8188613146565b90506001600160401b038616608084015282810360a084015261477d8186613146565b9150508260c083015298975050505050505050565b600081518084526020808501808196508360051b8101915082860160005b858110156147da5782840389526147c8848351613146565b988501989350908401906001016147b0565b5091979650505050505050565b6000815160e084526147fc60e0850182613146565b9050602083015184820360208601526148158282613146565b91505060408301516001600160401b0380821660408701526060850151915085830360608701526148468383613146565b925080608086015116608087015260a0850151915085830360a087015261486d8383614792565b92508060c08601511660c087015250508091505092915050565b602081526000612bea60208301846147e7565b60c0815260006148ad60c0830189613146565b82810360208401526148bf8189613146565b905082810360408401526148d38188613146565b905082810360608401526148e78187614792565b9150506001600160401b03808516608084015280841660a084015250979650505050505050565b60006020808352835160408083860152815181606087015261493360a08701826147e7565b92840151868403605f19016080880152805180855290850193915084820190600581901b8301860160005b828110156149ae57848203601f190184528651805187845261498288850182613146565b918a0151848303858c015291905061499a8183613146565b988a0198958a01959350505060010161495e565b50958901516001600160a01b038116858a0152959998505050505050505050565b60c0815260006149e260c0830187613146565b9050846020830152614a0b60408301858051825260208082015190830152604090810151910152565b6001600160a01b039290921660a091909101529392505050565b60008351614a37818460208801613122565b60c09390931b6001600160c01b0319169190920190815260080192915050565b60008851614a69818460208d01613122565b885190830190614a7d818360208d01613122565b60c089811b6001600160c01b03199081169390920192835288811b8216600884015287901b1660108201528451614abb816018840160208901613122565b8451910190614ad1816018840160208801613122565b016018019998505050505050505050565b60008851614af4818460208d01613122565b885190830190614b08818360208d01613122565b60c089811b6001600160c01b03199081169390920192835288901b1660088201528551614b3c816010840160208a01613122565b8551910190614b52816010840160208901613122565b8451910190614b68816010840160208801613122565b016010019998505050505050505050565b600181815b80851115614bb4578160001904821115614b9a57614b9a6141eb565b80851615614ba757918102915b93841c9390800290614b7e565b509250929050565b600082614bcb57506001612d1d565b81614bd857506000612d1d565b8160018114614bee5760028114614bf857614c14565b6001915050612d1d565b60ff841115614c0957614c096141eb565b50506001821b612d1d565b5060208310610133831016604e8410600b8410161715614c37575081810a612d1d565b614c418383614b79565b8060001904821115614c5557614c556141eb565b029392505050565b6000612bea8383614bbc56fea2646970667358221220dfd2a46d40cfe5e84f3438fdfd2e1f1d61b2ec0aab2ee282408018a2459d1f3164736f6c63430008110033
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.