Skip to content

feat: add Stargate V2 swapper#12262

Open
swdiscordia wants to merge 13 commits intoshapeshift:developfrom
swdiscordia:feat/stargate-swapper
Open

feat: add Stargate V2 swapper#12262
swdiscordia wants to merge 13 commits intoshapeshift:developfrom
swdiscordia:feat/stargate-swapper

Conversation

@swdiscordia
Copy link
Copy Markdown

@swdiscordia swdiscordia commented Apr 8, 2026

Description

Integrates Stargate V2 as a new cross-chain swapper. Stargate is a liquidity bridge protocol built on LayerZero that enables native asset transfers across chains without wrapped tokens.

Supports cross-chain swaps of USDC, USDT, ETH and other assets between Ethereum, Arbitrum, Optimism, Base, and other Stargate-supported chains.

Issue (if applicable)

closes #

Risk

Low — new swapper integration, entirely behind VITE_FEATURE_STARGATE_SWAP feature flag. No changes to existing swap flows or other swappers.

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

Stargate V2 bridge contracts only. ERC20 approval + send() call to Stargate pool contracts. No changes to existing swappers or EVM flows.

Testing

Engineering

  1. Set VITE_FEATURE_STARGATE_SWAP=true in .env.development
  2. Connect a native wallet with USDC on Ethereum
  3. Navigate to Trade, select USDC (Ethereum) → USDC (Arbitrum One)
  4. Enter an amount — verify Stargate appears as Protocol with a valid quote
  5. Click Preview Trade → verify "Swap via Stargate in ~1m"
  6. Confirm and Trade → Approve USDC → Sign & Swap
  7. Verify success toast: "Your swap of X USDC to Y USDC is complete."

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

Quote — Protocol: Stargate selected (USDC Ethereum → USDC Arbitrum One)
stargate-quote

Confirm Details — Swap via Stargate in ~1m
stargate-confirm

Swap complete
stargate-complete

On-chain verification

Summary by CodeRabbit

  • New Features

    • Stargate swap integration for cross‑chain quotes, execution, fee estimation, and status checks.
  • UI

    • Swapper selector now displays a Stargate icon.
  • Chores

    • Feature flag VITE_FEATURE_STARGATE_SWAP added (enabled in dev, disabled in prod); preferences wired to toggle it.
  • Security

    • Content Security Policy extended to allow LayerZero Scan endpoints.
  • Tests

    • Unit tests for Stargate quote logic and new e2e fixture for USDC Ethereum→Arbitrum.
  • Assets

    • Added Stargate-related asset metadata for additional chains.

swdiscordia and others added 7 commits April 7, 2026 11:02
Integrate Stargate V2 (LayerZero) as a cross-chain bridge swapper.
- 14 EVM chains supported (ETH, ARB, OP, BASE, POLYGON, BSC, AVAX, etc.)
- On-chain quotes via quoteOFT/quoteSend contract calls
- USDC, USDT, ETH, mETH, EURC asset support
- Transaction status tracking via LayerZero scan API
- Feature-flagged (disabled by default)
- Add VITE_FEATURE_STARGATE_SWAP to .env.development and .env.production
- Remove unused CSP domain from Stargate.ts
- Fix unsafe double cast in fetchStargateTrade
Replace dead scan.layerzero-api.com with working
api-mainnet.layerzero-scan.com for status tracking.
Odos integration is incomplete and unrelated to Stargate. Moving all
Odos references to a dedicated feat/odos-swapper branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@swdiscordia swdiscordia requested a review from a team as a code owner April 8, 2026 12:28
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Stargate cross-chain swapper: feature flag and config, CSP entry, full Stargate swapper implementation (constants, types, ABI helpers, service, endpoints, quote/rate/fee/tx logic, status checks), UI/state wiring, tests, and e2e fixture.

Changes

