Skip to content

Chore/updated relayer encoding fix #430

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

Draft
wants to merge 17 commits into
base: dev
Choose a base branch
from

Conversation

mani99brar
Copy link
Contributor

@mani99brar mani99brar commented Aug 13, 2025

PR-Codex overview

This PR focuses on enhancing the messaging functionality between contracts by refining the handling of message data, including sender information, and implementing an allowlist mechanism for message relay authorization.

Detailed summary

  • Updated sendMessage function parameters in several contracts to include from address.
  • Added receiveMessageArray function to IReceiverGatewayMock.
  • Introduced allowlist functionality in IVeaOutboxOnL1 and related contracts.
  • Modified tests to accommodate new message data structure and allowlist checks.
  • Improved encoding methods for message data.
  • Adjusted snapshot saving and verification processes to include sender checks.

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

Summary by CodeRabbit

  • New Features

    • Added per-receiver allowlists for relaying messages, with optional “allow all” mode.
    • Sample gateways support sending and receiving dynamic array payloads.
  • Breaking Changes

    • Inbox message API simplified: sendMessage now takes (to, data) with selector embedded in data.
    • Outbox message relay now requires the sender address; message hashing includes the sender.
  • CLI

    • Relayer updated to fetch and pass the sender address; all relay paths use the new signature.
  • Subgraph

    • Updated message decoding to the new payload layout (separate sender field).

Copy link

netlify bot commented Aug 13, 2025

Deploy Preview for veascan ready!

Name Link
🔨 Latest commit a16ccf9
🔍 Latest deploy log https://app.netlify.com/projects/veascan/deploys/689c4860c031ad0007437c89
😎 Deploy Preview https://deploy-preview-430--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 13, 2025

Walkthrough

Consolidates inbox sendMessage API to (address, bytes) and updates Merkle leaf encoding to include msg.sender. Outboxes gain an allowlist and a new from parameter in sendMessage, with node hash updated accordingly. Test mocks, integration tests, relayer CLI, and subgraph parsing are updated to the new payload shape and flow.

Changes

Cohort / File(s) Summary of Changes
Contracts: Inbox API simplification
contracts/src/arbitrumToEth/VeaInboxArbToEth.sol, contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol, contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol
sendMessage signature reduced to (address _to, bytes calldata _data); removed _fnSelector; leaf data now abi.encodePacked(nonce, _to, msg.sender, _data).
Contracts: Outbox allowlist + from parameter
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol, contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol, contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
Added allowlist mapping and setAllowlist; sendMessage now takes _from; enforced allowlist; nodeHash includes _from; minor guard additions.
Interfaces
contracts/src/interfaces/inboxes/IVeaInbox.sol, contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol, contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol
IVeaInbox sendMessage simplified to (address, bytes); Outbox interfaces add _from to sendMessage and new setAllowlist(address,bool).
Test gateways/mocks
contracts/src/test/gateways/IReceiverGatewayMock.sol, contracts/src/test/gateways/ReceiverGatewayMock.sol, contracts/src/test/gateways/SenderGatewayMock.sol
Receiver iface drops msgSender param; adds array handlers; ReceiverGatewayMock updates modifiers, adds allowlist helpers and array path; SenderGatewayMock switches to abi.encodeWithSelector and adds sendMessageArray.
Utils
contracts/src/utils/veaInboxTouch.sol
Updated call to inbox.sendMessage(address, bytes) reflecting new interface.
Integration tests
contracts/test/integration/ArbToEth.ts, contracts/test/integration/ArbToGnosis.ts
Incorporate from into leaves and outbox calls; add allowlist setup and scenarios; add array-message tests; new helpers for decode/claim/verify; adjust flows to new signatures.
Relayer CLI
relayer-cli/src/utils/proof.ts, relayer-cli/src/utils/relay.ts, relayer-cli/src/utils/relay.test.ts
Message data now includes from; all sendMessage calls updated to 5-arg form; batch paths adjusted; minor logging; tests mock new tuple shape.
Subgraph (inbox)
relayer-subgraph-inbox/src/vea-inbox.ts
Adjusted offsets: extract msgSender earlier; data starts later; aligns with new leaf layout.

