Skip to content

feat: Cross-Chain E2E CI — Stellar ↔ EVM#109

Merged
JoE11-y merged 2 commits intomainfrom
stellar-integrations
Apr 12, 2026
Merged

feat: Cross-Chain E2E CI — Stellar ↔ EVM#109
JoE11-y merged 2 commits intomainfrom
stellar-integrations

Conversation

@JoE11-y
Copy link
Copy Markdown
Contributor

@JoE11-y JoE11-y commented Apr 12, 2026

Cross-Chain E2E CI — Stellar ↔ EVM

Summary

Wires up an end-to-end integration test that deploys ProofBridge on a local
Stellar network (ad chain) and an Anvil EVM node (order chain), then drives the
full bridge flow with four distinct role-separated actors. Runs on every PR
that touches contracts/, proof_circuits/, scripts/, or the workflow
itself.

Actors

Four actors, each provisioned by the shell orchestrator and passed to the TS
runner via env vars (no inline key generation):

Role Chain Identity Responsibility
Stellar admin Stellar admin (ed25519) Configures AdManager; signs manager pre-auth for create_ad / lock_for_order / unlock.
EVM admin EVM Anvil 0 Configures OrderPortal; signs manager pre-auth for createOrder / unlock.
Ad creator Stellar primary + EVM recipient alice (Stellar key) + Anvil 2 address (recv-only) Creates the ad, locks XLM in, receives test tokens on EVM at unlock.
Order creator ("bridger") EVM primary + Stellar recipient Anvil 1 key + bridger (Stellar key) Creates the order in test tokens, receives XLM on Stellar at unlock.

All role identities are configurable via env vars (STELLAR_ADMIN_ACCOUNT,
EVM_ADMIN_PRIVATE_KEY, etc.), with Anvil prefunded keys as defaults.

Flow

  1. Deploy Stellar contracts: Verifier (with VK), MerkleManager, native XLM
    SAC, AdManager. Wire MerkleManager to allow AdManager as manager.
  2. Deploy EVM contracts: Verifier, MerkleManager, wNativeToken, test
    ERC20, OrderPortal. Grant MANAGER_ROLE to OrderPortal.
  3. Cross-chain linking (set_chain / set_token_route on both sides).
  4. create_ad on Stellar — ad creator is tx source; admin signs manager
    pre-auth. Ad creator locks AMOUNT XLM into the ad.
  5. createOrder on EVM — order creator is msg.sender (own wallet + nonce
    tracker); admin signs pre-auth. Order creator pays AMOUNT test tokens.
  6. lock_for_order on Stellar — ad creator is tx source so
    ad.maker.require_auth() is auto-signed.
  7. Generate ZK proofs (bridger + ad-creator paths).
  8. Stellar unlock — order creator is tx source so
    order_recipient.require_auth() is auto-signed. Releases AMOUNT XLM to
    the order creator's Stellar address.
  9. EVM unlock — admin submits; releases AMOUNT test tokens to the ad
    creator's EVM recipient.

Assertions

  • EVM order status transitions Open (1)Filled (2).
  • Ad-creator nullifier consumed on EVM.
  • EVM balances: order creator ends at 9*AMOUNT (minted 10×, spent 1×),
    ad-creator EVM recipient ends at exactly AMOUNT.
  • Stellar balances (pre/post snapshots of both accounts on the XLM SAC):
    ad creator net -AMOUNT - fees, order creator net +AMOUNT - fees.
    Fee budget is 1 XLM (FEE_SLOP = 10_000_000 stroops), generous ceiling
    for localnet.

Running locally

bash scripts/run_cross_chain_e2e.sh

Requires: docker, stellar-cli, foundry (anvil, forge), pnpm,
node 18+, Rust + wasm32v1-none target.

Summary by CodeRabbit

  • New Features

    • Enabled automated cross-chain E2E workflow; added test token and nonce tracking; added helpers for key/account management and SAC deployment; runner now uses multi-actor Stellar/EVM roles and explicit sources.
  • Bug Fixes

    • Strengthened on-chain authorization checks so actions require the proper actor signatures.
  • Chores

    • Overhauled E2E scripts and CI setup, improved caching, Node/Rust toolchain setup, and local test node startup/port handling.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 12, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR enables and wires a cross-chain E2E workflow: it activates the GitHub Actions job, adds a test token, changes Soroban contracts to require explicit on-chain actor auth, introduces EVM nonce tracking, and refactors the TypeScript/Stellar scripts to a multi-actor flow for tests.