Cohort / File(s) Summary
Environment & Config
\.env, \.env.development, \.env.production, src/config.ts
Introduce VITE_FEATURE_STARGATE_SWAP (dev=true, prod=false) and validate it in config; minor .env EOF tweak.
CSP Headers
headers/csps/defi/swappers/Stargate.ts, headers/csps/index.ts
Add CSP connect-src for https://api-mainnet.layerzero-scan.com and register it in exported csps.
Swapper Core & Types
packages/swapper/src/types.ts, packages/swapper/src/constants.ts, packages/swapper/src/index.ts
Add SwapperName.Stargate, register Stargate in swappers map, default slippage const, mark auto-slippage unsupported, and re-export Stargate swapper.
Stargate Swapper Module
packages/swapper/src/swappers/StargateSwapper/...
New Stargate module: constants, types, swapper object, stargateApi endpoints, getTradeQuote/getTradeRate, large fetchStargateTrade (encoding/decoding, fee estimation, tx metadata), and related utilities.
ABI Helpers & HTTP Service
packages/swapper/src/swappers/StargateSwapper/utils/helpers.ts, .../stargateService.ts
Add Stargate ABI, encode/decode helpers, encodeSend, and an Axios-based stargateService wrapper.
Swapper Export & Wiring
packages/swapper/src/swappers/StargateSwapper/index.ts, packages/swapper/src/swappers/StargateSwapper/StargateSwapper.ts
Re-export Stargate symbols and export stargateSwapper implementing executeEvmTransaction.
UI & State Management
src/components/.../SwapperIcon/SwapperIcon.tsx, src/state/helpers.ts, src/state/slices/preferencesSlice/preferencesSlice.ts, src/test/mocks/store.ts
Add Stargate icon, include Stargate in cross-account & enabled swappers, add StargateSwap feature flag and test mock flag.
Tests & Fixtures
packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.test.ts, e2e/fixtures/stargate-usdc-eth-to-arb.yaml, e2e/fixtures/wallet-health.yaml
Add comprehensive unit tests for getTradeQuote, new e2e fixture for ETH→Arbitrum USDC Stargate flow, and adjust wallet-health password input step.
Test Data
packages/swapper/src/swappers/utils/test-data/assets.ts
Add Base/Polygon identifiers and multiple Stargate-related Asset exports (USDC/USDT variants, ETH_BASE, MATIC, BSC_USDC) for tests.
Misc docs
AGENTS.md
Add testing/generation and mocking guidance notes.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as UI / Swapper
    participant Api as App API (stargateApi)
    participant Contract as Stargate Contract
    participant EVM as EVM Adapter
    participant LZScan as LayerZero Scan

    User->>UI: Select Stargate & request quote
    UI->>Api: getTradeQuote(input)
    Api->>Contract: quoteOFT & quoteSend (ABI calls)
    Contract-->>Api: quote responses (amounts, fees)
    Api->>EVM: getFees()/estimate gas
    EVM-->>Api: fee estimates
    Api-->>UI: TradeQuote[] (includes stargateTransactionMetadata)

    UI->>Api: getUnsignedEvmTransaction / getEvmTransactionFees
    Api->>EVM: buildCustomApiTx / getFees
    EVM-->>Api: unsigned tx / fees
    Api-->>UI: Unsigned tx / fee data

    UI->>Api: checkTradeStatus(txHash)
    Api->>LZScan: Query LayerZero Scan for message status
    LZScan-->>Api: message status (INFLIGHT/CONFIRMING/DELIVERED/FAILED)
    Api-->>UI: TxStatus (+ optional buyTxHash)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped through bytes and bridged the chain,

Calldata snug, fees counted plain,
Quotes whispered across LayerZero's span,
A tiny rabbit building cross-chain plan,
Stargate opened — hop again!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add Stargate V2 swapper' accurately summarizes the main change—integrating Stargate V2 as a new cross-chain swapper behind a feature flag.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

🧹 Nitpick comments (1)
.env (1)

120-120: Feature flag placement and trailing newline.

Static analysis flagged two minor issues:

  1. VITE_FEATURE_STARGATE_SWAP should be ordered before VITE_FEATURE_STARKNET for alphabetical consistency
  2. Missing blank line at end of file

These are minor formatting nits that don't affect functionality.

🔧 Optional fix for ordering and trailing newline

Move the flag to maintain alphabetical order:

 VITE_FEATURE_ACROSS_SWAP=true
 VITE_FEATURE_DEBRIDGE_SWAP=true
-VITE_FEATURE_STARGATE_SWAP=false
+VITE_FEATURE_STARGATE_SWAP=false
 VITE_FEATURE_USERBACK=true

And ensure a trailing newline at end of file.

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

In @.env at line 120, Move the VITE_FEATURE_STARGATE_SWAP entry so it appears
alphabetically before VITE_FEATURE_STARKNET (i.e., place the line
"VITE_FEATURE_STARGATE_SWAP=false" above the "VITE_FEATURE_STARKNET" variable)
and ensure the .env file ends with a single trailing newline character; update
only ordering and add the final blank line.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env.production:
- Line 12: The VITE_FEATURE_STARGATE_SWAP env var is placed inside the Mixpanel
section causing dotenv-linter ordering errors; move the line defining
VITE_FEATURE_STARGATE_SWAP=false into the feature-flags block (the group where
other VITE_FEATURE_* keys live) so the variable is grouped with other feature
flags and the dotenv-linter ordering issue is resolved.

