Skip to content

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

Open
wants to merge 18 commits into
base: dev
Choose a base branch
from
Open

Fix/message encoding #429

wants to merge 18 commits into from

Conversation

mani99brar
Copy link
Contributor

@mani99brar mani99brar commented Aug 11, 2025

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

  • Added receiveMessage function to IReceiverGateway.
  • Modified sendMessage function in various contracts to include _from parameter.
  • Renamed receiveMessage to digestMessage in IReceiverGatewayMock.
  • Introduced digestMessageArray function for handling arrays.
  • Updated SenderGatewayMock to support sending arrays of messages.
  • Adjusted ReceiverGatewayMock to handle new message formats and internal calls.
  • Improved message decoding in integration tests to include from address.
  • Enhanced test cases to validate new message handling features.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Outboxes now forward the original sender to receiver gateways; gateways accept sender+payload and support array-based messages.
  • Refactor

    • Inbox API simplified to sendMessage(to, data) with calldata-only payloads.
    • Message/Merkle encoding updated to include sender provenance and simplified leaf layout.
  • Bug Fixes

    • Fixed claim handling in escape-hatch flow and tightened relay call paths through gateways.
  • Tests

    • Integration tests updated for array messages, new encoding, sender propagation, and end-to-end relay/verification flows.
  • Documentation

    • NatSpec and comments updated to reflect API and encoding changes.

Copy link

netlify bot commented Aug 11, 2025

Deploy Preview for veascan ready!

Name Link
🔨 Latest commit 806eac1
🔍 Latest deploy log https://app.netlify.com/projects/veascan/deploys/68a554b4045c970008b860f2
😎 Deploy Preview https://deploy-preview-429--veascan.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor

coderabbitai bot commented Aug 11, 2025

Walkthrough

Inbox APIs now accept full calldata (no selector) and include msg.sender in leaf encoding. Outboxes add an explicit _from parameter and relay via an IReceiverGateway.receiveMessage(from, message). Interfaces, tests, and gateway mocks were updated to the new message shape and relay path; Merkle leaf/hash inputs were adjusted accordingly.

Changes

Cohort / File(s) Summary
Inboxes: signature & leaf encoding
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol, contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol, contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol
Removed bytes4 selector from sendMessage; signature → sendMessage(address _to, bytes calldata _data); leaf encoding changed to abi.encodePacked(oldCount, _to, msg.sender, _data) and keccak inputs updated. Header docs updated.
Outboxes: gateway relay & _from parameter
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol, contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol, contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
sendMessage signature extended with address _from; Merkle leaf/hash now includes _from; replaced direct low-level (to).call(message) with IReceiverGateway(to).receiveMessage(_from, message); imported IReceiverGateway. Proof/replay logic preserved; small bug fixes in claimHashes assignments.
Interfaces: inbox/outbox & gateway API
contracts/src/interfaces/inboxes/IVeaInbox.sol, contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol, contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol, contracts/src/interfaces/gateways/IReceiverGateway.sol
IVeaInbox: drop selector param, _datacalldata. IVeaOutboxOnL1/OnL2: add _from parameter to sendMessage. IReceiverGateway: added receiveMessage(address msgSender, bytes calldata msgData). NatSpec updated.
Test gateways & mocks
contracts/src/test/gateways/IReceiverGatewayMock.sol, contracts/src/test/gateways/ReceiverGatewayMock.sol, contracts/src/test/gateways/SenderGatewayMock.sol
Receiver mock: receiveMessage now (address msgSender, bytes calldata data), delegates to internal digestMessage/digestMessageArray; added dataArray, onlyFromVeaBridge modifier, internal-call gating. Sender mock: use abi.encodeWithSelector with digestMessage/digestMessageArray selectors, added sendMessageArray. Interface mock signatures adjusted.
Utils
contracts/src/utils/veaInboxTouch.sol
Updated veaInbox.sendMessage call site to new two-argument form (address, bytes).
Integration tests & helpers
contracts/test/integration/ArbToEth.ts, contracts/test/integration/ArbToGnosis.ts
Tests updated to build/verify leaves including from; added decodeMessage helper; added array-message test paths and sendMessageArray usage; updated relay calls to sendMessage(..., to, from, msgData); centralized claim/verify helpers and timing/proof adjustments.
New/modified interface in tests
contracts/src/interfaces/gateways/IReceiverGateway.sol, contracts/src/test/gateways/IReceiverGatewayMock.sol
Added receiveMessage(address, bytes calldata) to gateway interface; test mock API adjusted to match new dispatch pattern.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Type: Feature🗿, Package: Contracts

