Skip to content

Feat: fix trade lifecyle ui flow#125

Merged
JoE11-y merged 3 commits intomainfrom
stellar-integrations
Apr 18, 2026
Merged

Feat: fix trade lifecyle ui flow#125
JoE11-y merged 3 commits intomainfrom
stellar-integrations

Conversation

@JoE11-y
Copy link
Copy Markdown
Contributor

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

fix: trade lifecycle UI flow

Summary

End-to-end fixes for the trade unlock flow — Stellar signature verification, auth-token loops, and several UX dead-ends that made the lifecycle unusable without
manually signing out or guessing at missing wallet connections.

  • Stellar unlock signature verification now matches Freighter's exact domain-separated digest and signs a human-readable JSON of the order (no more opaque hash).
  • Unlock-confirm no longer 404s — lookup dropped a signature filter that could never match (relayer sig vs user sig).
  • Auth interceptor no longer traps the user in an infinite /auth/refresh loop when the refresh token is stale.
  • Plus: dashboard/orders metric fixes, faucet addToken via Freighter, dead-click fix on Create Ad, modal z-ordering.

Details

Stellar unlock signature verification

  • ChainAdapter.verifyOrderSignature now takes orderHash explicitly instead of recomputing from orderParams (the old path double-converted the decimal salt string
    through uuidToBigInt, producing a garbage hash that never matched the frontend's).
  • Backend + frontend both build the same pretty-printed JSON via buildStellarUnlockMessage (kept byte-identical across the two files), so Freighter shows the order
    fields instead of a bare 32-byte hex.
  • Backend stellarSignedMessageDigest now applies sha256("Stellar Signed Message:\n" + message) before ed25519 verify — matching Freighter's actual signMessage behavior.
  • scripts/relayer-e2e/flows/trade-lifecycle.ts updated to sign via the same JSON + sha256 preimage.

Unlock-confirm 404

  • authorizationLog.findFirst used to filter by signature: dto.signature, but the log was stored with the user's auth signature while the frontend sent back the
    relayer's on-chain request signature — two different strings. The filter was dropped; tradeId + userAddress IN callerLinked is sufficient, and reqHash (validated
    on-chain inside confirm) remains the true integrity gate.
  • Frontend confirmUnlockFunds call sites no longer pass signature.

Auth token handling (api.instance.ts)

  • 401 on /auth/refresh → clear both cookies and stop. Breaks the recursion that previously hammered /auth/refresh ~1200 times and forced manual sign-out.
  • 401 on any other endpoint → single silent refresh attempt. If that fails, the inner 401 takes the clear-cookies branch. No redirect — the auth-guard layout picks up
    the missing cookie.
  • 403 branch removed (it was attempting a refresh with no try/catch, leaving stale cookies on failure).

UX fixes

  • Orders + Home dashboards: "Completed orders" and "Avg. completion" were keying off LOCKED; fixed to COMPLETED. "Pending orders" now covers INACTIVE | ACTIVE | LOCKED.
  • Create Ad dead-click: AddLiquidity now gates the Preview Ad button on the destination wallet being connected (was only checking base chain), and handleCreateAd toasts
    errors instead of swallowing them. Previously an ETH → Stellar ad with no Stellar wallet linked would silently throw inside the confirm modal.
  • Faucet page: "Add to wallet" now uses addToken({ contractId, networkPassphrase }) for Freighter with a 30s timeout + clipboard fallback; EVM side refetches
    getWalletClient after switchChainAsync so watchAsset doesn't silently no-op on a stale client.
  • CreateOrderSuccessModal: zIndex={1500} so it renders above the Stellar wallets kit's z-[999] overlay.
  • OrdersTable: added rowKey="id" (fixes React duplicate-key warning); simplified claim-modal copy.

Summary by CodeRabbit

  • New Features

    • Added success modal upon order submission displaying order summary with navigation to orders page.
    • Improved wallet token integration with better balance lookups and streamlined add-to-wallet functionality.
    • Enhanced trade filtering to support multiple wallet addresses simultaneously.
  • Bug Fixes

    • Improved API error handling and token timeout recovery.
  • Documentation & UX Updates

    • Updated marketing copy to reflect broader multi-ecosystem focus.
    • Refined dashboard metrics calculations for improved accuracy.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 18, 2026

Warning

Rate limit exceeded

@JoE11-y has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 13 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 13 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a020861-6b88-4296-8b69-810ab29f02a4

📥 Commits

Reviewing files that changed from the base of the PR and between d386e2f and a7f5b1d.

📒 Files selected for processing (5)
  • apps/backend-relayer/src/modules/trades/trade.service.ts
  • apps/frontend/app/(app)/(auth-protected)/faucet/page.tsx
  • apps/frontend/components/bridge-ui/TradeAd.tsx
  • apps/frontend/components/shared/Header.tsx
  • apps/frontend/services/api.instance.ts
📝 Walkthrough

Walkthrough

This PR extends signature verification across chain adapters to accept an orderParams parameter, redesigns Stellar unlock message construction from raw order hashes to structured JSON messages, updates trade querying to support address arrays, refactors frontend trading UI with wallet hub integration, migrates Stellar balance queries from Horizon to Soroban, and updates marketing copy to be ecosystem-agnostic rather than Ethereum/Stellar-specific.

Changes