Changes

Cohort / File(s) Summary
GitHub Actions Workflow
\.github/workflows/cross-chain-e2e.yml
Enabled workflow triggers, environment, and a cross-chain-e2e job that sets up Rust/Foundry/Node/Stellar CLI, caches Cargo/pnpm, and runs scripts/run_cross_chain_e2e.sh.
Stellar Contracts — Authorization
contracts/stellar/contracts/ad-manager/src/lib.rs, contracts/stellar/contracts/order-portal/src/lib.rs
Changed authorization model to require explicit on-chain actor auth: create_ad now accepts creator and calls creator.require_auth(); fund_ad/withdraw_from_ad/close_ad/lock_for_order use ad.maker.require_auth(); unlock uses order_recipient_addr.require_auth(). Removed manager-as-maker assumptions.
Test Token Contract
contracts/stellar/contracts/test-token/Cargo.toml, contracts/stellar/contracts/test-token/src/lib.rs
Added test-token Soroban crate: a minimal fungible token with constructor mint and permissionless mint() for E2E tests; implements FungibleToken.
Integration Test Update
contracts/stellar/tests/integration_test.rs
Updated create_ad call to pass new creator/admin argument.
EVM Nonce Tracking & Deployment
scripts/cross-chain-e2e/lib/evm.ts
Added exported NonceTracker to manage pending nonces; deployment and role-grant calls now pass explicit nonces and await tx receipts; EvmContracts now includes signer and nonces.
Proof Utilities
scripts/cross-chain-e2e/lib/proof.ts
Switched proofbridge-mmr imports to CommonJS interop; updated ORDER_TYPEHASH to use bytes32 for address-like fields; refactored/condensed Hash/Poseidon call formatting.
Signing Utilities Removal
scripts/cross-chain-e2e/lib/signing.ts
Removed setChainRequestHash() and setTokenRouteRequestHash() exports.
Stellar CLI Helpers
scripts/cross-chain-e2e/lib/stellar.ts
Made base32Decode() exported; added pubkeyToAddress(), generateAndFundKey(), deploySAC(); invokeContract() gains optional source parameter; removed stellarIdToEvmAddress().
E2E Runner Refactor
scripts/cross-chain-e2e/run.ts
Refactored runner to four-actor model (Stellar: admin/ad creator/order creator; EVM: admin/order creator), use signer-specific nonces, change Stellar CLI usage to --source/--params, update proof/param passing and expand multi-actor assertions.
E2E Shell Setup
scripts/run_cross_chain_e2e.sh
Replaced single-source account with role-specific Stellar accounts and separate EVM keys; exports new environment variables; adds Anvil pre-kill and --block-time 2.

Sequence Diagram(s)

sequenceDiagram
    participant StellarAdmin as Stellar Admin
    participant AdCreator as Ad Creator (Stellar)
    participant OrderCreator as Order Creator (Stellar)
    participant AdManager as Ad Manager Contract
    participant OrderPortal as Order Portal Contract
    participant EVMAdmin as EVM Admin
    participant EVMOrderCreator as EVM Order Creator

    StellarAdmin->>AdManager: create_ad(..., creator)
    AdManager->>AdManager: creator.require_auth()\nstore ad.maker = creator

    AdCreator->>AdManager: fund_ad(...)
    AdManager->>AdManager: ad.maker.require_auth()\nupdate ad balance

    OrderCreator->>OrderPortal: create_order(..., bridger)
    OrderPortal->>OrderPortal: bridger.require_auth()\ncreate order

    OrderCreator->>AdManager: lock_for_order(...)
    AdManager->>AdManager: ad.maker.require_auth()\nlock funds

    EVMOrderCreator->>EVMAdmin: submit proof/tx
    EVMAdmin->>OrderPortal: unlock(..., ad_recipient)
    OrderPortal->>OrderPortal: ad_recipient.require_auth()\nverify proof, release tokens

    OrderCreator->>AdManager: unlock(..., order_recipient)
    AdManager->>AdManager: order_recipient.require_auth()\nrelease ad maker funds
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • Ugo-X

Poem