In
`@packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.ts`:
- Around line 12-29: The early validation Errs for missing addresses should
include a structured TradeQuoteError code and details so callers can distinguish
them; update the two returns that check input.sendAddress and
input.receiveAddress to call makeSwapErrorRight with a TradeQuoteError value
(e.g., TradeQuoteError.MISSING_SEND_ADDRESS and
TradeQuoteError.MISSING_RECEIVE_ADDRESS or a single
TradeQuoteError.MISSING_REQUIRED_ADDRESS) and include a details object naming
the missing field (e.g., { field: 'sendAddress' } / { field: 'receiveAddress'
}); keep using the existing Err wrapper and functions (makeSwapErrorRight, Err)
and only add the code and details properties to the error payload so downstream
callers can inspect error.code and error.details.

In `@packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts`:
- Around line 174-182: The sendParam object currently sets minAmountLD to 0n
which ignores the selected/default slippage; before calling encodeSend() you
must compute minAmountLD = detailDstAmountLD * (1 -
slippageTolerancePercentageDecimal) (rounded down to an integer) and assign that
to sendParam.minAmountLD so the encoded send calldata will revert on fills below
the slippage-protected amount; update the same logic wherever sendParam is
constructed (references: sendParam, minAmountLD, detailDstAmountLD,
slippageTolerancePercentageDecimal, and encodeSend()) to ensure slippage is
applied consistently across all occurrences.

---

Nitpick comments:
In @.env:
- Line 120: Move the VITE_FEATURE_STARGATE_SWAP entry so it appears
alphabetically before VITE_FEATURE_STARKNET (i.e., place the line
"VITE_FEATURE_STARGATE_SWAP=false" above the "VITE_FEATURE_STARKNET" variable)
and ensure the .env file ends with a single trailing newline character; update
only ordering and add the final blank line.
🪄 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: 2d5a00af-084f-461b-8763-03f6ef61b0fd

📥 Commits

Reviewing files that changed from the base of the PR and between 5ef1966 and 1568656.