Cohort / File(s) Summary
Chain Adapter Signature Verification
apps/backend-relayer/src/chain-adapters/adapters/chain-adapter.abstract.ts, apps/backend-relayer/src/chain-adapters/adapters/evm-chain-adapter.ts, apps/backend-relayer/src/chain-adapters/adapters/stellar-chain-adapter.ts, apps/backend-relayer/test/setups/mock-chain-adapter.ts
Updated verifyOrderSignature abstract method and all concrete implementations (EVM, Stellar, mock) to accept an additional orderParams: T_OrderParams parameter positioned before the signature argument.
Stellar Signing & Message Construction
apps/backend-relayer/src/providers/stellar/stellar.service.ts, apps/backend-relayer/src/providers/stellar/utils/signing.ts, apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts
Added buildStellarUnlockMessage to construct JSON-formatted unlock authorization messages from order parameters, added stellarSignedMessageDigest to compute SHA-256 digest of formatted messages, and updated StellarService.verifyOrderSignature to hash and verify against this structured message instead of raw order hash.
Trade Service & DTOs
apps/backend-relayer/src/modules/trades/dto/trade.dto.ts, apps/backend-relayer/src/modules/trades/trade.service.ts
Extended QueryTradesDto fields (adCreatorAddress, bridgerAddress) to accept `string
Backend Proof & API
apps/backend-relayer/src/providers/noir/proof.service.ts, apps/frontend/services/api.instance.ts
Changed UltraHonkBackend thread configuration from 1 to 4; refactored token-refresh interceptor to only retry 401 errors on non-refresh endpoints and clean up tokens without redirect on refresh-endpoint failures.
Frontend Trading UI Components
apps/frontend/components/bridge-ui/TradeAd.tsx, apps/frontend/components/bridge-ui/CreateOrderSuccessModal.tsx, apps/frontend/components/ad-management-ui/AddLiquidity.tsx
Added CreateOrderSuccessModal component with order summary display; refactored TradeAd to use unified wallet hub for connections and display success modal; enhanced AddLiquidity with wallet readiness gating, token balance display (EVM via wagmi, Stellar via Soroban query), and improved error reporting.
Frontend Orders & Admin UI
apps/frontend/app/(app)/(auth-protected)/home/page.tsx, apps/frontend/app/(app)/(auth-protected)/orders/page.tsx, apps/frontend/components/orders/OrdersTable.tsx
Added memoized tradeMetrics to compute total/completed/avg-completion instead of inline calculations; updated OrdersTable to use linked wallet addresses from useCurrentUser instead of single wagmi account; added adapter-based connection readiness gating and ConnectHubModal integration; refactored modal control flow and status-based UI rendering.
Frontend Stellar Utilities
apps/frontend/utils/stellar/balance.ts, apps/frontend/utils/stellar/unlock-message.ts
Migrated getStellarTokenBalance from Horizon account-balance lookup to Soroban contract balance() read-only simulation; added defaultSorobanRpcUrl helper; added buildStellarUnlockMessage to construct JSON unlock authorization messages from trade parameters.
Frontend Hooks & Types
apps/frontend/hooks/useTrades.ts, apps/frontend/types/trades.ts
Updated Stellar unlock signing to use buildStellarUnlockMessage instead of raw order hash; made IConfirmUnlockFundsRequest.signature optional; extended IGetTradesParams address filters to accept `string
Frontend Configuration & Styling
apps/frontend/utils/wagmi-config.ts, apps/frontend/app/globals.css, apps/frontend/components/shared/Header.tsx
Removed hederaTestnet from wagmi chain configuration; added .signal-line-link CSS rules with hover animations; updated header navigation spacing and link wrapper structure.
Marketing Copy & Landing Pages
apps/frontend/app/(app)/bridge/page.tsx, apps/frontend/components/landing/Approach.tsx, apps/frontend/components/landing/Features.tsx, apps/frontend/components/landing/Hero.tsx, apps/frontend/components/landing/Hero-Alt.tsx, apps/frontend/components/landing/ReImagining.tsx, apps/frontend/components/landing/LandingHeader-Alt.tsx
Updated marketing messaging across landing and bridge pages to use ecosystem-agnostic phrasing ("across ecosystems", "connecting multiple ecosystems") instead of explicit "Ethereum and Stellar" references; minor formatting and capitalization fixes.
Frontend Dependencies
apps/frontend/package.json
Added @stellar/freighter-api@^6.0.1 dependency for Stellar wallet integration.
E2E Test Scripts
scripts/relayer-e2e/flows/trade-lifecycle.ts
Updated Stellar unlock test flow to build unlock message from order parameters and hash it before signing, aligning with backend service behavior.

Sequence Diagram

sequenceDiagram
    participant User as Frontend App
    participant Builder as Stellar Utils
    participant Service as StellarService
    participant Verify as verifyOrderSignature

    User->>Builder: buildStellarUnlockMessage(orderParams)
    Builder-->>User: JSON message string

    User->>User: SHA256 digest of "Stellar Signed Message:\n" + message
    User->>User: Sign digest with ed25519 keypair

    User->>Service: confirmUnlockFunds(tradeId, signature)
    Service->>Service: extract orderParams from trade
    Service->>Verify: verifyOrderSignature(address, orderHash, orderParams, signature)

    Verify->>Builder: buildStellarUnlockMessage(orderParams)
    Builder-->>Verify: JSON message string
    Verify->>Verify: stellarSignedMessageDigest(message)
    Verify->>Verify: verifyEd25519(digest, signature)
    Verify-->>Service: boolean result

    Service-->>User: confirmation result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Impl Stellar UI integrations #115: Modifies chain-adapter signature-verification surface and Stellar/EVM verification logic — this PR extends the same verifyOrderSignature pattern and builds directly on earlier changes to Stellar signature handling.
  • chore: refactor backend relayer to reflect contract update for evm addresses #110: Touches TradesService.unlock and orderParams construction — this PR adds passing orderParams into signature verification while the related PR converts those same fields to bytes32.
  • Frontend in app #27: Both PRs modify useTrades.ts and types/trades.ts together and introduce compatible changes to Stellar unlock message signing and trade filtering types.

Suggested reviewers

  • Ugo-X

Poem

🐰 A rabbit hops through order flows so neat,
With messages built from parameters sweet,
From Stellar chains to adapters aligned,
Signatures verified, ecosystems combined!
Now wallets connect in one gleaming hub,
And ProofBridge bridges all lands above! 🌉✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title is vague and partially related to the changeset. While the PR addresses trade lifecycle UI flow, it uses a typo ('lifecyle' instead of 'lifecycle'), lacks specificity about the main fixes (Stellar verification, auth loops, wallet gating), and doesn't clearly convey the scope of backend changes alongside frontend UI fixes. Consider revising the title to be more specific and typo-free, such as 'Fix trade unlock flow: Stellar verification, auth-token refresh, and wallet connection gating' to better reflect the core changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 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: 7

Caution

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

⚠️ Outside diff range comments (4)
apps/frontend/utils/wagmi-config.ts (1)

2-20: ⚠️ Potential issue | 🟠 Major

Remove Hedera references or re-add to wagmi config.