🐰 I hopped through code with a tiny cheer,
Adding keys, nonces, and roles quite clear,
Creators, orders, admins in line,
Proofs and tokens in cross-chain rhyme,
A rabbit's hop—tests now ready to steer. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: Cross-Chain E2E CI — Stellar ↔ EVM' clearly summarizes the main change: adding cross-chain end-to-end integration testing and CI infrastructure for Stellar and EVM bridge functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch stellar-integrations

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
contracts/stellar/contracts/ad-manager/src/lib.rs (1)

232-275: ⚠️ Potential issue | 🟠 Major

Bind creator into the signed create_ad request.

creator.require_auth() proves who pays, but the manager pre-auth no longer proves who is allowed to become the maker. As written, any funded account that obtains the same manager signature can swap in its own creator, front-run the intended LP, and consume the ad_id first. Include creator in create_ad_request_hash and verify that version instead.

Minimal callsite change
         let message = auth::create_ad_request_hash(
             &env,
+            &creator,
             &ad_id,
             &ad_token,
             initial_amount,
             order_chain_id,
             &ad_recipient,

You'd also need the corresponding auth::create_ad_request_hash(...) update so the creator bytes are hashed into the signed payload.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/stellar/contracts/ad-manager/src/lib.rs` around lines 232 - 275,
The create_ad flow currently omits binding the caller into the signed payload,
allowing any funded account to reuse a manager signature with a swapped creator;
update the call to auth::create_ad_request_hash in the function that builds the
message so it includes the creator (e.g., pass creator.as_bytes() or its
BytesN/Address representation into create_ad_request_hash), then update the
auth::create_ad_request_hash signature/implementation to include and hash the
creator bytes, and ensure Self::verify_request uses the new hashed message
variant; keep creator.require_auth() as-is but verify against the new
creator-bound hash so the manager signature is valid only for that specific
creator.
scripts/cross-chain-e2e/run.ts (1)

591-623: ⚠️ Potential issue | 🟠 Major

Send the EVM unlock from the intended non-admin actor.

Line 615 still submits unlock through the admin-bound evm.orderPortal instance with nonces.next(). That means this E2E is not actually exercising the role-separated unlock path, and it will be wrong if OrderPortal.unlock() now depends on msg.sender. If the order creator is the intended caller, use the creator-bound instance here; if it's another actor, plumb that wallet in instead.

Suggested fix if the order creator is the intended caller
-    const tx = await evm.orderPortal.getFunction("unlock")(
+    const tx = await orderPortalAsCreator.getFunction("unlock")(
       unlockSig,
       evmAuthToken2,
       EVM_TIME_TO_EXPIRE,
       evmOrderParams,
       nullifierHash,
       targetRoot,
       proofHex,
-      { nonce: nonces.next() },
+      { nonce: orderCreatorNonces.next() },
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cross-chain-e2e/run.ts` around lines 591 - 623, The test is sending
the unlock via the admin-bound evm.orderPortal instance and nonces.next(), so
change the call to invoke OrderPortal.unlock from the intended actor's bound
instance and nonce/signer instead of evmSigner/nonces.next(); locate the
evm.orderPortal.getFunction("unlock") call and replace it to use the
order-creator (or other intended actor) bound contract instance and that actor's
nonce/signer (e.g., the creator-bound orderPortal instance and its nonce
provider) so msg.sender in OrderPortal.unlock reflects the correct actor.
🧹 Nitpick comments (4)
scripts/cross-chain-e2e/lib/proof.ts (1)

163-266: Clean up Barretenberg and the temp MMR dir in a finally block.

If anything throws after Barretenberg.new() or after the LevelDB directory is created, this function leaks both resources and leaves stale /tmp/e2e-mmr-* state behind. Wrapping the proof pipeline in try/finally will make failure cases much easier to debug in CI.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cross-chain-e2e/lib/proof.ts` around lines 163 - 266, Wrap the
pipeline that starts with creating Barretenberg (Barretenberg.new()) and
initializing the LevelDB/MMR (dbPath, new LevelDB(...), await db.init(), new
MMR(...)) in a try/finally so resources are always cleaned: move all work (MMR
append/getMerkleProof, Noir/Honk execution, proof generation, building public
inputs) into the try block and call cleanup in the finally block
(fs.rmSync(dbPath, { recursive: true, force: true }) and await bb.destroy()).
Ensure bb and dbPath are defined in the outer scope so the finally can check and
safely cleanup only if they were created.
contracts/stellar/tests/integration_test.rs (1)

514-520: Use the fixture ad creator here, not admin_addr.

This setup still creates the ad as the manager account, so these tests never exercise the new creator.require_auth() path with a non-manager maker. That leaves the multi-actor auth change largely untested at the contract-test level. Consider funding/deriving tp.ad_creator and passing that address here instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/stellar/tests/integration_test.rs` around lines 514 - 520, The test
is creating the ad with the manager account (admin_addr) instead of the fixture
ad creator, so it never exercises creator.require_auth(); replace admin_addr
with the fixture creator (tp.ad_creator) in the ad_manager.create_ad call and
ensure you derive/fund tp.ad_creator and use the corresponding signature and
pubkey for that actor (i.e., construct ad_creator_signature and
ad_creator_pubkey and pass them in place of signature/admin_pubkey) so the call
runs under the non-manager creator and triggers creator.require_auth().
scripts/cross-chain-e2e/run.ts (2)

55-63: Fail fast on missing environment variables.

The ! assertions only move the failure to whichever later call touches undefined. A tiny requireEnv() helper would make CI/local misconfig much easier to diagnose.

One simple way to tighten this up
+function requireEnv(name: string): string {
+  const value = process.env[name];
+  if (!value) throw new Error(`Missing required env: ${name}`);
+  return value;
+}
+
-const ROOT_DIR = process.env.ROOT_DIR!;
-const EVM_RPC_URL = process.env.EVM_RPC_URL!;
-const EVM_ADMIN_PRIVATE_KEY = process.env.EVM_ADMIN_PRIVATE_KEY!;
-const EVM_ORDER_CREATOR_PRIVATE_KEY =
-  process.env.EVM_ORDER_CREATOR_PRIVATE_KEY!;
-const STELLAR_AD_CREATOR_ACCOUNT = process.env.STELLAR_AD_CREATOR_ACCOUNT!;
-const STELLAR_ORDER_CREATOR_ACCOUNT =
-  process.env.STELLAR_ORDER_CREATOR_ACCOUNT!;
-const AD_CREATOR_EVM_RECIPIENT = process.env.AD_CREATOR_EVM_RECIPIENT!;
+const ROOT_DIR = requireEnv("ROOT_DIR");
+const EVM_RPC_URL = requireEnv("EVM_RPC_URL");
+const EVM_ADMIN_PRIVATE_KEY = requireEnv("EVM_ADMIN_PRIVATE_KEY");
+const EVM_ORDER_CREATOR_PRIVATE_KEY = requireEnv(
+  "EVM_ORDER_CREATOR_PRIVATE_KEY",
+);
+const STELLAR_AD_CREATOR_ACCOUNT = requireEnv("STELLAR_AD_CREATOR_ACCOUNT");
+const STELLAR_ORDER_CREATOR_ACCOUNT = requireEnv(
+  "STELLAR_ORDER_CREATOR_ACCOUNT",
+);
+const AD_CREATOR_EVM_RECIPIENT = requireEnv("AD_CREATOR_EVM_RECIPIENT");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cross-chain-e2e/run.ts` around lines 55 - 63, Replace the blind
non-null assertions for env vars (ROOT_DIR, EVM_RPC_URL, EVM_ADMIN_PRIVATE_KEY,
EVM_ORDER_CREATOR_PRIVATE_KEY, STELLAR_AD_CREATOR_ACCOUNT,
STELLAR_ORDER_CREATOR_ACCOUNT, AD_CREATOR_EVM_RECIPIENT) with a fail-fast
helper: implement a small requireEnv(key) that reads process.env[key], throws a
descriptive Error if missing, and use requireEnv("ROOT_DIR") etc. Update where
these constants are initialized to call requireEnv for each symbol so CI/local
runs error immediately with a clear message rather than later with an undefined
value.

403-431: Build the EVM/proof/Stellar order payloads from one source.

These blocks re-encode the same order in three shapes. A later field change can update one and silently desync the Solidity call, the proof hash, and the Soroban JSON. A small canonical builder/helper would make this much harder to break.

Also applies to: 470-485

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cross-chain-e2e/run.ts` around lines 403 - 431, Create a single
canonical builder (e.g., buildOrderPayload or createCanonicalOrder) that returns
a base order object with the shared fields (orderChainToken, adChainToken,
amount, bridger, orderRecipient, orderChainId, orderPortal, adChainId,
adManager, adId, adCreator, adRecipient, salt) and use it to derive the three
shapes currently constructed separately (evmOrderParams, orderParams, and the
payload built at the later block around 470-485); replace the duplicated literal
objects with calls to that builder and lightweight mappers to produce the
EVM-specific, proof/hash-specific, and Soroban/Stellar-specific shapes so all
fields originate from one source of truth (update usages of evmOrderParams and
orderParams to use the new builder/mappers).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contracts/stellar/contracts/test-token/src/lib.rs`:
- Around line 17-24: The mint function currently allows anyone to mint; modify
the contract to persist an admin/minter in the constructor and enforce auth in
mint: in __constructor(e, owner, initial_supply) store owner (or a specified
admin/minter) in contract storage (e.g., a named data key) after calling
Base::mint, and in pub fn mint(e: &Env, to: Address, amount: i128) check the
caller/sender against that stored admin/minter and return or abort if not
authorized before calling Base::mint; update any access utilities or helpers
used to read/write the admin/minter value accordingly.

In `@scripts/cross-chain-e2e/lib/stellar.ts`:
- Around line 69-80: The generateAndFundKey helper currently swallows all errors
in both try/catch blocks, masking real failures; update generateAndFundKey so
each catch captures the thrown error (e.g., catch (err)) and only suppresses it
when the error message or exit code clearly indicates the idempotent cases
("already exists" for stellar(`keys generate`) and "already funded" / equivalent
for stellar(`keys fund`) — otherwise rethrow the error; keep using stellar(...)
for command execution and return getAddress(name) as before.

In `@scripts/cross-chain-e2e/run.ts`:
- Around line 136-140: The synchronous call to getPublicKey from
import("@noble/ed25519") depends on a sha512Sync backend being configured
elsewhere (ed.etc.sha512Sync) and will break if import ordering changes; fix by
either explicitly configuring the noble ed25519 hash backend in this file before
calling getPublicKey (set ed.etc.sha512Sync to the same implementation used in
scripts/cross-chain-e2e/lib/signing.ts) or replace the synchronous call with the
asynchronous API getPublicKeyAsync and await it (use
import("@noble/ed25519").getPublicKeyAsync) so no external configuration is
required; update references to stellarAdminPubKey/stellerAdminSecretKey
accordingly.

In `@scripts/run_cross_chain_e2e.sh`:
- Around line 114-116: The script currently force-kills whatever process is
listening on $ANVIL_PORT; instead, detect the PID(s) from lsof -ti
:"$ANVIL_PORT", inspect each PID's command (e.g. via /proc/<pid>/comm or ps -o
comm= -p <pid>) and only kill when the command matches the anvil binary (or
known anvil spawners); otherwise return a non-zero error and exit (fail fast) so
the user can resolve the port conflict. Update the section around the current
lsof/kill call in run_cross_chain_e2e.sh to implement this safe-check logic
using ANVIL_PORT and the discovered PIDs before sending any kill signals.

---

Outside diff comments:
In `@contracts/stellar/contracts/ad-manager/src/lib.rs`:
- Around line 232-275: The create_ad flow currently omits binding the caller
into the signed payload, allowing any funded account to reuse a manager
signature with a swapped creator; update the call to
auth::create_ad_request_hash in the function that builds the message so it
includes the creator (e.g., pass creator.as_bytes() or its BytesN/Address
representation into create_ad_request_hash), then update the
auth::create_ad_request_hash signature/implementation to include and hash the
creator bytes, and ensure Self::verify_request uses the new hashed message
variant; keep creator.require_auth() as-is but verify against the new
creator-bound hash so the manager signature is valid only for that specific
creator.

In `@scripts/cross-chain-e2e/run.ts`:
- Around line 591-623: The test is sending the unlock via the admin-bound
evm.orderPortal instance and nonces.next(), so change the call to invoke
OrderPortal.unlock from the intended actor's bound instance and nonce/signer
instead of evmSigner/nonces.next(); locate the
evm.orderPortal.getFunction("unlock") call and replace it to use the
order-creator (or other intended actor) bound contract instance and that actor's
nonce/signer (e.g., the creator-bound orderPortal instance and its nonce
provider) so msg.sender in OrderPortal.unlock reflects the correct actor.

---

Nitpick comments:
In `@contracts/stellar/tests/integration_test.rs`:
- Around line 514-520: The test is creating the ad with the manager account
(admin_addr) instead of the fixture ad creator, so it never exercises
creator.require_auth(); replace admin_addr with the fixture creator
(tp.ad_creator) in the ad_manager.create_ad call and ensure you derive/fund
tp.ad_creator and use the corresponding signature and pubkey for that actor
(i.e., construct ad_creator_signature and ad_creator_pubkey and pass them in
place of signature/admin_pubkey) so the call runs under the non-manager creator
and triggers creator.require_auth().

In `@scripts/cross-chain-e2e/lib/proof.ts`:
- Around line 163-266: Wrap the pipeline that starts with creating Barretenberg
(Barretenberg.new()) and initializing the LevelDB/MMR (dbPath, new LevelDB(...),
await db.init(), new MMR(...)) in a try/finally so resources are always cleaned:
move all work (MMR append/getMerkleProof, Noir/Honk execution, proof generation,
building public inputs) into the try block and call cleanup in the finally block
(fs.rmSync(dbPath, { recursive: true, force: true }) and await bb.destroy()).
Ensure bb and dbPath are defined in the outer scope so the finally can check and
safely cleanup only if they were created.

In `@scripts/cross-chain-e2e/run.ts`:
- Around line 55-63: Replace the blind non-null assertions for env vars
(ROOT_DIR, EVM_RPC_URL, EVM_ADMIN_PRIVATE_KEY, EVM_ORDER_CREATOR_PRIVATE_KEY,
STELLAR_AD_CREATOR_ACCOUNT, STELLAR_ORDER_CREATOR_ACCOUNT,
AD_CREATOR_EVM_RECIPIENT) with a fail-fast helper: implement a small
requireEnv(key) that reads process.env[key], throws a descriptive Error if
missing, and use requireEnv("ROOT_DIR") etc. Update where these constants are
initialized to call requireEnv for each symbol so CI/local runs error
immediately with a clear message rather than later with an undefined value.
- Around line 403-431: Create a single canonical builder (e.g.,
buildOrderPayload or createCanonicalOrder) that returns a base order object with
the shared fields (orderChainToken, adChainToken, amount, bridger,
orderRecipient, orderChainId, orderPortal, adChainId, adManager, adId,
adCreator, adRecipient, salt) and use it to derive the three shapes currently
constructed separately (evmOrderParams, orderParams, and the payload built at
the later block around 470-485); replace the duplicated literal objects with
calls to that builder and lightweight mappers to produce the EVM-specific,
proof/hash-specific, and Soroban/Stellar-specific shapes so all fields originate
from one source of truth (update usages of evmOrderParams and orderParams to use
the new builder/mappers).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a7bb29f-3b90-4f08-bca5-76a580e65133

📥 Commits

Reviewing files that changed from the base of the PR and between 72a020a and 250a706.

⛔ Files ignored due to path filters (1)
  • contracts/stellar/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • .github/workflows/cross-chain-e2e.yml
  • contracts/stellar/contracts/ad-manager/src/lib.rs
  • contracts/stellar/contracts/order-portal/src/lib.rs
  • contracts/stellar/contracts/test-token/Cargo.toml
  • contracts/stellar/contracts/test-token/src/lib.rs
  • contracts/stellar/test_snapshots/test_ad_manager_lock_for_order.1.json
  • contracts/stellar/test_snapshots/test_ad_manager_unlock_with_bridger_proof.1.json
  • contracts/stellar/test_snapshots/test_full_cross_chain_flow.1.json
  • contracts/stellar/test_snapshots/test_nullifier_prevents_double_unlock.1.json
  • contracts/stellar/test_snapshots/test_order_portal_create_and_unlock.1.json
  • contracts/stellar/tests/integration_test.rs
  • scripts/cross-chain-e2e/lib/evm.ts
  • scripts/cross-chain-e2e/lib/proof.ts
  • scripts/cross-chain-e2e/lib/signing.ts
  • scripts/cross-chain-e2e/lib/stellar.ts
  • scripts/cross-chain-e2e/run.ts
  • scripts/run_cross_chain_e2e.sh
💤 Files with no reviewable changes (1)
  • scripts/cross-chain-e2e/lib/signing.ts

Comment thread contracts/stellar/contracts/test-token/src/lib.rs
Comment thread scripts/cross-chain-e2e/lib/stellar.ts
Comment thread scripts/cross-chain-e2e/run.ts
Comment thread scripts/run_cross_chain_e2e.sh
@JoE11-y JoE11-y merged commit 0bb282e into main Apr 12, 2026
3 of 4 checks passed
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