Sequence Diagram(s)

sequenceDiagram
  participant SenderGateway
  participant VeaInbox
  participant MerkleTree
  participant Relayer
  participant VeaOutbox
  participant Receiver

  SenderGateway->>VeaInbox: sendMessage(to, abi.encodeWithSelector(selector, args))
  VeaInbox->>MerkleTree: leaf = (nonce, to, msg.sender, data)
  Relayer->>VeaOutbox: sendMessage(proof, nonce, to, from, data)
  VeaOutbox->>VeaOutbox: verify proof & allowlist[to][from] || [to][0x0]
  VeaOutbox->>Receiver: low-level call(data)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Package: Contracts, Package: Bots, Type: Maintenance :construction:

Suggested reviewers

  • jaybuidl
  • alcercu
  • madhurMongia

Poem

A hop and a hash, I pack up the bytes,
With sender in tow through merklized nights.
Gate’s got a list—are friends allowed through?
I twitch both my ears: permit me, will you?
Then off to the outbox I bound with delight—
Relay, relay—what a byte-perfect flight! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/updated-relayer-encoding-fix

🪧 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

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: 2

🔭 Outside diff range comments (2)
contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (1)

441-443: Critical bug: assignment replaced with equality in claim hash update

This line uses == instead of =, so the updated claim hash is never written, breaking the escape hatch flow.

Apply this fix:

-                claimHashes[_epoch] == hashClaim(_claim);
+                claimHashes[_epoch] = hashClaim(_claim);
contracts/src/arbitrumToEth/VeaOutboxArbToEth.sol (1)

498-498: Critical bug: equality used instead of assignment in claim hash update

Same issue as in Arb->Gnosis outbox escape hatch path: uses == instead of =, so state isn’t updated.

Apply this fix:

-                claimHashes[_epoch] == hashClaim(_claim);
+                claimHashes[_epoch] = hashClaim(_claim);
🧹 Nitpick comments (17)
contracts/src/test/gateways/IReceiverGatewayMock.sol (1)

17-18: API naming nit: prefer plural for array variant

Consider renaming receiveMessageArray to receiveMessages for semantic clarity and to match common naming patterns for batch methods.

Apply:

-    /// Receive the message array from the sender gateway.
-    function receiveMessageArray(uint256[] calldata _data) external;
+    /// Receive a batch of messages from the sender gateway.
+    function receiveMessages(uint256[] calldata _data) external;
contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol (2)

18-18: Doc specificity: clarify what “sender” means across chains

To avoid ambiguity, explicitly state that _from is the originating contract address on the other domain (the authenticated sender expected by the receiver).

-    /// @param _from The address of the message sender.
+    /// @param _from The originating contract address on the source chain (authenticated sender expected by the receiver).

34-38: Clarify self-service allowlist semantics in docs

The implementation is intended to be permissionless/self-service per receiver. Make this explicit so integrators understand setAllowlist config applies to msg.sender’s allowlist. Also mention how address(0) interacts with specific entries.

-    /// @dev Sets the allowlist for the sender gateway.
-    /// Note: Address(0) is used to allow all addresses.
+    /// @dev Sets the allowlist for the caller (msg.sender).
+    /// Self-service: each receiver manages its own allowlist by calling this function.
+    /// Note: Address(0) enables or disables a global allow for all senders for the caller.
-    /// @param _from The address to allow or disallow
+    /// @param _from The sender address to allow or disallow (use address(0) for global toggle).

I can replicate similar doc clarifications across the L1 interface for consistency—say the word.

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

15-17: API shift to (address, bytes): docs should reflect selector and sender argument placement

