UNPKG

@kleros/vea-contracts

Version:

Smart contracts for Vea

444 lines (443 loc) 48.4 kB
{ "address": "0xF6C5640de593fEf76129F1F1A863F7ddc65776C9", "abi": [ { "inputs": [ { "internalType": "uint256", "name": "_epochPeriod", "type": "uint256" }, { "internalType": "address", "name": "_veaOutboxArbToEth", "type": "address" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "bytes", "name": "_nodeData", "type": "bytes" } ], "name": "MessageSent", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "bytes32", "name": "_snapshot", "type": "bytes32" }, { "indexed": false, "internalType": "uint256", "name": "_epoch", "type": "uint256" }, { "indexed": false, "internalType": "uint64", "name": "_count", "type": "uint64" } ], "name": "SnapshotSaved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "uint256", "name": "_epochSent", "type": "uint256" }, { "indexed": false, "internalType": "bytes32", "name": "_ticketId", "type": "bytes32" } ], "name": "SnapshotSent", "type": "event" }, { "inputs": [], "name": "count", "outputs": [ { "internalType": "uint64", "name": "", "type": "uint64" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "_timestamp", "type": "uint256" } ], "name": "epochAt", "outputs": [ { "internalType": "uint256", "name": "epoch", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "epochFinalized", "outputs": [ { "internalType": "uint256", "name": "epoch", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "epochNow", "outputs": [ { "internalType": "uint256", "name": "epoch", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "epochPeriod", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "saveSnapshot", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "_to", "type": "address" }, { "internalType": "bytes4", "name": "_fnSelector", "type": "bytes4" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "name": "sendMessage", "outputs": [ { "internalType": "uint64", "name": "", "type": "uint64" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "_epoch", "type": "uint256" }, { "components": [ { "internalType": "bytes32", "name": "stateRoot", "type": "bytes32" }, { "internalType": "address", "name": "claimer", "type": "address" }, { "internalType": "uint32", "name": "timestampClaimed", "type": "uint32" }, { "internalType": "uint32", "name": "timestampVerification", "type": "uint32" }, { "internalType": "uint32", "name": "blocknumberVerification", "type": "uint32" }, { "internalType": "enum Party", "name": "honest", "type": "uint8" }, { "internalType": "address", "name": "challenger", "type": "address" } ], "internalType": "struct Claim", "name": "_claim", "type": "tuple" } ], "name": "sendSnapshot", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "epoch", "type": "uint256" } ], "name": "snapshots", "outputs": [ { "internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "veaOutboxArbToEth", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" } ], "transactionHash": "0x125f717c4127a8cd53667887d4fb8572b500d1036e071aa6f7b4c7d9772c0d41", "receipt": { "to": null, "from": "0xFa00D29d378EDC57AA1006946F0fc6230a5E3288", "contractAddress": "0xF6C5640de593fEf76129F1F1A863F7ddc65776C9", "transactionIndex": 3, "gasUsed": "738227", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x288f0a278c562336e29920935758ecebc0056acfb5d8806cd155f6a89dd9057e", "transactionHash": "0x125f717c4127a8cd53667887d4fb8572b500d1036e071aa6f7b4c7d9772c0d41", "logs": [], "blockNumber": 129093493, "cumulativeGasUsed": "1458003", "status": 1, "byzantium": true }, "args": [ 1800, "0xb1f5125b52CE23D3763AC1C9ACEf0668825A66c0" ], "numDeployments": 4, "solcInputHash": "c9b5f40be4cc59cdaa11ec8b822d1bfe", "metadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_epochPeriod\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_veaOutboxArbToEth\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_nodeData\",\"type\":\"bytes\"}],\"name\":\"MessageSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"_snapshot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_epoch\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"_count\",\"type\":\"uint64\"}],\"name\":\"SnapshotSaved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_epochSent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"_ticketId\",\"type\":\"bytes32\"}],\"name\":\"SnapshotSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"count\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_timestamp\",\"type\":\"uint256\"}],\"name\":\"epochAt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochFinalized\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochNow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epochPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"saveSnapshot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"_fnSelector\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"sendMessage\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_epoch\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"claimer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"timestampClaimed\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"timestampVerification\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blocknumberVerification\",\"type\":\"uint32\"},{\"internalType\":\"enum Party\",\"name\":\"honest\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"}],\"internalType\":\"struct Claim\",\"name\":\"_claim\",\"type\":\"tuple\"}],\"name\":\"sendSnapshot\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"}],\"name\":\"snapshots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"veaOutboxArbToEth\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Vea Inbox From Arbitrum to Ethereum. Note: This contract is deployed on Arbitrum.\",\"events\":{\"MessageSent(bytes)\":{\"details\":\"Relayers watch for these events to construct merkle proofs to execute transactions on Ethereum.\",\"params\":{\"_nodeData\":\"The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, message), outbox relays to.call(message).\"}},\"SnapshotSaved(bytes32,uint256,uint64)\":{\"params\":{\"_count\":\"The count of messages in the merkle tree.\",\"_epoch\":\"The epoch of the snapshot.\",\"_snapshot\":\"The snapshot of the merkle tree state root.\"}},\"SnapshotSent(uint256,bytes32)\":{\"details\":\"The event is emitted when a snapshot is sent through the canonical arbitrum bridge.\",\"params\":{\"_epochSent\":\"The epoch of the snapshot.\",\"_ticketId\":\"The ticketId of the L2->L1 message.\"}}},\"kind\":\"dev\",\"methods\":{\"constructor\":{\"details\":\"Constructor. Note: epochPeriod must match the VeaOutboxArbToEth contract deployment on Ethereum, since it's on a different chain, we can't read it and trust the deployer to set a correct value\",\"params\":{\"_epochPeriod\":\"The duration in seconds between epochs.\",\"_veaOutboxArbToEth\":\"The veaOutbox on ethereum.\"}},\"epochAt(uint256)\":{\"details\":\"Get the epoch from the inbox's point of view using timestamp.\",\"params\":{\"_timestamp\":\"The timestamp to calculate the epoch from.\"},\"returns\":{\"epoch\":\"The calculated epoch.\"}},\"epochFinalized()\":{\"details\":\"Get the most recent epoch for which snapshots are finalized.\",\"returns\":{\"epoch\":\"The epoch associated with the current inbox block.timestamp\"}},\"epochNow()\":{\"details\":\"Get the current epoch from the inbox's point of view using the Arbitrum L2 clock.\",\"returns\":{\"epoch\":\"The epoch associated with the current inbox block.timestamp\"}},\"saveSnapshot()\":{\"details\":\"Saves snapshot of state root. Snapshots can be saved a maximum of once per epoch. `O(log(count))` where count number of messages in the inbox. Note: See merkle tree docs for details how inbox manages state.\"},\"sendMessage(address,bytes4,bytes)\":{\"details\":\"Sends an arbitrary message to Ethereum. `O(log(count))` where count is the number of messages already sent. Amortized cost is constant. Note: See docs for details how inbox manages merkle tree state.\",\"params\":{\"_data\":\"The message calldata, abi.encode(param1, param2, ...)\",\"_fnSelector\":\"The function selector of the receiving contract.\",\"_to\":\"The address of the contract on the receiving chain which receives the calldata.\"},\"returns\":{\"_0\":\"msgId The zero based index of the message in the inbox.\"}},\"sendSnapshot(uint256,(bytes32,address,uint32,uint32,uint32,uint8,address))\":{\"details\":\"Sends the state root snapshot using Arbitrum's canonical bridge.\",\"params\":{\"_claim\":\"The claim associated with the epoch.\",\"_epoch\":\"The epoch of the snapshot requested to send.\"}}},\"version\":1},\"userdoc\":{\"events\":{\"SnapshotSaved(bytes32,uint256,uint64)\":{\"notice\":\"The bridgers can watch this event to claim the stateRoot on the veaOutbox.\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/arbitrumToEth/VeaInboxArbToEth.sol\":\"VeaInboxArbToEth\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/arbitrumToEth/VeaInboxArbToEth.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@jaybuidl, @shotaronowhere]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"../canonical/arbitrum/IArbSys.sol\\\";\\nimport \\\"../interfaces/inboxes/IVeaInbox.sol\\\";\\nimport \\\"../interfaces/outboxes/IVeaOutboxOnL1.sol\\\";\\n\\n/// @dev Vea Inbox From Arbitrum to Ethereum.\\n/// Note: This contract is deployed on Arbitrum.\\ncontract VeaInboxArbToEth is IVeaInbox {\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n // Arbitrum precompile ArbSys for L2->L1 messaging: https://developer.arbitrum.io/arbos/precompiles#arbsys\\n IArbSys internal constant ARB_SYS = IArbSys(address(100));\\n\\n uint256 public immutable epochPeriod; // Epochs mark the period between potential snapshots.\\n address public immutable veaOutboxArbToEth; // The vea outbox on ethereum.\\n\\n mapping(uint256 epoch => bytes32) public snapshots; // epoch => state root snapshot\\n\\n // Inbox represents minimum data availability to maintain incremental merkle tree.\\n // Supports a max of 2^64 - 1 messages. See merkle tree docs for details how inbox manages state.\\n\\n bytes32[64] internal inbox; // stores minimal set of complete subtree roots of the merkle tree to increment.\\n uint64 public count; // count of messages in the merkle tree\\n\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n\\n /// @dev Relayers watch for these events to construct merkle proofs to execute transactions on Ethereum.\\n /// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, message), outbox relays to.call(message).\\n event MessageSent(bytes _nodeData);\\n\\n /// The bridgers can watch this event to claim the stateRoot on the veaOutbox.\\n /// @param _snapshot The snapshot of the merkle tree state root.\\n /// @param _epoch The epoch of the snapshot.\\n /// @param _count The count of messages in the merkle tree.\\n event SnapshotSaved(bytes32 _snapshot, uint256 _epoch, uint64 _count);\\n\\n /// @dev The event is emitted when a snapshot is sent through the canonical arbitrum bridge.\\n /// @param _epochSent The epoch of the snapshot.\\n /// @param _ticketId The ticketId of the L2->L1 message.\\n event SnapshotSent(uint256 indexed _epochSent, bytes32 _ticketId);\\n\\n /// @dev Constructor.\\n /// Note: epochPeriod must match the VeaOutboxArbToEth contract deployment on Ethereum, since it's on a different chain, we can't read it and trust the deployer to set a correct value\\n /// @param _epochPeriod The duration in seconds between epochs.\\n /// @param _veaOutboxArbToEth The veaOutbox on ethereum.\\n constructor(uint256 _epochPeriod, address _veaOutboxArbToEth) {\\n epochPeriod = _epochPeriod;\\n veaOutboxArbToEth = _veaOutboxArbToEth;\\n }\\n\\n // ************************************* //\\n // * State Modifiers * //\\n // ************************************* //\\n\\n /// @dev Sends an arbitrary message to Ethereum.\\n /// `O(log(count))` where count is the number of messages already sent.\\n /// Amortized cost is constant.\\n /// Note: See docs for details how inbox manages merkle tree state.\\n /// @param _to The address of the contract on the receiving chain which receives the calldata.\\n /// @param _fnSelector The function selector of the receiving contract.\\n /// @param _data The message calldata, abi.encode(param1, param2, ...)\\n /// @return msgId The zero based index of the message in the inbox.\\n function sendMessage(address _to, bytes4 _fnSelector, bytes memory _data) external override returns (uint64) {\\n uint64 oldCount = count;\\n\\n // Given arbitrum's speed limit of 7 million gas / second, it would take atleast 8 million years of full blocks to overflow.\\n // It *should* be impossible to overflow, but we check to be safe when appending to the tree.\\n require(oldCount < type(uint64).max, \\\"Inbox is full.\\\");\\n\\n bytes memory nodeData = abi.encodePacked(\\n oldCount,\\n _to,\\n // _data is abi.encode(param1, param2, ...), we need to encode it again to get the correct leaf data\\n abi.encodePacked( // equivalent to abi.encodeWithSelector(fnSelector, msg.sender, param1, param2, ...)\\n _fnSelector,\\n bytes32(uint256(uint160(msg.sender))), // big endian padded encoding of msg.sender, simulating abi.encodeWithSelector\\n _data\\n )\\n );\\n\\n // single hashed leaf\\n bytes32 newInboxNode = keccak256(nodeData);\\n\\n // double hashed leaf\\n // avoids second order preimage attacks\\n // https://flawed.net.nz/2018/02/21/attacking-merkle-trees-with-a-second-preimage-attack/\\n assembly {\\n // efficient hash using EVM scratch space\\n mstore(0x00, newInboxNode)\\n newInboxNode := keccak256(0x00, 0x20)\\n }\\n\\n // increment merkle tree calculating minimal number of hashes\\n unchecked {\\n uint256 height;\\n\\n // x = oldCount + 1; acts as a bit mask to determine if a hash is needed\\n // note: x is always non-zero, and x is bit shifted to the right each loop\\n // hence this loop will always terminate in a maximum of log_2(oldCount + 1) iterations\\n for (uint64 x = oldCount + 1; x & 1 == 0; x = x >> 1) {\\n // sort sibling hashes as a convention for efficient proof validation\\n newInboxNode = sortConcatAndHash(inbox[height], newInboxNode);\\n height++;\\n }\\n\\n inbox[height] = newInboxNode;\\n\\n // finally increment count\\n count = oldCount + 1;\\n }\\n\\n emit MessageSent(nodeData);\\n\\n // old count is the zero indexed leaf position in the tree, acts as a msgId\\n // gateways should index these msgIds to later relay proofs\\n return oldCount;\\n }\\n\\n /// @dev Saves snapshot of state root. Snapshots can be saved a maximum of once per epoch.\\n /// `O(log(count))` where count number of messages in the inbox.\\n /// Note: See merkle tree docs for details how inbox manages state.\\n function saveSnapshot() external {\\n uint256 epoch;\\n bytes32 stateRoot;\\n\\n unchecked {\\n epoch = block.timestamp / epochPeriod;\\n\\n // calculate the current root of the incremental merkle tree encoded in the inbox\\n\\n uint256 height;\\n\\n // x acts as a bit mask to determine if the hash stored in the inbox contributes to the root\\n uint256 x;\\n\\n // x is bit shifted to the right each loop, hence this loop will always terminate in a maximum of log_2(count) iterations\\n for (x = uint256(count); x > 0; x = x >> 1) {\\n if ((x & 1) == 1) {\\n // first hash is special case\\n // inbox stores the root of complete subtrees\\n // eg if count = 4 = 0b100, then the first complete subtree is inbox[2]\\n // inbox = [H(3), H(1,2), H(1,4)], we read inbox[2] directly\\n\\n stateRoot = inbox[height];\\n break;\\n }\\n height++;\\n }\\n\\n // after the first hash, we can calculate the root incrementally\\n for (x = x >> 1; x > 0; x = x >> 1) {\\n height++;\\n if ((x & 1) == 1) {\\n // sort sibling hashes as a convention for efficient proof validation\\n stateRoot = sortConcatAndHash(inbox[height], stateRoot);\\n }\\n }\\n }\\n\\n snapshots[epoch] = stateRoot;\\n\\n emit SnapshotSaved(stateRoot, epoch, count);\\n }\\n\\n /// @dev Helper function to calculate merkle tree interior nodes by sorting and concatenating and hashing a pair of children nodes, left and right.\\n /// Note: EVM scratch space is used to efficiently calculate hashes.\\n /// @param _left The left hash.\\n /// @param _right The right hash.\\n /// @return parent The parent hash.\\n function sortConcatAndHash(bytes32 _left, bytes32 _right) internal pure returns (bytes32 parent) {\\n // sort sibling hashes as a convention for efficient proof validation\\n if (_left < _right) {\\n // efficient hash using EVM scratch space\\n assembly {\\n mstore(0x00, _left)\\n mstore(0x20, _right)\\n parent := keccak256(0x00, 0x40)\\n }\\n } else {\\n assembly {\\n mstore(0x00, _right)\\n mstore(0x20, _left)\\n parent := keccak256(0x00, 0x40)\\n }\\n }\\n }\\n\\n /// @dev Sends the state root snapshot using Arbitrum's canonical bridge.\\n /// @param _epoch The epoch of the snapshot requested to send.\\n /// @param _claim The claim associated with the epoch.\\n function sendSnapshot(uint256 _epoch, Claim memory _claim) external virtual {\\n unchecked {\\n require(_epoch < block.timestamp / epochPeriod, \\\"Can only send past epoch snapshot.\\\");\\n }\\n\\n bytes memory data = abi.encodeCall(IVeaOutboxOnL1.resolveDisputedClaim, (_epoch, snapshots[_epoch], _claim));\\n\\n // Arbitrum -> Ethereum message with native bridge\\n // docs: https://developer.arbitrum.io/for-devs/cross-chain-messsaging#arbitrum-to-ethereum-messaging\\n // example: https://github.com/OffchainLabs/arbitrum-tutorials/blob/2c1b7d2db8f36efa496e35b561864c0f94123a5f/packages/greeter/contracts/arbitrum/GreeterL2.sol#L25\\n bytes32 ticketID = bytes32(ARB_SYS.sendTxToL1(veaOutboxArbToEth, data));\\n\\n emit SnapshotSent(_epoch, ticketID);\\n }\\n\\n // ************************************* //\\n // * Pure / Views * //\\n // ************************************* //\\n\\n /// @dev Get the current epoch from the inbox's point of view using the Arbitrum L2 clock.\\n /// @return epoch The epoch associated with the current inbox block.timestamp\\n function epochNow() external view returns (uint256 epoch) {\\n epoch = block.timestamp / epochPeriod;\\n }\\n\\n /// @dev Get the most recent epoch for which snapshots are finalized.\\n /// @return epoch The epoch associated with the current inbox block.timestamp\\n function epochFinalized() external view returns (uint256 epoch) {\\n epoch = block.timestamp / epochPeriod - 1;\\n }\\n\\n /// @dev Get the epoch from the inbox's point of view using timestamp.\\n /// @param _timestamp The timestamp to calculate the epoch from.\\n /// @return epoch The calculated epoch.\\n function epochAt(uint256 _timestamp) external view returns (uint256 epoch) {\\n epoch = _timestamp / epochPeriod;\\n }\\n}\\n\",\"keccak256\":\"0xe3fdd0cc51b541482e72b8cf37981499dc301556f77b78666c5b3b22237dd05e\",\"license\":\"MIT\"},\"src/canonical/arbitrum/IArbSys.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n// https://developer.arbitrum.io/arbos/precompiles#arbsys\\n// https://github.com/OffchainLabs/nitro-contracts/blob/39ea5a163afc637e2706d9be29cf7a289c300d00/src/precompiles/ArbSys.sol\\n// https://arbiscan.io/address/0x0000000000000000000000000000000000000064#code\\n// interface is pruned for relevant function stubs\\n\\npragma solidity 0.8.24;\\n\\n///@title System level functionality\\n///@notice For use by contracts to interact with core L2-specific functionality.\\n///Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064.\\ninterface IArbSys {\\n /// @notice Send a transaction to L1\\n /// @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data\\n /// to a contract address without any code (as enforced by the Bridge contract).\\n /// @param destination recipient address on L1\\n /// @param data (optional) calldata for L1 contract call\\n /// @return a unique identifier for this L2-to-L1 transaction.\\n function sendTxToL1(address destination, bytes calldata data) external payable returns (uint256);\\n}\\n\",\"keccak256\":\"0x5ae1fd0267552160821402b9bc50b2551b086904436e5abe838599179b279420\",\"license\":\"BUSL-1.1\"},\"src/interfaces/inboxes/IVeaInbox.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@jaybuidl, @shotaronowhere]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\ninterface IVeaInbox {\\n /// @dev Sends an arbitrary message to receiving chain.\\n /// Note: Calls authenticated by receiving gateway checking the sender argument.\\n /// @param _to The cross-domain contract address which receives the calldata.\\n /// @param _fnSelection The function selector of the receiving contract.\\n /// @param _data The message calldata, abi.encode(...)\\n /// @return msgId The index of the message in the inbox, as a message Id, needed to relay the message.\\n function sendMessage(address _to, bytes4 _fnSelection, bytes memory _data) external returns (uint64 msgId);\\n\\n /// @dev Snapshots can be saved a maximum of once per epoch.\\n /// Saves snapshot of state root.\\n /// `O(log(count))` where count number of messages in the inbox.\\n function saveSnapshot() external;\\n}\\n\",\"keccak256\":\"0xa8e2f65b7596235422f39933af80f02473493d2b15b398d7e34b81c82bd24a29\",\"license\":\"MIT\"},\"src/interfaces/outboxes/IVeaOutboxOnL1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@jaybuidl, @shotaronowhere]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nimport \\\"../types/VeaClaim.sol\\\";\\n\\n/// @dev Interface of the Vea Outbox on L1 chains like Ethereum, Gnosis, Polygon POS where storage is expensive.\\ninterface IVeaOutboxOnL1 {\\n /// @dev Verifies and relays the message.\\n /// Note: Gateways expect first argument of message call to be the arbitrum message sender, used for authentication.\\n /// @param _proof The merkle proof to prove the message.\\n /// @param _msgId The zero based index of the message in the inbox.\\n /// @param _to The address to send the message to.\\n /// @param _message The message to relay.\\n function sendMessage(bytes32[] calldata _proof, uint64 _msgId, address _to, bytes calldata _message) external;\\n\\n /// @dev Resolves any challenge of the optimistic claim for 'epoch' using the canonical bridge.\\n /// Note: Access restricted to canonical bridge.\\n /// @param _epoch The epoch to verify.\\n /// @param _stateRoot The true state root for the epoch.\\n /// @param _claim The claim associated with the epoch.\\n function resolveDisputedClaim(uint256 _epoch, bytes32 _stateRoot, Claim memory _claim) external;\\n}\\n\",\"keccak256\":\"0xf1d52e289e790088502b7909f11f47bc33ddd3fc545636b7fb29c01ed00d3ff3\",\"license\":\"MIT\"},\"src/interfaces/types/VeaClaim.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\n/// @custom:authors: [@jaybuidl, @shotaronowhere]\\n/// @custom:reviewers: []\\n/// @custom:auditors: []\\n/// @custom:bounties: []\\n/// @custom:deployments: []\\n\\npragma solidity 0.8.24;\\n\\nenum Party {\\n None,\\n Claimer,\\n Challenger\\n}\\n\\nstruct Claim {\\n bytes32 stateRoot;\\n address claimer;\\n uint32 timestampClaimed;\\n uint32 timestampVerification;\\n uint32 blocknumberVerification;\\n Party honest;\\n address challenger;\\n}\\n\",\"keccak256\":\"0xfef781e359c97aebbe8dbfcb75edb7cb962139fd9ea538b8b89a3f2e13a05bfe\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x60c060405234801561001057600080fd5b50604051610c34380380610c3483398101604081905261002f91610046565b6080919091526001600160a01b031660a052610083565b6000806040838503121561005957600080fd5b825160208401519092506001600160a01b038116811461007857600080fd5b809150509250929050565b60805160a051610b626100d26000396000818161012801526105e1015260008181610167015281816101c3015281816101f60152818161022c0152818161025c01526104ee0152610b626000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80635f85896c116100665780635f85896c14610110578063744b49bf14610123578063b5b7a18414610162578063c705e41214610189578063d6565a2d1461019c57600080fd5b806306661abd146100a3578063222ae786146100d55780633ac3b6b6146100eb5780634a439cfe146100f35780635192053514610106575b600080fd5b6041546100b79067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b6100dd6101bc565b6040519081526020016100cc565b6100dd6101ed565b6100dd6101013660046106bd565b610225565b61010e610257565b005b6100b761011e366004610762565b61037b565b61014a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100cc565b6100dd7f000000000000000000000000000000000000000000000000000000000000000081565b61010e61019736600461083b565b6104ec565b6100dd6101aa3660046106bd565b60006020819052908152604090205481565b60006101e87f000000000000000000000000000000000000000000000000000000000000000042610903565b905090565b6000600161021b7f000000000000000000000000000000000000000000000000000000000000000042610903565b6101e89190610925565b60006102517f000000000000000000000000000000000000000000000000000000000000000083610903565b92915050565b6000807f00000000000000000000000000000000000000000000000000000000000000004281610289576102896108ed565b604154919004925060009067ffffffffffffffff165b80156102d857806001166001036102cc57600182604081106102c3576102c3610946565b015492506102d8565b6001918201911c61029f565b60011c5b801561031a5760019182019181811690036103125761030f6001836040811061030757610307610946565b01548461068c565b92505b60011c6102dc565b505060008281526020818152604091829020839055604154825184815291820185905267ffffffffffffffff168183015290517f592424eb1d6135501bd20833f15fd127c29d08eed4f03872f6f75182126b1e489181900360600190a15050565b60415460009067ffffffffffffffff9081169081106103d25760405162461bcd60e51b815260206004820152600e60248201526d24b73137bc1034b990333ab6361760911b60448201526064015b60405180910390fd5b604051600090829087906103ee90889033908990602001610980565b60408051601f198184030181529082905261040d9392916020016109b6565b60408051601f1981840301815291905280516020808301919091206000908152908120919250600184015b60018116600003610471576104596001836040811061030757610307610946565b92506001918201911c677fffffffffffffff16610438565b50816001826040811061048657610486610946565b0155506041805467ffffffffffffffff19166001850167ffffffffffffffff161790556040517f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036906104d9908490610a31565b60405180910390a1509095945050505050565b7f0000000000000000000000000000000000000000000000000000000000000000428161051b5761051b6108ed565b0482106105755760405162461bcd60e51b815260206004820152602260248201527f43616e206f6e6c792073656e6420706173742065706f636820736e617073686f6044820152613a1760f11b60648201526084016103c9565b6000828152602081905260408082205490516105979185918590602401610a4b565b60408051601f198184030181529181526020820180516001600160e01b0316630f0adca560e01b179052516349460b4d60e11b815290915060009060649063928c169a9061060b907f0000000000000000000000000000000000000000000000000000000000000000908690600401610ae7565b6020604051808303816000875af115801561062a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064e9190610b13565b60405181815290915084907f6fdd49f435101fc7b6ebdec7c8972932a926d18f6cb78a8891dfe950743b6b829060200160405180910390a250505050565b6000818310156106aa57826000528160205260406000209050610251565b5060009081526020919091526040902090565b6000602082840312156106cf57600080fd5b5035919050565b80356001600160a01b03811681146106ed57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff8111828210171561072b5761072b6106f2565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561075a5761075a6106f2565b604052919050565b60008060006060848603121561077757600080fd5b610780846106d6565b92506020848101356001600160e01b03198116811461079e57600080fd5b9250604085013567ffffffffffffffff808211156107bb57600080fd5b818701915087601f8301126107cf57600080fd5b8135818111156107e1576107e16106f2565b6107f3601f8201601f19168501610731565b9150808252888482850101111561080957600080fd5b80848401858401376000848284010152508093505050509250925092565b803563ffffffff811681146106ed57600080fd5b60008082840361010081121561085057600080fd5b8335925060e0601f198201121561086657600080fd5b5061086f610708565b60208401358152610882604085016106d6565b602082015261089360608501610827565b60408201526108a460808501610827565b60608201526108b560a08501610827565b608082015260c0840135600381106108cc57600080fd5b60a08201526108dd60e085016106d6565b60c0820152809150509250929050565b634e487b7160e01b600052601260045260246000fd5b60008261092057634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561025157634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60005b8381101561097757818101518382015260200161095f565b50506000910152565b63ffffffff60e01b84168152826004820152600082516109a781602485016020870161095c565b91909101602401949350505050565b67ffffffffffffffff60c01b8460c01b1681526bffffffffffffffffffffffff198360601b166008820152600082516109f681601c85016020870161095c565b91909101601c01949350505050565b60008151808452610a1d81602086016020860161095c565b601f01601f19169290920160200192915050565b602081526000610a446020830184610a05565b9392505050565b6000610120820190508482528360208301528251604083015260018060a01b036020840151166060830152604083015163ffffffff80821660808501528060608601511660a08501528060808601511660c0850152505060a083015160038110610ac557634e487b7160e01b600052602160045260246000fd5b60e083015260c092909201516001600160a01b03166101009091015292915050565b6001600160a01b0383168152604060208201819052600090610b0b90830184610a05565b949350505050565b600060208284031215610b2557600080fd5b505191905056fea264697066735822122052ab92a3bd54fdf96a56eeb8ed53ec6cad87ba800e51ccfae5b27362acb753c764736f6c63430008180033", "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061009e5760003560e01c80635f85896c116100665780635f85896c14610110578063744b49bf14610123578063b5b7a18414610162578063c705e41214610189578063d6565a2d1461019c57600080fd5b806306661abd146100a3578063222ae786146100d55780633ac3b6b6146100eb5780634a439cfe146100f35780635192053514610106575b600080fd5b6041546100b79067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020015b60405180910390f35b6100dd6101bc565b6040519081526020016100cc565b6100dd6101ed565b6100dd6101013660046106bd565b610225565b61010e610257565b005b6100b761011e366004610762565b61037b565b61014a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100cc565b6100dd7f000000000000000000000000000000000000000000000000000000000000000081565b61010e61019736600461083b565b6104ec565b6100dd6101aa3660046106bd565b60006020819052908152604090205481565b60006101e87f000000000000000000000000000000000000000000000000000000000000000042610903565b905090565b6000600161021b7f000000000000000000000000000000000000000000000000000000000000000042610903565b6101e89190610925565b60006102517f000000000000000000000000000000000000000000000000000000000000000083610903565b92915050565b6000807f00000000000000000000000000000000000000000000000000000000000000004281610289576102896108ed565b604154919004925060009067ffffffffffffffff165b80156102d857806001166001036102cc57600182604081106102c3576102c3610946565b015492506102d8565b6001918201911c61029f565b60011c5b801561031a5760019182019181811690036103125761030f6001836040811061030757610307610946565b01548461068c565b92505b60011c6102dc565b505060008281526020818152604091829020839055604154825184815291820185905267ffffffffffffffff168183015290517f592424eb1d6135501bd20833f15fd127c29d08eed4f03872f6f75182126b1e489181900360600190a15050565b60415460009067ffffffffffffffff9081169081106103d25760405162461bcd60e51b815260206004820152600e60248201526d24b73137bc1034b990333ab6361760911b60448201526064015b60405180910390fd5b604051600090829087906103ee90889033908990602001610980565b60408051601f198184030181529082905261040d9392916020016109b6565b60408051601f1981840301815291905280516020808301919091206000908152908120919250600184015b60018116600003610471576104596001836040811061030757610307610946565b92506001918201911c677fffffffffffffff16610438565b50816001826040811061048657610486610946565b0155506041805467ffffffffffffffff19166001850167ffffffffffffffff161790556040517f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036906104d9908490610a31565b60405180910390a1509095945050505050565b7f0000000000000000000000000000000000000000000000000000000000000000428161051b5761051b6108ed565b0482106105755760405162461bcd60e51b815260206004820152602260248201527f43616e206f6e6c792073656e6420706173742065706f636820736e617073686f6044820152613a1760f11b60648201526084016103c9565b6000828152602081905260408082205490516105979185918590602401610a4b565b60408051601f198184030181529181526020820180516001600160e01b0316630f0adca560e01b179052516349460b4d60e11b815290915060009060649063928c169a9061060b907f0000000000000000000000000000000000000000000000000000000000000000908690600401610ae7565b6020604051808303816000875af115801561062a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064e9190610b13565b60405181815290915084907f6fdd49f435101fc7b6ebdec7c8972932a926d18f6cb78a8891dfe950743b6b829060200160405180910390a250505050565b6000818310156106aa57826000528160205260406000209050610251565b5060009081526020919091526040902090565b6000602082840312156106cf57600080fd5b5035919050565b80356001600160a01b03811681146106ed57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff8111828210171561072b5761072b6106f2565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561075a5761075a6106f2565b604052919050565b60008060006060848603121561077757600080fd5b610780846106d6565b92506020848101356001600160e01b03198116811461079e57600080fd5b9250604085013567ffffffffffffffff808211156107bb57600080fd5b818701915087601f8301126107cf57600080fd5b8135818111156107e1576107e16106f2565b6107f3601f8201601f19168501610731565b9150808252888482850101111561080957600080fd5b80848401858401376000848284010152508093505050509250925092565b803563ffffffff811681146106ed57600080fd5b60008082840361010081121561085057600080fd5b8335925060e0601f198201121561086657600080fd5b5061086f610708565b60208401358152610882604085016106d6565b602082015261089360608501610827565b60408201526108a460808501610827565b60608201526108b560a08501610827565b608082015260c0840135600381106108cc57600080fd5b60a08201526108dd60e085016106d6565b60c0820152809150509250929050565b634e487b7160e01b600052601260045260246000fd5b60008261092057634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561025157634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60005b8381101561097757818101518382015260200161095f565b50506000910152565b63ffffffff60e01b84168152826004820152600082516109a781602485016020870161095c565b91909101602401949350505050565b67ffffffffffffffff60c01b8460c01b1681526bffffffffffffffffffffffff198360601b166008820152600082516109f681601c85016020870161095c565b91909101601c01949350505050565b60008151808452610a1d81602086016020860161095c565b601f01601f19169290920160200192915050565b602081526000610a446020830184610a05565b9392505050565b6000610120820190508482528360208301528251604083015260018060a01b036020840151166060830152604083015163ffffffff80821660808501528060608601511660a08501528060808601511660c0850152505060a083015160038110610ac557634e487b7160e01b600052602160045260246000fd5b60e083015260c092909201516001600160a01b03166101009091015292915050565b6001600160a01b0383168152604060208201819052600090610b0b90830184610a05565b949350505050565b600060208284031215610b2557600080fd5b505191905056fea264697066735822122052ab92a3bd54fdf96a56eeb8ed53ec6cad87ba800e51ccfae5b27362acb753c764736f6c63430008180033", "devdoc": { "details": "Vea Inbox From Arbitrum to Ethereum. Note: This contract is deployed on Arbitrum.", "events": { "MessageSent(bytes)": { "details": "Relayers watch for these events to construct merkle proofs to execute transactions on Ethereum.", "params": { "_nodeData": "The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, message), outbox relays to.call(message)." } }, "SnapshotSaved(bytes32,uint256,uint64)": { "params": { "_count": "The count of messages in the merkle tree.", "_epoch": "The epoch of the snapshot.", "_snapshot": "The snapshot of the merkle tree state root." } }, "SnapshotSent(uint256,bytes32)": { "details": "The event is emitted when a snapshot is sent through the canonical arbitrum bridge.", "params": { "_epochSent": "The epoch of the snapshot.", "_ticketId": "The ticketId of the L2->L1 message." } } }, "kind": "dev", "methods": { "constructor": { "details": "Constructor. Note: epochPeriod must match the VeaOutboxArbToEth contract deployment on Ethereum, since it's on a different chain, we can't read it and trust the deployer to set a correct value", "params": { "_epochPeriod": "The duration in seconds between epochs.", "_veaOutboxArbToEth": "The veaOutbox on ethereum." } }, "epochAt(uint256)": { "details": "Get the epoch from the inbox's point of view using timestamp.", "params": { "_timestamp": "The timestamp to calculate the epoch from." }, "returns": { "epoch": "The calculated epoch." } }, "epochFinalized()": { "details": "Get the most recent epoch for which snapshots are finalized.", "returns": { "epoch": "The epoch associated with the current inbox block.timestamp" } }, "epochNow()": { "details": "Get the current epoch from the inbox's point of view using the Arbitrum L2 clock.", "returns": { "epoch": "The epoch associated with the current inbox block.timestamp" } }, "saveSnapshot()": { "details": "Saves snapshot of state root. Snapshots can be saved a maximum of once per epoch. `O(log(count))` where count number of messages in the inbox. Note: See merkle tree docs for details how inbox manages state." }, "sendMessage(address,bytes4,bytes)": { "details": "Sends an arbitrary message to Ethereum. `O(log(count))` where count is the number of messages already sent. Amortized cost is constant. Note: See docs for details how inbox manages merkle tree state.", "params": { "_data": "The message calldata, abi.encode(param1, param2, ...)", "_fnSelector": "The function selector of the receiving contract.", "_to": "The address of the contract on the receiving chain which receives the calldata." }, "returns": { "_0": "msgId The zero based index of the message in the inbox." } }, "sendSnapshot(uint256,(bytes32,address,uint32,uint32,uint32,uint8,address))": { "details": "Sends the state root snapshot using Arbitrum's canonical bridge.", "params": { "_claim": "The claim associated with the epoch.", "_epoch": "The epoch of the snapshot requested to send." } } }, "version": 1 }, "userdoc": { "events": { "SnapshotSaved(bytes32,uint256,uint64)": { "notice": "The bridgers can watch this event to claim the stateRoot on the veaOutbox." } }, "kind": "user", "methods": {}, "version": 1 }, "storageLayout": { "storage": [ { "astId": 24, "contract": "src/arbitrumToEth/VeaInboxArbToEth.sol:VeaInboxArbToEth", "label": "snapshots", "offset": 0, "slot": "0", "type": "t_mapping(t_uint256,t_bytes32)" }, { "astId": 28, "contract": "src/arbitrumToEth/VeaInboxArbToEth.sol:VeaInboxArbToEth", "label": "inbox", "offset": 0, "slot": "1", "type": "t_array(t_bytes32)64_storage" }, { "astId": 30, "contract": "src/arbitrumToEth/VeaInboxArbToEth.sol:VeaInboxArbToEth", "label": "count", "offset": 0, "slot": "65", "type": "t_uint64" } ], "types": { "t_array(t_bytes32)64_storage": { "base": "t_bytes32", "encoding": "inplace", "label": "bytes32[64]", "numberOfBytes": "2048" }, "t_bytes32": { "encoding": "inplace", "label": "bytes32", "numberOfBytes": "32" }, "t_mapping(t_uint256,t_bytes32)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => bytes32)", "numberOfBytes": "32", "value": "t_bytes32" }, "t_uint256": { "encoding": "inplace", "label": "uint256", "numberOfBytes": "32" }, "t_uint64": { "encoding": "inplace", "label": "uint64", "numberOfBytes": "8" } } } }