From d8774d1a19fce9dcd0baa0ba1cc2717b8a5a68c4 Mon Sep 17 00:00:00 2001 From: jaybuidl Date: Mon, 22 May 2023 22:17:29 +0100 Subject: [PATCH] feat: improved distinction between the outbox and router implementations for L1 and L2 --- .../deploy/02-inbox/02-arb-to-eth-inbox.ts | 1 - .../deploy/02-inbox/02-arb-to-gnosis-inbox.ts | 1 - .../src/arbitrumToEth/VeaInboxArbToEth.sol | 6 ++--- .../src/arbitrumToEth/VeaOutboxArbToEth.sol | 4 +-- .../arbitrumToGnosis/RouterArbToGnosis.sol | 10 +++---- .../arbitrumToGnosis/VeaInboxArbToGnosis.sol | 6 ++--- .../arbitrumToGnosis/VeaOutboxArbToGnosis.sol | 4 +-- .../src/arbitrumToOptimism/RouterArbToOp.sol | 8 +++--- .../arbitrumToOptimism/VeaInboxArbToOp.sol | 7 ++--- .../arbitrumToOptimism/VeaOutboxArbToOp.sol | 4 +-- ...aOutboxEthChain.sol => IVeaOutboxOnL1.sol} | 21 +++------------ ...ptimisticRollup.sol => IVeaOutboxOnL2.sol} | 4 +-- ...outerToEthChain.sol => IRouterToAltL1.sol} | 11 +++++--- ...ToOptimisticRollup.sol => IRouterToL2.sol} | 5 +++- contracts/src/interfaces/types/VeaClaim.sol | 26 +++++++++++++++++++ .../ArbitrumToEth/VeaInboxMockArbToEth.sol | 4 +-- 16 files changed, 68 insertions(+), 54 deletions(-) rename contracts/src/interfaces/outboxes/{IVeaOutboxEthChain.sol => IVeaOutboxOnL1.sol} (74%) rename contracts/src/interfaces/outboxes/{IVeaOutboxOptimisticRollup.sol => IVeaOutboxOnL2.sol} (88%) rename contracts/src/interfaces/routers/{IRouterToEthChain.sol => IRouterToAltL1.sol} (63%) rename contracts/src/interfaces/routers/{IRouterToOptimisticRollup.sol => IRouterToL2.sol} (73%) create mode 100644 contracts/src/interfaces/types/VeaClaim.sol diff --git a/contracts/deploy/02-inbox/02-arb-to-eth-inbox.ts b/contracts/deploy/02-inbox/02-arb-to-eth-inbox.ts index 36d410ee..804ca096 100644 --- a/contracts/deploy/02-inbox/02-arb-to-eth-inbox.ts +++ b/contracts/deploy/02-inbox/02-arb-to-eth-inbox.ts @@ -3,7 +3,6 @@ import { DeployFunction } from "hardhat-deploy/types"; enum SenderChains { ARBITRUM = 42161, - ARBITRUM_GOERLI = 421613, HARDHAT = 31337, } const paramsByChainId = { diff --git a/contracts/deploy/02-inbox/02-arb-to-gnosis-inbox.ts b/contracts/deploy/02-inbox/02-arb-to-gnosis-inbox.ts index 2db3da15..3f1be8b2 100644 --- a/contracts/deploy/02-inbox/02-arb-to-gnosis-inbox.ts +++ b/contracts/deploy/02-inbox/02-arb-to-gnosis-inbox.ts @@ -3,7 +3,6 @@ import { DeployFunction } from "hardhat-deploy/types"; enum SenderChains { ARBITRUM = 42161, - ARBITRUM_GOERLI = 421613, HARDHAT = 31337, } const paramsByChainId = { diff --git a/contracts/src/arbitrumToEth/VeaInboxArbToEth.sol b/contracts/src/arbitrumToEth/VeaInboxArbToEth.sol index 8e90478d..9a52ab00 100644 --- a/contracts/src/arbitrumToEth/VeaInboxArbToEth.sol +++ b/contracts/src/arbitrumToEth/VeaInboxArbToEth.sol @@ -12,7 +12,7 @@ pragma solidity 0.8.18; import "../canonical/arbitrum/IArbSys.sol"; import "../interfaces/inboxes/IVeaInbox.sol"; -import "../interfaces/outboxes/IVeaOutboxEthChain.sol"; +import "../interfaces/outboxes/IVeaOutboxOnL1.sol"; /** * Vea Bridge Inbox From Arbitrum to Ethereum. @@ -213,12 +213,12 @@ contract VeaInboxArbToEth is IVeaInbox { * @param epoch The epoch of the snapshot requested to send. * @param claim The claim associated with the epoch. */ - function sendSnapshot(uint256 epoch, IVeaOutboxEthChain.Claim memory claim) external virtual { + function sendSnapshot(uint256 epoch, Claim memory claim) external virtual { unchecked { require(epoch < block.timestamp / epochPeriod, "Can only send past epoch snapshot."); } - bytes memory data = abi.encodeCall(IVeaOutboxEthChain.resolveDisputedClaim, (epoch, snapshots[epoch], claim)); + bytes memory data = abi.encodeCall(IVeaOutboxOnL1.resolveDisputedClaim, (epoch, snapshots[epoch], claim)); // Arbitrum -> Ethereum message with native bridge // docs: https://developer.arbitrum.io/for-devs/cross-chain-messsaging#arbitrum-to-ethereum-messaging diff --git a/contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol b/contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol index cb9043b5..b35361d3 100644 --- a/contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol +++ b/contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol @@ -12,12 +12,12 @@ pragma solidity 0.8.18; import "../canonical/arbitrum/IBridge.sol"; import "../canonical/arbitrum/IOutbox.sol"; -import "../interfaces/outboxes/IVeaOutboxEthChain.sol"; +import "../interfaces/outboxes/IVeaOutboxOnL1.sol"; /** * Vea Bridge Outbox From Arbitrum to Ethereum. */ -contract VeaOutboxArbToEth is IVeaOutboxEthChain { +contract VeaOutboxArbToEth is IVeaOutboxOnL1 { IBridge public immutable bridge; // The address of the Arbitrum bridge contract. address public immutable veaInbox; // The address of the veaInbox on arbitrum. diff --git a/contracts/src/arbitrumToGnosis/RouterArbToGnosis.sol b/contracts/src/arbitrumToGnosis/RouterArbToGnosis.sol index 4a29216b..ffb09860 100644 --- a/contracts/src/arbitrumToGnosis/RouterArbToGnosis.sol +++ b/contracts/src/arbitrumToGnosis/RouterArbToGnosis.sol @@ -13,13 +13,13 @@ pragma solidity 0.8.18; import "../canonical/gnosis-chain/IAMB.sol"; import "../canonical/arbitrum/IBridge.sol"; import "../canonical/arbitrum/IOutbox.sol"; -import "../interfaces/routers/IRouterToEthChain.sol"; -import "../interfaces/outboxes/IVeaOutboxEthChain.sol"; +import "../interfaces/routers/IRouterToAltL1.sol"; +import "../interfaces/outboxes/IVeaOutboxOnL1.sol"; /** * Router on Ethereum from Arbitrum to Gnosis Chain. */ -contract RouterArbToGnosis is IRouterToEthChain { +contract RouterArbToGnosis is IRouterToAltL1 { // ************************************* // // * Storage * // // ************************************* // @@ -60,7 +60,7 @@ contract RouterArbToGnosis is IRouterToEthChain { * @param epoch The epoch to verify. * @param stateroot The true batch merkle root for the epoch. */ - function route(uint256 epoch, bytes32 stateroot, IVeaOutboxEthChain.Claim calldata claim) external { + function route(uint256 epoch, bytes32 stateroot, Claim calldata claim) external { // Arbitrum -> Ethereum message sender authentication // docs: https://developer.arbitrum.io/arbos/l2-to-l1-messaging/ // example: https://github.com/OffchainLabs/arbitrum-tutorials/blob/2c1b7d2db8f36efa496e35b561864c0f94123a5f/packages/greeter/contracts/ethereum/GreeterL1.sol#L50 @@ -73,7 +73,7 @@ contract RouterArbToGnosis is IRouterToEthChain { // Ethereum -> Gnosis message passing with the AMB, the canonical Ethereum <-> Gnosis bridge. // https://docs.tokenbridge.net/amb-bridge/development-of-a-cross-chain-application/how-to-develop-xchain-apps-by-amb#receive-a-method-call-from-the-amb-bridge - bytes memory data = abi.encodeCall(IVeaOutboxEthChain.resolveDisputedClaim, (epoch, stateroot, claim)); + bytes memory data = abi.encodeCall(IVeaOutboxOnL1.resolveDisputedClaim, (epoch, stateroot, claim)); // Note: using maxGasPerTx here means the relaying txn on Gnosis will need to pass that (large) amount of gas, though almost all will be unused and refunded. This is preferred over hardcoding a gas limit. bytes32 ticketID = amb.requireToPassMessage(veaOutbox, data, amb.maxGasPerTx()); emit Routed(epoch, ticketID); diff --git a/contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol b/contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol index 04831081..8c997068 100644 --- a/contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol +++ b/contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol @@ -12,7 +12,7 @@ pragma solidity 0.8.18; import "../canonical/arbitrum/IArbSys.sol"; import "../interfaces/inboxes/IVeaInbox.sol"; -import "../interfaces/routers/IRouterToEthChain.sol"; +import "../interfaces/routers/IRouterToAltL1.sol"; /** * Vea Bridge Inbox From Arbitrum to Gnosis. @@ -213,12 +213,12 @@ contract VeaInboxArbToGnosis is IVeaInbox { * @param epoch The epoch of the snapshot requested to send. * @param claim The claim associated with the epoch */ - function sendSnapshot(uint256 epoch, IVeaOutboxEthChain.Claim memory claim) external virtual { + function sendSnapshot(uint256 epoch, Claim memory claim) external virtual { unchecked { require(epoch < block.timestamp / epochPeriod, "Can only send past epoch snapshot."); } - bytes memory data = abi.encodeCall(IRouterToEthChain.route, (epoch, snapshots[epoch], claim)); + bytes memory data = abi.encodeCall(IRouterToAltL1.route, (epoch, snapshots[epoch], claim)); // Arbitrum -> Ethereum message with native bridge // docs: https://developer.arbitrum.io/for-devs/cross-chain-messsaging#arbitrum-to-ethereum-messaging diff --git a/contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol b/contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol index 08abae64..09001bac 100644 --- a/contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol +++ b/contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol @@ -11,13 +11,13 @@ pragma solidity 0.8.18; import "../canonical/gnosis-chain/IAMB.sol"; -import "../interfaces/outboxes/IVeaOutboxEthChain.sol"; +import "../interfaces/outboxes/IVeaOutboxOnL1.sol"; /** * Vea Bridge Outbox From Arbitrum to Gnosis. * Note: This contract is deployed on Gnosis. */ -contract VeaOutboxArbToGnosis is IVeaOutboxEthChain { +contract VeaOutboxArbToGnosis is IVeaOutboxOnL1 { IAMB public immutable amb; // The address of the AMB contract on Gnosis. address public immutable routerArbToGnosis; // The address of the router from Arbitrum to Gnosis on ethereum. diff --git a/contracts/src/arbitrumToOptimism/RouterArbToOp.sol b/contracts/src/arbitrumToOptimism/RouterArbToOp.sol index 9d915207..f780faaa 100644 --- a/contracts/src/arbitrumToOptimism/RouterArbToOp.sol +++ b/contracts/src/arbitrumToOptimism/RouterArbToOp.sol @@ -14,13 +14,13 @@ pragma solidity 0.8.18; // TODO: implement Optimism messaging. import "../canonical/arbitrum/IBridge.sol"; import "../canonical/arbitrum/IOutbox.sol"; -import "../interfaces/routers/IRouterToOptimisticRollup.sol"; -import "../interfaces/outboxes/IVeaOutboxOptimisticRollup.sol"; +import "../interfaces/routers/IRouterToL2.sol"; +import "../interfaces/outboxes/IVeaOutboxOnL2.sol"; /** * Router on Ethereum from Arbitrum to Optimism. */ -contract RouterArbToOptimism is IRouterToOptimisticRollup { +contract RouterArbToOptimism is IRouterToL2 { // ************************************* // // * Storage * // // ************************************* // @@ -73,7 +73,7 @@ contract RouterArbToOptimism is IRouterToOptimisticRollup { require(IOutbox(bridge.activeOutbox()).l2ToL1Sender() == veaInbox, "veaInbox only."); - bytes memory data = abi.encodeCall(IVeaOutboxOptimisticRollup.resolveDisputedClaim, (epoch, stateroot)); + bytes memory data = abi.encodeCall(IVeaOutboxOnL2.resolveDisputedClaim, (epoch, stateroot)); // TODO: Send message to Optimism. } diff --git a/contracts/src/arbitrumToOptimism/VeaInboxArbToOp.sol b/contracts/src/arbitrumToOptimism/VeaInboxArbToOp.sol index 305ba1dd..ef6841dd 100644 --- a/contracts/src/arbitrumToOptimism/VeaInboxArbToOp.sol +++ b/contracts/src/arbitrumToOptimism/VeaInboxArbToOp.sol @@ -12,7 +12,7 @@ pragma solidity 0.8.18; import "../canonical/arbitrum/IArbSys.sol"; import "../interfaces/inboxes/IVeaInbox.sol"; -import "../interfaces/outboxes/IVeaOutboxOptimisticRollup.sol"; +import "../interfaces/outboxes/IVeaOutboxOnL2.sol"; /** * Vea Bridge Inbox From Arbitrum to Optimism. @@ -206,10 +206,7 @@ contract VeaInboxArbToOpt is IVeaInbox { require(epochSend < block.timestamp / epochPeriod, "Can only send past epoch snapshot."); } - bytes memory data = abi.encodeCall( - IVeaOutboxOptimisticRollup.resolveDisputedClaim, - (epochSend, snapshots[epochSend]) - ); + bytes memory data = abi.encodeCall(IVeaOutboxOnL2.resolveDisputedClaim, (epochSend, snapshots[epochSend])); bytes32 ticketID = bytes32(ARB_SYS.sendTxToL1(veaOutbox, data)); diff --git a/contracts/src/arbitrumToOptimism/VeaOutboxArbToOp.sol b/contracts/src/arbitrumToOptimism/VeaOutboxArbToOp.sol index bd8c566e..b278c0c3 100644 --- a/contracts/src/arbitrumToOptimism/VeaOutboxArbToOp.sol +++ b/contracts/src/arbitrumToOptimism/VeaOutboxArbToOp.sol @@ -14,12 +14,12 @@ pragma solidity 0.8.18; // warning: this is a work in progress import "../canonical/arbitrum/IBridge.sol"; import "../canonical/arbitrum/IOutbox.sol"; -import "../interfaces/outboxes/IVeaOutboxOptimisticRollup.sol"; +import "../interfaces/outboxes/IVeaOutboxOnL2.sol"; /** * Vea Bridge Outbox From Arbitrum to Optimism. */ -contract VeaOutboxArbToOpt is IVeaOutboxOptimisticRollup { +contract VeaOutboxArbToOpt is IVeaOutboxOnL2 { IBridge public immutable bridge; // The address of the Arbitrum bridge contract. address public immutable veaInbox; // The address of the veaInbox on arbitrum. diff --git a/contracts/src/interfaces/outboxes/IVeaOutboxEthChain.sol b/contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol similarity index 74% rename from contracts/src/interfaces/outboxes/IVeaOutboxEthChain.sol rename to contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol index cc2b2f68..920d26c5 100644 --- a/contracts/src/interfaces/outboxes/IVeaOutboxEthChain.sol +++ b/contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol @@ -10,25 +10,12 @@ pragma solidity 0.8.18; +import "../types/VeaClaim.sol"; + /** - * @dev Interface of the Vea Outbox on Ethereum-like L1 chains eg Ethereum, Gnosis, Polygon POS + * @dev Interface of the Vea Outbox on L1 chains like Ethereum, Gnosis, Polygon POS where storage is expensive. */ -interface IVeaOutboxEthChain { - enum Party { - None, - Claimer, - Challenger - } - - struct Claim { - bytes32 stateRoot; - address claimer; - uint32 timestamp; - uint32 blocknumber; - Party honest; - address challenger; - } - +interface IVeaOutboxOnL1 { /** * Note: Gateways expect first argument of message call to be the arbitrum message sender, used for authentication. * @dev Verifies and relays the message. diff --git a/contracts/src/interfaces/outboxes/IVeaOutboxOptimisticRollup.sol b/contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol similarity index 88% rename from contracts/src/interfaces/outboxes/IVeaOutboxOptimisticRollup.sol rename to contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol index 7804668b..5fe7c1c6 100644 --- a/contracts/src/interfaces/outboxes/IVeaOutboxOptimisticRollup.sol +++ b/contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol @@ -11,9 +11,9 @@ pragma solidity 0.8.18; /** - * @dev Interface of the Vea Outbox on Optimistic Rollups eg. Arbitrum, Optimism, Base, Specular, etc. + * @dev Interface of the Vea Outbox on L2s like Arbitrum, Optimism, Base, Specular where storage is inexpensive. */ -interface IVeaOutboxOptimisticRollup { +interface IVeaOutboxOnL2 { /** * Note: Gateways expect first argument of message call to be the inbox sender, used for authentication. * @dev Verifies and relays the message. diff --git a/contracts/src/interfaces/routers/IRouterToEthChain.sol b/contracts/src/interfaces/routers/IRouterToAltL1.sol similarity index 63% rename from contracts/src/interfaces/routers/IRouterToEthChain.sol rename to contracts/src/interfaces/routers/IRouterToAltL1.sol index 59b1c4f2..79fa168a 100644 --- a/contracts/src/interfaces/routers/IRouterToEthChain.sol +++ b/contracts/src/interfaces/routers/IRouterToAltL1.sol @@ -8,11 +8,14 @@ * @deployments: [] */ -import "../outboxes/IVeaOutboxEthChain.sol"; - pragma solidity 0.8.18; -interface IRouterToEthChain { +import "../types/VeaClaim.sol"; + +/** + * @dev Interface of the Vea Router on Ethereum L1 which routes messages to alt-L1 chains like Gnosis, Polygon POS etc. + */ +interface IRouterToAltL1 { /** * Note: Access restricted to arbitrum canonical bridge. * @dev Routes state root snapshots from arbitrum to gnosis @@ -20,5 +23,5 @@ interface IRouterToEthChain { * @param stateRoot The true state root for the epoch. * @param claim The claim associated with the epoch. */ - function route(uint256 epoch, bytes32 stateRoot, IVeaOutboxEthChain.Claim memory claim) external; + function route(uint256 epoch, bytes32 stateRoot, Claim memory claim) external; } diff --git a/contracts/src/interfaces/routers/IRouterToOptimisticRollup.sol b/contracts/src/interfaces/routers/IRouterToL2.sol similarity index 73% rename from contracts/src/interfaces/routers/IRouterToOptimisticRollup.sol rename to contracts/src/interfaces/routers/IRouterToL2.sol index 6ec8d8a1..32f700c3 100644 --- a/contracts/src/interfaces/routers/IRouterToOptimisticRollup.sol +++ b/contracts/src/interfaces/routers/IRouterToL2.sol @@ -10,7 +10,10 @@ pragma solidity 0.8.18; -interface IRouterToOptimisticRollup { +/** + * @dev Interface of the Vea Router on Ethereum L1 which routes messages to L2s like Arbitrum, Optimism, Base, Specular where storage is expensive. + */ +interface IRouterToL2 { /** * Note: Access restricted to canonical bridge. * @dev Resolves any challenge of the optimistic claim for 'epoch' using the canonical bridge. diff --git a/contracts/src/interfaces/types/VeaClaim.sol b/contracts/src/interfaces/types/VeaClaim.sol new file mode 100644 index 00000000..7b980c2e --- /dev/null +++ b/contracts/src/interfaces/types/VeaClaim.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +/** + * @authors: [@jaybuidl, @shotaronowhere] + * @reviewers: [] + * @auditors: [] + * @bounties: [] + * @deployments: [] + */ + +pragma solidity 0.8.18; + +enum Party { + None, + Claimer, + Challenger +} + +struct Claim { + bytes32 stateRoot; + address claimer; + uint32 timestamp; + uint32 blocknumber; + Party honest; + address challenger; +} diff --git a/contracts/src/test/ArbitrumToEth/VeaInboxMockArbToEth.sol b/contracts/src/test/ArbitrumToEth/VeaInboxMockArbToEth.sol index 89951063..4c6630e9 100644 --- a/contracts/src/test/ArbitrumToEth/VeaInboxMockArbToEth.sol +++ b/contracts/src/test/ArbitrumToEth/VeaInboxMockArbToEth.sol @@ -22,11 +22,11 @@ contract VeaInboxMockArbToEth is VeaInboxArbToEth { /** * @dev Sends the state root using Arbitrum's canonical bridge. */ - function sendSnapshot(uint256 _epochSnapshot, IVeaOutboxEthChain.Claim calldata claim) external override { + function sendSnapshot(uint256 _epochSnapshot, Claim calldata claim) external override { uint256 epoch = uint256(block.timestamp) / epochPeriod; require(_epochSnapshot <= epoch, "Epoch in the future."); bytes memory data = abi.encodeCall( - IVeaOutboxEthChain.resolveDisputedClaim, + IVeaOutboxOnL1.resolveDisputedClaim, (_epochSnapshot, snapshots[_epochSnapshot], claim) );