Good change to calldata. Tighten the comment to guide callers to embed the selector and, where required by receivers, include the authenticated “from” as the first ABI-encoded argument.

-    /// @param _data The message calldata, abi.encodeWithSelector(...)
+    /// @param _data The full calldata payload, abi.encodeWithSelector(...)
+    ///             If the receiver expects an authenticated sender, encode it as the first argument.
-    function sendMessage(address _to, bytes calldata _data) external returns (uint64 msgId);
+    function sendMessage(address _to, bytes calldata _data) external returns (uint64 msgId);

The signature change to calldata is an improvement in gas and aligns with the broader refactor.

contracts/src/utils/veaInboxTouch.sol (1)

23-23: Use address(0) constant for clarity

Prefer the typed address(0) over a hex literal.

-        veaInbox.sendMessage(0x0000000000000000000000000000000000000000, abi.encode(random));
+        veaInbox.sendMessage(address(0), abi.encode(random));
contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol (1)

37-41: Clarify self-service allowlist semantics (mirror L2 docs)

Document that the allowlist is managed by the receiver (msg.sender) and how the global toggle behaves.

-    /// @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
+    /// @dev Sets the allowlist for the caller (msg.sender).
+    /// Self-service: each receiver manages its own allowlist by calling this function.
+    /// Note: Address(0) enables or disables a global allow for all senders for the caller.
+    /// @param _from The sender address to allow or disallow (use address(0) for global toggle).
contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol (1)

74-76: Public API consolidation looks good; update event docs to reflect new leaf layout

The signature change to (address _to, bytes calldata _data) and the clarified param doc are aligned with the PR objective.

However, the MessageSent event doc above still claims abi.encodePacked(msgId, to, message), which is now outdated because the leaf includes msg.sender as a separate field. Please update the event doc to avoid tooling/subgraph confusion.

Proposed doc tweak (outside the selected range):

/// @dev Relayers watch for these events to construct merkle proofs to execute transactions on Ethereum.
/// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, from, message), outbox relays to.call(message).
event MessageSent(bytes _nodeData);
contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (1)

299-305: Permissionless allowlist setter is correct; consider clarifying wildcard behavior in NatSpec

Implementation aligns with the intended self-service pattern. As a minor doc improvement, mention that _from = address(0) allows all senders for msg.sender.

Suggested doc tweak:

-/// @dev Sets the allowlist for the sender gateway.
+/// @dev Sets the allowlist for the receiver (msg.sender).
+/// Note: Setting `_from` to address(0) allows all senders for this receiver.
contracts/src/arbitrumToGnosis/VeaInboxArbToGnosis.sol (1)

73-76: API consolidation to (address, bytes) is correct; update event docs for leaf shape

The signature change and calldata usage improve gas and align with embedding the selector in _data.

The MessageSent event doc still says abi.encodePacked(msgId, to, message) but the node now includes msg.sender. Please update to abi.encodePacked(msgId, to, from, message) to keep relayers/subgraphs consistent.

Proposed doc tweak (outside the selected range):

/// @dev Relayers watch for these events to construct merkle proofs to execute transactions on Gnosis.
/// @param _nodeData The data to create leaves in the merkle tree. abi.encodePacked(msgId, to, from, message), outbox relays to.call(message).
event MessageSent(bytes _nodeData);
contracts/test/integration/ArbToGnosis.ts (4)

250-311: Test flow updated to new payload shape — good coverage; consider using decoded nonce consistently

The test correctly:

  • Uses decodeMessage to extract (nonce, to, from, msgData).
  • Constructs the new leaf as MerkleTree.makeLeafNode(nonce, to, from, msgData).
  • Calls the outbox with 5-arg sendMessage.

Minor consistency/nitpick: In later tests you sometimes pass a literal 0 for _msgId instead of the decoded nonce. Prefer passing nonce everywhere to reduce brittleness.

Example tweak:

-const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, 0, receiverGateway.target, from, msgData);
+const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, nonce, receiverGateway.target, from, msgData);