⛔ Files ignored due to path filters (1)
  • src/components/MultiHopTrade/components/TradeInput/components/SwapperIcon/stargate-icon.png is excluded by !**/*.png
📒 Files selected for processing (23)
  • .env
  • .env.development
  • .env.production
  • headers/csps/defi/swappers/Stargate.ts
  • headers/csps/index.ts
  • packages/swapper/src/constants.ts
  • packages/swapper/src/index.ts
  • packages/swapper/src/swappers/StargateSwapper/StargateSwapper.ts
  • packages/swapper/src/swappers/StargateSwapper/constant.ts
  • packages/swapper/src/swappers/StargateSwapper/endpoints.ts
  • packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.ts
  • packages/swapper/src/swappers/StargateSwapper/getTradeRate/getTradeRate.ts
  • packages/swapper/src/swappers/StargateSwapper/index.ts
  • packages/swapper/src/swappers/StargateSwapper/types.ts
  • packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts
  • packages/swapper/src/swappers/StargateSwapper/utils/helpers.ts
  • packages/swapper/src/swappers/StargateSwapper/utils/stargateService.ts
  • packages/swapper/src/types.ts
  • src/components/MultiHopTrade/components/TradeInput/components/SwapperIcon/SwapperIcon.tsx
  • src/config.ts
  • src/state/helpers.ts
  • src/state/slices/preferencesSlice/preferencesSlice.ts
  • src/test/mocks/store.ts

Comment thread .env.production Outdated
…es, add tests

- Apply slippage to sendParam.minAmountLD before encodeSend() so on-chain fills
  worse than quote+slippage will revert (was hardcoded 0n, ignoring slippage)
- Add TradeQuoteError.InternalError codes to sendAddress/receiveAddress validation
  errors in getTradeQuote so callers can distinguish input errors from route failures
- Move VITE_FEATURE_STARGATE_SWAP into the feature-flags section in .env.production
- Add getTradeQuote.test.ts with 9 test cases covering happy path, error cases,
  slippage application, fee structure, and step metadata

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
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.

🧹 Nitpick comments (3)
packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts (3)

287-293: Consider logging the fee estimation failure.

The catch block silently falls back to a hardcoded gas limit estimate. Per coding guidelines, errors should be logged for debugging, especially when they affect user-visible values (network fees).

♻️ Suggested improvement
       return feeData.networkFeeCryptoBaseUnit
-    } catch {
+    } catch (e) {
+      console.warn('[Stargate] Fee estimation failed, using fallback gas limit', {
+        error: e instanceof Error ? e.message : String(e),
+        sellAsset: sellAsset.assetId,
+      })
       return evm.calcNetworkFeeCryptoBaseUnit({
         ...average,
         supportsEIP1559,
         gasLimit: '500000',
       })
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts`
around lines 287 - 293, The catch block in fetchStargateTrade is swallowing the
fee-estimation error; change it to catch (error) and log the error before
returning the fallback: call your existing logger (e.g., logger.error or
processLogger.error) or console.error with a clear message and include the error
object and context (average, supportsEIP1559) and then return
evm.calcNetworkFeeCryptoBaseUnit({ ...average, supportsEIP1559, gasLimit:
'500000' }).

241-245: Simplify redundant type assertions.

The rawMessagingFee is cast to the same type twice. Consider adding proper return type to decodeQuoteSendResult or cast once.

♻️ Suggested simplification
 const rawMessagingFee = decodeQuoteSendResult(quoteSendResult.data as Hex)
+const typedMessagingFee = rawMessagingFee as { nativeFee: bigint; lzTokenFee: bigint }
 const messagingFee: StargateMessagingFee = {
-  nativeFee: (rawMessagingFee as { nativeFee: bigint; lzTokenFee: bigint }).nativeFee,
-  lzTokenFee: (rawMessagingFee as { nativeFee: bigint; lzTokenFee: bigint }).lzTokenFee,
+  nativeFee: typedMessagingFee.nativeFee,
+  lzTokenFee: typedMessagingFee.lzTokenFee,
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts`
around lines 241 - 245, The code redundantly casts rawMessagingFee twice; update
the decodeQuoteSendResult return type to include { nativeFee: bigint;
lzTokenFee: bigint } or cast its single result once and destructure to build
messagingFee. Locate decodeQuoteSendResult and change its signature to return
the proper typed object, or in fetchStargateTrade.ts cast rawMessagingFee once
(e.g., const { nativeFee, lzTokenFee } = decodeQuoteSendResult(...) as {
nativeFee: bigint; lzTokenFee: bigint }) and then construct the
StargateMessagingFee using those variables instead of repeating the type
assertion.

296-301: Hardcoded gasLimit in metadata is later compared with fee estimation.

While stargateTransactionMetadata.gasLimit is hardcoded to '500000', the executeSwap endpoint extracts this value and compares it against the fee-estimated gasLimit using BigNumber.max(gasLimitFromApi ?? '0', feeData.gasLimit). This ensures the final transaction uses the higher of the two values, mitigating the risk of insufficient gas.

However, estimating gasLimit during the quote phase (when evm.getFees is available) and storing the actual estimate in metadata would be more efficient than hardcoding a fallback value.

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

In `@packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts`
around lines 296 - 301, stargateTransactionMetadata currently hardcodes gasLimit
to '500000'; instead, when evm.getFees is available during quote construction in
fetchStargateTrade, call evm.getFees (or reuse existing fees lookup) to estimate
gas and set stargateTransactionMetadata.gasLimit to that estimated value
(stringified) rather than the fixed '500000', so executeSwap’s
BigNumber.max(gasLimitFromApi ?? '0', feeData.gasLimit) can pick the accurate
higher value; update the metadata assignment that creates
stargateTransactionMetadata (referencing sendCalldata, txValue, contractAddress)
to use the estimated feeData.gasLimit when present and fall back to the previous
hardcoded value only if no estimate exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts`:
- Around line 287-293: The catch block in fetchStargateTrade is swallowing the
fee-estimation error; change it to catch (error) and log the error before
returning the fallback: call your existing logger (e.g., logger.error or
processLogger.error) or console.error with a clear message and include the error
object and context (average, supportsEIP1559) and then return
evm.calcNetworkFeeCryptoBaseUnit({ ...average, supportsEIP1559, gasLimit:
'500000' }).
- Around line 241-245: The code redundantly casts rawMessagingFee twice; update
the decodeQuoteSendResult return type to include { nativeFee: bigint;
lzTokenFee: bigint } or cast its single result once and destructure to build
messagingFee. Locate decodeQuoteSendResult and change its signature to return
the proper typed object, or in fetchStargateTrade.ts cast rawMessagingFee once
(e.g., const { nativeFee, lzTokenFee } = decodeQuoteSendResult(...) as {
nativeFee: bigint; lzTokenFee: bigint }) and then construct the
StargateMessagingFee using those variables instead of repeating the type
assertion.
- Around line 296-301: stargateTransactionMetadata currently hardcodes gasLimit
to '500000'; instead, when evm.getFees is available during quote construction in
fetchStargateTrade, call evm.getFees (or reuse existing fees lookup) to estimate
gas and set stargateTransactionMetadata.gasLimit to that estimated value
(stringified) rather than the fixed '500000', so executeSwap’s
BigNumber.max(gasLimitFromApi ?? '0', feeData.gasLimit) can pick the accurate
higher value; update the metadata assignment that creates
stargateTransactionMetadata (referencing sendCalldata, txValue, contractAddress)
to use the estimated feeData.gasLimit when present and fall back to the previous
hardcoded value only if no estimate exists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 123a4865-9897-4233-97b3-31d3c646d7a4

📥 Commits

Reviewing files that changed from the base of the PR and between 1568656 and e0c5912.

📒 Files selected for processing (4)
  • .env.production
  • packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.test.ts
  • packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.ts
  • packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.ts

@swdiscordia swdiscordia force-pushed the feat/stargate-swapper branch from 75e32fc to e0c5912 Compare April 12, 2026 12:57
Discostu and others added 4 commits April 12, 2026 14:59
Tests fail with "generated/ethereum/runtime not found" if the OpenAPI
clients haven't been generated. Document the required generate step and
the correct vi.importActual pattern for mocks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Destructure decodeQuoteSendResult with single cast instead of double
- Add console.warn in fee-estimation catch block (matches swapper pattern)
- Capture gasLimit from evm.getFees and use in stargateTransactionMetadata
- Move VITE_FEATURE_STARGATE_SWAP to correct alphabetical position in .env

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e, error cases

- ETH (mainnet) → ETH (Arbitrum): verifies native txValue = nativeFee + sellAmount
- USDC (Arbitrum) → USDC (Mainnet): verifies reverse direction with Arbitrum sell chain
- Unsupported buy chain: complements existing sell-chain error test
- No Stargate contract for sell asset (FOX): expects UnsupportedTradePair error
- Extend viemClientByChainId mock to cover arbitrumChainId

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Unit tests (20 total, +6 new pairs):
- USDC ETH → Optimism, Base, Polygon
- USDT ETH → USDT Arbitrum
- ETH → ETH Base native bridge
- USDC Base → USDC Arbitrum (L2-to-L2)

test-data/assets.ts:
- Add USDT_MAINNET, USDT_ARBITRUM
- Add USDC_OPTIMISM, USDC_BASE, USDC_POLYGON
- Add ETH_BASE, MATIC, BSC_USDC
- Add baseChainId, polygonChainId imports

E2E fixture:
- stargate-usdc-eth-to-arb.yaml for agent-browser manual/automated QA

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
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

🧹 Nitpick comments (3)
packages/swapper/src/swappers/utils/test-data/assets.ts (1)

262-374: Optional: reduce fixture duplication with a small asset factory.

Not blocking, but a helper for repeated token metadata would reduce copy/paste drift across future Stargate fixture additions.

♻️ Example refactor direction
+type EvmTokenFixtureInput = {
+  assetId: string
+  chainId: string
+  symbol: string
+  name: string
+  precision: number
+  color: string
+  icon: string
+  explorer: string
+}
+
+const createEvmTokenFixture = (input: EvmTokenFixtureInput): Asset => ({
+  ...input,
+  explorerAddressLink: `${input.explorer}/address/`,
+  explorerTxLink: `${input.explorer}/tx/`,
+  relatedAssetKey: null,
+})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/swapper/src/swappers/utils/test-data/assets.ts` around lines 262 -
374, Many assets in assets.ts (e.g., USDT_MAINNET, USDT_ARBITRUM, USDC_OPTIMISM,
USDC_BASE, USDC_POLYGON, ETH_BASE, MATIC, BSC_USDC) repeat the same fields;
create a small factory helper (e.g., makeErc20Asset / makeAsset) that accepts
the unique pieces (assetId, chainId, symbol, name, optional precision, explorer
base URL, icon, color, relatedAssetKey) and fills common defaults (precision,
explorerAddressLink/TxLink format, relatedAssetKey=null) and replace repeated
literal objects with factory calls to reduce duplication and drift. Ensure the
factory preserves special network-only fields (like networkName, networkColor
for ETH_BASE) via optional overrides and update each exported constant to call
the factory with its unique values.
packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts (1)

275-299: Robust gas estimation with sensible fallback.

The try-catch pattern ensures quote generation doesn't fail on gas estimation errors, falling back to a conservative estimate. The warning log includes useful context for debugging.

Consider extracting the default gas limit to a named constant for clarity:

♻️ Optional: Extract magic number to constant
+const DEFAULT_STARGATE_GAS_LIMIT = '500000'
+
 // ... in the function
-    let gasLimit = '500000'
+    let gasLimit = DEFAULT_STARGATE_GAS_LIMIT
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts`
around lines 275 - 299, Replace the magic string '500000' by introducing a named
constant (e.g. DEFAULT_GAS_LIMIT) and use it to initialize gasLimit and as the
fallback gasLimit passed into evm.calcNetworkFeeCryptoBaseUnit; update the async
block around evm.getFees / evm.calcNetworkFeeCryptoBaseUnit so gasLimit is
initialized from DEFAULT_GAS_LIMIT and the same constant is used in the catch
branch, keeping the rest of the logic intact (symbols to edit: gasLimit,
networkFeeCryptoBaseUnit, evm.getFees, evm.calcNetworkFeeCryptoBaseUnit,
average, supportsEIP1559, sellAsset.assetId).
e2e/fixtures/stargate-usdc-eth-to-arb.yaml (1)

86-90: Consider extending bridge completion timeout to reduce flakiness.

Line 89’s 180s cap is tight for cross-chain settlement under congestion. Increasing to 300s is a safer default for CI stability.

Suggested timeout adjustment
   - name: Wait for Stargate bridge completion
     instruction: >
       Cross-chain Stargate bridges take 1-3 minutes (LayerZero messaging).
-      Wait up to 180 seconds for the swap to complete. Check every 10 seconds.
+      Wait up to 300 seconds for the swap to complete. Check every 10 seconds.
       Look for: trade page reappearing, success notification, Arbitrum USDC
       balance increased, or "Awaiting swap" disappearing.
       A feedback dialog may appear — dismiss it with "Maybe Later".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/fixtures/stargate-usdc-eth-to-arb.yaml` around lines 86 - 90, Update the
"Wait for Stargate bridge completion" step in the stargate-usdc-eth-to-arb
fixture to increase the bridge completion timeout from 180 seconds to 300
seconds to reduce CI flakiness; locate the YAML step titled "Wait for Stargate
bridge completion" and change the wait cap (currently "Wait up to 180 seconds")
to "Wait up to 300 seconds" while keeping the polling interval (every 10
seconds) and the success checks (trade page reappearing, success notification,
Arbitrum USDC) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env:
- Line 365: dotenv-linter flags a missing trailing newline at EOF for the .env
file containing VITE_AGENTIC_SERVER_BASE_URL; fix it by editing the .env file
and adding a single blank line (newline character) after the last line (the
VITE_AGENTIC_SERVER_BASE_URL entry) so the file ends with a newline and the
EndingBlankLine warning is cleared.

In `@e2e/fixtures/stargate-usdc-eth-to-arb.yaml`:
- Around line 50-66: Relax the brittle hardcoded numeric expectations in the
quote and fee test steps: update the "Quote shown..." expected from the strict
"~$0.98-$1.00 USDC" to a broader or percentage-based tolerance (e.g. accept any
receive amount within ±10% of $1 or a generic "≈ $1 USDC") and change the
protocol fee expectation in the "Verify protocol fee is displayed" step from
"roughly $0.005-$0.01 for a $1 swap" to a flexible check that asserts the fee
label (Stargate/oft fee) is present and that the displayed fee is non-zero or
within a wider percent range (e.g. 0.1%–5%), so the steps "Quote shown with
receive amount..." and "Protocol fee visible..." accept normal routing/fee
variance for tiny notional swaps.

---

Nitpick comments:
In `@e2e/fixtures/stargate-usdc-eth-to-arb.yaml`:
- Around line 86-90: Update the "Wait for Stargate bridge completion" step in
the stargate-usdc-eth-to-arb fixture to increase the bridge completion timeout
from 180 seconds to 300 seconds to reduce CI flakiness; locate the YAML step
titled "Wait for Stargate bridge completion" and change the wait cap (currently
"Wait up to 180 seconds") to "Wait up to 300 seconds" while keeping the polling
interval (every 10 seconds) and the success checks (trade page reappearing,
success notification, Arbitrum USDC) unchanged.

In `@packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts`:
- Around line 275-299: Replace the magic string '500000' by introducing a named
constant (e.g. DEFAULT_GAS_LIMIT) and use it to initialize gasLimit and as the
fallback gasLimit passed into evm.calcNetworkFeeCryptoBaseUnit; update the async
block around evm.getFees / evm.calcNetworkFeeCryptoBaseUnit so gasLimit is
initialized from DEFAULT_GAS_LIMIT and the same constant is used in the catch
branch, keeping the rest of the logic intact (symbols to edit: gasLimit,
networkFeeCryptoBaseUnit, evm.getFees, evm.calcNetworkFeeCryptoBaseUnit,
average, supportsEIP1559, sellAsset.assetId).

In `@packages/swapper/src/swappers/utils/test-data/assets.ts`:
- Around line 262-374: Many assets in assets.ts (e.g., USDT_MAINNET,
USDT_ARBITRUM, USDC_OPTIMISM, USDC_BASE, USDC_POLYGON, ETH_BASE, MATIC,
BSC_USDC) repeat the same fields; create a small factory helper (e.g.,
makeErc20Asset / makeAsset) that accepts the unique pieces (assetId, chainId,
symbol, name, optional precision, explorer base URL, icon, color,
relatedAssetKey) and fills common defaults (precision,
explorerAddressLink/TxLink format, relatedAssetKey=null) and replace repeated
literal objects with factory calls to reduce duplication and drift. Ensure the
factory preserves special network-only fields (like networkName, networkColor
for ETH_BASE) via optional overrides and update each exported constant to call
the factory with its unique values.
🪄 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: aa0dcd51-efcc-4225-96bb-3ac2bd15977d

📥 Commits

Reviewing files that changed from the base of the PR and between 75e32fc and 620afcd.

📒 Files selected for processing (6)
  • .env
  • AGENTS.md
  • e2e/fixtures/stargate-usdc-eth-to-arb.yaml
  • packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.test.ts
  • packages/swapper/src/swappers/StargateSwapper/utils/fetchStargateTrade.ts
  • packages/swapper/src/swappers/utils/test-data/assets.ts
✅ Files skipped from review due to trivial changes (1)
  • AGENTS.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/swapper/src/swappers/StargateSwapper/getTradeQuote/getTradeQuote.test.ts

Comment thread .env

# agentic chat
VITE_AGENTIC_SERVER_BASE_URL=https://api.agent.shapeshift.com
VITE_AGENTIC_SERVER_BASE_URL=https://api.agent.shapeshift.com No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add trailing blank line to satisfy dotenv-linter.

dotenv-linter reports EndingBlankLine at Line 365. Add a newline at EOF to clear the warning.

🔧 Minimal fix
 VITE_AGENTIC_SERVER_BASE_URL=https://api.agent.shapeshift.com
+
📝 Committable suggestion

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

Suggested change
VITE_AGENTIC_SERVER_BASE_URL=https://api.agent.shapeshift.com
VITE_AGENTIC_SERVER_BASE_URL=https://api.agent.shapeshift.com
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 365-365: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

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

In @.env at line 365, dotenv-linter flags a missing trailing newline at EOF for
the .env file containing VITE_AGENTIC_SERVER_BASE_URL; fix it by editing the
.env file and adding a single blank line (newline character) after the last line
(the VITE_AGENTIC_SERVER_BASE_URL entry) so the file ends with a newline and the
EndingBlankLine warning is cleared.

Comment on lines +50 to +66
Wait up to 15 seconds for a quote to appear. Verify that:
1. The "You Get" field shows a USDC amount close to $1 (slightly less due to fees)
2. Stargate appears as the swapper source (look for "Stargate" label)
3. The "Preview Trade" button is enabled
If multiple swappers are shown, check that Stargate is one of them.
expected: >
Quote shown with receive amount ~$0.98-$1.00 USDC, Stargate visible as source,
Preview Trade button enabled
screenshot: true

- name: Verify protocol fee is displayed
instruction: >
In the quote view, look for a fee breakdown section. Verify that a protocol fee
is shown (the Stargate OFT fee, typically 0.5-1% of the swap amount).
Note the fee amount shown.
expected: Protocol fee visible, roughly $0.005-$0.01 for a $1 swap
screenshot: true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hardcoded quote/fee ranges are too strict for a $1 cross-chain swap.

Line 56 (~$0.98-$1.00) and Line 65 ($0.005-$0.01) are brittle and can fail under normal fee/route variance, especially at tiny notional size. This will introduce flaky e2e runs.

Proposed fixture expectation hardening
   - name: Wait for Stargate quote
     instruction: >
       Wait up to 15 seconds for a quote to appear. Verify that:
-      1. The "You Get" field shows a USDC amount close to $1 (slightly less due to fees)
+      1. The "You Get" field shows a non-zero USDC amount lower than the sell amount
       2. Stargate appears as the swapper source (look for "Stargate" label)
       3. The "Preview Trade" button is enabled
       If multiple swappers are shown, check that Stargate is one of them.
     expected: >
-      Quote shown with receive amount ~$0.98-$1.00 USDC, Stargate visible as source,
+      Quote shown with non-zero receive amount below sell amount, Stargate visible as source,
       Preview Trade button enabled
@@
   - name: Verify protocol fee is displayed
     instruction: >
       In the quote view, look for a fee breakdown section. Verify that a protocol fee
-      is shown (the Stargate OFT fee, typically 0.5-1% of the swap amount).
+      is shown (amount may vary by route and market conditions).
       Note the fee amount shown.
-    expected: Protocol fee visible, roughly $0.005-$0.01 for a $1 swap
+    expected: Protocol fee visible and greater than $0.00
📝 Committable suggestion

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

Suggested change
Wait up to 15 seconds for a quote to appear. Verify that:
1. The "You Get" field shows a USDC amount close to $1 (slightly less due to fees)
2. Stargate appears as the swapper source (look for "Stargate" label)
3. The "Preview Trade" button is enabled
If multiple swappers are shown, check that Stargate is one of them.
expected: >
Quote shown with receive amount ~$0.98-$1.00 USDC, Stargate visible as source,
Preview Trade button enabled
screenshot: true
- name: Verify protocol fee is displayed
instruction: >
In the quote view, look for a fee breakdown section. Verify that a protocol fee
is shown (the Stargate OFT fee, typically 0.5-1% of the swap amount).
Note the fee amount shown.
expected: Protocol fee visible, roughly $0.005-$0.01 for a $1 swap
screenshot: true
Wait up to 15 seconds for a quote to appear. Verify that:
1. The "You Get" field shows a non-zero USDC amount lower than the sell amount
2. Stargate appears as the swapper source (look for "Stargate" label)
3. The "Preview Trade" button is enabled
If multiple swappers are shown, check that Stargate is one of them.
expected: >
Quote shown with non-zero receive amount below sell amount, Stargate visible as source,
Preview Trade button enabled
screenshot: true
- name: Verify protocol fee is displayed
instruction: >
In the quote view, look for a fee breakdown section. Verify that a protocol fee
is shown (amount may vary by route and market conditions).
Note the fee amount shown.
expected: Protocol fee visible and greater than $0.00
screenshot: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/fixtures/stargate-usdc-eth-to-arb.yaml` around lines 50 - 66, Relax the
brittle hardcoded numeric expectations in the quote and fee test steps: update
the "Quote shown..." expected from the strict "~$0.98-$1.00 USDC" to a broader
or percentage-based tolerance (e.g. accept any receive amount within ±10% of $1
or a generic "≈ $1 USDC") and change the protocol fee expectation in the "Verify
protocol fee is displayed" step from "roughly $0.005-$0.01 for a $1 swap" to a
flexible check that asserts the fee label (Stargate/oft fee) is present and that
the displayed fee is non-zero or within a wider percent range (e.g. 0.1%–5%), so
the steps "Quote shown with receive amount..." and "Protocol fee visible..."
accept normal routing/fee variance for tiny notional swaps.

Enable VITE_FEATURE_STARGATE_SWAP feature flag. Stargate V2 is fully
implemented with cross-chain USDC bridging via LayerZero, ERC-20 approval
flow, and slippage handling.

Also fix wallet-health.yaml to use `fill` for password input instead of
JS eval + press char-by-char, which was unreliable and based on an
outdated assumption about React controlled inputs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
.env (1)

365-365: ⚠️ Potential issue | 🟡 Minor

Add trailing newline at EOF (still failing dotenv-linter).

Line 365 needs a final blank line to clear EndingBlankLine.

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

In @.env at line 365, The .env file is missing a trailing newline which triggers
dotenv-linter's EndingBlankLine error; open the .env containing the
VITE_AGENTIC_SERVER_BASE_URL entry and add a final blank line (ensure the file
ends with a newline character after the last line
VITE_AGENTIC_SERVER_BASE_URL=https://api.agent.shapeshift.com) and save so the
linter no longer flags EndingBlankLine.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.env:
- Line 365: The .env file is missing a trailing newline which triggers
dotenv-linter's EndingBlankLine error; open the .env containing the
VITE_AGENTIC_SERVER_BASE_URL entry and add a final blank line (ensure the file
ends with a newline character after the last line
VITE_AGENTIC_SERVER_BASE_URL=https://api.agent.shapeshift.com) and save so the
linter no longer flags EndingBlankLine.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 85135e69-d0d2-4806-b08e-47fcae04014e

📥 Commits

Reviewing files that changed from the base of the PR and between 620afcd and 7b6b763.

📒 Files selected for processing (2)
  • .env
  • e2e/fixtures/wallet-health.yaml

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