Skip to content

fix: chainflip swap explorer link and solana compute budget#12178

Open
gomesalexandre wants to merge 7 commits intodevelopfrom
fix/chainflip-swap-link
Open

fix: chainflip swap explorer link and solana compute budget#12178
gomesalexandre wants to merge 7 commits intodevelopfrom
fix/chainflip-swap-link

Conversation

@gomesalexandre
Copy link
Contributor

@gomesalexandre gomesalexandre commented Mar 16, 2026

Description

Two fixes for Chainflip swaps:

1. Wrong explorer link in action center (#11899)

"View Transaction" linked to scan.chainflip.io/swaps/<broker_channel_id> (e.g. /swaps/47079) instead of the real Chainflip network swap ID (e.g. /swaps/1403671). The broker deposit channel ID was stored at swap creation time, but the real swap ID only becomes available from the status API after deposit detection.

Fix: extract the real swapId from the status-by-id response and use it for the explorer link. Before deposit detection (when swapId isn't in the response yet), fall back to the regular chain explorer link instead of a wrong Chainflip scan link.

2. SOL -> USDT(SOL) via Chainflip fails with "Computational budget exceeded"

Chainflip deposit addresses are program-owned accounts that need more compute than a regular SOL transfer. The simulated compute units were too low, causing broadcast failure.

Fix: apply a 50k floor with 1.6x margin (matching Jupiter's recommendation) for Chainflip Solana transactions.

Issue (if applicable)

closes #11899

Risk

Low - read-only status field extraction for explorer links, and compute budget increase for Solana Chainflip txs (higher budget = slightly higher fee but tx actually lands).

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Chainflip swaps: explorer links in action center, and Solana sell-side transaction broadcast.

Testing

Engineering

Swap link fix:

  1. Execute any Chainflip swap (e.g. ETH -> WBTC)
  2. While swap is pending (before deposit detected), "View Transaction" should show etherscan link (not a wrong Chainflip scan link)
  3. After deposit is detected by Chainflip, "View Transaction" should update to the correct scan.chainflip.io/swaps/<real_swap_id>

Compute budget fix:

  1. Execute SOL -> USDT(SOL) via Chainflip (min ~0.11 SOL)
  2. Transaction should broadcast successfully (previously failed with "Computational budget exceeded")

Operations

  • Chainflip swap "View Transaction" links to the correct swap on scan.chainflip.io
  • SOL -> USDT via Chainflip broadcasts and completes successfully

Screenshots (if applicable)

Swap link fix

https://jam.dev/c/3ab56ba6-2ee7-44ab-bfdd-626d27afe313

SOL compute budget fix

Summary by CodeRabbit

  • New Features

    • Added Chainflip swap ID tracking across trade flows for improved transaction visibility and metadata propagation.
    • Broader support for swap ID formats (number or string) to improve cross-service compatibility.
    • Safer Solana transaction handling: boosted compute-unit calculation and fee adjustment to reduce execution failures.
  • Bug Fixes

    • More robust status handling with null-safe checks to ensure reliable trade state updates.

gomes-bot and others added 2 commits March 16, 2026 18:08
The status-by-id endpoint returns the real Chainflip network swap ID
in status.swapId, but we were using the broker deposit channel ID
from swap creation for the scan.chainflip.io link. The channel ID
points to a completely different (or nonexistent) swap.

Now we extract the real swapId from the status response and only
use it for the explorer link once available. Before deposit detection
(when swapId isn't in the response yet), we fall back to the regular
chain explorer link instead of a wrong Chainflip scan link.

closes #11899

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chainflip deposit addresses are program-owned accounts that require
more compute than a regular SOL transfer. The simulated compute units
were too low, causing "Computational budget exceeded" on broadcast.

Apply a 50k floor with 1.6x margin to match Jupiter's recommendation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gomesalexandre gomesalexandre requested a review from a team as a code owner March 16, 2026 18:13
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Walkthrough

Destructures and propagates Chainflip swap native IDs (swapId → chainflipSwapId) through swapper, types, trade-execution, and action-center flows; Solana compute units/fee calculations apply a ceil(max(simulated, 50_000) * 1.6) boost and computeUnitLimit/fee returns are stringified.

Changes

Cohort / File(s) Summary
Chainflip swapper endpoints & types
packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts, packages/swapper/src/swappers/ChainflipSwapper/types.ts
Destructure swapId from status, add optional swapId?: string to ChainFlipStatus, include chainflipSwapId: swapId ?? undefined in Pending/Confirmed payloads. Compute boosted Solana computeUnits = ceil(max(existing, 50_000) * 1.6) and store/return computeUnitLimit as a string.
Solana fee computation
packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts
Mirror compute-budget boost in fee calc: compute boostedUnits, ratio = boostedUnits / simulatedUnits (or 1), and return boosted tx fee as a string.
Core types & public store
packages/swapper/src/types.ts, packages/public-api/src/lib/quoteStore.ts
Widen Chainflip ID types to `number
Trade execution & UI hooks
src/lib/tradeExecution.ts, src/components/MultiHopTrade/.../useTradeExecution.tsx, src/components/MultiHopTrade/.../useChainflipStreamingProgress.tsx
Propagate chainflipSwapId from swapper.checkTradeStatus through fetchTradeStatus and execution events; update swap upsert/update logic to trigger on presence of chainflipSwapId. Broaden null checks (== null / != null) and accept `number
Action center subscriber & notification linking
src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
Add chainflipSwapId from status; resolve and prefer real native ID when building tx links; use chainflipSwapId?.toString() when constructing links and merge into swap action metadata on updates/terminal states.
Misc UI/type widening
src/components/..., other referenced files
Minor null-check and type widenings to accept string IDs; no control-flow changes beyond propagation of chainflipSwapId.

Sequence Diagram

sequenceDiagram
    participant API as Chainflip API
    participant Swapper as ChainflipSwapper\n(endpoints.ts)
    participant Types as Types / QuoteStore
    participant Exec as tradeExecution.ts
    participant Subscriber as useSwapActionSubscriber
    participant UI as Action Center / UI

    API->>Swapper: respond to checkTradeStatus() with { status: { swapEgress, swapId, ... } }
    Swapper->>Swapper: compute boosted computeUnits = ceil(max(simulatedUnits, 50000) * 1.6)\nstringify computeUnitLimit\ncompute boosted fee via ratio
    Swapper->>Exec: return TradeStatus including chainflipSwapId (swapId ?? undefined)
    Exec->>Subscriber: emit status event with chainflipSwapId
    Subscriber->>Subscriber: resolve/merge chainflipSwapId into swap.metadata
    Subscriber->>UI: build tx link using chainflipSwapId?.toString()
    UI->>API: user views scan.chainflip.io/swaps/<chainflipSwapId>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐇 I hopped through types and endpoints with glee,
Found the true swapId and set the links free.
I boosted Solana compute—ceil and stringify,
Now tx links land proper — hop, hop, hi! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the two main fixes: explorer link correction for Chainflip swaps and Solana compute budget increases, matching the changeset content.
Linked Issues check ✅ Passed The PR implements the required fixes from issue #11899: propagating the real Chainflip nativeId (swapId) through the codebase and applying compute budget margins to Solana transactions, with type updates to support the new chainflipSwapId field.
Out of Scope Changes check ✅ Passed All changes are scoped to the two stated objectives: type definitions for chainflipSwapId propagation and compute budget adjustments for Solana Chainflip deposits. No extraneous modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/chainflip-swap-link
📝 Coding Plan
  • Generate coding plan for human review comments

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
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/lib/tradeExecution.ts (1)

91-119: ⚠️ Potential issue | 🟠 Major

chainflipSwapId is fetched but never emitted in status events.

fetchTradeStatus() now returns chainflipSwapId, but _execWalletAgnostic() drops it when constructing StatusArgs. This prevents useTradeExecution from receiving and persisting the resolved Chainflip swap id during polling.

💡 Minimal fix
           const {
             status,
             message,
             buyTxHash,
             relayerTxHash,
             relayerExplorerTxLink,
             actualBuyAmountCryptoBaseUnit,
+            chainflipSwapId,
           } = await queryClient.fetchQuery({
             queryKey: tradeStatusQueryKey(swap.id, updatedSwap.sellTxHash),
             queryFn: () =>
               fetchTradeStatus({
@@
           const payload: StatusArgs = {
             stepIndex,
             status,
             message,
             buyTxHash,
             relayerTxHash,
             actualBuyAmountCryptoBaseUnit,
+            chainflipSwapId,
           }

Also applies to: 268-315

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

In `@src/lib/tradeExecution.ts` around lines 91 - 119,
fetchTradeStatus()/swapper.checkTradeStatus now returns chainflipSwapId but
_execWalletAgnostic constructs StatusArgs without it, so the status events never
carry the Chainflip swap id; update _execWalletAgnostic (and the other similar
block around the 268-315 range) to include chainflipSwapId in the StatusArgs you
emit/return so the value flows through StatusArgs -> status events ->
useTradeExecution for persistence; look for references to StatusArgs,
_execWalletAgnostic, fetchTradeStatus/checkTradeStatus, and ensure
chainflipSwapId is added to the returned object and any emitted event payloads.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts`:
- Around line 238-239: The code is converting Chainflip's swapId (a u64 provided
as a string) to Number, which risks precision loss; update the type for
chainflipSwapId in packages/swapper/src/types.ts to accept string and stop
coercing swapId to Number: keep the destructured status: { swapEgress, swapId }
as a string, remove the Number(...) wrappers in the return statements (the three
places that convert swapId to Number in endpoints.ts), and ensure any callers
that build the status URL use the string value unchanged (refer to the swapId
symbol and the functions that return it).

---

Outside diff comments:
In `@src/lib/tradeExecution.ts`:
- Around line 91-119: fetchTradeStatus()/swapper.checkTradeStatus now returns
chainflipSwapId but _execWalletAgnostic constructs StatusArgs without it, so the
status events never carry the Chainflip swap id; update _execWalletAgnostic (and
the other similar block around the 268-315 range) to include chainflipSwapId in
the StatusArgs you emit/return so the value flows through StatusArgs -> status
events -> useTradeExecution for persistence; look for references to StatusArgs,
_execWalletAgnostic, fetchTradeStatus/checkTradeStatus, and ensure
chainflipSwapId is added to the returned object and any emitted event payloads.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ba12dcff-c33d-4458-a43b-515863920290

📥 Commits

Reviewing files that changed from the base of the PR and between 1ef75b6 and aac2897.

📒 Files selected for processing (6)
  • packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts
  • packages/swapper/src/swappers/ChainflipSwapper/types.ts
  • packages/swapper/src/types.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
  • src/hooks/useActionCenterSubscribers/useSwapActionSubscriber.tsx
  • src/lib/tradeExecution.ts

swapId is a u64 on-chain, can exceed JS Number.MAX_SAFE_INTEGER.
Remove Number() coercion from status response, widen type to
number | string to accept both SDK (number) and status API (string).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts`:
- Around line 172-184: The fee-quoting path must mirror the boosted compute
budget used in getUnsignedSolanaTransaction(); in getSolanaTransactionFees()
compute the same computeUnits value (e.g., computeUnits =
Math.ceil(Math.max(Number(fast.chainSpecific.computeUnits), 50_000) * 1.6)) or
otherwise apply the same floor and 1.6 multiplier, and use that adjusted
computeUnitLimit when deriving the SOL fee (instead of returning the original
fast.txFee from the unadjusted simulation) so the returned fee matches the
increased compute-unit limit used in
buildSendApiTransaction/getUnsignedSolanaTransaction.

In
`@src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx`:
- Around line 26-29: The guard that treats swapId as falsy should be changed to
a nullish check so numeric 0 remains valid: in getChainflipStreamingSwap (and
the useQuery gate inside useChainflipStreamingProgress) replace the truthy
checks like `if (!swapId)` / `if (!queryEnabled)` with explicit null/undefined
checks using `swapId == null` / `swapId != null` (or the inverse) so both
numeric 0 and string IDs are accepted while still excluding null/undefined.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 512f3b9c-e48c-42ca-9c15-d8e6942546fd

📥 Commits

Reviewing files that changed from the base of the PR and between aac2897 and a9dbf0a.

📒 Files selected for processing (4)
  • packages/public-api/src/lib/quoteStore.ts
  • packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts
  • packages/swapper/src/types.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx

…Id checks

- getSolanaTransactionFees now mirrors the same 1.6x compute unit boost
  as getUnsignedSolanaTransaction to avoid underquoting fees
- Use nullish checks (== null / != null) for chainflipSwapId since 0
  is a valid u64 swap ID but falsy in JS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@NeOMakinG
Copy link
Collaborator

⚠️ QA Blocked: Cannot test locally - TypeScript compilation fails with errors related to chainflipSwapId property not existing on types. The type definitions in packages/swapper/src/types.ts may need updating.

Errors:

  • packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts:244 - Property 'swapId' does not exist
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:264 - Property 'chainflipSwapId' does not exist on type 'StatusArgs'
  • src/lib/tradeExecution.ts:91 - Property 'chainflipSwapId' does not exist on type 'TradeStatus'

Please ensure the type definitions are in sync with the implementation.

@gomesalexandre
Copy link
Contributor Author

⚠️ QA Blocked: Cannot test locally - TypeScript compilation fails with errors related to chainflipSwapId property not existing on types. The type definitions in packages/swapper/src/types.ts may need updating.

Errors:

  • packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts:244 - Property 'swapId' does not exist
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:264 - Property 'chainflipSwapId' does not exist on type 'StatusArgs'
  • src/lib/tradeExecution.ts:91 - Property 'chainflipSwapId' does not exist on type 'TradeStatus'

Please ensure the type definitions are in sync with the implementation.

bad bot ser pls pull @NeOMakinG

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.

Caution

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

⚠️ Outside diff range comments (1)
packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts (1)

223-225: ⚠️ Potential issue | 🟠 Major

Use a nullish guard for chainflipSwapId (Line 224), not a truthy guard.

if (!chainflipSwapId) rejects valid 0 swap IDs. This can incorrectly throw for a valid u64 ID. Use == null instead.

🔧 Proposed fix
-    if (!chainflipSwapId) throw Error(`chainflipSwapId is required`)
+    if (chainflipSwapId == null) throw Error(`chainflipSwapId is required`)

Based on learnings: In packages/swapper/src/swappers/ChainflipSwapper, chainflipSwapId intentionally uses number | string, and 0 is valid while string swap IDs must flow without coercion.

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

In `@packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts` around lines 223
- 225, The guard for chainflipSwapId currently uses a truthy check which will
reject valid numeric IDs like 0; update the validation to use a nullish check
(chainflipSwapId == null) so only null or undefined cause the Error, and keep
the variable type as number | string so string IDs pass without coercion—locate
the check around the chainflipSwapId declaration in endpoints.ts and replace the
truthy guard with a nullish guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts`:
- Around line 223-225: The guard for chainflipSwapId currently uses a truthy
check which will reject valid numeric IDs like 0; update the validation to use a
nullish check (chainflipSwapId == null) so only null or undefined cause the
Error, and keep the variable type as number | string so string IDs pass without
coercion—locate the check around the chainflipSwapId declaration in endpoints.ts
and replace the truthy guard with a nullish guard.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 31bfc8c5-45b1-4d99-bb30-0ed863404248

📥 Commits

Reviewing files that changed from the base of the PR and between a9dbf0a and 98fa43f.

📒 Files selected for processing (2)
  • packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx

0 is a valid u64 swap ID but falsy in JS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gomesalexandre
Copy link
Contributor Author

Re: outside-diff comment on line 224 (checkTradeStatus nullish guard) - dis tackled, using == null now. @coderabbitai

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

Tip

For best results, initiate chat on the files or code changes.

@gomesalexandre Thanks for the confirmation! Using == null is indeed the right approach here — 0 is a valid u64 swap ID and would be incorrectly discarded by a falsy check. ✅


✏️ Learnings added
Learnt from: gomesalexandre
URL: https://github.com/shapeshift/web/pull/12178

Timestamp: 2026-03-16T21:35:02.138Z
Learning: In packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts (and related files like src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx), nullish checks (`== null` / `!= null`) MUST be used for `chainflipSwapId` instead of falsy checks, because `0` is a valid u64 swap ID that is falsy in JavaScript. Using `if (!chainflipSwapId)` would incorrectly discard a valid swap ID of `0`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11335
File: packages/swapper/src/swappers/CetusSwapper/endpoints.ts:66-68
Timestamp: 2025-12-09T21:06:15.748Z
Learning: In packages/swapper/src/swappers/CetusSwapper/endpoints.ts, gomesalexandre is comfortable with throwing errors directly in getUnsignedSuiTransaction and similar transaction preparation methods, rather than using the Result pattern. The Result pattern with makeSwapErrorRight/TradeQuoteError is primarily for the main swapper API methods (getTradeQuote, getTradeRate), while helper/preparation methods can use throws.

Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-11-24T21:20:17.804Z
Learning: Applies to **/swapper{s,}/**/*.{ts,tsx} : ALWAYS use `makeSwapErrorRight` for swapper errors with `TradeQuoteError` enum for error codes and provide detailed error information

Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/**/*.ts : Avoid side effects in swap logic; ensure swap methods are deterministic and stateless

Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) for all code in the Swapper system

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 12178
File: packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts:238-239
Timestamp: 2026-03-16T18:38:36.156Z
Learning: In packages/swapper/src/swappers/ChainflipSwapper, `chainflipSwapId` intentionally uses a `number | string` union type. The Chainflip SDK (`swapResponse.id`) returns a `number`, while the status API (`status.swapId`) returns a `string` representing a u64. The `Number()` coercion must NOT be applied to the status API value because u64 can exceed JavaScript's `Number.MAX_SAFE_INTEGER` (2^53-1), causing precision loss. The string is kept as-is and flows directly into URL parameters and metadata.

Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterBuyAssetsBySellAssetId method to filter assets by supported chain IDs in the buy property

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx:0-0
Timestamp: 2025-09-12T10:44:46.723Z
Learning: gomesalexandre dismissed a clipboard error handling suggestion in PR `#10461` for SendTransactionContent.tsx, demonstrating that the current navigator.clipboard.writeText implementation works as expected and preferring to keep it simple without additional try/catch error handling.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 12111
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:433-444
Timestamp: 2026-03-07T14:20:48.662Z
Learning: In shapeshift/web, thrown Error messages for runtime invariant violations in `src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx` and `src/lib/tradeExecution.ts` are intentionally hardcoded English strings (e.g., `throw new Error('Wallet does not support ...')`). This is an established convention for developer-facing invariant errors, not user-facing copy — they are not subject to i18n/translation key requirements. Broadening i18n coverage for the trade execution error boundary layer is a separate, larger concern.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10139
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx:109-115
Timestamp: 2025-07-29T15:04:28.083Z
Learning: In src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx, the component is used under an umbrella that 100% of the time contains the quote, making the type assertion `activeTradeQuote?.steps[currentHopIndex] as TradeQuoteStep` safe. Adding conditional returns before hooks would violate React's Rules of Hooks.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10985
File: packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx:130-141
Timestamp: 2025-11-03T05:46:24.190Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx, gomesalexandre prefers "let it crash" approach when Portals returns zero outputAmount or 100% buffer causing division by zero, rather than adding defensive guards to surface zero quotes. He wants to fail fast with exceptions that bubble up to the try/catch wrapper, surfacing upstream data issues rather than masking them with defensive programming.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10219
File: src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx:175-180
Timestamp: 2025-08-11T09:45:51.174Z
Learning: gomesalexandre prefers truthy checks over explicit boolean comparisons (e.g., `walletSupportsSellAssetChain` instead of `walletSupportsSellAssetChain === true`) when dealing with tri-state values (boolean | null) in TypeScript, as the falsy behavior for null/undefined is intentional and acceptable.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx:41-41
Timestamp: 2025-08-08T11:40:55.734Z
Learning: In MultiHopTrade confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx and related hooks), there is only one active trade per flow. Because of this, persistent (module/Redux) dedupe for QuotesReceived in useTrackTradeQuotes is not necessary; the existing ref-based dedupe is acceptable.

Learnt from: premiumjibles
Repo: shapeshift/web PR: 10215
File: src/components/MultiHopTrade/hooks/useGetTradeRateInput.ts:65-67
Timestamp: 2025-08-10T21:09:25.643Z
Learning: In the MultiHopTrade components, `selectInputBuyAsset` and `selectInputSellAsset` selectors from `tradeInputSlice` always return defined values because they have default values in the initial state (BTC for buyAsset, ETH for sellAsset, with fallback to defaultAsset). Null checks for these assets are unnecessary when using these selectors.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx:108-111
Timestamp: 2025-08-22T12:58:26.590Z
Learning: In the RFOX GenericTransactionDisplayType flow in src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx, the txHash is always guaranteed to be present according to NeOMakinG, so defensive null checks for txLink are not needed in this context.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11281
File: packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts:98-106
Timestamp: 2025-12-04T11:05:01.146Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts, getSquidTrackingLink should return blockchain explorer links (using Asset.explorerTxLink) rather than API endpoints. For non-GMP Squid swaps: return source chain explorer link with sourceTxHash when pending/failed, and destination chain explorer link with destinationTxHash when confirmed.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11170
File: patches/@shapeshiftoss+bitcoinjs-lib+7.0.0-shapeshift.0.patch:9-19
Timestamp: 2025-11-25T21:43:10.838Z
Learning: In shapeshift/web, gomesalexandre will not expand PR scope to fix latent bugs in unused API surface (like bitcoinjs-lib patch validation methods) when comprehensive testing proves the actual used code paths work correctly, preferring to avoid costly hdwallet/web verdaccio publish cycles and full regression testing for conceptual issues with zero runtime impact.

Learnt from: gomes-bot
Repo: shapeshift/web PR: 12024
File: src/pages/ChainflipLending/Pool/components/Deposit/DepositConfirm.tsx:220-225
Timestamp: 2026-02-24T17:33:14.888Z
Learning: In Chainflip Lending PoC (src/pages/ChainflipLending), gomesalexandre prefers to keep raw error messages from the deposit machine context displayed directly in the UI for debugging purposes, deferring user-friendly error message mapping to a future improvement rather than implementing it during initial development.

Learnt from: gomes-bot
Repo: shapeshift/web PR: 12024
File: src/lib/chainflip/rpc.ts:59-81
Timestamp: 2026-02-24T17:32:50.105Z
Learning: In src/lib/chainflip/rpc.ts, the chainflipRpc wrapper is intentionally kept thin without defensive null/undefined checks on result. Downstream consumers handle edge cases (e.g., cf_free_balances returns `{}` for non-existent accounts) with Array.isArray guards at the call site, rather than adding validation in the RPC layer.

Learnt from: gomes-bot
Repo: shapeshift/web PR: 12024
File: src/lib/chainflip/constants.ts:75-81
Timestamp: 2026-02-24T17:32:38.362Z
Learning: In src/lib/chainflip/constants.ts, FLIP intentionally appears in CHAINFLIP_LENDING_ASSET_IDS_BY_ASSET but is excluded from CHAINFLIP_LENDING_ASSET_BY_ASSET_ID. The reverse mapping (CHAINFLIP_LENDING_ASSET_BY_ASSET_ID) is specifically for lending-enabled assets (BTC, ETH, SOL, USDC, USDT). FLIP is only used for account funding via the Gateway contract, not as a lending pool asset.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 12111
File: packages/swapper/src/swappers/BebopSwapper/utils/fetchFromBebop.ts:208-224
Timestamp: 2026-03-07T14:20:46.655Z
Learning: In packages/swapper/src/swappers/BebopSwapper/utils/fetchFromBebop.ts, the shared Solana fetcher `fetchBebopSolanaQuote` always sends `gasless=true` in its query params. The Bebop Solana API guarantees `QUOTE_SUCCESS` status and a `solana_tx` field in responses when `gasless=true` is used, regardless of whether the taker/receiver address is a real address or a dummy address (BEBOP_SOLANA_DUMMY_ADDRESS). The `QUOTE_INDIC_ROUTE` status only occurs with `gasless=false&skip_validation=true`, which is not used. Therefore, enforcing `status === 'QUOTE_SUCCESS'` and `solana_tx` presence in the shared fetcher is correct and does not incorrectly block the rate/price path.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:133-137
Timestamp: 2025-09-12T10:15:10.389Z
Learning: gomesalexandre has identified that EIP-712 domain chainId should be preferred over request context chainId for accuracy in WalletConnect dApps structured signing flows. The domain chainId from the parsed message is more specific and accurate than the general request context, especially for asset resolution and network-specific operations.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10985
File: packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.ts:0-0
Timestamp: 2025-11-03T22:31:30.786Z
Learning: In packages/swapper/src/swappers/PortalsSwapper, the rate and quote files intentionally use different approaches for calculating buyAmountBeforeSlippageCryptoBaseUnit: getPortalsTradeRate.tsx uses minOutputAmount / (1 - buffer) for conservative estimates, while getPortalsTradeQuote.ts uses outputAmount / (1 - buffer) for final quote display. This difference is validated by on-chain simulation testing and is intentional.

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

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.

Caution

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

⚠️ Outside diff range comments (1)
packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts (1)

32-33: ⚠️ Potential issue | 🟠 Major

Use nullish checks for all chainflipSwapId guards.

Lines 32, 72, 108, 132, 158, 201 still use falsy checks (!chainflipSpecific?.chainflipSwapId) and will incorrectly reject valid chainflipSwapId = 0 (a valid u64 value). Line 224 is already correct with chainflipSwapId == null.

Replace all falsy checks with nullish checks:

Proposed fix
-    if (!chainflipSpecific?.chainflipSwapId) throw Error('Missing swap id')
+    if (chainflipSpecific?.chainflipSwapId == null) throw Error('Missing swap id')

Apply to lines 32, 72, 108, 132, 158, 201.

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

In `@packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts` around lines 32
- 33, Replace all falsy guards that use "!chainflipSpecific?.chainflipSwapId"
with nullish checks that detect only null/undefined (e.g.
"chainflipSpecific?.chainflipSwapId == null") so a valid 0 value is not
rejected; update every occurrence of the pattern involving the chainflipSpecific
variable and its chainflipSwapId property (the checks at the top-level guards in
endpoints.ts) to use "== null" (or "=== undefined" if you prefer explicitness)
before throwing the error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts`:
- Around line 32-33: Replace all falsy guards that use
"!chainflipSpecific?.chainflipSwapId" with nullish checks that detect only
null/undefined (e.g. "chainflipSpecific?.chainflipSwapId == null") so a valid 0
value is not rejected; update every occurrence of the pattern involving the
chainflipSpecific variable and its chainflipSwapId property (the checks at the
top-level guards in endpoints.ts) to use "== null" (or "=== undefined" if you
prefer explicitness) before throwing the error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8ca43731-a430-482e-8a58-873489977749

📥 Commits

Reviewing files that changed from the base of the PR and between 98fa43f and 3e28e7a.

📒 Files selected for processing (1)
  • packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts

Copy link
Collaborator

@NeOMakinG NeOMakinG left a comment

Choose a reason for hiding this comment

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

QA Code Review ✅

PR: fix: chainflip swap explorer link and solana compute budget

Code Analysis

1. Chainflip Swap ID Fix

  • Changed chainflipSwapId type from number to number | string for flexibility
  • Now extracts real swapId from Chainflip API status response
  • Propagates swap ID through status checks → trade execution → swap metadata
  • Fixes broken explorer links by using actual swap ID

2. Solana Compute Budget Fix

  • Increased compute units by 1.6x multiplier with 50,000 minimum floor
  • Prevents "Computational budget exceeded" errors on Chainflip deposit addresses
  • Fee estimation updated to match actual compute budget

3. Testing
✅ App builds and loads successfully
✅ Code changes are correct and comprehensive

Recommendation: Approve - Both fixes are well-implemented and address real user issues.

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.

Chainflip giving old TXID in notification centre

2 participants