hederaTestnet is removed from chainList and transports in wagmi-config.ts, but still referenced in apps/frontend/lib/chain-icons.ts and hardcoded in apps/frontend/components/dashboard/AdCard.tsx:21-23 (explorer_urls). If the backend returns ads with a Hedera chainId, they will render in AdCard with working explorer links, but writeContractAsync calls for withdraw/top-up/close will fail since the chain has no transport configured.

Either remove Hedera from chain-icons.ts and AdCard's explorer_urls, or re-add it to wagmi-config with a transport to maintain full support.

Fix to restore Hedera support
-import { foundry, sepolia, type Chain } from "viem/chains"
+import { foundry, hederaTestnet, sepolia, type Chain } from "viem/chains"

 const chainList: readonly [Chain, ...Chain[]] = localEnabled
-  ? [foundry, sepolia]
-  : [sepolia]
+  ? [foundry, sepolia, hederaTestnet]
+  : [sepolia, hederaTestnet]

 export const config = createConfig({
   chains: chainList,
   transports: {
     [foundry.id]: http(anvilRpc),
     [sepolia.id]: http(),
+    [hederaTestnet.id]: http(),
   },
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/utils/wagmi-config.ts` around lines 2 - 20, The wagmi config
removed hederaTestnet but other code (chain-icons.ts and AdCard.tsx's
explorer_urls) still expect it, causing writeContractAsync calls to fail without
a transport; either fully remove Hedera references or re-add it to the wagmi
configuration. Fix option A: remove hederaTestnet usages by deleting Hedera
entries from chain-icons.ts and remove/guard explorer_urls in AdCard.tsx
(references to explorer_urls and any hedera chainId checks). Fix option B:
re-add hederaTestnet into the chainList and transports passed to createConfig
(ensure you import the hederaTestnet Chain, add it to chainList when
appropriate, and provide a corresponding http transport entry keyed by
hederaTestnet.id) so writeContractAsync has a transport; pick one approach and
make the code changes consistently across chain-icons.ts, AdCard.tsx
(explorer_urls), and wagmi-config's createConfig.
apps/backend-relayer/src/modules/trades/trade.service.ts (2)

1051-1051: ⚠️ Potential issue | 🟡 Minor

Remove stray console.log(e) from catch block.

This dumps full error objects (possibly including signatures, addresses, stack traces with internals) to stdout in production. Prefer the framework Logger at warn/error level, or drop it now that behavior is stable.

🧹 Proposed fix
     } catch (e) {
-      console.log(e);
       if (e instanceof Error) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend-relayer/src/modules/trades/trade.service.ts` at line 1051, Stray
console.log(e) in the catch block of TradeService should be removed and replaced
with the framework logger; locate the catch in
apps/backend-relayer/src/modules/trades/trade.service.ts (class TradeService /
the method containing the shown catch) and either drop the console.log(e)
entirely or call the project's logger at the appropriate level (e.g.
this.logger.error('Descriptive message', e) or Logger.error('Descriptive
message', e, 'TradeService')) so sensitive error objects are not printed to
stdout — ensure you use the existing logger instance/name used elsewhere in
TradeService for consistency.

1355-1355: ⚠️ Potential issue | 🟡 Minor

Leftover debug console.log(dto) in confirmUnlockChainAction.

dto contains txHash and (optionally) signature — neither catastrophic, but this is clearly a debugging artifact and should be removed before merge.

🧹 Proposed fix
       // delete the log entry
       await this.prisma.authorizationLog.delete({
         where: { id: authorizationLog.id },
       });

-      console.log(dto);
-
       return {
         tradeId: updatedTrade.id,
         success: true,
       };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend-relayer/src/modules/trades/trade.service.ts` at line 1355,
Remove the leftover debug console.log by deleting the console.log(dto) call in
confirmUnlockChainAction; locate the console.log in the confirmUnlockChainAction
function in trade.service.ts and simply remove that statement so sensitive or
unnecessary txHash/signature data are not output to logs.
apps/frontend/components/bridge-ui/TradeAd.tsx (1)

179-201: ⚠️ Potential issue | 🟡 Minor

handleCreateTrade silently swallows mutateAsync failures and there is no error feedback.

If mutateAsync rejects, execution skips setSuccessSummary / toggleModal (good — the success modal won't lie), but the user gets no toast or other feedback in this component, and the rejection becomes an unhandled promise rejection from the onClick handler. The sibling AddLiquidity.handleCreateAd was just updated in this PR to wrap the call in try/catch and toast the error — apply the same pattern here for consistency.

♻️ Suggested fix
   const handleCreateTrade = async () => {
     if (!bridgerDstAddress) return
     if (!scaled || !scaled.ok) return
-    await mutateAsync({
-      payload: {
-        adId: props.id,
-        routeId: props.routeId,
-        amount: scaled.orderAmount.toString(),
-        bridgerDstAddress,
-      },
-      orderTokenId: props.orderTokenId,
-    })
-    setSuccessSummary({
-      payAmount: formatUnits(scaled.orderAmount, props.orderToken.decimals),
-      payTokenSymbol: props.orderToken.symbol,
-      receiveAmount: String(Number(amount) - txFee),
-      receiveTokenSymbol: props.adToken.symbol,
-      orderChainName,
-      adChainName,
-      recipient: bridgerDstAddress,
-    })
-    toggleModal()
+    try {
+      await mutateAsync({
+        payload: {
+          adId: props.id,
+          routeId: props.routeId,
+          amount: scaled.orderAmount.toString(),
+          bridgerDstAddress,
+        },
+        orderTokenId: props.orderTokenId,
+      })
+      setSuccessSummary({
+        payAmount: formatUnits(scaled.orderAmount, props.orderToken.decimals),
+        payTokenSymbol: props.orderToken.symbol,
+        receiveAmount: String(Number(amount) - txFee),
+        receiveTokenSymbol: props.adToken.symbol,
+        orderChainName,
+        adChainName,
+        recipient: bridgerDstAddress,
+      })
+      toggleModal()
+    } catch (err) {
+      // toast/error surface — match AddLiquidity.handleCreateAd
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/components/bridge-ui/TradeAd.tsx` around lines 179 - 201, Wrap
the async call in handleCreateTrade in a try/catch so mutateAsync failures are
caught and reported (like AddLiquidity.handleCreateAd): await mutateAsync(...)
inside try, then call setSuccessSummary(...) and toggleModal() on success; in
catch call the same toast/error helper used elsewhere (e.g., toast.error or the
project’s useToast) with the caught error to surface the failure to the user and
prevent an unhandled promise rejection; ensure you reference mutateAsync,
setSuccessSummary, toggleModal, and handleCreateTrade when making the change.
🧹 Nitpick comments (11)
apps/backend-relayer/src/providers/noir/proof.service.ts (1)

19-19: Make thread count configurable instead of hardcoded.

At Line 19, threads: 4 may over/under-utilize different runtime environments. Consider reading this from config/env (with a safe default) so ops can tune per deployment without code changes.

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

In `@apps/backend-relayer/src/providers/noir/proof.service.ts` at line 19, Replace
the hardcoded threads: 4 with a configurable value read from environment or app
config (e.g., process.env.NOIR_THREADS or the existing config service) inside
the same module (proof.service.ts) where the threads option is set; parse the
value to an integer, validate it (>0), and fall back to a safe default such as
os.cpus().length or 4 if missing/invalid. Ensure you import/require os if using
os.cpus(), use Number.parseInt and isNaN checks to validate, and apply the
resulting numeric variable in place of the literal in the threads option so
deployments can tune it via env/config.
apps/frontend/app/globals.css (1)

159-164: Mirror the hover affordance for keyboard focus.

The new underline/color treatment is hover-only. Add :focus-visible so keyboard users get the same navigation cue.

♿ Proposed focus-visible parity
-.signal-line-link > a:hover {
+.signal-line-link > a:hover,
+.signal-line-link > a:focus-visible {
   color: var(--color-primary);
 }
 
-.signal-line-link > a:hover::after {
+.signal-line-link > a:hover::after,
+.signal-line-link > a:focus-visible::after {
   transform: scaleX(1);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/app/globals.css` around lines 159 - 164, The hover-only
underline/color affordance on .signal-line-link > a:hover and .signal-line-link
> a:hover::after should also be applied for keyboard focus: add matching
.signal-line-link > a:focus-visible and .signal-line-link >
a:focus-visible::after rules that set color: var(--color-primary) and transform:
scaleX(1) respectively (and ensure any transition/outline handling matches the
hover behavior) so keyboard users receive the same visual cue.
apps/frontend/app/(app)/bridge/page.tsx (1)

17-22: Remove the empty paragraph tag.

The text update successfully generalizes the messaging. However, line 22 contains an empty <p></p> tag that serves no purpose and should be removed.

🧹 Proposed fix to remove dead code
              <p className="text-[13px]">
                Unlocking the next generation of cross-chain bridging{" "}
                <Link href={"/"} className="underline text-primary">
                  create ad
                </Link>
              </p>
-              <p></p>
            </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/app/`(app)/bridge/page.tsx around lines 17 - 22, Remove the
dead empty paragraph tag that follows the Link in the bridge page component:
locate the block containing the text "Unlocking the next generation of
cross-chain bridging" and the Link component (the JSX with Link href="/" and
text "create ad") and delete the trailing empty <p></p> element so there is no
blank paragraph rendered.
scripts/relayer-e2e/flows/trade-lifecycle.ts (1)

291-301: Inline digest re-implements stellarSignedMessageDigest — import it instead.

The script already reaches into apps/backend-relayer/.../utils/unlock-message.js for buildStellarUnlockMessage; doing the same for the digest helper keeps the signing preimage in lock-step with what the relayer actually verifies. Otherwise a future change to the prefix string or hash function in signing.ts will silently desynchronize the e2e flow from production.

♻️ Proposed refactor
-import { createHash } from "crypto";
 import { Keypair } from "@stellar/stellar-sdk";
 import { getAddress, parseEther } from "viem";
 import { privateKeyToAccount } from "viem/accounts";
 import { TypedDataEncoder } from "ethers";
 import { buildStellarUnlockMessage } from "../../../apps/backend-relayer/src/providers/stellar/utils/unlock-message.js";
+import { stellarSignedMessageDigest } from "../../../apps/backend-relayer/src/providers/stellar/utils/signing.js";
@@
-    const bridgerMessage = buildStellarUnlockMessage({
-      ...bridgerOrderParams,
-      orderHash: bridgerOrderHash,
-    });
-    const bridgerDigest = createHash("sha256")
-      .update(Buffer.concat([
-        Buffer.from("Stellar Signed Message:\n", "utf8"),
-        Buffer.from(bridgerMessage, "utf8"),
-      ]))
-      .digest();
-    const bridgerSigBytes = bridgerStellar.sign(bridgerDigest);
+    const bridgerMessage = buildStellarUnlockMessage({
+      ...bridgerOrderParams,
+      orderHash: bridgerOrderHash,
+    });
+    const bridgerDigest = stellarSignedMessageDigest(bridgerMessage);
+    const bridgerSigBytes = bridgerStellar.sign(bridgerDigest);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/relayer-e2e/flows/trade-lifecycle.ts` around lines 291 - 301, The
code re-implements the Stellar signed-message digest instead of using the shared
helper; replace the manual creation of bridgerDigest with a call to the
canonical helper stellarSignedMessageDigest(bridgerMessage) (import that
function alongside buildStellarUnlockMessage) and pass its return value into
bridgerStellar.sign so the e2e signing preimage matches production verification
(update imports to include stellarSignedMessageDigest and remove the
Buffer/sha256 manual logic around bridgerDigest).
apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts (1)

5-33: Duplicated message schema creates maintenance risk — shared utility would prevent future drift.

Both apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts and apps/frontend/utils/stellar/unlock-message.ts implement byte-identical JSON builders. Field order and types currently match perfectly, but because the implementations are separate, any future field addition/rename/reorder risks silencing unlock signature failures (verifyEd25519 will fail with no obvious error trail).

Instead of duplicating the builder, consider:

  1. Moving the builder to a shared types/utilities package both backend and frontend import from.
  2. If that's infeasible, add cross-reference comments in both files pointing to each other, plus a snapshot test that asserts both helpers emit identical JSON for a fixed T_OrderParams / ITradeParams test input.

All T_OrderParams and ITradeParams field types are JSON-safe (Bytes32Hex/Address from viem are both 0x${string} template types; amount, chain IDs, and salt are strings; decimals are numbers), so no bigint serialization risk exists.

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

In `@apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts` around
lines 5 - 33, The backend buildStellarUnlockMessage implementation duplicates
the frontend builder (apps/frontend/utils/stellar/unlock-message.ts), risking
drift; either extract the JSON builder into a shared utility/types package and
have both import that single function (reference: buildStellarUnlockMessage) or,
if sharing is infeasible, add explicit cross-reference comments in both files
pointing to each other and add a snapshot test that imports both builders
(backend's buildStellarUnlockMessage and the frontend's equivalent) and asserts
their outputs are byte-identical for a fixed T_OrderParams/ITradeParams fixture
(use a deterministic fixture including orderHash, salt, decimals, amounts,
chain/token fields).
apps/frontend/utils/stellar/unlock-message.ts (1)

5-29: Current implementations are synchronized; consider defensive measures to prevent future drift.

The frontend and backend buildStellarUnlockMessage helpers currently stringify the identical set of fields in the same order, and ITradeParams includes all required fields including orderHash. No current schema mismatch exists.

However, to guard against future divergence:

  • Add a brief comment link between apps/frontend/utils/stellar/unlock-message.ts and apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts (e.g., // MUST stay in sync with backend unlock-message.ts — any field/order difference breaks ed25519 verification).
  • Consider a fixture-based snapshot test that runs both implementations on shared test data and asserts byte-for-byte equality. This is especially valuable given the cryptographic sensitivity: even a single field reorder or type stringification difference would silently fail Stellar signature verification.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/utils/stellar/unlock-message.ts` around lines 5 - 29, Add a
defensive sync note and a cross-implementation snapshot test: put a succinct
comment inside buildStellarUnlockMessage (e.g., "// MUST stay in sync with
backend unlock-message.ts — any field/order difference breaks ed25519
verification") to tie it to
apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts, and add a
fixture-based test that runs frontend buildStellarUnlockMessage and the backend
equivalent on the same test data and asserts exact byte-for-byte equality of the
JSON output to catch any future field/order/serialization drift.
apps/frontend/app/(app)/(auth-protected)/orders/page.tsx (1)

29-42: Memoize linkedAddresses for consistency and stable query keys.

linkedAddresses is rebuilt on every render as a new array reference. apps/frontend/app/(app)/(auth-protected)/home/page.tsx (lines 21–24) wraps the equivalent computation in React.useMemo. If useGetAllTrades keys on reference identity (common with react-query serialization of params), the unstable reference could cause redundant refetches. Worth aligning both pages.

♻️ Proposed refactor
   const { data: currentUser } = useCurrentUser()
-  const linkedAddresses =
-    currentUser?.wallets?.map((w) => w.address).filter(Boolean) ?? []
+  const linkedAddresses = useMemo(
+    () => currentUser?.wallets?.map((w) => w.address).filter(Boolean) ?? [],
+    [currentUser],
+  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/app/`(app)/(auth-protected)/orders/page.tsx around lines 29 -
42, The linkedAddresses array is recreated on every render causing unstable
references for useGetAllTrades' params; wrap the computation of linkedAddresses
(derived from useCurrentUser()?.wallets) in React.useMemo so it returns a stable
array identity across renders, then pass that memoized linkedAddresses into
useGetAllTrades (the adCreatorAddress/bridgerAddress args) to prevent
unnecessary refetches and ensure consistent query keys.
apps/backend-relayer/src/modules/trades/dto/trade.dto.ts (1)

31-59: Consider per-element validation for adCreatorAddress/bridgerAddress.

After removing @IsString(), these fields accept any value that passes through @Transform. Non-string entries (e.g., numbers, booleans in an array) reach the service, which relies on normalizeChainAddress throwing inside a try/catchBadRequestException('Invalid address filter'). This works but produces generic errors. A class-validator-level check gives better validation with field-specific messages.

The split condition also differs from participantAddresses: here, a comma-less string returns as-is (a plain string), while participantAddresses always produces an array. That asymmetry is fine given the string | string[] type.

♻️ Proposed hardening
   `@IsOptional`()
   `@Transform`(({ value }) =>
     Array.isArray(value)
       ? value
       : typeof value === 'string' && value.includes(',')
         ? value.split(',').filter(Boolean)
         : value,
   )
+  `@ValidateIf`((_, v) => v !== undefined)
+  `@IsString`({ each: true })
   adCreatorAddress?: string | string[];

(Apply the same to bridgerAddress. @IsString({ each: true }) validates arrays element-wise and also accepts a single string.)

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

In `@apps/backend-relayer/src/modules/trades/dto/trade.dto.ts` around lines 31 -
59, Add per-element string validation to the adCreatorAddress and bridgerAddress
DTO properties: keep the existing `@IsOptional`() and `@Transform`(...) logic but
add `@IsString`({ each: true }) above each property so class-validator enforces
that every array element (and single string) is a string; apply the same change
to bridgerAddress and leave the current Transform behavior unchanged.
apps/backend-relayer/src/providers/stellar/stellar.service.ts (1)

589-608: Protect against drift between frontend/backend buildStellarUnlockMessage.

Both implementations currently match perfectly in key order and indentation, producing identical JSON output. However, since these helpers are duplicated across apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts and apps/frontend/utils/stellar/unlock-message.ts, the risk of silent drift remains: adding a field or reordering keys in only one copy silently produces Invalid User Signature at the adapter boundary with no obvious root cause.

Two options, in order of preference:

  1. Share the helper from a single package (e.g., libs/shared) imported by both apps/backend-relayer and apps/frontend, so there is only one source of truth.
  2. If sharing isn't feasible, add a snapshot test on both sides pinning the exact serialized output for a fixed T_OrderParams fixture — any drift fails CI immediately.

The current sigBytes.length !== 64 check correctly rejects signatures of any other length; consider adding an early string-shape check (e.g., reject input longer than ~200 chars) to avoid calling Buffer.from(..., 'base64') on clearly malformed input.

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

In `@apps/backend-relayer/src/providers/stellar/stellar.service.ts` around lines
589 - 608, The verifyOrderSignature function risks silent drift because
buildStellarUnlockMessage is duplicated; either move the unlock-message helper
into a shared package (e.g., libs/shared) and import it into both apps so both
backend verifyOrderSignature and the frontend use the single source of truth, or
add snapshot tests in both apps that pin the exact serialized output of
buildStellarUnlockMessage for a fixed T_OrderParams fixture so any divergence
fails CI; additionally harden verifyOrderSignature by adding an early
input-shape guard in verifyOrderSignature (reject overly long or clearly
non-hex/base64 signature strings before calling Buffer.from) while keeping the
existing sigBytes.length !== 64 check.
apps/frontend/components/bridge-ui/CreateOrderSuccessModal.tsx (1)

91-96: “Submitted” timestamp is computed on every render rather than at submit time.

moment() is evaluated each render, so the displayed “Submitted” time drifts as React re-renders the modal. It's not the time the order was actually submitted — it's "now" at paint time. Consider including submittedAt (a string/number captured when setSuccessSummary is called) on CreatedOrderSummary and rendering that, so the timestamp is stable and accurate.

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

In `@apps/frontend/components/bridge-ui/CreateOrderSuccessModal.tsx` around lines
91 - 96, The modal currently calls moment() during render in
CreateOrderSuccessModal which yields a drifting "Submitted" time; change the
data flow so the actual submit timestamp is captured when setSuccessSummary is
called and stored on the CreatedOrderSummary object (add a submittedAt field of
type string|number), then update CreateOrderSuccessModal to read and format
summary.submittedAt (using moment(summary.submittedAt)) instead of calling
moment() directly so the displayed timestamp is stable and reflects the real
submit time.
apps/frontend/utils/stellar/balance.ts (1)

78-81: Widen scValToNative cast for type accuracy — runtime is safe but type is too narrow.

scValToNative returns any and can return bigint (for i128/u128), number (for u32/i32), string (for some types), boolean, Uint8Array, arrays, maps, or the original xdr.ScVal depending on the SCVal kind. The as bigint | number cast is narrower than the SDK's actual return type. BigInt(native) safely accepts all of these at runtime, but the cast masks type information and could silently break if the contract return type or SDK behavior changes. Widen to as bigint | number | string | boolean or use a runtime guard for clarity.

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

In `@apps/frontend/utils/stellar/balance.ts` around lines 78 - 81, The narrow cast
on the result of scValToNative risks losing type info; update the handling in
the simulate path (where success.result.retval is converted) so that the value
from scValToNative is widened (e.g. treat native as bigint | number | string |
boolean) or remove the cast and add a small runtime guard before calling
BigInt(native) that accepts bigint/number/string/boolean and converts
appropriately; locate the conversion around the variable native (from
scValToNative(success.result.retval)) and the BigInt(native) call (in this file)
and implement the widened type or guard there.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/backend-relayer/src/modules/trades/trade.service.ts`:
- Around line 901-926: Remove the leftover console.log debug statements from the
unlock flow: delete the console.log(e) inside the catch block that surrounds the
unlock/signature verification logic and delete the console.log(dto) that logs
the response object; locate these by finding the verifyOrderSignature call in
the unlock flow (references: orderParams,
this.chainAdapters.forChain(...).verifyOrderSignature, dto) and remove the two
console.log lines (optionally replace with existing processLogger methods if
structured logging is required).

In `@apps/frontend/app/`(app)/(auth-protected)/faucet/page.tsx:
- Around line 109-133: The Promise.race using freighterAddToken leaves the 30s
timer running and doesn't handle clipboard.writeText failures; fix by capturing
the timeout id returned by setTimeout before calling Promise.race (or wrap the
race so you can clearTimeout(timerId) when freighterAddToken settles) and call
clearTimeout(timerId) when the race resolves successfully or with the timeout
result, and when handling the res.error branch wrap
navigator.clipboard.writeText(contractId) in its own try/catch to catch
permission/rejection errors and surface a clear message (e.g., fallback UI
instruction to manually copy the contract id) instead of letting it bubble to
the outer catch; reference freighterAddToken, Promise.race, the timeout id, and
navigator.clipboard.writeText to locate the changes.

In `@apps/frontend/components/bridge-ui/TradeAd.tsx`:
- Around line 165-170: The insufficientBalance calculation treats
orderBalanceRaw === undefined as "not insufficient", enabling the Bridge button
while balances are still loading; update the logic in the insufficientBalance
computation (or the Bridge button disabled predicate) to treat unknown balance
as disabling—e.g. include the relevant loading flags so the result is
true/disabled when loading: reference scaled, orderBalanceRaw, and
isStellarOrder, and fold in stellarBalance.isLoading or (balance.isLoading ||
nativeBalance.isLoading) so the Bridge action cannot be clicked until the
balance queries complete.

In `@apps/frontend/components/orders/OrdersTable.tsx`:
- Around line 35-36: The ownsAddress helper lowercases addresses even though
backend guarantees canonical (normalized) addresses; update ownsAddress (and
callers comparing linkedAddresses with rowData.bridgerAddress/adCreatorAddress)
to either add a clarifying comment that addresses are expected pre-normalized by
the API or replace the lowercase call with a chain-aware normalization helper;
specifically, annotate the ownsAddress function with a brief comment about
backend normalization (or swap to a new normalizeAddressForComparison(addr,
chainKind?) helper) so the intent and fallback behavior are explicit and future
comparisons use the typed helper instead of ad-hoc toLowerCase().

In `@apps/frontend/components/shared/Header.tsx`:
- Around line 20-23: The external GitHub Link in Header (component Header.tsx,
JSX element Link with href "https://github.com/JoE11-y/ProofBridge" and
target="_blank") lacks rel="noopener noreferrer"; update that Link element to
include rel="noopener noreferrer" to prevent window.opener attacks and improve
security when opening in a new tab.
- Line 18: The parent div currently uses the "uppercase" utility in className
("flex items-center justify-between text-sm gap-8 uppercase") which cascades
into child components like ConnectWalletButton and alters wallet text; remove
"uppercase" from that parent className and instead add "uppercase" to the nav
link wrapper elements (the elements that wrap the navigation anchors) so only
the nav links are uppercased while ConnectWalletButton and other children retain
their original casing.

In `@apps/frontend/services/api.instance.ts`:
- Around line 64-77: In the refresh-failure branch of
apps/frontend/services/api.instance.ts, ensure any non-401 refresh errors also
clear auth cookies and propagate failure: when the api.post("/v1/auth/refresh",
...) inside the interceptor throws for any reason, remove/clear both
"auth_token" and "refresh_token" (same behavior as the isRefreshEndpoint branch)
before rethrowing so the auth-guard sees missing cookies. Also, when refresh
succeeds (you already set Cookies.set for res.data.tokens.access/refresh),
replay the original failed request using the saved error.config (e.g., set
Authorization header to the new access token on error.config.headers and return
await api.request(error.config)) so the caller receives the retried response
instead of the original rejection. Follow these changes around the existing
api.post call, error.config handling, and cookie set/remove logic.

---

Outside diff comments:
In `@apps/backend-relayer/src/modules/trades/trade.service.ts`:
- Line 1051: Stray console.log(e) in the catch block of TradeService should be
removed and replaced with the framework logger; locate the catch in
apps/backend-relayer/src/modules/trades/trade.service.ts (class TradeService /
the method containing the shown catch) and either drop the console.log(e)
entirely or call the project's logger at the appropriate level (e.g.
this.logger.error('Descriptive message', e) or Logger.error('Descriptive
message', e, 'TradeService')) so sensitive error objects are not printed to
stdout — ensure you use the existing logger instance/name used elsewhere in
TradeService for consistency.
- Line 1355: Remove the leftover debug console.log by deleting the
console.log(dto) call in confirmUnlockChainAction; locate the console.log in the
confirmUnlockChainAction function in trade.service.ts and simply remove that
statement so sensitive or unnecessary txHash/signature data are not output to
logs.

In `@apps/frontend/components/bridge-ui/TradeAd.tsx`:
- Around line 179-201: Wrap the async call in handleCreateTrade in a try/catch
so mutateAsync failures are caught and reported (like
AddLiquidity.handleCreateAd): await mutateAsync(...) inside try, then call
setSuccessSummary(...) and toggleModal() on success; in catch call the same
toast/error helper used elsewhere (e.g., toast.error or the project’s useToast)
with the caught error to surface the failure to the user and prevent an
unhandled promise rejection; ensure you reference mutateAsync,
setSuccessSummary, toggleModal, and handleCreateTrade when making the change.

In `@apps/frontend/utils/wagmi-config.ts`:
- Around line 2-20: The wagmi config removed hederaTestnet but other code
(chain-icons.ts and AdCard.tsx's explorer_urls) still expect it, causing
writeContractAsync calls to fail without a transport; either fully remove Hedera
references or re-add it to the wagmi configuration. Fix option A: remove
hederaTestnet usages by deleting Hedera entries from chain-icons.ts and
remove/guard explorer_urls in AdCard.tsx (references to explorer_urls and any
hedera chainId checks). Fix option B: re-add hederaTestnet into the chainList
and transports passed to createConfig (ensure you import the hederaTestnet
Chain, add it to chainList when appropriate, and provide a corresponding http
transport entry keyed by hederaTestnet.id) so writeContractAsync has a
transport; pick one approach and make the code changes consistently across
chain-icons.ts, AdCard.tsx (explorer_urls), and wagmi-config's createConfig.

---

Nitpick comments:
In `@apps/backend-relayer/src/modules/trades/dto/trade.dto.ts`:
- Around line 31-59: Add per-element string validation to the adCreatorAddress
and bridgerAddress DTO properties: keep the existing `@IsOptional`() and
`@Transform`(...) logic but add `@IsString`({ each: true }) above each property so
class-validator enforces that every array element (and single string) is a
string; apply the same change to bridgerAddress and leave the current Transform
behavior unchanged.

In `@apps/backend-relayer/src/providers/noir/proof.service.ts`:
- Line 19: Replace the hardcoded threads: 4 with a configurable value read from
environment or app config (e.g., process.env.NOIR_THREADS or the existing config
service) inside the same module (proof.service.ts) where the threads option is
set; parse the value to an integer, validate it (>0), and fall back to a safe
default such as os.cpus().length or 4 if missing/invalid. Ensure you
import/require os if using os.cpus(), use Number.parseInt and isNaN checks to
validate, and apply the resulting numeric variable in place of the literal in
the threads option so deployments can tune it via env/config.

In `@apps/backend-relayer/src/providers/stellar/stellar.service.ts`:
- Around line 589-608: The verifyOrderSignature function risks silent drift
because buildStellarUnlockMessage is duplicated; either move the unlock-message
helper into a shared package (e.g., libs/shared) and import it into both apps so
both backend verifyOrderSignature and the frontend use the single source of
truth, or add snapshot tests in both apps that pin the exact serialized output
of buildStellarUnlockMessage for a fixed T_OrderParams fixture so any divergence
fails CI; additionally harden verifyOrderSignature by adding an early
input-shape guard in verifyOrderSignature (reject overly long or clearly
non-hex/base64 signature strings before calling Buffer.from) while keeping the
existing sigBytes.length !== 64 check.

In `@apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts`:
- Around line 5-33: The backend buildStellarUnlockMessage implementation
duplicates the frontend builder (apps/frontend/utils/stellar/unlock-message.ts),
risking drift; either extract the JSON builder into a shared utility/types
package and have both import that single function (reference:
buildStellarUnlockMessage) or, if sharing is infeasible, add explicit
cross-reference comments in both files pointing to each other and add a snapshot
test that imports both builders (backend's buildStellarUnlockMessage and the
frontend's equivalent) and asserts their outputs are byte-identical for a fixed
T_OrderParams/ITradeParams fixture (use a deterministic fixture including
orderHash, salt, decimals, amounts, chain/token fields).

In `@apps/frontend/app/`(app)/(auth-protected)/orders/page.tsx:
- Around line 29-42: The linkedAddresses array is recreated on every render
causing unstable references for useGetAllTrades' params; wrap the computation of
linkedAddresses (derived from useCurrentUser()?.wallets) in React.useMemo so it
returns a stable array identity across renders, then pass that memoized
linkedAddresses into useGetAllTrades (the adCreatorAddress/bridgerAddress args)
to prevent unnecessary refetches and ensure consistent query keys.

In `@apps/frontend/app/`(app)/bridge/page.tsx:
- Around line 17-22: Remove the dead empty paragraph tag that follows the Link
in the bridge page component: locate the block containing the text "Unlocking
the next generation of cross-chain bridging" and the Link component (the JSX
with Link href="/" and text "create ad") and delete the trailing empty <p></p>
element so there is no blank paragraph rendered.

In `@apps/frontend/app/globals.css`:
- Around line 159-164: The hover-only underline/color affordance on
.signal-line-link > a:hover and .signal-line-link > a:hover::after should also
be applied for keyboard focus: add matching .signal-line-link > a:focus-visible
and .signal-line-link > a:focus-visible::after rules that set color:
var(--color-primary) and transform: scaleX(1) respectively (and ensure any
transition/outline handling matches the hover behavior) so keyboard users
receive the same visual cue.

In `@apps/frontend/components/bridge-ui/CreateOrderSuccessModal.tsx`:
- Around line 91-96: The modal currently calls moment() during render in
CreateOrderSuccessModal which yields a drifting "Submitted" time; change the
data flow so the actual submit timestamp is captured when setSuccessSummary is
called and stored on the CreatedOrderSummary object (add a submittedAt field of
type string|number), then update CreateOrderSuccessModal to read and format
summary.submittedAt (using moment(summary.submittedAt)) instead of calling
moment() directly so the displayed timestamp is stable and reflects the real
submit time.

In `@apps/frontend/utils/stellar/balance.ts`:
- Around line 78-81: The narrow cast on the result of scValToNative risks losing
type info; update the handling in the simulate path (where success.result.retval
is converted) so that the value from scValToNative is widened (e.g. treat native
as bigint | number | string | boolean) or remove the cast and add a small
runtime guard before calling BigInt(native) that accepts
bigint/number/string/boolean and converts appropriately; locate the conversion
around the variable native (from scValToNative(success.result.retval)) and the
BigInt(native) call (in this file) and implement the widened type or guard
there.

In `@apps/frontend/utils/stellar/unlock-message.ts`:
- Around line 5-29: Add a defensive sync note and a cross-implementation
snapshot test: put a succinct comment inside buildStellarUnlockMessage (e.g.,
"// MUST stay in sync with backend unlock-message.ts — any field/order
difference breaks ed25519 verification") to tie it to
apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts, and add a
fixture-based test that runs frontend buildStellarUnlockMessage and the backend
equivalent on the same test data and asserts exact byte-for-byte equality of the
JSON output to catch any future field/order/serialization drift.

In `@scripts/relayer-e2e/flows/trade-lifecycle.ts`:
- Around line 291-301: The code re-implements the Stellar signed-message digest
instead of using the shared helper; replace the manual creation of bridgerDigest
with a call to the canonical helper stellarSignedMessageDigest(bridgerMessage)
(import that function alongside buildStellarUnlockMessage) and pass its return
value into bridgerStellar.sign so the e2e signing preimage matches production
verification (update imports to include stellarSignedMessageDigest and remove
the Buffer/sha256 manual logic around bridgerDigest).
🪄 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: 2311be28-f0a3-4a6f-9dda-6a559bf8e04b

📥 Commits

Reviewing files that changed from the base of the PR and between c90f656 and d386e2f.

⛔ Files ignored due to path filters (2)
  • apps/frontend/app/favicon.ico is excluded by !**/*.ico
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • apps/backend-relayer/src/chain-adapters/adapters/chain-adapter.abstract.ts
  • apps/backend-relayer/src/chain-adapters/adapters/evm-chain-adapter.ts
  • apps/backend-relayer/src/chain-adapters/adapters/stellar-chain-adapter.ts
  • apps/backend-relayer/src/modules/trades/dto/trade.dto.ts
  • apps/backend-relayer/src/modules/trades/trade.service.ts
  • apps/backend-relayer/src/providers/noir/proof.service.ts
  • apps/backend-relayer/src/providers/stellar/stellar.service.ts
  • apps/backend-relayer/src/providers/stellar/utils/signing.ts
  • apps/backend-relayer/src/providers/stellar/utils/unlock-message.ts
  • apps/backend-relayer/test/setups/mock-chain-adapter.ts
  • apps/frontend/app/(app)/(auth-protected)/faucet/page.tsx
  • apps/frontend/app/(app)/(auth-protected)/home/page.tsx
  • apps/frontend/app/(app)/(auth-protected)/orders/page.tsx
  • apps/frontend/app/(app)/bridge/page.tsx
  • apps/frontend/app/globals.css
  • apps/frontend/components/ad-management-ui/AddLiquidity.tsx
  • apps/frontend/components/bridge-ui/CreateOrderSuccessModal.tsx
  • apps/frontend/components/bridge-ui/TradeAd.tsx
  • apps/frontend/components/landing/Approach.tsx
  • apps/frontend/components/landing/Features.tsx
  • apps/frontend/components/landing/Hero-Alt.tsx
  • apps/frontend/components/landing/Hero.tsx
  • apps/frontend/components/landing/LandingHeader-Alt.tsx
  • apps/frontend/components/landing/ReImagining.tsx
  • apps/frontend/components/orders/OrdersTable.tsx
  • apps/frontend/components/shared/Header.tsx
  • apps/frontend/hooks/useTrades.ts
  • apps/frontend/package.json
  • apps/frontend/services/api.instance.ts
  • apps/frontend/types/trades.ts
  • apps/frontend/utils/stellar/balance.ts
  • apps/frontend/utils/stellar/unlock-message.ts
  • apps/frontend/utils/wagmi-config.ts
  • scripts/relayer-e2e/flows/trade-lifecycle.ts

Comment thread apps/backend-relayer/src/modules/trades/trade.service.ts
Comment thread apps/frontend/app/(app)/(auth-protected)/faucet/page.tsx
Comment thread apps/frontend/components/bridge-ui/TradeAd.tsx
Comment thread apps/frontend/components/orders/OrdersTable.tsx
Comment thread apps/frontend/components/shared/Header.tsx Outdated
Comment thread apps/frontend/components/shared/Header.tsx
Comment thread apps/frontend/services/api.instance.ts
@JoE11-y JoE11-y merged commit 1df8e7c into main Apr 18, 2026
5 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