761-771: Use decoded nonce instead of literal 0 for relay consistency

You decode nonce earlier; use it directly rather than hardcoding 0. Avoids coupling to current message ordering.

Apply similarly to all occurrences:

-const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, 0, receiverGateway.target, from, msgData);
+const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, nonce, receiverGateway.target, from, msgData);

939-948: Same nit: prefer decoded nonce over 0

For consistency and resilience, pass nonce instead of 0 as _msgId.

-const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, 0, receiverGateway.target, from, msgData);
+const relayTx = await veaOutbox.connect(receiver).sendMessage(proof, nonce, receiverGateway.target, from, msgData);

1087-1093: Add basic validation to decodeMessage to catch malformed inputs

Current slicing assumes msg is long enough. Consider asserting minimum length and returning typed fields.

Example:

-async function decodeMessage(msg: any) {
+async function decodeMessage(msg: string): Promise<{ nonce: string; to: string; from: string; msgData: string }> {
+  if (typeof msg !== "string" || !msg.startsWith("0x") || msg.length < 2 + 16 + 40 + 40) {
+    throw new Error("Invalid nodeData encoding");
+  }
   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/gnosisToArbitrum/VeaOutboxGnosisToArb.sol (1)

307-308: Consider adding an event for better observability when messages are rejected.

While the allowlist check logic is correct, adding an event when a message is rejected due to allowlist restrictions would improve monitoring and debugging capabilities.

Consider emitting an event when the allowlist check fails:

+    /// @dev This event indicates that a message was rejected due to allowlist restrictions.
+    /// @param _msgId The msgId of the rejected message.
+    /// @param _from The sender address that was not allowed.
+    /// @param _to The receiver address that rejected the message.
+    event MessageRejected(uint64 indexed _msgId, address indexed _from, address indexed _to);

     function sendMessage(
         bytes32[] memory _proof,
         uint64 _msgId,
         address _to,
         address _from,
         bytes memory _message
     ) external {
         require(_proof.length < 64, "Proof too long.");
         bool isAllowed = allowlist[_to][_from] || allowlist[_to][address(0)];
-        require(isAllowed, "Message sender not allowed to call receiver.");
+        if (!isAllowed) {
+            emit MessageRejected(_msgId, _from, _to);
+            revert("Message sender not allowed to call receiver.");
+        }
contracts/src/test/gateways/ReceiverGatewayMock.sol (1)

47-50: Consider adding validation for the data array.

The receiveMessageArray function doesn't validate the input array before storing it. Consider adding checks for array size limits to prevent potential gas issues with unbounded arrays.

Consider adding array size validation:

     function receiveMessageArray(uint256[] calldata _data) external onlyFromVeaBridge {
+        require(_data.length > 0 && _data.length <= 100, "Invalid array size");
         _receiveMessage();
         dataArray = _data;
     }
relayer-cli/src/utils/relay.ts (1)

145-145: Remove or convert console.log to proper logging.

Debug console.log statement should be removed or converted to use proper logging mechanism for production code.

-      console.log(targets, datas);
+      // Consider using a proper logger instead of console.log
+      // logger.debug("Batch relay targets and data", { targets, datas });
contracts/test/integration/ArbToEth.ts (1)

1241-1302: Consider adding return type annotation for better type safety.

The claimAndVerify helper function would benefit from explicit return type annotation.

 async function claimAndVerify({
   veaInbox,
   veaOutbox,
   bridger,
   epoch,
   batchMerkleRoot,
   ethers,
   network,
   mine,
 }: {
   veaInbox: any;
   veaOutbox: any;
   bridger: any;
   epoch: number;
   batchMerkleRoot: string;
   ethers: any;
   network: any;
   mine: (blocks: number) => Promise<void>;
-}) {
+}): Promise<void> {
📜 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 a16ccf9.

📒 Files selected for processing (19)
  • 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 (29 hunks)
  • contracts/test/integration/ArbToGnosis.ts (7 hunks)
  • relayer-cli/src/utils/proof.ts (2 hunks)
  • relayer-cli/src/utils/relay.test.ts (1 hunks)
  • relayer-cli/src/utils/relay.ts (4 hunks)
  • relayer-subgraph-inbox/src/vea-inbox.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (13)
📚 Learning: 2025-08-11T09:26:45.968Z
Learnt from: mani99brar
PR: kleros/vea#429
File: contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol:0-0
Timestamp: 2025-08-11T09:26:45.968Z
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/src/interfaces/outboxes/IVeaOutboxOnL2.sol
  • contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol
  • contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol
  • contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol
  • contracts/src/test/gateways/ReceiverGatewayMock.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/interfaces/outboxes/IVeaOutboxOnL1.sol
  • contracts/test/integration/ArbToGnosis.ts
  • relayer-cli/src/utils/relay.ts
  • 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/ArbToGnosis.ts
  • 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: 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-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/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-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: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-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
🧬 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). (6)
  • GitHub Check: Redirect rules - veascan
  • GitHub Check: Analyze (javascript)
  • GitHub Check: dependency-review
  • GitHub Check: test
  • GitHub Check: Header rules - veascan
  • GitHub Check: Pages changed - veascan
🔇 Additional comments (41)
contracts/src/test/gateways/IReceiverGatewayMock.sol (1)

15-15: No signature mismatch—ignore this comment
IReceiverGateway doesn’t declare any receiveMessage methods, so the mock’s single-argument receiveMessage(uint256) is self-contained and correctly implemented by ReceiverGatewayMock. There’s no dropped parameter on a parent interface.

Likely an incorrect or invalid review comment.

contracts/src/interfaces/outboxes/IVeaOutboxOnL2.sol (1)

20-26: All sendMessage call sites and implementations now use the five-argument signature
No references to the old four-argument sendMessage(...) remain outside of the interface. All OutboxOnL2 implementations and their callers have been updated to include the new _from parameter.

contracts/src/interfaces/outboxes/IVeaOutboxOnL1.sol (1)

20-28: Ignore outdated five-argument sendMessage concern

All L1 outbox contracts and the IVeaOutboxOnL1 interface now use the 4-argument signature

sendMessage(bytes32[] calldata _proof, uint64 _msgId, address _to, bytes calldata _message)

and proofs are encoded/hashed as (msgId, to, message). There is no _from parameter to propagate through leaf/node encoding or auth checks—those are handled natively via msg.sender and the bridge. You can safely disregard the previous 5-arg verification request.

Likely an incorrect or invalid review comment.

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

3-3: LGTM! Author added to attribution.

The addition of @mani99brar to the authors list properly acknowledges their contribution to this contract update.


73-73: Documentation accurately reflects the new encoding approach.

The parameter documentation correctly specifies that _data should be encoded with abi.encodeWithSelector, which aligns with the removal of the separate _fnSelector parameter.


75-75: Function signature simplified appropriately.

The change from bytes memory to bytes calldata is a good optimization that avoids unnecessary memory allocation for the input data.


82-82: Msg.sender inclusion is consistent and outboxes require no on-chain decode changes

All three inbox contracts now pack msg.sender into their Merkle leaves:

  • src/arbitrumToEth/VeaInboxArbToEth.sol:82
  • src/arbitrumToGnosis/VeaInboxArbToGnosis.sol:82
  • src/gnosisToArbitrum/VeaInboxGnosisToArb.sol:83

Outboxes verify proofs over abi.encodePacked(msgId, to, message), where message itself already contains the selector and padded msg.sender. There is no on-chain abi.decode of a 4-tuple; relayers off-chain extract and pass the full message payload (including sender) into sendMessage. No further code changes are needed.

relayer-cli/src/utils/proof.ts (3)

8-10: LGTM! Message structure properly extended.

The addition of msgSender field to the MessageSentData interface correctly reflects the new message structure that includes the sender information.


40-42: GraphQL query correctly fetches sender information.

The query properly retrieves the msgSender.id field, which is essential for the new message relay flow.


48-48: All consumers properly handle the updated three‐element return format

The helper getMessageDataToRelay now returns [to, msgSender, data], and every usage in relay.ts destructures it as [to, from, data] before calling sendMessage, matching the updated contract signature.

relayer-cli/src/utils/relay.test.ts (1)

64-64: Test mock correctly updated for new data structure.

The mock now returns the three-element array ["to", "from", "data"] which properly reflects the updated message structure used throughout the codebase.

relayer-subgraph-inbox/src/vea-inbox.ts (2)

36-38: Data extraction correctly adjusted for new offset.

The data now starts at byte 48 (8 bytes nonce + 20 bytes to + 20 bytes msgSender), which correctly aligns with the new message structure.


34-34: msgSender extraction offset is correct

The 20-byte slice starting at offset 28 (8 byte nonce + 20 byte to address) aligns with the contract’s abi.encodePacked(uint64, address, address, bytes) layout—no change needed.

contracts/src/test/gateways/SenderGatewayMock.sol (2)

25-29: Message encoding correctly updated to use single bytes parameter.

The change to use abi.encodeWithSelector properly embeds the function selector within the data payload, aligning with the new IVeaInbox.sendMessage(address, bytes) signature.


31-35: Array message functionality validated

– IReceiverGatewayMock.sol defines receiveMessageArray(uint256[] calldata) at line 18
– ReceiverGatewayMock.sol implements receiveMessageArray(uint256[] calldata) at line 47
sendMessageArray in SenderGatewayMock correctly encodes and dispatches the array payload

All required interface and implementation pieces are present.

contracts/src/gnosisToArbitrum/VeaInboxGnosisToArb.sol (1)

83-83: Leaf encoding now includes msg.sender — consistent with Outbox verification

Encoding nodeData as abi.encodePacked(oldCount, _to, msg.sender, _data) matches the updated outbox verification: keccak256(abi.encodePacked(_msgId, _to, _from, _message)) with double-hash. This keeps proofs consistent. LGTM.

contracts/src/arbitrumToGnosis/VeaOutboxArbToGnosis.sol (3)

45-45: Allowlist mapping shape and semantics are appropriate

Per the design, allowlist is per-receiver and supports address(0) as a wildcard. This matches the “self-service” allowlist approach captured in our learnings; no admin or events required.


313-324: New 5-arg sendMessage gating and node hash are correct

  • Proof length bound (< 64) matches 64-level tree max for uint64 messages.
  • Allowlist check (per-sender or global) prevents unsolicited relays.
  • Node hash now includes _from and matches the updated inbox node layout.

367-373: Replay protection placement is safe against reentrancy on relay path

Bitmap is updated before the untrusted call. This prevents reentrancy replay of the same message within the same tx. Good defensive ordering.

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

3-3: Author metadata update acknowledged

No code impact; consistent with PR authorship changes.


82-83: Leaf encoding includes msg.sender — matches updated Outbox verification

abi.encodePacked(oldCount, _to, msg.sender, _data) is consistent with outbox expectations (and double-hash process). Good.

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

45-45: Per-receiver allowlist with address(0) wildcard is correct

Matches the intended self-service allowlist design. Public mapping exposure is helpful for off-chain tooling.


355-362: Allowlist setter matches intended security model

Clear doc notes address(0) semantics. Implementation is minimal and correct.


370-381: 5-arg relay method with allowlist check and updated leaf hash is correct

  • Proof length guard (< 64) is appropriate.
  • Gating: allowlist[_to][_from] || allowlist[_to][address(0)] matches design.
  • Node hash includes _from and aligns with inbox leaf encoding.
contracts/test/integration/ArbToGnosis.ts (2)

316-369: Negative test for allowlist rejection matches on-chain revert reason

Asserts "Message sender not allowed to call receiver." which matches the contract. Good.


371-433: Global allowlist path is exercised correctly

allowlistAllSender(true) scenario verifies the address(0) wildcard behavior and the relay succeeds. Good.

contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol (3)

44-44: LGTM! Allowlist mapping design is appropriate.

The allowlist mapping structure mapping(address => mapping(address => bool)) follows the correct pattern where the receiver controls their own allowlist of senders. This aligns with the self-service design pattern mentioned in the retrieved learnings.


285-291: LGTM! Allowlist setter follows self-service design pattern.

The setAllowlist function correctly implements the permissionless, self-service pattern where receivers (msg.sender) control which sender addresses can relay messages to them. The use of address(0) as a wildcard for "allow all" is a good design choice.


310-310: LGTM! Merkle leaf encoding correctly includes sender address.

The updated node hash calculation correctly includes the _from parameter in the expected position, maintaining compatibility with the inbox's message encoding format.

contracts/src/test/gateways/ReceiverGatewayMock.sol (2)

34-36: LGTM! Allowlist management functions correctly implemented.

The allowlistSender function properly calls the outbox's setAllowlist with the senderGateway address, enabling the receiver to control who can send messages to it.


38-40: LGTM! Global allowlist management correctly implemented.

The allowlistAllSender function properly uses address(0) as the wildcard to allow or disallow all senders, following the established pattern.

relayer-cli/src/utils/relay.ts (3)

62-63: LGTM! Message data destructuring correctly updated.

The destructuring now correctly extracts three elements [to, from, data] from the message data, aligning with the new message format that includes the sender address.


130-133: LGTM! Batch relay correctly handles the new message format.

The batch relay function properly destructures the message data and uses the 5-argument sendMessage signature in both the static call and the encoded function data.


197-199: LGTM! relayAllFrom correctly handles the new message format.

The function properly destructures the message data and encodes the function data with all five parameters including the from address.

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

56-56: LGTM! Test setup correctly enables allowlist.

The test correctly sets up the allowlist by calling allowlistSender(true) in the beforeEach hook, ensuring the sender gateway is allowed to send messages to the receiver gateway.


253-253: LGTM! Message decoding and Merkle tree construction updated correctly.

The test correctly:

  1. Uses the new decodeMessage utility to extract all four fields (nonce, to, from, msgData)
  2. Constructs Merkle tree leaves with all four parameters using MerkleTree.makeLeafNode(nonce, to, from, msgData)

This aligns with the updated message format that includes the sender address.

Also applies to: 264-265


276-285: LGTM! Good extraction of common test logic.

The extraction of claim and verification logic into the claimAndVerify helper function improves code reusability and reduces duplication across test cases.


300-353: LGTM! Comprehensive test for allowlist rejection.

The test properly verifies that messages are rejected when the sender is not in the allowlist, with the expected error message "Message sender not allowed to call receiver."


355-413: LGTM! Dynamic array test correctly implemented.

The test properly verifies that messages with dynamic arrays can be sent and relayed through the bridge, using the new sendMessageArray function and correctly handling the message format.


415-470: LGTM! Global allowlist test validates wildcard functionality.

The test correctly verifies that setting allowlistAllSender(true) allows any sender to relay messages, even when the specific sender is not explicitly allowed.


1304-1310: LGTM! Clean utility function for message decoding.

The decodeMessage utility function correctly extracts all four components (nonce, to, from, msgData) from the encoded message data, following the expected format.

Comment on lines +297 to +298
/// @param _from The address of the message sender
/// @param _message The message in the vea inbox as abi.encodeWithSelector(fnSelector, param1, param2, ...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Parameter documentation is incomplete.

The NatSpec comment for the _from parameter doesn't match the actual parameter name or purpose correctly.

Apply this diff to fix the documentation:

-    /// @param _from The address of the message sender
+    /// @param _from The address of the message sender on the source chain.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// @param _from The address of the message sender
/// @param _message The message in the vea inbox as abi.encodeWithSelector(fnSelector, param1, param2, ...)
/// @param _from The address of the message sender on the source chain.
/// @param _message The message in the vea inbox as abi.encodeWithSelector(fnSelector, param1, param2, ...)
🤖 Prompt for AI Agents
In contracts/src/gnosisToArbitrum/VeaOutboxGnosisToArb.sol around lines 297 to
298, the NatSpec @param for `_from` is incorrect or misleading; update the
comment to use the correct parameter name and describe its actual purpose (e.g.,
the original sender/address that posted the message into the Vea inbox on the
source chain) and ensure the `_message` param line remains accurate (message
ABI-encoded with selector and parameters).

/// @return msgId The index of the message in the inbox, as a message Id, needed to relay the message.
function sendMessage(address _to, bytes4 _fnSelection, bytes memory _data) external returns (uint64 msgId);
function sendMessage(address _to, bytes calldata _data) external returns (uint64 msgId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Locate and update all callers to the new 2-arg signature

Make sure internal tools, relayers, and tests no longer pass a separate selector/arg.


🏁 Script executed:

#!/bin/bash
# Find old-style 3-arg calls
rg -n -A1 -B2 $'sendMessage\\s*\\(\\s*[^,]+,\\s*[^,]+,\\s*[^)]*\\)' -g '!**/interfaces/**'

# List all sendMessage calls for manual review
rg -n -A1 -B2 $'sendMessage\\s*\\('

Length of output: 312375


Update all sendMessage invocations to drop the removed selector/from argument

The inbox sendMessage signature has been simplified to two parameters (address _to, bytes calldata _data), and the outbox sendMessage no longer takes a separate sender argument. Please remove the extra argument from every call and merge the former from (or selector) into the calldata.

Affected call sites:
• relay-cli/src/utils/relay.ts (around lines 61–64):

  • Change
    veaOutbox.sendMessage(proof, nonce, to, from, data)
    to
    veaOutbox.sendMessage(proof, nonce, to, dataWithSender)
    • contracts/test/integration/ArbToGnosis.ts (lines 304, 308, 366, 430, 769, 946):
  • Replace each
    …sendMessage(proof, nonce, to, from, msgData)
    with
    …sendMessage(proof, nonce, to, msgDataWithSender)
    • contracts/test/integration/ArbToEth.ts (lines 287, 292, 295, 348, 402, 407, 410, 463, 468, 541, 625, 847, 975):
  • Same 5-arg → 4-arg update
    • Search for any other .sendMessage( invocations with three or more comma-separated args (outside /interfaces) and refactor accordingly.

Ensure the passed bytes payload includes both selector and original sender where required.

🤖 Prompt for AI Agents
In contracts/src/interfaces/inboxes/IVeaInbox.sol around line 17, the
sendMessage signature was simplified to (address _to, bytes calldata _data);
update all call sites to remove the extra sender/selector argument and instead
embed the former from/selector into the bytes calldata payload. Specifically, in
relay-cli/src/utils/relay.ts (around lines 61–64) change
veaOutbox.sendMessage(proof, nonce, to, from, data) to
veaOutbox.sendMessage(proof, nonce, to, dataWithSender) where dataWithSender is
data prefixed or merged with the sender/selector; in
contracts/test/integration/ArbToGnosis.ts (lines ~304, 308, 366, 430, 769, 946)
and contracts/test/integration/ArbToEth.ts (lines ~287, 292, 295, 348, 402, 407,
410, 463, 468, 541, 625, 847, 975) replace each 5-arg call with the 4-arg
variant and construct msgDataWithSender by concatenating the selector/sender
into the bytes payload; also grep the repo for any other .sendMessage( calls
with 3+ comma-separated args (excluding /interfaces) and refactor them similarly
so the bytes payload contains selector and original sender where 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