Suggested reviewers

  • jaybuidl
  • alcercu

Poem

"I nibble bytes and hop through trees,
Selector folded into data with ease.
A tiny gateway opens wide,
From hops along the sender's stride.
Thump—relay sent, the proofs abide. 🐇"

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
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/message-encoding

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 update

In 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 consistency

Consider 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) spelling

Use 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 readability

abi.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 path

Consistent 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 example

To 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 pattern

Comment 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 calldata

If 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 observability

Recommend 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 API

Clarify 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

📥 Commits

Reviewing files that changed from the base of the PR and between 24b8a82 and eb9f428.

📒 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 validated

IReceiverGateway 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 update

Looks fine.


82-82: Outbox leaf hashing and allowlist enforcement align with inbox encoding

The 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/auth

abi.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 flow

Adding _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 correct

Including 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 signer

Without .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: include from 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 capitalization

Per 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 NatSpec

Tighten 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 copies

Small 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 name

The 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 slicing

Keeps 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 typed

Minor 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 name

Same 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 accordingly

Encoding 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 typed

Keeps 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

📥 Commits

Reviewing files that changed from the base of the PR and between eb9f428 and 717e89e.

📒 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 good

No issues. Matches project conventions.


75-75: Signature/data location change is correct and gas-friendly

bytes calldata is appropriate; interface alignment is good.

contracts/test/integration/ArbToEth.ts (1)

56-56: Enable per-sender allowlist in setup

Good default for tests that need allowlist enforcement.

contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol (2)

3-3: Author/header update looks good

No issues.


75-75: Signature/data location change is correct

bytes calldata is appropriate; interface alignment is good.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between 717e89e and 7c7b750.

📒 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.

coderabbitai[bot]
coderabbitai bot previously approved these changes Aug 11, 2025
@mani99brar mani99brar marked this pull request as ready for review August 11, 2025 11:05
@mani99brar mani99brar requested a review from jaybuidl as a code owner August 11, 2025 11:05
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 in withdrawChallengerEscapeHatch
The line below uses == instead of =, so claimHashes[_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 update

Same 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 requested

Switching _data to bytes 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 hardcoded nonce=0 in sendMessage calls across integration tests

We’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 consistency

Outboxes 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 duplication

The 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 and abi.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 unnecessary await 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 to contracts/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 type veaOutbox to the interface and compare against address(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.

📥 Commits

Reviewing files that changed from the base of the PR and between 7c7b750 and 970b424.

📒 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 and digestMessageArray extend the gateway mock cleanly, and using calldata on the array is gas-optimal for external calls.

contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (4)

15-15: Correct: Gateway interface import

Importing 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 — OK

Relaying 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 include msg.sender
We’ve verified that every outbox contract and interface now uses the updated signature with address _from and bytes calldata _message, and that every inbox implementation’s abi.encodePacked call includes msg.sender.

contracts/src/interfaces/inboxes/IVeaInbox.sol (1)

14-15: Docstring updates are coherent with gateway-authenticated flow

Docs 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 import

Import aligns with switching to gateway-based message relay.


303-311: Signature change and doc updates look correct

Added _from and switched to bytes 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 include from.

  • sendMessageArray usage is correct.
  • decodeMessage and MerkleTree.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 hit digest* functions.
  • address(this).call(data) pairs correctly with abi.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 suggestion

There 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.

coderabbitai[bot]
coderabbitai bot previously approved these changes Aug 20, 2025
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 for sendMessage(_to, _from)

Insert the following checks at the top of sendMessage in contracts/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.

📥 Commits

Reviewing files that changed from the base of the PR and between 970b424 and 806eac1.

📒 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 — LGTM

Attribution update looks fine.


15-15: Gateway relay import added — aligns with new relay path

Importing IReceiverGateway is consistent with the new gateway-based relay model.


431-431: Bug fix: assignment restored in escape hatch — LGTM

Setting 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 outbox

PR 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 builder

All 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 implementations

All 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.sol

No further updates to call sites are needed.

contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (4)

15-15: Gateway import aligns with the new relay model

Switching 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 clearer

Calling 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 assignment

Assigning claimHashes[_epoch] = hashClaim(_claim) is the correct behavior here. Good catch.


370-370: All leaf encodings include from 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant