-
Notifications
You must be signed in to change notification settings - Fork 7
Fix/message encoding #429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Fix/message encoding #429
Conversation
✅ Deploy Preview for veascan ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
WalkthroughInbox APIs now accept full calldata (no selector) and include msg.sender in leaf encoding. Outboxes add an explicit Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant L2Sender as L2 Sender (contract)
participant Inbox as Inbox (L2)
participant Bridge as Bridge / Snapshot
participant Outbox as Outbox (L1/L2)
participant Gateway as Receiver Gateway
participant Receiver as Receiver Contract
L2Sender->>Inbox: sendMessage(to, data)
Inbox->>Inbox: leaf = keccak256(oldCount, to, msg.sender, data)
Inbox-->>Bridge: publish snapshot / batch root
Bridge-->>Outbox: submit proof + batch root
Outbox->>Outbox: verify proof for (msgId, to, from, message)
Outbox->>Outbox: compute nodeHash := keccak256(msgId, to, from, message)
Outbox->>Gateway: IReceiverGateway(to).receiveMessage(from, message)
Gateway->>Receiver: internal dispatch (call message)
Receiver-->>Gateway: success / revert
Gateway-->>Outbox: relay result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🔭 Outside diff range comments (1)
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (1)
496-500
: Critical: assignment typo prevents claimHashes updateIn withdrawChallengerEscapeHatch, this line uses equality (==) instead of assignment (=), leaving claimHashes unchanged:
- claimHashes[_epoch] == hashClaim(_claim); + claimHashes[_epoch] = hashClaim(_claim);This blocks correctly evolving the claim state in the escape-hatch path.
🧹 Nitpick comments (16)
contracts/src/test/gateways/IReceiverGatewayMock.sol (1)
17-18
: Array entrypoint looks good; consider naming consistencyConsider naming the method receiveMessageBatch for consistency with common batch terminology across gateways.
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol (1)
20-20
: Doc nit: address(0) spellingUse address(0) (lowercase) consistently in docs.
contracts/src/utils/veaInboxTouch.sol (1)
23-23
: Clarify intent and drop payable (not used)
- This utility intentionally sends opaque bytes (no selector) to address(0) purely to advance the inbox and snapshot. Add a note to avoid confusion with IVeaInbox docs that mention full calldata.
- payable is unused; remove to prevent accidental ETH sends.
-contract VeaInboxTouch { +contract VeaInboxTouch { @@ - function touch(uint256 random) external payable { - veaInbox.sendMessage(0x0000000000000000000000000000000000000000, abi.encode(random)); + /// @dev Sends an opaque, non-executable payload to address(0) to cheaply advance the inbox before snapshotting. + function touch(uint256 random) external { + // Not intended for execution; selector omitted on purpose. + veaInbox.sendMessage(address(0), abi.encode(random)); veaInbox.saveSnapshot(); }Add a brief comment above sendMessage explaining that this message will never be relayed/executed.
contracts/src/test/gateways/SenderGatewayMock.sol (2)
27-29
: Prefer abi.encodeCall for type-safety and readabilityabi.encodeCall ensures the selector and argument types match the target signature at compile time.
- bytes4 methodSelector = IReceiverGatewayMock.receiveMessage.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, _data); - veaInbox.sendMessage(receiverGateway, data); + bytes memory data = abi.encodeCall(IReceiverGatewayMock.receiveMessage, (_data)); + veaInbox.sendMessage(receiverGateway, data);
31-35
: Same here: use abi.encodeCall for the array pathConsistent with the single-item path, improves safety and clarity.
- bytes4 methodSelector = IReceiverGatewayMock.receiveMessageArray.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, _data); - veaInbox.sendMessage(receiverGateway, data); + bytes memory data = abi.encodeCall(IReceiverGatewayMock.receiveMessageArray, (_data)); + veaInbox.sendMessage(receiverGateway, data);contracts/src/interfaces/inboxes/IVeaInbox.sol (1)
15-15
: Doc: emphasize “full calldata” and show abi.encodeCall exampleTo reduce ambiguity, state that _data must be the full calldata (including the function selector). Consider documenting abi.encodeCall usage as the preferred pattern.
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol (4)
73-76
: Docs and signature aligned with full-calldata patternComment now references abi.encodeWithSelector; signature matches IVeaInbox. Consider adding “full calldata (including selector)” wording for clarity, mirroring the interface doc.
41-43
: Update MessageSent event doc to reflect new nodeData shape (includes sender)nodeData now encodes oldCount, _to, msg.sender, _data. The event doc still mentions only msgId, to, message.
- /// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, message), outbox relays to.call(message). + /// @param _nodeData The data to create leaves in the merkle tree: abi.encodePacked(msgId, to, from, message). + /// The Outbox relays to.call(message) after authenticating that 'from' is allowlisted.Also applies to: 82-83
75-75
: Future optimization after interface switch to calldataIf IVeaInbox is updated to bytes calldata, mirror it here for gas savings:
- function sendMessage(address _to, bytes memory _data) external override returns (uint64) { + function sendMessage(address _to, bytes calldata _data) external override returns (uint64) {Ensure all chain-specific inboxes adopt the same change to keep interfaces consistent.
78-80
: Minor grammar nit in comment“Atleast” → “at least”.
- // Given arbitrum's speed limit of 7 million gas / second, it would take atleast 8 million years of full blocks to overflow. + // Given Arbitrum's speed limit of 7 million gas/second, it would take at least 8 million years of full blocks to overflow.contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol (1)
69-76
: Fix docs: direction and calldata wording are outdated
- Line 69 says “Sends an arbitrary message to Gnosis” but this inbox sends from Gnosis to Arbitrum. Replace “to Gnosis” with “to Arbitrum”.
- Line 74: Replace “abi.encodeWithSelector(fnSelector, …)” with “abi.encodeWithSelector(selector, …)” and clarify that _data is the full calldata (including selector) the outbox will call with.
Example:
-/// @dev Sends an arbitrary message to Gnosis. +/// @dev Sends an arbitrary message to Arbitrum. ... -/// @param _data The message calldata, abi.encodeWithSelector(fnSelector, param1, param2, ...) +/// @param _data The full calldata to relay (e.g., abi.encodeWithSelector(selector, arg1, arg2, ...)).contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol (1)
34-39
: Consider an AllowlistUpdated event for observabilityRecommend adding an event to track allowlist changes (e.g., AllowlistUpdated(address indexed receiver, address indexed from, bool allowed)) so off-chain components can react to ACL changes.
contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol (1)
73-76
: Polish _data param docs to reflect the new APIClarify that _data is the full calldata (including the function selector). Replace “fnSelector” wording.
-/// @param _data The message calldata, abi.encodeWithSelector(fnSelector, param1, param2, ...) +/// @param _data The full calldata to relay (e.g., abi.encodeWithSelector(selector, arg1, arg2, ...)).contracts/test/integration/ArbToEth.ts (2)
354-356
: Use standard revert assertion (drop “itself”)Prefer the canonical form for revert assertions.
- await expect(veaOutbox.connect(relayer).sendMessage(proof, nonce, to, from, msgData)).itself.be.revertedWith( + await expect(veaOutbox.connect(relayer).sendMessage(proof, nonce, to, from, msgData)).to.be.revertedWith( "Message sender not allowed to call receiver." );
261-265
: Deduplicate node decoding by reusing decodeMessage(msg2)You already added decodeMessage; use it instead of manual slicing for msg2 to reduce duplication and errors.
Example:
const { nonce: nonce2, to: to2, from: from2, msgData: msgData2 } = await decodeMessage(msg2);Also applies to: 323-327, 378-382, 441-445
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (1)
44-45
: Allowlist + sender-aware relay: solid design
- Per-receiver allowlist with wildcard (address(0)) is simple and effective.
- sendMessage now binds the proof to (_msgId, _to, _from, _message), which aligns with inbox leaf encoding.
- Gatekeeping before proof verification avoids unnecessary hash work on unauthorized calls.
Consider emitting an event on allowlist updates for monitoring:
event AllowlistUpdated(address indexed receiver, address indexed from, bool allowed);and emit in setAllowlist.
Also applies to: 355-362, 367-375, 377-381
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol
(2 hunks)contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
(3 hunks)contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol
(2 hunks)contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
(3 hunks)contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol
(1 hunks)contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
(2 hunks)contracts/src/interfaces/inboxes/IVeaInbox.sol
(1 hunks)contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
(1 hunks)contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol
(1 hunks)contracts/src/test/gateways/IReceiverGatewayMock.sol
(1 hunks)contracts/src/test/gateways/ReceiverGatewayMock.sol
(2 hunks)contracts/src/test/gateways/SenderGatewayMock.sol
(1 hunks)contracts/src/utils/veaInboxTouch.sol
(1 hunks)contracts/test/integration/ArbToEth.ts
(12 hunks)contracts/test/integration/ArbToGnosis.ts
(6 hunks)
🧰 Additional context used
🧠 Learnings (10)
📚 Learning: 2024-12-09T09:40:28.400Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:13-13
Timestamp: 2024-12-09T09:40:28.400Z
Learning: In `bridger-cli/src/utils/transactionHandler.ts`, the `veaOutbox` implementations differ for each chain, but a common interface should be defined for type checks to enhance type safety.
Applied to files:
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-16T09:22:57.434Z
Learnt from: mani99brar
PR: kleros/vea#383
File: contracts/test/integration/ArbToGnosis.ts:114-114
Timestamp: 2024-12-16T09:22:57.434Z
Learning: In the local Hardhat deployment for testing, `VeaInboxArbToGnosisMock` is deployed with the identifier name `VeaInboxArbToGnosis`, so it's appropriate to retrieve it using `getContract("VeaInboxArbToGnosis")` and cast it to `VeaInboxArbToGnosisMock` in `ArbToGnosis.ts`.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-02T10:16:56.825Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:829-840
Timestamp: 2024-12-02T10:16:56.825Z
Learning: In the `validator-cli/src/ArbToEth/watcherArbToGnosis.ts` file, avoid adding redundant error handling in functions like `reconstructChallengeProgress` when error handling is already adequately managed.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-11-26T08:37:47.591Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:829-1112
Timestamp: 2024-11-26T08:37:47.591Z
Learning: Refactoring the `reconstructChallengeProgress` function in `validator-cli/src/ArbToEth/watcherArbToGnosis.ts` into smaller functions is considered unnecessary abstraction.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-11-20T10:49:25.392Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts:93-98
Timestamp: 2024-11-20T10:49:25.392Z
Learning: In `contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts`, when resurrecting testnets, it's acceptable to use `getContractAddress()` for contract address prediction.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2025-06-05T12:17:21.782Z
Learnt from: mani99brar
PR: kleros/vea#424
File: validator-cli/src/helpers/claimer.ts:72-76
Timestamp: 2025-06-05T12:17:21.782Z
Learning: In validator-cli/src/helpers/claimer.ts, the outboxStateRoot captured at the beginning of the checkAndClaim function won't change for the epoch being claimed, so there's no race condition concern when reusing it in makeClaim/makeClaimDevnet functions.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T09:42:34.067Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:64-77
Timestamp: 2024-12-09T09:42:34.067Z
Learning: In the `TransactionHandler` class (`bridger-cli/src/utils/transactionHandler.ts`), it's acceptable to let methods like `makeClaim` fail without additional error handling.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T10:54:09.943Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/claim.ts:42-51
Timestamp: 2024-12-09T10:54:09.943Z
Learning: In the `bridger-cli/src/utils/claim.ts` file, within the `fetchClaim` function, explicit error handling for provider calls and event queries is not required; errors should be allowed to propagate naturally.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T09:42:51.590Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:79-101
Timestamp: 2024-12-09T09:42:51.590Z
Learning: In the `bridger-cli/src/utils/transactionHandler.ts` file, within the `TransactionHandler` class, it's acceptable to let methods like `startVerification` fail without additional error handling.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-11T08:52:17.062Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/epochHandler.ts:13-13
Timestamp: 2024-12-11T08:52:17.062Z
Learning: In `bridger-cli/src/utils/epochHandler.ts`, the `veaOutbox` parameter is intentionally typed as `any` because the script is designed to be agnostic for multiple contracts.
Applied to files:
contracts/test/integration/ArbToEth.ts
🧬 Code Graph Analysis (2)
contracts/test/integration/ArbToGnosis.ts (2)
contracts/test/integration/ArbToEth.ts (1)
decodeMessage
(1322-1328)contracts/test/merkle/MerkleTree.ts (1)
MerkleTree
(9-248)
contracts/test/integration/ArbToEth.ts (1)
contracts/test/merkle/MerkleTree.ts (1)
MerkleTree
(9-248)
🪛 Biome (2.1.2)
contracts/test/integration/ArbToEth.ts
[error] 1321-1328: Do not export from a test file.
(lint/suspicious/noExportsInTest)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: dependency-review
- GitHub Check: test
- GitHub Check: Analyze (javascript)
🔇 Additional comments (22)
contracts/src/test/gateways/IReceiverGatewayMock.sol (1)
15-16
: receiveMessage signature alignment validatedIReceiverGateway and ReceiverGatewayMock both declare
function receiveMessage(uint256 _data) external;ensuring they share the exact signature and there are no inheritance conflicts.
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol (2)
3-3
: Author metadata updateLooks fine.
82-82
: Outbox leaf hashing and allowlist enforcement align with inbox encodingThe outbox in contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol:
- Reconstructs the node hash with
keccak256(abi.encodePacked(_msgId, _to, _from, _message))
(line 380), matching the inbox’s
abi.encodePacked(oldCount, _to, msg.sender, _data)
.- Enforces that the captured sender (
_from
) is allowed via
allowlist[_to][_from] || allowlist[_to][address(0)]
immediately before relay.No changes needed here.
contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol (1)
83-87
: Leaf encoding LGTM; includes sender for allowlist/authabi.encodePacked(oldCount, _to, msg.sender, _data) aligns with the new outbox hashing that includes _from. Double-hashing mitigates second preimage. No ambiguity because bytes payload is last.
contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol (1)
20-26
: API update matches new leaf encoding and relay flowAdding _from to sendMessage is consistent with including the sender in the leaf and with allowlist authentication at the receiver.
contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol (2)
3-3
: Author update acknowledged
82-86
: Leaf encoding LGTM; sender inclusion is correctIncluding msg.sender in nodeData matches new outbox verification and allowlist checks. Double-hash remains for preimage resistance.
contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (3)
45-45
: LGTM! Well-structured allowlist mapping.The two-level mapping with address(0) as a wildcard is an efficient design for per-receiver access control.
299-304
: LGTM! Proper receiver-controlled allowlist management.The function correctly allows receivers to manage their own allowlist entries.
306-323
: LGTM! Secure implementation of sender authentication.The allowlist check correctly handles both specific and wildcard allowances, and the leaf hash properly includes the sender address for verification.
contracts/src/test/gateways/ReceiverGatewayMock.sol (5)
12-12
: LGTM! Required import for allowlist functionality.
22-22
: LGTM! Test data storage for array messages.
29-32
: LGTM! Correct bridge-based authentication.
34-40
: LGTM! Test helpers for allowlist configuration.The functions properly configure specific and wildcard allowlists for testing.
43-59
: LGTM! Proper message handling for testing.The functions correctly handle both single and array messages with appropriate bridge authentication.
contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol (1)
310-310
: LGTM! Correct leaf hash computation.The leaf hash properly includes the sender address.
contracts/test/integration/ArbToGnosis.ts (6)
5-5
: LGTM! Good code reuse.Importing the decodeMessage helper reduces code duplication.
250-312
: LGTM! Comprehensive test for message relay with allowlist.The test properly validates the new allowlist mechanism and array message handling.
314-370
: LGTM! Important negative test case.Validates that the allowlist is properly enforced.
372-434
: LGTM! Tests wildcard allowlist functionality.Validates that address(0) wildcard properly allows all senders.
746-772
: LGTM! Dispute resolution test properly updated.Test correctly handles allowlist setup for message relay after dispute resolution.
923-949
: LGTM! Consistent test updates for dishonest claim scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🔭 Outside diff range comments (2)
contracts/test/integration/ArbToEth.ts (1)
861-869
: Withdraw should be performed by the bridger signerWithout .connect(bridger), the call is sent by the default signer and may revert due to access control/intent.
- await veaOutbox.withdrawClaimDeposit(epoch, { + await veaOutbox.connect(bridger).withdrawClaimDeposit(epoch, { stateRoot: batchMerkleRoot, claimer: bridger.address, timestampClaimed: block.timestamp, timestampVerification: blockStartValidation.timestamp!, blocknumberVerification: startValidationTxn.blockNumber!, honest: 1, challenger: challenger.address, });contracts/test/integration/ArbToGnosis.ts (1)
382-386
: Same issue: includefrom
for dynamic array test- let nodes: string[] = []; - nodes.push(MerkleTree.makeLeafNode(nonce, to, msgData)); - const mt = new MerkleTree(nodes); - const proof = mt.getHexProof(nodes[0]); + let nodes: string[] = []; + nodes.push(MerkleTree.makeLeafNode(nonce, to, from, msgData)); + const mt = new MerkleTree(nodes); + const proof = mt.getHexProof(nodes[0]);Also applies to: 380-386
♻️ Duplicate comments (1)
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol (1)
37-41
: Document permissionless self-service semantics; clarify address(0) wildcard; fix capitalizationPer the intended design, receivers (msg.sender) manage their own allowlists. Make this explicit and correct the address(0) notation.
- /// @dev Sets the allowlist for the sender gateway. - /// Note: Address(0) is used to allow all addresses. - /// @param _from The address to allow or disallow - /// @param _allow Whether to allow or disallow the address. + /// @dev Sets the per-receiver allowlist of permitted L2 senders for msg.sender (self-service). + /// Access: permissionless — this only affects msg.sender's own allowlist. + /// Note: address(0) acts as a wildcard to allow all senders; disabling it reverts to per-address checks. + /// @param _from The L2 sender to allow or disallow (use address(0) for wildcard). + /// @param _allow Whether to allow or disallow the address. function setAllowlist(address _from, bool _allow) external;Optional (nice-to-have): consider a view helper like isAllowed(address receiver, address from) to aid off-chain consumers since this is event-less by design.
if an earlier review suggested event emission, intentionally skipping that per the recorded design choice (permissionless, no events).
🧹 Nitpick comments (9)
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol (2)
20-28
: Clarify_from
semantics (allowlist + leaf verification) in NatSpecTighten the docs so implementers consistently include
_from
in the leaf/hash and in allowlist checks.- /// @param _from The address of the contract on L2 that sent the message, used for authentication. + /// @param _from The L2 sender address. Implementations MUST include `_from` in the leaf/hash verification and enforce the per-receiver allowlist (for `_to`) against `_from`.
35-35
: Prefer calldata for Claim to avoid unnecessary copiesSmall gas/readability improvement for external interface parameters.
- function resolveDisputedClaim(uint256 _epoch, bytes32 _stateRoot, Claim memory _claim) external; + function resolveDisputedClaim(uint256 _epoch, bytes32 _stateRoot, Claim calldata _claim) external;contracts/src/arbitrumToEth/VeaInboxArbToEth.sol (2)
73-73
: Doc nit: avoid referring to a removed parameter nameThe example references fnSelector even though the selector is now embedded in _data. Reword to avoid implying a separate param.
- /// @param _data The message calldata, abi.encodeWithSelector(fnSelector, param1, param2, ...) + /// @param _data The full message calldata. It must start with a function selector, e.g. + /// abi.encodeWithSelector(selector, param1, param2, ...)
82-82
: Leaf change: include sender in nodeData (aligns with outbox allowlist)Encoding oldCount, _to, msg.sender, _data is sound. One follow-up: event docs still say abi.encodePacked(msgId, to, message) without mentioning from. Consider updating event docs in this file and the interface for clarity.
- /// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, message), outbox relays to.call(message). + /// @param _nodeData The data to create leaves in the merkle tree: + /// abi.encodePacked(msgId, to, from, message). + /// The outbox relays with the provided message and may use `from` for allowlist checks.contracts/test/integration/ArbToEth.ts (2)
259-263
: Use the same decode helper for msg2 to avoid manual slicingKeeps tests consistent and less error-prone.
- const msg2 = MessageSentEvent[1].args._nodeData; - - let nodes: string[] = []; - - const nonce2 = "0x" + msg2.slice(2, 18); - const to2 = "0x" + msg2.slice(18, 58); //18+40 - const from2 = "0x" + msg2.slice(58, 98); //58+40 - const msgData2 = "0x" + msg2.slice(98); + const msg2 = MessageSentEvent[1].args._nodeData; + let nodes: string[] = []; + const { nonce: nonce2, to: to2, from: from2, msgData: msgData2 } = await decodeMessage(msg2);Also applies to: 253-254
1306-1312
: Helper can be non-async and typedMinor polish; removes unnecessary async and clarifies return shape.
-async function decodeMessage(msg: any) { +type DecodedMsg = { nonce: string; to: string; from: string; msgData: string }; +function decodeMessage(msg: string): DecodedMsg { const nonce = "0x" + msg.slice(2, 18); const to = "0x" + msg.slice(18, 58); //18+40 const from = "0x" + msg.slice(58, 98); //58+40 const msgData = "0x" + msg.slice(98); return { nonce, to, from, msgData }; }contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol (2)
73-73
: Doc nit: remove reference to nonexistent parameter nameSame as ArbToEth inbox; keep the guidance but avoid implying a param.
- /// @param _data The message calldata, abi.encodeWithSelector(fnSelector, param1, param2, ...) + /// @param _data The full message calldata. It must start with a function selector, e.g. + /// abi.encodeWithSelector(selector, param1, param2, ...)
82-82
: Leaf now includes sender; update event doc accordinglyEncoding abi.encodePacked(oldCount, _to, msg.sender, _data) is correct. Consider updating the MessageSent doc to include from like in the ArbToEth review.
- /// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, message), outbox relays to.call(message). + /// @param _nodeData The data to create leaves in the merkle tree: + /// abi.encodePacked(msgId, to, from, message). + /// The outbox relays with the provided message and may use `from` for allowlist checks.contracts/test/integration/ArbToGnosis.ts (1)
1087-1093
: Helper can be non-async and typedKeeps helpers consistent with ArbToEth and improves clarity.
-async function decodeMessage(msg: any) { +type DecodedMsg = { nonce: string; to: string; from: string; msgData: string }; +function decodeMessage(msg: string): DecodedMsg { const nonce = "0x" + msg.slice(2, 18); const to = "0x" + msg.slice(18, 58); //18+40 const from = "0x" + msg.slice(58, 98); //58+40 const msgData = "0x" + msg.slice(98); return { nonce, to, from, msgData }; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol
(2 hunks)contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
(3 hunks)contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol
(2 hunks)contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
(3 hunks)contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol
(1 hunks)contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
(2 hunks)contracts/src/interfaces/inboxes/IVeaInbox.sol
(1 hunks)contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
(1 hunks)contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol
(1 hunks)contracts/test/integration/ArbToEth.ts
(29 hunks)contracts/test/integration/ArbToGnosis.ts
(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol
- contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
- contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
- contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
- contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol
- contracts/src/interfaces/inboxes/IVeaInbox.sol
🧰 Additional context used
🧠 Learnings (14)
📚 Learning: 2024-12-16T09:22:57.434Z
Learnt from: mani99brar
PR: kleros/vea#383
File: contracts/test/integration/ArbToGnosis.ts:114-114
Timestamp: 2024-12-16T09:22:57.434Z
Learning: In the local Hardhat deployment for testing, `VeaInboxArbToGnosisMock` is deployed with the identifier name `VeaInboxArbToGnosis`, so it's appropriate to retrieve it using `getContract("VeaInboxArbToGnosis")` and cast it to `VeaInboxArbToGnosisMock` in `ArbToGnosis.ts`.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
contracts/test/integration/ArbToEth.ts
📚 Learning: 2025-08-11T09:26:45.958Z
Learnt from: mani99brar
PR: kleros/vea#429
File: contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol:0-0
Timestamp: 2025-08-11T09:26:45.958Z
Learning: In the Vea bridge contracts, the `setAllowlist` function is designed as a permissionless, self-service function where receivers (msg.sender) can control which sender addresses are allowed to relay messages to them. No access control or events are needed for this function as it's intended to be called by anyone to manage their own allowlist.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
📚 Learning: 2025-06-05T12:17:21.782Z
Learnt from: mani99brar
PR: kleros/vea#424
File: validator-cli/src/helpers/claimer.ts:72-76
Timestamp: 2025-06-05T12:17:21.782Z
Learning: In validator-cli/src/helpers/claimer.ts, the outboxStateRoot captured at the beginning of the checkAndClaim function won't change for the epoch being claimed, so there's no race condition concern when reusing it in makeClaim/makeClaimDevnet functions.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-02T10:16:56.825Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:829-840
Timestamp: 2024-12-02T10:16:56.825Z
Learning: In the `validator-cli/src/ArbToEth/watcherArbToGnosis.ts` file, avoid adding redundant error handling in functions like `reconstructChallengeProgress` when error handling is already adequately managed.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-11-27T04:18:05.872Z
Learnt from: mani99brar
PR: kleros/vea#344
File: validator-cli/src/ArbToEth/watcherArbToEth.ts:732-745
Timestamp: 2024-11-27T04:18:05.872Z
Learning: In `validator-cli/src/ArbToEth/watcherArbToEth.ts`, input validation inside the `hashClaim` function is unnecessary because the upper layer ensures valid input before calling it.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-11-26T08:37:47.591Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:829-1112
Timestamp: 2024-11-26T08:37:47.591Z
Learning: Refactoring the `reconstructChallengeProgress` function in `validator-cli/src/ArbToEth/watcherArbToGnosis.ts` into smaller functions is considered unnecessary abstraction.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-11-20T10:49:25.392Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts:93-98
Timestamp: 2024-11-20T10:49:25.392Z
Learning: In `contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts`, when resurrecting testnets, it's acceptable to use `getContractAddress()` for contract address prediction.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-11T08:52:23.697Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/epochHandler.ts:38-50
Timestamp: 2024-12-11T08:52:23.697Z
Learning: The `getBlockNumberFromEpoch` function in `bridger-cli/src/utils/epochHandler.ts` is currently unused and will be addressed in a future issue.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T09:40:28.400Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:13-13
Timestamp: 2024-12-09T09:40:28.400Z
Learning: In `bridger-cli/src/utils/transactionHandler.ts`, the `veaOutbox` implementations differ for each chain, but a common interface should be defined for type checks to enhance type safety.
Applied to files:
contracts/test/integration/ArbToEth.ts
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
📚 Learning: 2024-12-09T09:42:34.067Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:64-77
Timestamp: 2024-12-09T09:42:34.067Z
Learning: In the `TransactionHandler` class (`bridger-cli/src/utils/transactionHandler.ts`), it's acceptable to let methods like `makeClaim` fail without additional error handling.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T10:54:09.943Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/claim.ts:42-51
Timestamp: 2024-12-09T10:54:09.943Z
Learning: In the `bridger-cli/src/utils/claim.ts` file, within the `fetchClaim` function, explicit error handling for provider calls and event queries is not required; errors should be allowed to propagate naturally.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-11T08:52:17.062Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/epochHandler.ts:13-13
Timestamp: 2024-12-11T08:52:17.062Z
Learning: In `bridger-cli/src/utils/epochHandler.ts`, the `veaOutbox` parameter is intentionally typed as `any` because the script is designed to be agnostic for multiple contracts.
Applied to files:
contracts/test/integration/ArbToEth.ts
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
📚 Learning: 2024-12-09T09:42:51.590Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:79-101
Timestamp: 2024-12-09T09:42:51.590Z
Learning: In the `bridger-cli/src/utils/transactionHandler.ts` file, within the `TransactionHandler` class, it's acceptable to let methods like `startVerification` fail without additional error handling.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T10:53:55.715Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/bridger.ts:25-109
Timestamp: 2024-12-09T10:53:55.715Z
Learning: In the `bridger-cli/src/bridger.ts` file, refactoring the main loop and adding additional error handling are not needed unless deemed necessary by the developer.
Applied to files:
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
🧬 Code Graph Analysis (2)
contracts/test/integration/ArbToGnosis.ts (1)
contracts/test/merkle/MerkleTree.ts (1)
MerkleTree
(9-248)
contracts/test/integration/ArbToEth.ts (1)
contracts/test/merkle/MerkleTree.ts (1)
MerkleTree
(9-248)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: dependency-review
- GitHub Check: test
- GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol (2)
3-3
: Author/header update looks goodNo issues. Matches project conventions.
75-75
: Signature/data location change is correct and gas-friendlybytes calldata is appropriate; interface alignment is good.
contracts/test/integration/ArbToEth.ts (1)
56-56
: Enable per-sender allowlist in setupGood default for tests that need allowlist enforcement.
contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol (2)
3-3
: Author/header update looks goodNo issues.
75-75
: Signature/data location change is correctbytes calldata is appropriate; interface alignment is good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
contracts/test/integration/ArbToGnosis.ts (2)
255-257
: Make event query deterministic (use block range).Querying without a block range can pick up stale logs across redeploys. Prefer querying from the block of the send tx.
- await senderGateway.connect(sender).sendMessageArray(data); + const sendTx = await senderGateway.connect(sender).sendMessageArray(data); + const sendRcpt = await sendTx.wait(); await veaInbox.connect(bridger).saveSnapshot(); - const MessageSent = veaInbox.filters.MessageSent(); - const MessageSentEvent = await veaInbox.queryFilter(MessageSent); + const MessageSent = veaInbox.filters.MessageSent(); + const MessageSentEvent = await veaInbox.queryFilter( + MessageSent, + sendRcpt!.blockNumber, + sendRcpt!.blockNumber + ); const msg = MessageSentEvent[0].args._nodeData;
1087-1093
: Type and robustness improvements for decodeMessage.
- Not asynchronous; remove async.
- Add typing and basic guards (prefix and length).
- Optional: avoid magic numbers by documenting field sizes.
-async function decodeMessage(msg: any) { - const nonce = "0x" + msg.slice(2, 18); - const to = "0x" + msg.slice(18, 58); //18+40 - const from = "0x" + msg.slice(58, 98); //58+40 - const msgData = "0x" + msg.slice(98); - return { nonce, to, from, msgData }; -} +function decodeMessage( + msg: string +): { nonce: string; to: string; from: string; msgData: string } { + if (typeof msg !== "string" || !msg.startsWith("0x")) { + throw new Error("Invalid nodeData format"); + } + // bytes8 (16 hex chars) + address (40) + address (40) + const MIN_LEN = 2 + 16 + 40 + 40; // 2 for '0x' + if (msg.length < MIN_LEN) { + throw new Error("nodeData too short"); + } + const nonce = "0x" + msg.slice(2, 18); + const to = "0x" + msg.slice(18, 58); + const from = "0x" + msg.slice(58, 98); + const msgData = "0x" + msg.slice(98); + return { nonce, to, from, msgData }; +}Note: If you adopt these types, drop the unnecessary
await
at call sites.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
contracts/test/integration/ArbToEth.ts
(29 hunks)contracts/test/integration/ArbToGnosis.ts
(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- contracts/test/integration/ArbToEth.ts
🧰 Additional context used
🧠 Learnings (9)
📚 Learning: 2024-11-21T07:44:06.942Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: relayer-cli/src/devnetRelayExample.ts:5-6
Timestamp: 2024-11-21T07:44:06.942Z
Learning: The files `contracts/deploy/02-inbox/02-arb-sepolia-to-chiado-inbox.ts` and `contracts/deploy/02-inbox/02-arb-sepolia-to-sepolia-inbox.ts` are not part of the current scope in this PR.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-11-20T10:49:25.392Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts:93-98
Timestamp: 2024-11-20T10:49:25.392Z
Learning: In `contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts`, when resurrecting testnets, it's acceptable to use `getContractAddress()` for contract address prediction.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-02T10:08:28.998Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:625-648
Timestamp: 2024-12-02T10:08:28.998Z
Learning: In `validator-cli/src/ArbToEth/watcherArbToGnosis.ts`, the function `findLatestL2BatchAndBlock` already handles the case when `fromArbBlock > latestBlockNumber`, so additional error handling for this case is unnecessary.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-02T10:16:56.825Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:829-840
Timestamp: 2024-12-02T10:16:56.825Z
Learning: In the `validator-cli/src/ArbToEth/watcherArbToGnosis.ts` file, avoid adding redundant error handling in functions like `reconstructChallengeProgress` when error handling is already adequately managed.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-11-20T11:50:19.381Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/utils/arbMsgExecutor.ts:44-44
Timestamp: 2024-11-20T11:50:19.381Z
Learning: In `validator-cli/src/utils/arbMsgExecutor.ts`, when calling `childToParentMessage.execute()`, pass `childProvider` as the argument since `childToParentMessage` already contains the parent (Ethereum) RPC context internally.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2025-06-05T12:17:21.782Z
Learnt from: mani99brar
PR: kleros/vea#424
File: validator-cli/src/helpers/claimer.ts:72-76
Timestamp: 2025-06-05T12:17:21.782Z
Learning: In validator-cli/src/helpers/claimer.ts, the outboxStateRoot captured at the beginning of the checkAndClaim function won't change for the epoch being claimed, so there's no race condition concern when reusing it in makeClaim/makeClaimDevnet functions.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-10T04:59:10.224Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/claim.ts:23-32
Timestamp: 2024-12-10T04:59:10.224Z
Learning: In `bridger-cli/src/utils/claim.ts`, within the `fetchClaim` function, when `claimData` is undefined, avoid initializing it with default values, as this can result in incorrect claim values and make issues harder to identify.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-16T09:22:57.434Z
Learnt from: mani99brar
PR: kleros/vea#383
File: contracts/test/integration/ArbToGnosis.ts:114-114
Timestamp: 2024-12-16T09:22:57.434Z
Learning: In the local Hardhat deployment for testing, `VeaInboxArbToGnosisMock` is deployed with the identifier name `VeaInboxArbToGnosis`, so it's appropriate to retrieve it using `getContract("VeaInboxArbToGnosis")` and cast it to `VeaInboxArbToGnosisMock` in `ArbToGnosis.ts`.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-09T09:40:28.400Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:13-13
Timestamp: 2024-12-09T09:40:28.400Z
Learning: In `bridger-cli/src/utils/transactionHandler.ts`, the `veaOutbox` implementations differ for each chain, but a common interface should be defined for type checks to enhance type safety.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
🧬 Code Graph Analysis (1)
contracts/test/integration/ArbToGnosis.ts (1)
contracts/test/merkle/MerkleTree.ts (1)
MerkleTree
(9-248)
🔇 Additional comments (10)
contracts/test/integration/ArbToGnosis.ts (10)
260-264
: Leaf encoding updated correctly to include from.Good fix: node data now hashes nonce, to, from, and msgData; proof generation will match the on-chain encoding.
301-311
: Relay path and duplicate-relay assertion look correct.
- Allowlist toggled before relay.
- sendMessage uses new 5-arg signature.
- Duplicate relay reverts as expected.
316-316
: Sender mock call matches new encoding flow.Using senderGateway.sendMessage aligns with selector-included encoding.
322-328
: Consistent leaf format in non-array flow.Includes from in leaf; proof creation remains correct.
366-369
: Correct revert on missing allowlist.Expecting "Message sender not allowed to call receiver." matches the added sender validation.
382-386
: Array message leaf/proof generation is correct.Leaf includes from; proof derived from single-node tree is valid (empty proof).
423-433
: Global allowance path validated.allowlistAllSender(true) enables relay; duplicate relay reverts as expected.
518-522
: Challenge setup helper usage is clean.Good reuse of setupClaimAndChallenge; event assertion remains intact.
803-807
: Challenge submission flow looks good.Helper used correctly; expected event asserted.
938-948
: Bug: Same nonce=0 issue in dishonest-claim resolution path.Passing 0 instead of the decoded nonce will not match the leaf/proof you computed.
- await receiverGateway.allowlistSender(true); - const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, 0, receiverGateway.target, from, msgData); + await receiverGateway.allowlistSender(true); + const relayTx = await veaOutbox + .connect(receiver) + .sendMessage(proof, nonce, to, from, msgData);Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (1)
487-487
: Fix no-op comparison inwithdrawChallengerEscapeHatch
The line below uses==
instead of=
, soclaimHashes[_epoch]
is never updated and the challenger escape hatch can never complete.Apply this change:
- claimHashes[_epoch] == hashClaim(_claim); + claimHashes[_epoch] = hashClaim(_claim);Locations needing this fix:
- contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol: line 487
Also add a unit test for
withdrawChallengerEscapeHatch
that exercises both claimer and challenger paths to catch this in CI.contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (1)
431-431
: Bug: '==' instead of '=' causes missing state updateSame issue as in the Arb->Eth outbox. This line should assign, not compare.
Apply this fix:
- claimHashes[_epoch] == hashClaim(_claim); + claimHashes[_epoch] = hashClaim(_claim);Add/extend tests to cover
withdrawChallengerEscapeHatch
for this branch.
♻️ Duplicate comments (2)
contracts/src/interfaces/inboxes/IVeaInbox.sol (1)
17-17
: Calldata optimization applied as previously requestedSwitching
_data
tobytes calldata
is the intended gas optimization and matches the implementing contracts. Thanks for addressing earlier feedback.contracts/test/integration/ArbToGnosis.ts (1)
643-644
: Replace hardcodednonce=0
insendMessage
calls across integration testsWe’re still seeing literal
0
passed as the nonce in several test files. Please update these to use a dynamic value or a named constant, and re-run the grep check to catch any others.Instances to fix:
- contracts/test/integration/ArbToGnosis.ts: lines 643, 818
- contracts/test/integration/ArbToEth.ts: lines 428, 512, 734, 862
🧹 Nitpick comments (10)
contracts/src/interfaces/gateways/IReceiverGateway.sol (1)
16-16
: Align parameter names with call sites for consistencyOutboxes call
receiveMessage(_from, _message)
. Consider renaming the interface params to match for readability and consistency across the codebase (ABI unchanged).- function receiveMessage(address msgSender, bytes calldata msgData) external; + function receiveMessage(address _from, bytes calldata _message) external;contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (1)
299-365
: Optional: Factor common relay logic into a shared library to reduce duplicationThe proof verification, replay protection, and gateway call are duplicated across outboxes. Consider extracting into an internal library (e.g., RelayLib) to centralize:
- Node hash computation (including
_from
)- Proof verification (sorted hashing)
- Replay bitmap operations
- Emitting
MessageRelayed
This reduces maintenance surface and keeps semantics aligned across chains.
I can draft a
library RelayLib
with well-typed helpers if helpful.contracts/src/test/gateways/SenderGatewayMock.sol (1)
11-11
: Prefer interface-based selectors and abi.encodeCall for type safety (decouple from concrete mock).Using the concrete
ReceiverGatewayMock
to fetch selectors couples the sender to a specific implementation. Switch to the interface andabi.encodeCall
to gain compile-time checks and reduce coupling.Apply:
-import "./ReceiverGatewayMock.sol"; +import "./IReceiverGatewayMock.sol";- bytes4 methodSelector = ReceiverGatewayMock.digestMessage.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, _data); + bytes memory data = abi.encodeCall(IReceiverGatewayMock.digestMessage, (_data)); veaInbox.sendMessage(receiverGateway, data);- bytes4 methodSelector = ReceiverGatewayMock.digestMessageArray.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, _data); + bytes memory data = abi.encodeCall(IReceiverGatewayMock.digestMessageArray, (_data)); veaInbox.sendMessage(receiverGateway, data);Also applies to: 26-29, 31-34
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol (1)
40-43
: Update event/docs to reflect new leaf format and relay flow.Docs still mention the old 3-field leaf and direct
to.call(message)
. They should reflect(msgId, to, from, msgData)
and the gateway relay path.Apply:
- /// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, message), outbox relays to.call(message). + /// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, from, msgData). + /// The outbox calls IReceiverGateway(_to).receiveMessage(from, msgData), and the receiver gateway dispatches msgData.- /// @param _data The message data for the receiving gateway. + /// @param _data The message calldata for the receiving gateway (e.g., abi.encodeCall(ReceiverGateway.digestMessage, (...))).And the leaf construction comment can be clarified inline if desired:
- bytes memory nodeData = abi.encodePacked(oldCount, _to, msg.sender, _data); + // Leaf encodes: (nonce=oldCount [uint64], to [address], from=msg.sender [address], msgData [bytes]) + bytes memory nodeData = abi.encodePacked(oldCount, _to, msg.sender, _data);Also applies to: 68-76, 82-83
contracts/test/integration/ArbToGnosis.ts (2)
643-644
: Use decoded nonce instead of hardcoded 0 to avoid brittle tests.Even if the current test happens to use nonce 0, prefer the decoded
nonce
for clarity and resilience.Apply:
- const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, 0, receiverGateway.target, from, msgData); + const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, nonce, to, from, msgData);- const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, 0, receiverGateway.target, from, msgData); + const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, nonce, to, from, msgData);Also applies to: 818-819
959-965
: Deduplicate and de-async decodeMessage helper.
- This helper is duplicated across test suites; consider moving to a shared test util (e.g., contracts/test/utils/messages.ts).
- It doesn’t use await; drop
async
and remove unnecessaryawait
at call sites.Apply in this file:
-async function decodeMessage(msg: any) { +function decodeMessage(msg: string) { const nonce = "0x" + msg.slice(2, 18); const to = "0x" + msg.slice(18, 58); //18+40 const from = "0x" + msg.slice(58, 98); //58+40 const msgData = "0x" + msg.slice(98); return { nonce, to, from, msgData }; }- const { nonce, to, from, msgData } = await decodeMessage(msg); + const { nonce, to, from, msgData } = decodeMessage(msg);- const { nonce, to, from, msgData } = await decodeMessage(msg); + const { nonce, to, from, msgData } = decodeMessage(msg);Optional follow-up: move
decodeMessage
tocontracts/test/utils/messages.ts
and import it here and in ArbToEth.ts for consistency.Also applies to: 258-259, 637-638
contracts/src/test/gateways/ReceiverGatewayMock.sol (2)
12-12
: Remove unused import.
IVeaOutboxOnL1
is imported but not used. Clean it up or typeveaOutbox
to the interface and compare againstaddress(veaOutbox)
.Apply (simple removal):
-import "../../interfaces/outboxes/IVeaOutboxOnL1.sol";
22-23
: Consider adding a convenience getter for the entire array.Public dynamic array getters require an index; a helper improves test readability.
Add:
function getDataArray() external view returns (uint256[] memory) { return dataArray; }contracts/test/integration/ArbToEth.ts (2)
428-429
: Use decoded nonce instead of 0 to avoid assumptions about leaf position.Keeps tests correct if more than one message is in the batch or ordering changes.
Apply:
- const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, 0, to, from, msgData); + const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, nonce, to, from, msgData);- const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, 0, to, from, msgData); + const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, nonce, to, from, msgData);- const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, 0, to, from, msgData); + const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, nonce, to, from, msgData);- const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, 0, to, from, msgData); + const verifyAndRelayTx = await veaOutbox.connect(relayer).sendMessage(proof, nonce, to, from, msgData);Also applies to: 512-514, 734-735, 862-864
1191-1197
: Deduplicate decodeMessage helper across suites.Same helper exists in ArbToGnosis.ts. Consider moving to a shared test util (e.g., contracts/test/utils/messages.ts) and importing it here and there.
Optionally, add a type:
type DecodedMsg = { nonce: string; to: `0x${string}`; from: `0x${string}`; msgData: `0x${string}` };Also applies to: 252-253, 368-372, 769-773, 897-901
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (15)
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol
(2 hunks)contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
(4 hunks)contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol
(2 hunks)contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
(4 hunks)contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol
(1 hunks)contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
(3 hunks)contracts/src/interfaces/gateways/IReceiverGateway.sol
(1 hunks)contracts/src/interfaces/inboxes/IVeaInbox.sol
(1 hunks)contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
(1 hunks)contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol
(1 hunks)contracts/src/test/gateways/IReceiverGatewayMock.sol
(1 hunks)contracts/src/test/gateways/ReceiverGatewayMock.sol
(2 hunks)contracts/src/test/gateways/SenderGatewayMock.sol
(2 hunks)contracts/test/integration/ArbToEth.ts
(28 hunks)contracts/test/integration/ArbToGnosis.ts
(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol
- contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol
- contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
- contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
- contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol
🧰 Additional context used
🧠 Learnings (22)
📚 Learning: 2024-12-09T09:40:28.400Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:13-13
Timestamp: 2024-12-09T09:40:28.400Z
Learning: In `bridger-cli/src/utils/transactionHandler.ts`, the `veaOutbox` implementations differ for each chain, but a common interface should be defined for type checks to enhance type safety.
Applied to files:
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-11-26T08:37:47.591Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:829-1112
Timestamp: 2024-11-26T08:37:47.591Z
Learning: Refactoring the `reconstructChallengeProgress` function in `validator-cli/src/ArbToEth/watcherArbToGnosis.ts` into smaller functions is considered unnecessary abstraction.
Applied to files:
contracts/test/integration/ArbToEth.ts
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-11-27T04:18:05.872Z
Learnt from: mani99brar
PR: kleros/vea#344
File: validator-cli/src/ArbToEth/watcherArbToEth.ts:732-745
Timestamp: 2024-11-27T04:18:05.872Z
Learning: In `validator-cli/src/ArbToEth/watcherArbToEth.ts`, input validation inside the `hashClaim` function is unnecessary because the upper layer ensures valid input before calling it.
Applied to files:
contracts/test/integration/ArbToEth.ts
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-02T10:16:56.825Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:829-840
Timestamp: 2024-12-02T10:16:56.825Z
Learning: In the `validator-cli/src/ArbToEth/watcherArbToGnosis.ts` file, avoid adding redundant error handling in functions like `reconstructChallengeProgress` when error handling is already adequately managed.
Applied to files:
contracts/test/integration/ArbToEth.ts
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2025-06-05T12:17:21.782Z
Learnt from: mani99brar
PR: kleros/vea#424
File: validator-cli/src/helpers/claimer.ts:72-76
Timestamp: 2025-06-05T12:17:21.782Z
Learning: In validator-cli/src/helpers/claimer.ts, the outboxStateRoot captured at the beginning of the checkAndClaim function won't change for the epoch being claimed, so there's no race condition concern when reusing it in makeClaim/makeClaimDevnet functions.
Applied to files:
contracts/test/integration/ArbToEth.ts
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-09T10:54:09.943Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/claim.ts:42-51
Timestamp: 2024-12-09T10:54:09.943Z
Learning: In the `bridger-cli/src/utils/claim.ts` file, within the `fetchClaim` function, explicit error handling for provider calls and event queries is not required; errors should be allowed to propagate naturally.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T10:54:57.068Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/claim.ts:56-69
Timestamp: 2024-12-09T10:54:57.068Z
Learning: In the TypeScript file 'bridger-cli/src/utils/claim.ts', the upper layers handle input validation for the 'hashClaim' function. Therefore, explicit input validation within 'hashClaim' is not necessary.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T09:42:34.067Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:64-77
Timestamp: 2024-12-09T09:42:34.067Z
Learning: In the `TransactionHandler` class (`bridger-cli/src/utils/transactionHandler.ts`), it's acceptable to let methods like `makeClaim` fail without additional error handling.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T10:53:55.715Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/bridger.ts:25-109
Timestamp: 2024-12-09T10:53:55.715Z
Learning: In the `bridger-cli/src/bridger.ts` file, refactoring the main loop and adding additional error handling are not needed unless deemed necessary by the developer.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-10T04:59:10.224Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/claim.ts:23-32
Timestamp: 2024-12-10T04:59:10.224Z
Learning: In `bridger-cli/src/utils/claim.ts`, within the `fetchClaim` function, when `claimData` is undefined, avoid initializing it with default values, as this can result in incorrect claim values and make issues harder to identify.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T09:03:31.474Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/graphQueries.ts:12-34
Timestamp: 2024-12-09T09:03:31.474Z
Learning: In `bridger-cli/src/utils/graphQueries.ts`, within the `getClaimForEpoch` function, returning `result['claims'][0]` is sufficient because it will be `undefined` if `result['claims']` is an empty array, making additional checks unnecessary.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T10:18:00.133Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/ethers.ts:20-82
Timestamp: 2024-12-09T10:18:00.133Z
Learning: In `bridger-cli/src/utils/ethers.ts`, prefer to keep the existing `chainId` checks without refactoring to avoid overcomplicating the code with additional conditional logic.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-11T08:52:23.697Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/epochHandler.ts:38-50
Timestamp: 2024-12-11T08:52:23.697Z
Learning: The `getBlockNumberFromEpoch` function in `bridger-cli/src/utils/epochHandler.ts` is currently unused and will be addressed in a future issue.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-11T08:52:17.062Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/epochHandler.ts:13-13
Timestamp: 2024-12-11T08:52:17.062Z
Learning: In `bridger-cli/src/utils/epochHandler.ts`, the `veaOutbox` parameter is intentionally typed as `any` because the script is designed to be agnostic for multiple contracts.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-12-09T09:42:51.590Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:79-101
Timestamp: 2024-12-09T09:42:51.590Z
Learning: In the `bridger-cli/src/utils/transactionHandler.ts` file, within the `TransactionHandler` class, it's acceptable to let methods like `startVerification` fail without additional error handling.
Applied to files:
contracts/test/integration/ArbToEth.ts
📚 Learning: 2024-11-21T07:44:06.942Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: relayer-cli/src/devnetRelayExample.ts:5-6
Timestamp: 2024-11-21T07:44:06.942Z
Learning: The files `contracts/deploy/02-inbox/02-arb-sepolia-to-chiado-inbox.ts` and `contracts/deploy/02-inbox/02-arb-sepolia-to-sepolia-inbox.ts` are not part of the current scope in this PR.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-11-20T10:49:25.392Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts:93-98
Timestamp: 2024-11-20T10:49:25.392Z
Learning: In `contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts`, when resurrecting testnets, it's acceptable to use `getContractAddress()` for contract address prediction.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-02T10:08:28.998Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/ArbToEth/watcherArbToGnosis.ts:625-648
Timestamp: 2024-12-02T10:08:28.998Z
Learning: In `validator-cli/src/ArbToEth/watcherArbToGnosis.ts`, the function `findLatestL2BatchAndBlock` already handles the case when `fromArbBlock > latestBlockNumber`, so additional error handling for this case is unnecessary.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-11-20T11:50:19.381Z
Learnt from: madhurMongia
PR: kleros/vea#359
File: validator-cli/src/utils/arbMsgExecutor.ts:44-44
Timestamp: 2024-11-20T11:50:19.381Z
Learning: In `validator-cli/src/utils/arbMsgExecutor.ts`, when calling `childToParentMessage.execute()`, pass `childProvider` as the argument since `childToParentMessage` already contains the parent (Ethereum) RPC context internally.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-16T09:24:33.478Z
Learnt from: mani99brar
PR: kleros/vea#383
File: contracts/test/integration/ArbToGnosis.ts:520-520
Timestamp: 2024-12-16T09:24:33.478Z
Learning: In the TypeScript integration tests (`contracts/test/integration/ArbToGnosis.ts`), adding null checks after retrieving blocks using `await ethers.provider.getBlock` is unnecessary because the test will fail if the block is not found.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-11-27T05:02:48.754Z
Learnt from: mani99brar
PR: kleros/vea#344
File: relayer-cli/src/utils/relay.ts:42-73
Timestamp: 2024-11-27T05:02:48.754Z
Learning: In the `relayBatch` function of `relayer-cli/src/utils/relay.ts`, the current code cannot go into an infinite loop according to the user.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
📚 Learning: 2024-12-16T09:22:57.434Z
Learnt from: mani99brar
PR: kleros/vea#383
File: contracts/test/integration/ArbToGnosis.ts:114-114
Timestamp: 2024-12-16T09:22:57.434Z
Learning: In the local Hardhat deployment for testing, `VeaInboxArbToGnosisMock` is deployed with the identifier name `VeaInboxArbToGnosis`, so it's appropriate to retrieve it using `getContract("VeaInboxArbToGnosis")` and cast it to `VeaInboxArbToGnosisMock` in `ArbToGnosis.ts`.
Applied to files:
contracts/test/integration/ArbToGnosis.ts
🧬 Code Graph Analysis (2)
contracts/test/integration/ArbToEth.ts (1)
contracts/test/merkle/MerkleTree.ts (1)
MerkleTree
(9-248)
contracts/test/integration/ArbToGnosis.ts (1)
contracts/test/merkle/MerkleTree.ts (1)
MerkleTree
(9-248)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Redirect rules - veascan
- GitHub Check: Header rules - veascan
- GitHub Check: Pages changed - veascan
- GitHub Check: test
- GitHub Check: dependency-review
- GitHub Check: Analyze (javascript)
🔇 Additional comments (19)
contracts/src/test/gateways/IReceiverGatewayMock.sol (1)
15-18
: Good addition: calldata usage and array support look correct
digestMessage
anddigestMessageArray
extend the gateway mock cleanly, and usingcalldata
on the array is gas-optimal for external calls.contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (4)
15-15
: Correct: Gateway interface importImporting and using
IReceiverGateway
is aligned with the new gateway-based relay flow.
370-370
: Leaf encoding updated to include_from
— correct
keccak256(abi.encodePacked(_msgId, _to, _from, _message))
matches the new message shape. Fixed-size fields first then variable bytes at the end avoids ambiguity.
418-418
: Gateway-based relay replaces low-level call — OKRelaying via
IReceiverGateway(_to).receiveMessage(_from, _message)
is correct. Reentrancy is mitigated by setting the replay bit before the external call; reverts will undo state. No further state writes after the call — safe pattern.
359-367
: All sendMessage signatures include_from
, and inbox leaf encodings includemsg.sender
We’ve verified that every outbox contract and interface now uses the updated signature withaddress _from
andbytes calldata _message
, and that every inbox implementation’sabi.encodePacked
call includesmsg.sender
.contracts/src/interfaces/inboxes/IVeaInbox.sol (1)
14-15
: Docstring updates are coherent with gateway-authenticated flowDocs now reflect that
_to
receives the message and_data
is the message bytes. Looks good.contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (4)
15-15
: Correct: Gateway interface importImport aligns with switching to gateway-based message relay.
303-311
: Signature change and doc updates look correctAdded
_from
and switched tobytes calldata _message
. Matches the new Merkle leaf composition and relay semantics.
314-314
: Leaf includes_from
— consistent with new message format
keccak256(abi.encodePacked(_msgId, _to, _from, _message))
is correct and consistent with other outboxes.
362-362
: Gateway relay call is correct
IReceiverGateway(_to).receiveMessage(_from, _message)
properly routes through the receiver gateway.contracts/src/test/gateways/SenderGatewayMock.sol (1)
25-29
: LGTM: Encoded selector and new inbox API usage are correct.
abi.encodeWithSelector
path matches the new receiver gateway dispatcher.veaInbox.sendMessage(receiverGateway, data)
aligns with the updated signature.Also applies to: 31-35
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol (1)
73-76
: LGTM: Signature and leaf encoding change are correct and collision-safe.
- Removing the selector parameter and packing
(nonce, to, from, data)
is consistent with the new outbox/receiver flow.- Fixed-width fields (uint64, address, address) followed by bytes ensure unambiguous decoding.
Also applies to: 82-83
contracts/test/integration/ArbToGnosis.ts (1)
251-253
: LGTM: Array messaging path and leaf construction includefrom
.
sendMessageArray
usage is correct.decodeMessage
andMerkleTree.makeLeafNode(nonce, to, from, msgData)
align with the new leaf format.Also applies to: 258-262, 261-264
contracts/src/test/gateways/ReceiverGatewayMock.sol (1)
29-38
: LGTM: Bridge gating + internal self-call dispatcher is sound.
onlyFromVeaBridge
properly checks the outbox caller and the asserted sender gateway.internalCall
ensures only the internal dispatch can hitdigest*
functions.address(this).call(data)
pairs correctly withabi.encodeCall(...digest*)
at the sender side.Also applies to: 41-45, 48-57
contracts/test/integration/ArbToEth.ts (5)
252-265
: LGTM: Tests align with new encoding (from included) and 5-arg relay API.
- Leaves include
(nonce, to, from, msgData)
.- Relay uses
sendMessage(proof, nonce, to, from, msgData)
consistently.- Helper
claimAndVerify
reduces boilerplate.Also applies to: 275-285, 291-297, 323-357, 369-376, 418-427
286-296
: Good negative-path coverage for proof validation and duplicate relay.
- Asserting "Invalid proof." and "Message already relayed" covers the key revert paths.
Also applies to: 351-356
241-247
: Nice: Adds dynamic array relay path coverage.
sendMessageArray
and subsequent proof/relay assertions verify the new array messaging flow end-to-end.Also applies to: 299-307
528-535
: Challenge/resolve flow updates look consistent with the new verification pipeline.
- Using fully-qualified
challenge(...)
signature avoids ambiguity.- Cross-chain dispute resolution via
sendSnapshot
remains intact.Also applies to: 572-574, 589-601, 821-834, 949-962, 1048-1060, 1091-1100, 1102-1114
351-356
: Ignore allowlist negative‐path test suggestionThere is no allowlist functionality in VeaOutboxArbToEth.sol, so adding a test for a non‐allowlisted sender is not applicable. Please disregard this comment.
Likely an incorrect or invalid review comment.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (1)
362-362
: Harden against accidental EOAs as _to (optional)A gateway call to an EOA would “succeed” without executing logic, marking the message as relayed. If you want to prevent that class of mistakes, add a code-size check.
Apply this diff near the call:
// UNTRUSTED. - IReceiverGateway(_to).receiveMessage(_from, _message); + require(_to.code.length > 0, "Target must be a contract"); + IReceiverGateway(_to).receiveMessage(_from, _message);contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (1)
359-367
: Add zero-address guards forsendMessage(_to, _from)
Insert the following checks at the top of
sendMessage
incontracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
to fail fast on malformed inputs:function sendMessage( bytes32[] calldata _proof, uint64 _msgId, address _to, address _from, bytes calldata _message ) external { + require(_to != address(0), "Invalid _to."); + require(_from != address(0), "Invalid _from."); require(_proof.length < 64, "Proof too long.");Verified that the
IVeaOutboxOnL1.sendMessage
interface and this implementation both include_from
, and no callers remain on the old signature.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
(5 hunks)contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
(5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-06-05T12:17:21.782Z
Learnt from: mani99brar
PR: kleros/vea#424
File: validator-cli/src/helpers/claimer.ts:72-76
Timestamp: 2025-06-05T12:17:21.782Z
Learning: In validator-cli/src/helpers/claimer.ts, the outboxStateRoot captured at the beginning of the checkAndClaim function won't change for the epoch being claimed, so there's no race condition concern when reusing it in makeClaim/makeClaimDevnet functions.
Applied to files:
contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
📚 Learning: 2024-12-09T09:40:28.400Z
Learnt from: mani99brar
PR: kleros/vea#370
File: bridger-cli/src/utils/transactionHandler.ts:13-13
Timestamp: 2024-12-09T09:40:28.400Z
Learning: In `bridger-cli/src/utils/transactionHandler.ts`, the `veaOutbox` implementations differ for each chain, but a common interface should be defined for type checks to enhance type safety.
Applied to files:
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Analyze (javascript)
- GitHub Check: dependency-review
- GitHub Check: test
🔇 Additional comments (10)
contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (6)
3-3
: Authors metadata updated — LGTMAttribution update looks fine.
15-15
: Gateway relay import added — aligns with new relay pathImporting IReceiverGateway is consistent with the new gateway-based relay model.
431-431
: Bug fix: assignment restored in escape hatch — LGTMSetting claimHashes[_epoch] = hashClaim(_claim) (instead of comparing) mirrors the claimer path and fixes the state update. Good catch.
303-311
: Confirm allowlist expectations for this outboxPR objectives mention adding allowlist management in outbox implementations. This file does not enforce an allowlist for sendMessage. If intentional (e.g., allowlisting enforced at the receiver gateway layer only), disregard. Otherwise, consider whether this outbox should validate _from or _to against an allowlist.
Would you like me to propose a minimal allowlist pattern consistent with other outboxes in this codebase?
314-314
: Leaf encoding consistency on-chain verified; please confirm off-chain builderAll on-chain inbox contracts use the same tuple ordering and encoding as the outbox:
- contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol:82
abi.encodePacked(oldCount, _to, msg.sender, _data)
- contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol:83
abi.encodePacked(oldCount, _to, msg.sender, _data)
- contracts/src/arbitrumToEth/VeaInboxArbToEth.sol:82
abi.encodePacked(oldCount, _to, msg.sender, _data)
These correspond exactly to the outbox’s
keccak256(abi.encodePacked(_msgId, _to, _from, _message))
. No on-chain changes needed. Ensure your off-chain tree builder uses the identical tuple ordering and encoding.
303-311
: API change verified: sendMessage signature updated across outbox interfaces and implementationsAll
sendMessage
declarations now include the new_from
parameter, and there are no internal call sites in this repo that invoke these outbox methods:• contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol –
sendMessage(bytes32[] calldata _proof, uint64 _msgId, address _to, address _from, …)
• contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol –sendMessage(bytes32[] calldata _proof, uint64 _msgId, address _to, address _from, …)
• contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
• contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol
• contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.solNo further updates to call sites are needed.
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (4)
15-15
: Gateway import aligns with the new relay modelSwitching from low-level target calls to IReceiverGateway is the right move for typed message delivery and reduces footguns.
418-418
: Typed gateway call replaces low-level call: safer and clearerCalling IReceiverGateway(_to).receiveMessage(_from, _message) is an improvement over raw .call. Effects are applied before interaction; reverts will properly roll back the replay bit. LGTM.
487-487
: Fix in challenger escape hatch assignmentAssigning claimHashes[_epoch] = hashClaim(_claim) is the correct behavior here. Good catch.
370-370
: All leaf encodings includefrom
in the correct position
Verified that every inbox and outbox contract uses abi.encodePacked(msgId/count, to, from, message/data) in the exact same ordering. No mismatches detected:• contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (line 370)
• contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (line 314)
• contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol (line 300)
• contracts/src/arbitrumToEth/VeaInboxArbToEth.sol (line 83)
• contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol (line 82)
• contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol (line 83)No action required.
PR-Codex overview
This PR focuses on enhancing the messaging system in the smart contracts by updating function signatures, adding new functionality for message handling, and improving the overall structure and clarity of the code.
Detailed summary
receiveMessage
function toIReceiverGateway
.sendMessage
function in various contracts to include_from
parameter.receiveMessage
todigestMessage
inIReceiverGatewayMock
.digestMessageArray
function for handling arrays.SenderGatewayMock
to support sending arrays of messages.ReceiverGatewayMock
to handle new message formats and internal calls.from
address.Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Tests
Documentation