Skip to content

feat: starknet implementation#11511

Merged
NeOMakinG merged 29 commits intodevelopfrom
starknet
Dec 30, 2025
Merged

feat: starknet implementation#11511
NeOMakinG merged 29 commits intodevelopfrom
starknet

Conversation

@NeOMakinG
Copy link
Collaborator

@NeOMakinG NeOMakinG commented Dec 22, 2025

Description

To be tested with hdwallet fren: https://github.com/shapeshift/hdwallet/pull/774/files#diff-5f742e6bef51b5334a6a133d812213b430d7b01ca375fd6864d8b4b0e75aa957
As usually, new chain =

  • New starknet chain adapter, using the public rpc from lava (which is the best I could find, others were a bit flacky
  • It's a second class chain that can't rely on the EVM base adapter as its quite different
  • Fee estimation should work as expected querying the RPC
  • Account derivation does work
    -- Using a fresh new account will require to deploy an account on chain, will cost less than 1 sent, implemented a modal for that
  • Send, Swap from and to starknet works using near
  • TX are upserted in the history
  • Actions are resolved based on the tx status on chain
  • Balances are updated when swapping or sending

Notes to be fixed as follow up prefered:

  • TX History might need a bit more of massage, parsing send/swap txs properly
  • Deploying a new account on chain sends the amount you wanted to send, we might want to avoid that or fine a better UX
  • Our way of working might not work with other wallets, it depends on which smart contract they use, we are using the open zeppelin one deployed on starknet, if users import the seed phrase on another wallet, they might end up in a situation where their public key is different because the deployed account will use another smart contract, thats kind of expected
  • Duplicate starknet asset (we might want to exclude it like we did for SUI)

Issue (if applicable)

Nothing to close

Risk

Low, behind a flag

High Risk PRs Require 2 approvals

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

Testing

  • All the smoke test for a new chain!
  • Send, Trade, Account derivation, Balances, fees sanity
  • Verify the "Deploy account" modal and behavior, you can test by sending funds to any other derivated account

Engineering

Operations

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

Screenshots (if applicable)

https://jam.dev/c/62a96c16-a8d8-4dc5-bc3a-d0aa5796770c

Summary by CodeRabbit

  • New Features

    • Full Starknet support: STRK asset, on‑chain send/transaction flows, account deployment, and trading integration.
    • Swapper and trade UI now handle Starknet quotes, fees, and execution.
    • Feature flag to enable/disable Starknet and configurable Starknet RPC URL.
    • UI translations and plugin registration for Starknet.
  • Bug Fixes / Improvements

    • Improved asset/icon handling for Starknet tokens (CoinGecko/Trust Wallet).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

📝 Walkthrough

Walkthrough

Adds end-to-end Starknet support: environment flags and node URL, a Starknet chain adapter and types, asset generation and native STRK asset, UI/account deployment flows, swapper and trade execution integrations, feature-flag gating, CSP updates, and related tests/hooks across the codebase.

Changes

Cohort / File(s) Summary
Environment & Config
.env, .env.development, src/config.ts
Add VITE_FEATURE_STARKNET flag and VITE_STARKNET_NODE_URL with validation and defaults.
CSPs
headers/csps/chains/starknet.ts, headers/csps/index.ts, headers/csps/marketService/coingecko.ts
New CSP modules for Starknet RPC and Coingecko image domain; csps export extended.
CAIP constants & adapters
packages/caip/src/constants.ts, packages/caip/src/adapters/coingecko/index.ts
Add Starknet chain/asset identifiers, namespaces, fee asset mapping, and Coingecko platform mapping.
Chain adapters & types
packages/chain-adapters/src/starknet/*, packages/chain-adapters/src/index.ts, packages/chain-adapters/src/types.ts
New Starknet ChainAdapter implementation, types, and re-exports (account deploy, build/sign/broadcast, fee estimation).
Swapper integration
packages/swapper/src/**, packages/swapper/src/types.ts, packages/swapper/src/utils.ts
Swapper types, execution surface, tests, and executeStarknetTransaction added; NearIntents swappers extended for Starknet.
Asset pipeline & base assets
packages/utils/src/assetData/*, scripts/generateAssetData/*
Add STRK base asset; Coingecko/TrustWallet asset fetching for Starknet; blacklist and generation pipeline updated.
UI: Send / Deploy / Trade flows
src/components/Modals/Send/*, src/components/MultiHopTrade/*, src/hooks/useIsStarknetAccountDeployed/*
Add deployment-check/install flow, fee estimation, transaction building/signing/broadcasting, and UI messaging for Starknet accounts.
Plugins & runtime wiring
src/plugins/starknet/index.tsx, src/plugins/activePlugins.ts, src/context/PluginProvider/PluginProvider.tsx
New Starknet plugin that registers the adapter using VITE_STARKNET_NODE_URL and feature-flag gating in plugin provider.
App state, utils & portfolio
src/state/**, src/lib/**, src/hooks/**, src/constants/chains.ts
Feature flag added to preferences; portfolio, account derivation, trade execution, swapper deps, action-center polling, and utilities extended to support Starknet, with gating by feature flag.
Translations & migrations
src/assets/translations/en/main.json, src/state/migrations/index.ts
Added Starknet UI translations and new clear-assets migration entry.
Misc / tooling
packages/caip/src/adapters/coincap/index.ts, scripts/generateTradableAssetMap/index.ts, test mocks
CoinCap env key handling, node URL templating for scripts, and test mocks updated with Starknet flag.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant UI as Client UI
participant Plugin as PluginRegistry
participant Adapter as Starknet ChainAdapter
participant Wallet as HDWallet
participant RPC as Starknet RPC
rect rgb(220,235,255)
Note over UI,Plugin: Account deployment & send flow (feature-flag gated)
end
UI->>Plugin: request Starknet adapter (getConfig.VITE_FEATURE_STARKNET)
Plugin->>Adapter: construct with RPC URL (VITE_STARKNET_NODE_URL)
alt Account not deployed
UI->>Adapter: deployAccount(txParams)
Adapter->>Wallet: sign deploy transaction
Wallet-->>Adapter: signature
Adapter->>RPC: submit deploy transaction
RPC-->>Adapter: tx_hash
Adapter->>RPC: poll receipt
RPC-->>Adapter: receipt (SUCCEEDED/REVERTED)
Adapter-->>UI: deployment result
end
UI->>Adapter: buildSendTransaction(params)
Adapter->>Wallet: request signature (Starknet sign)
Wallet-->>Adapter: signed payload
Adapter->>RPC: broadcast signed invoke
RPC-->>Adapter: tx_hash
Adapter-->>UI: tx_hash / status

Note over Adapter,RPC: errors map to TxStatus (Confirmed/Failed/Unknown)

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

high risk

Poem

🐰 A hop, a stitch, a Starknet thread,

I fetched the RPC and signed with my head.
From plugins born to assets bright,
STRK now dances into the night.
Hop on — deployments take flight!

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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: starknet implementation' directly summarizes the main change—adding Starknet support—and aligns with the PR's primary objective of implementing a complete Starknet chain adapter with associated functionality.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch starknet

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.

gomesalexandre and others added 12 commits December 24, 2025 23:55
- Import and use isStarknetChainAdapter type guard
- Remove all 'as any' casts for adapter methods (isAccountDeployed, deployAccount, getStarknetProvider)
- Fix feeData.fast.chainSpecific.maxFee access without casting
- Affected files: Form.tsx (4 fixes), TradeFooterButton.tsx (4 fixes), useSendActionSubscriber.tsx (1 fix)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Issue #3 - Debug Code:
- Remove 25+ console.log/console.debug statements from StarknetChainAdapter
- Remove debug log from NearIntentsSwapper helpers
- Remove debug logs from Send Form deployment flow
- Keep console.error for error handling/logging

Issue #7 - RPC Error Handling:
- Remove silent fallback to '0x0' for nonce fetch failures
- Throw errors when nonce RPC call fails instead of silently continuing
- Prevents confusing transaction failures downstream

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Issue #4 - Test Files:
- Remove test-starknet-deploy.js from repo root
- Remove scripts/test-starknet-asset-generation.ts (untracked)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Match Sui/Tron pattern: throw errors from parseTx instead of returning Unknown status
- Remove unused computedAddress calculation block (leftover from debug code removal)
- Keep inner try-catch for optional detail fetches (block timestamp, tx details)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Remove temporary Starknet-only regeneration
- Restore full chain regeneration (all chains)
- Uncomment console.log for related asset processing
- Now that Starknet assets are added, can regenerate all chains normally

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Types cleanup:
- Move all inline RPC/Starknet types from ChainAdapter to types.ts
- Follow Sui/Tron pattern: no inline types in adapter
- Cleaner imports and better organization

Nonce handling fix:
- Fee estimation: Fallback to 0x0 if account not deployed (for estimates)
- buildSendApiTransaction: Check isAccountDeployed() first, use 0x0 for undeployed
- Prevents errors when trying to send before account deployment
- Matches expected Starknet behavior (0x0 nonce for first tx)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Assets:
- Add 38 Starknet assets (1 base + 37 tokens) to encoded asset data
- Update related asset index for Starknet assets
- Total assets now: 25,494 (from 25,456)

Dependencies:
- Bump hdwallet packages to 1.62.33-starknet.14
- Update yarn.lock

Migrations:
- Add migration 255 for asset data changes
- Keep single migration as per review guidelines

Lint:
- Fix line length in starknet/index.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add starknetAssetId to popular assets list when Starknet feature flag
is enabled, matching the pattern used for other second-class chains
(Sui, Tron, etc.).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Update yarn.lock with @shapeshiftoss/hdwallet-* packages to 1.62.33
- Fix duplicate imports in starknet types.ts
- Add starknet assets to asset generation script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Copy link
Contributor

@gomesalexandre gomesalexandre left a comment

Choose a reason for hiding this comment

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

See hdwallet review - functionally does the thing, additionally, added proper (ish, assuming it holds next regen) regen of starknet assets which was failing (not sure regen will work and it may ditch those, as there seems to be shenanigans here and super hard to debug, but #11520 will make that a breeze to debug. Feel free to run regen again and see if they hold in!)

⚠️ note this was just to test Starknet tokens and will need a new regen when we open this PR

Image Image Image
  • Few qs here re: cleanup .md/test/env vars for you to tackle before merging
  • also will definitely need a proper cleanup here, will do another implementation pass once opened, many many hacky bits that need cleanup, but functionally does the do
  • as you noted, the whole flow of send -> account creation is odd and feels broken, feels weird to have "Broadcasting transaction" spinning, but actually doesn't, then activation modal opens up on top of it, activation is broadcasted and modal closed, then send modal is visible without a loading state and automagically does the previous send after a sec or 2.
    Maybe defer activation to earlier in the flow (i.e block flow and enforce activation when attempting to do Starknet Tx bits in send/swapper land vs. letting it seemingly go through and then activate at broadcast time) so we 1. don't have to write so many hacky bits and 2. don't get into such flow in the first place?

Merry Christmas ser! 🎄

gomesalexandre and others added 2 commits December 25, 2025 00:36
Resolved conflicts in package.json files and yarn.lock by keeping
hdwallet packages at 1.62.33 (our version).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@gomesalexandre gomesalexandre marked this pull request as ready for review December 26, 2025 14:41
@gomesalexandre gomesalexandre requested a review from a team as a code owner December 26, 2025 14:41
- Remove debug console.log statements
- Update hdwallet dependencies to 1.62.34

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
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: 7

♻️ Duplicate comments (1)
STARKNET_SWAP_SUPPORT.md (1)

1-136: Documentation file noted - decision needed on whether to keep.

This documentation provides useful internal reference for Starknet swap implementation, including file locations, troubleshooting tips, and testing instructions. However, the specific line number references (e.g., "Lines 239-256") will become stale as the codebase evolves.

If keeping this documentation, consider:

  1. Removing specific line number references or linking to GitHub permalinks instead
  2. Moving to a more permanent documentation location (e.g., internal wiki or ADR)

Addressing the previous review comment: This decision should be made by the maintainers based on documentation strategy.

🧹 Nitpick comments (10)
packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts (1)

64-69: Consider simplifying the redundant chainId checks.

Lines 68-69 check asset.chainId === suiChainId and asset.chainId === starknetChainId, but these are redundant because:

  • nearNetwork is derived from chainIdToNearIntentsChain[asset.chainId]
  • If nearNetwork is 'sui' or 'starknet', then asset.chainId must already be suiChainId or starknetChainId respectively
  • The isTokenLookupChain(nearNetwork) check on line 66 already covers both cases

The condition could be simplified to:

const requiresLookup =
  isNep245Chain(nearNetwork) ||
  isTokenLookupChain(nearNetwork) ||
  asset.chainId === solanaChainId
🔎 Proposed simplification
 const requiresLookup =
   isNep245Chain(nearNetwork) ||
   isTokenLookupChain(nearNetwork) ||
-  asset.chainId === solanaChainId ||
-  asset.chainId === suiChainId ||
-  asset.chainId === starknetChainId
+  asset.chainId === solanaChainId
src/components/MultiHopTrade/hooks/useGetTradeQuotes/getTradeQuoteOrRateInput.ts (1)

239-256: LGTM with optional refinement suggestion.

The Starknet case implementation correctly follows the pattern established by Solana and Sui cases. The adapter retrieval, address derivation, and return value structure are all consistent.

Optional: Consider explicit type cast for consistency

For consistency with other cases (EVM uses as EvmChainId, Cosmos uses as CosmosSdkChainId, etc.), consider explicitly casting the chainId on line 253:

      return {
        ...tradeQuoteInputCommonArgs,
-       chainId: sellAsset.chainId,
+       chainId: sellAsset.chainId as StarknetChainId,
        sendAddress,
      } as GetTradeQuoteInput

This would align with the pattern used in lines 109, 128, 170, 193, 217, and 235, though the current implementation may work if StarknetChainId is compatible with the base ChainId type.

scripts/generateAssetData/coingecko.ts (1)

170-177: Hardcoded explorer URLs differ from the pattern used by other chains.

Other chains import explorer configuration from @shapeshiftoss/utils (e.g., ethereum.explorer, solana.explorerAddressLink), while Starknet hardcodes the StarkScan URLs directly. Similarly, category is hardcoded as 'starknet' rather than using adapters.chainIdToCoingeckoAssetPlatform(chainId).

This works but diverges from the established pattern. Consider extracting Starknet explorer config to @shapeshiftoss/utils in a follow-up for consistency.

src/lib/utils/starknet.ts (1)

36-36: Consider typing the receipt if the Starknet provider types are available.

Using any here works, but if @starknet/starknet.js provides receipt types, using them would improve type safety.

🔎 Potential improvement
-    const receipt: any = await provider.getTransactionReceipt(txHash)
+    const receipt = await provider.getTransactionReceipt(txHash)

If the provider's return type is properly typed, this would give you compile-time safety on the execution_status property access.

src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx (1)

190-195: Info toast will persist indefinitely.

The info toast uses duration: null which means it won't auto-dismiss. After the success toast appears, the info toast may remain visible unless explicitly closed. Consider either:

  1. Closing it manually before showing the success toast
  2. Using a finite duration
🔎 Potential approach
+                   const infoToastId = toast({
-                   toast({
                      status: 'info',
                      title: translate('starknet.deployAccount.deployingTitle'),
                      description: translate('starknet.deployAccount.deployingDescription'),
                      duration: null,
+                     id: 'starknet-deploy-info',
                    })

                    // ... wait for transaction ...

+                   toast.close('starknet-deploy-info')
                    toast({
                      status: 'success',
src/components/Modals/Send/Form.tsx (1)

265-271: Consider handling undefined accountMetadata more defensively.

If selectPortfolioAccountMetadataByAccountId returns undefined, the code defaults accountNumber to 0. This silent fallback may mask configuration issues. Consider logging a warning or validating the account exists.

 const accountMetadata = selectPortfolioAccountMetadataByAccountId(
   store.getState(),
   {
     accountId: formAccountId,
   },
 )
-const accountNumber = accountMetadata?.bip44Params.accountNumber ?? 0
+if (!accountMetadata) {
+  console.warn('Account metadata not found for Starknet deployment, defaulting to account 0')
+}
+const accountNumber = accountMetadata?.bip44Params.accountNumber ?? 0
scripts/generateAssetData/starknet/index.ts (1)

35-54: Consider using const with reduce pattern instead of let for modifiedAssets.

Per coding guidelines, avoid let variable assignments. The batch processing loop could use a functional approach.

🔎 Alternative using reduce
-let modifiedAssets: Asset[] = []
-
-for (const [i, batch] of assetBatches.entries()) {
-  console.info(`processing Starknet batch ${i + 1} of ${assetBatches.length}`)
-  const promises = batch.map(({ assetId }) => {
-    const { info } = generateTrustWalletUrl(assetId)
-    return axios.head(info)
-  })
-  const result = await Promise.allSettled(promises)
-  const newModifiedTokens = result.map((res, idx) => {
-    const key = i * batchSize + idx
-    if (res.status === 'rejected') {
-      return uniqueAssets[key]
-    } else {
-      const { icon } = generateTrustWalletUrl(uniqueAssets[key].assetId)
-      return { ...uniqueAssets[key], icon }
-    }
-  })
-  modifiedAssets = modifiedAssets.concat(newModifiedTokens)
-}
+const modifiedAssets: Asset[] = []
+
+for (const [i, batch] of assetBatches.entries()) {
+  console.info(`processing Starknet batch ${i + 1} of ${assetBatches.length}`)
+  const promises = batch.map(({ assetId }) => {
+    const { info } = generateTrustWalletUrl(assetId)
+    return axios.head(info)
+  })
+  const result = await Promise.allSettled(promises)
+  const newModifiedTokens = result.map((res, idx) => {
+    const key = i * batchSize + idx
+    if (res.status === 'rejected') {
+      return uniqueAssets[key]
+    } else {
+      const { icon } = generateTrustWalletUrl(uniqueAssets[key].assetId)
+      return { ...uniqueAssets[key], icon }
+    }
+  })
+  modifiedAssets.push(...newModifiedTokens)
+}

Note: Using push with spread on a const array is acceptable since we're mutating the array contents, not reassigning the variable.

packages/chain-adapters/src/starknet/StarknetChainAdapter.ts (3)

77-79: Consider using the enumIndex pattern for getName() for consistency.

Based on learnings, other chain adapters use the pattern Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.XXX) to reverse-lookup the enum key. While the hardcoded string works, using the established pattern ensures consistency across all chain adapters.

🔎 Consistent pattern with other adapters
 getName() {
-  return 'Starknet'
+  const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(
+    ChainAdapterDisplayName.Starknet,
+  )
+  return Object.keys(ChainAdapterDisplayName)[enumIndex]
 }

210-216: Simplify duplicate return statements.

The error handling has redundant return false statements that can be consolidated.

🔎 Simplified error handling
       // If we get an error, account is not deployed
       if (result.error) {
-        // Error code 20 = CONTRACT_NOT_FOUND means not deployed
-        if (result.error.code === 20) {
-          return false
-        }
+        // Error code 20 = CONTRACT_NOT_FOUND means not deployed
+        // Other errors also indicate the account is not accessible/deployed
         return false
       }

432-727: Large method could benefit from extraction, but acceptable for initial implementation.

The buildSendApiTransaction method is quite large (~295 lines) with multiple responsibilities: balance fetching for sendMax, nonce retrieval, fee estimation, calldata building, and transaction hash calculation. While this could be refactored into smaller helper methods for maintainability, it's acceptable for the initial Starknet implementation. Consider extracting helpers in a follow-up.

@gomesalexandre gomesalexandre changed the title fix: starknet implementation feat: starknet implementation Dec 26, 2025
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: 0

♻️ Duplicate comments (1)
packages/chain-adapters/src/starknet/StarknetChainAdapter.ts (1)

905-950: ** Fee estimation uses unrealistic hardcoded gas values.**

As noted in the previous review, the hardcoded typicalL1GasConsumed value of 100,000 (0x186a0) is 20-100x higher than actual typical L1 gas consumption for Starknet v3 transactions (typically ~1,000-5,000 gas for simple operations). This will cause significantly overestimated fees displayed to users.

For accurate fee estimation, consider:

  1. Using transaction-specific fee estimation via starknet_estimateFee for each transaction type
  2. If generic estimates are needed, use more realistic baseline values (e.g., 2,000-5,000 instead of 100,000)

Based on web search results from the previous review analyzing Starknet mainnet fee consumption patterns.

🧹 Nitpick comments (2)
packages/chain-adapters/src/starknet/StarknetChainAdapter.ts (2)

77-79: Consider using the established getName() pattern for consistency.

Almost all other chain adapters (Bitcoin, Ethereum, Litecoin, etc.) use the pattern that reverse-lookups the enum key from its value. For consistency across adapters, consider:

🔎 Suggested refactor to match established pattern
  getName() {
-   return 'Starknet'
+   const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.Starknet)
+   return Object.keys(ChainAdapterDisplayName)[enumIndex]
  }

Based on learnings, this is the established pattern used consistently across almost all chain adapters for reverse-lookup of enum keys.


202-223: Consider specific error code handling to avoid masking RPC failures.

Lines 214-215 return false for any error other than code 20, which may mask genuine RPC failures (network issues, auth failures, etc.). Consider only treating specific "not found" error codes as "not deployed" and propagating unexpected errors.

🔎 Suggested improvement
      // If we get an error, account is not deployed
      if (result.error) {
        // Error code 20 = CONTRACT_NOT_FOUND means not deployed
        if (result.error.code === 20) {
          return false
        }
-       return false
+       // Unexpected error - propagate it
+       throw new Error(`Unexpected RPC error: ${result.error.message}`)
      }

      // If we got a nonce, account is deployed
      return true
    } catch (error) {
-     return false
+     // Only treat "not found" errors as not deployed
+     const errorMessage = error instanceof Error ? error.message : String(error)
+     if (errorMessage.includes('not found') || errorMessage.includes('CONTRACT_NOT_FOUND')) {
+       return false
+     }
+     throw error
    }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c306926 and 23fd3c0.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • package.json
  • packages/chain-adapters/package.json
  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
  • packages/swapper/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/chain-adapters/package.json
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
🧠 Learnings (20)
📓 Common learnings
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/components/Stake/components/StakeSummary.tsx:112-114
Timestamp: 2025-08-22T13:00:44.879Z
Learning: NeOMakinG prefers to keep PR changes minimal and focused on the core objectives, avoiding cosmetic or defensive code improvements that aren't directly related to the PR scope, even when they would improve robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/error-handling.mdc:266-274
Timestamp: 2025-07-29T10:35:22.059Z
Learning: NeOMakinG prefers less nitpicky suggestions on documentation and best practices files, finding overly detailed suggestions on minor implementation details (like console.error vs logger.error) too granular for cursor rules documentation.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/pages/Dashboard/components/AccountList/AccountTable.tsx:60-0
Timestamp: 2025-09-02T08:34:08.157Z
Learning: NeOMakinG prefers code review comments to focus only on actual PR changes, not pre-existing code issues, unless there are critical security or correctness concerns directly related to the new functionality.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:42-86
Timestamp: 2025-08-08T11:41:22.794Z
Learning: NeOMakinG prefers not to include refactors in move-only PRs; such suggestions should be deferred to follow-up issues instead of being applied within the same PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/Table/Table.theme.ts:177-180
Timestamp: 2025-09-02T12:38:46.940Z
Learning: NeOMakinG prefers to defer technical debt and CSS correctness issues (like improper hover selectors) to follow-up PRs when the current PR is already large and focused on major feature implementation, even when the issues are valid from a usability/technical perspective.
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • packages/swapper/package.json
📚 Learning: 2025-11-24T21:20:57.909Z
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 camelCase for variable and function names in the Swapper system

Applied to files:

  • packages/swapper/package.json
📚 Learning: 2025-11-19T22:20:25.661Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10767
File: package.json:324-324
Timestamp: 2025-11-19T22:20:25.661Z
Learning: In shapeshift/web package.json, the resolution "gridplus-sdk/bs58check": "2.1.2" is intentional and must not be removed. It forces gridplus-sdk's transitive bs58check dependency from 4.0.0 down to 2.1.2 because bs58check 4.0.0 breaks legacy address validation (due to bs58 v6.0.0 and noble/hash vs 2.1.2's bs58 v4.0.0 and create-hash).

Applied to files:

  • packages/swapper/package.json
  • package.json
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • packages/swapper/package.json
  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-08-08T20:16:12.898Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10222
File: package.json:202-202
Timestamp: 2025-08-08T20:16:12.898Z
Learning: In shapeshift/web, the semver package must be included in dependencies (not devDependencies) because hdwallet packages have transient dependencies that require semver but don't ship it themselves. This ensures semver is available at runtime for hdwallet functionality.

Applied to files:

  • packages/swapper/package.json
  • package.json
📚 Learning: 2025-08-08T20:27:02.203Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10222
File: package.json:202-202
Timestamp: 2025-08-08T20:27:02.203Z
Learning: In shapeshift/web, while gomesalexandre generally prefers pinned dependencies for security, semver with a caret range (^7.7.2) is acceptable as an exception since it's already a transient dependency of many packages and is being made explicit for hdwallet support.

Applied to files:

  • packages/swapper/package.json
  • package.json
📚 Learning: 2025-12-09T21:07:22.474Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11335
File: packages/swapper/src/swappers/CetusSwapper/utils/helpers.ts:3-3
Timestamp: 2025-12-09T21:07:22.474Z
Learning: In packages/swapper/src/swappers/CetusSwapper, mysten/sui types (SuiClient, Transaction) must be imported from the nested path within cetusprotocol/aggregator-sdk (e.g., 'cetusprotocol/aggregator-sdk/node_modules/mysten/sui/client') because the aggregator SDK bundles its own version of mysten/sui. Direct imports from 'mysten/sui' break at runtime even when specified in package.json.

Applied to files:

  • packages/swapper/package.json
  • package.json
📚 Learning: 2025-11-24T21:20:57.909Z
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 PascalCase for types, interfaces, and enums in the Swapper system

Applied to files:

  • packages/swapper/package.json
📚 Learning: 2025-11-24T21:20:57.909Z
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 : All swappers must implement the Swapper interface from packages/swapper/src/types.ts

Applied to files:

  • packages/swapper/package.json
📚 Learning: 2025-11-24T21:20:57.909Z
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 : Reuse executeEvmTransaction utility for EVM-based swappers instead of implementing custom transaction execution

Applied to files:

  • packages/swapper/package.json
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Import types from `shapeshiftoss/caip` for chain/account/asset IDs

Applied to files:

  • packages/swapper/package.json
  • package.json
📚 Learning: 2025-08-29T18:09:45.982Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10376
File: vite.config.mts:136-137
Timestamp: 2025-08-29T18:09:45.982Z
Learning: In the ShapeShift web repository vite.config.mts, the commonjsOptions.exclude configuration using bare package name strings like ['shapeshiftoss/caip', 'shapeshiftoss/types'] works correctly for excluding specific packages from CommonJS transformation, despite theoretical concerns about module ID matching patterns.

Applied to files:

  • packages/swapper/package.json
  • package.json
📚 Learning: 2025-11-20T12:00:45.005Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11078
File: src/setupVitest.ts:11-15
Timestamp: 2025-11-20T12:00:45.005Z
Learning: In shapeshift/web, src/setupVitest.ts must redirect 'ethers' to 'ethers5' for shapeshiftoss/hdwallet-trezor (and -trezor-connect), same as ledger and shapeshift-multichain. Removing 'trezor' from the regex causes CI/Vitest failures due to ethers v6 vs v5 API differences.

Applied to files:

  • packages/swapper/package.json
  • package.json
📚 Learning: 2025-12-04T22:57:50.850Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 11290
File: packages/chain-adapters/src/utxo/zcash/ZcashChainAdapter.ts:48-51
Timestamp: 2025-12-04T22:57:50.850Z
Learning: In packages/chain-adapters/src/**/*ChainAdapter.ts files, the getName() method uses the pattern `const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.XXX); return Object.keys(ChainAdapterDisplayName)[enumIndex]` to reverse-lookup the enum key from its value. This is the established pattern used consistently across almost all chain adapters (Bitcoin, Ethereum, Litecoin, Dogecoin, Polygon, Arbitrum, Cosmos, etc.) and should be preserved for consistency when adding new chain adapters.

Applied to files:

  • package.json
  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-11-19T16:59:50.569Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11012
File: src/context/WalletProvider/Vultisig/components/Connect.tsx:24-59
Timestamp: 2025-11-19T16:59:50.569Z
Learning: In src/context/WalletProvider/*/components/Connect.tsx files across the ShapeShift web codebase, the established pattern for handling null/undefined adapter from getAdapter() is to simply check `if (adapter) { ... }` without an else clause. All wallet Connect components (Coinbase, Keplr, Phantom, Ledger, MetaMask, WalletConnectV2, KeepKey, Vultisig) follow this pattern—they reset loading state after the if block but do not show error messages when adapter is null. This is an intentional design decision and should be maintained for consistency.

Applied to files:

  • package.json
📚 Learning: 2025-12-17T14:50:01.629Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11449
File: packages/chain-adapters/src/tron/TronChainAdapter.ts:570-596
Timestamp: 2025-12-17T14:50:01.629Z
Learning: In packages/chain-adapters/src/tron/TronChainAdapter.ts, the parseTx method uses `unknown` type for the txHashOrTx parameter intentionally. TRON is a "second-class chain" that works differently from other chains - it accepts either a string hash (to fetch TronTx via unchained client) or a TronTx object directly. The base chain-adapter interface is strongly typed and doesn't accommodate this flexible signature, so `unknown` is used as an appropriate escape hatch rather than a type safety issue.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-12T13:43:19.770Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts:94-103
Timestamp: 2025-09-12T13:43:19.770Z
Learning: gomesalexandre has implemented a reliable gasLimit flow in WalletConnect dApps where Tenderly simulation provides gas estimates that get written to the form via setValue in GasSelectionMenu.tsx, making customTransactionData.gasLimit the primary reliable source. The sendTransaction.gasLimit fallback is kept as "paranoia" but may rarely be hit in practice due to this simulation-based architecture.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-11-12T12:18:00.863Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-145
Timestamp: 2025-11-12T12:18:00.863Z
Learning: NEAR Intents swapper: The NEAR 1Click API does not provide gas limit estimation logic like other swappers (e.g., magic gasLimit fields). For ERC20 token swaps in getTradeQuote, accurate fee estimation requires token approval and sufficient balance; without these prerequisites, fees may display as 0 or use inaccurate native transfer estimates. This is a known limitation of the NEAR Intents integration.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-08-22T12:58:26.590Z
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.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
🔇 Additional comments (14)
package.json (1)

103-120: LGTM! Consistent hdwallet package version bumps.

All 18 hdwallet packages are consistently updated from 1.62.32 to 1.62.34, maintaining proper synchronization across the hoisted dependencies. This aligns with the PR's Starknet implementation objectives, where account derivation and wallet support are core requirements.

packages/swapper/package.json (1)

42-42: Remove this verification request - hdwallet-core v1.62.34 does not include Starknet support.

The shapeshift/hdwallet repository has no Starknet implementation. Starknet support in this PR is provided by shapeshift/web's own chain adapters (packages/chain-adapters/src/starknet/), not by the hdwallet-core dependency. The version bump to 1.62.34 should be verified for its actual purpose (bug fixes, other features), not Starknet alignment.

Likely an incorrect or invalid review comment.

packages/chain-adapters/src/starknet/StarknetChainAdapter.ts (12)

45-50: LGTM - Well-defined constants.

The STRK token address and OpenZeppelin account class hash are correctly defined as module-level constants for reuse throughout the adapter.


52-75: LGTM - Proper initialization and wallet validation.

The class structure follows established patterns from other chain adapters, with proper BIP44 parameters and wallet type assertions.


107-132: LGTM - Address derivation logic is sound.

The method correctly handles the pubKey shortcut, validates wallet support, and derives the address using BIP44 parameters. The TODO for Ledger verification is acceptable for initial implementation.


134-183: LGTM - Proper balance fetching with undeployed account handling.

The Uint256 balance reconstruction is correct, and the try-catch appropriately handles undeployed accounts that cannot return balances yet.


185-192: LGTM - Proper address validation.

Correctly delegates to starknet.js validateAndParseAddress and returns the appropriate ValidAddressResult type.


229-433: LGTM - Account deployment flow is comprehensive.

The deployment logic correctly:

  • Validates account state before deployment
  • Uses RPC fee estimation with appropriate fallbacks
  • Applies sensible margins (5x amount, 2x price) to resource bounds
  • Properly signs and broadcasts the deployment transaction

The hardcoded placeholder values in the initial fee estimation request (lines 281-284) are appropriate since the RPC returns actual estimates.


457-569: SendMax fee estimation logic appears sound.

The sendMax implementation:

  1. Queries the current balance
  2. Estimates fees for a dummy transaction with the full balance
  3. Subtracts estimated fees from balance to determine maximum sendable amount

This approach is reasonable for ERC-20 transfers where fees are paid in STRK.


571-742: LGTM - Transaction building logic is thorough.

The method properly:

  • Handles Uint256 value splitting for large amounts
  • Constructs ERC-20 transfer calls with correct selector
  • Manages nonce for both deployed and undeployed accounts
  • Estimates fees and applies consistent safety margins
  • Returns complete transaction details for signing

744-757: LGTM - Proper delegation pattern.

This wrapper correctly derives the sender address and delegates to buildSendApiTransaction.


759-828: LGTM - Signature flow correctly implemented.

The method properly:

  • Validates wallet support
  • Extracts transaction details and signs with the wallet
  • Formats signatures with hex prefixes
  • Serializes BigInt values to strings for JSON compatibility

830-903: LGTM - Sign and broadcast flow is correct.

The methods properly:

  • Chain signing and broadcasting operations
  • Handle JSON serialization/deserialization round-trip
  • Convert resource bounds through appropriate type transformations
  • Submit transactions via the correct RPC endpoint

964-1147: LGTM - Transaction parsing logic is comprehensive.

The parseTx method correctly:

  • Handles pending and not-found transactions gracefully
  • Maps Starknet execution status to internal TxStatus enum
  • Parses fees from multiple response formats (v3 object structure and legacy)
  • Extracts transfer events using the correct Transfer selector
  • Reconstructs Uint256 amounts from low/high parts
  • Creates both Send and Receive transfers based on address matching
  • Normalizes addresses for consistent comparison

The error handling is robust throughout.

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

♻️ Duplicate comments (1)
src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx (1)

133-141: Hardcoded toast strings should use translation keys.

The toast messages on lines 137-138 use hardcoded English strings instead of translation keys, which violates coding guidelines.

🧹 Nitpick comments (3)
src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts (1)

8-25: Minor: Avoid redundant fromAccountId call.

fromAccountId(accountId) is called on line 11, but the result isn't reused on line 19 where .account is needed. Consider destructuring account alongside chainId from the first call.

🔎 Suggested optimization
 const checkStarknetAccountDeployment = async (accountId: AccountId | undefined) => {
   if (!accountId) return true

-  const { chainId } = fromAccountId(accountId)
+  const { chainId, account: fromAddress } = fromAccountId(accountId)
   if (chainId !== starknetChainId) return true

   try {
     const chainAdapterManager = getChainAdapterManager()
     const adapter = chainAdapterManager.get(chainId)
     if (!isStarknetChainAdapter(adapter)) return true

-    const fromAddress = fromAccountId(accountId).account
     return await adapter.isAccountDeployed(fromAddress)
   } catch (error) {
     console.error('Failed to check Starknet account deployment status:', error)
     return true
   }
 }
src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx (1)

96-141: Consider extracting deployment mutation to a shared hook.

The deployAccountMutation logic here is nearly identical to the implementation in SendAmountDetails.tsx. This duplication could lead to divergence over time. Consider extracting this into a shared useDeployStarknetAccount hook that both components can consume.

Given the PR author's preference for minimal focused changes, this refactor can be deferred to a follow-up. Based on learnings, the PR author prefers keeping changes minimal.

src/components/Modals/Send/views/SendAmountDetails.tsx (1)

117-162: Code duplication with TradeFooterButton.tsx.

This deployAccountMutation is nearly identical to the one in TradeFooterButton.tsx. As mentioned in that file's review, consider extracting to a shared useDeployStarknetAccount hook.

Based on learnings, this can be deferred to a follow-up PR to keep changes focused.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 23fd3c0 and 6c00d2f.

📒 Files selected for processing (6)
  • .env
  • src/assets/translations/en/main.json
  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/assets/translations/en/main.json
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{tsx,jsx}: ALWAYS wrap React components in error boundaries and provide user-friendly fallback components with error logging
ALWAYS use useErrorToast hook for displaying errors with translated error messages and handle different error types appropriately

Use PascalCase for React component names and match the component name to the file name

Files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{jsx,tsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless absolutely necessary, and ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components; NEVER use default exports for components
KEEP component files under 200 lines when possible; BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly in async operations
ALWAYS provide user-friendly error messages in error handling
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components using React.lazy for code splitting
ALWAYS use Suspense wrapper for lazy loaded components
USE local state for component-level state; LIFT state up when needed across multiple components; USE Context for avoiding prop drilling; USE Redux only for global state shared across multiple places
Wrap components receiving props with memo for performance optimization

Files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

Ensure TypeScript types are explicit and proper; avoid use of any type

Files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
🧠 Learnings (51)
📓 Common learnings
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: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/components/Stake/components/StakeSummary.tsx:112-114
Timestamp: 2025-08-22T13:00:44.879Z
Learning: NeOMakinG prefers to keep PR changes minimal and focused on the core objectives, avoiding cosmetic or defensive code improvements that aren't directly related to the PR scope, even when they would improve robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/error-handling.mdc:266-274
Timestamp: 2025-07-29T10:35:22.059Z
Learning: NeOMakinG prefers less nitpicky suggestions on documentation and best practices files, finding overly detailed suggestions on minor implementation details (like console.error vs logger.error) too granular for cursor rules documentation.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/pages/Dashboard/components/AccountList/AccountTable.tsx:60-0
Timestamp: 2025-09-02T08:34:08.157Z
Learning: NeOMakinG prefers code review comments to focus only on actual PR changes, not pre-existing code issues, unless there are critical security or correctness concerns directly related to the new functionality.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:42-86
Timestamp: 2025-08-08T11:41:22.794Z
Learning: NeOMakinG prefers not to include refactors in move-only PRs; such suggestions should be deferred to follow-up issues instead of being applied within the same PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/Table/Table.theme.ts:177-180
Timestamp: 2025-09-02T12:38:46.940Z
Learning: NeOMakinG prefers to defer technical debt and CSS correctness issues (like improper hover selectors) to follow-up PRs when the current PR is already large and focused on major feature implementation, even when the issues are valid from a usability/technical perspective.
📚 Learning: 2025-10-21T17:11:18.087Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10871
File: src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx:426-428
Timestamp: 2025-10-21T17:11:18.087Z
Learning: In src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx, within the handleInputChange function, use .toFixed() without arguments (not .toString()) when converting BigNumber amounts for input field synchronization. This avoids exponential notation in the input while preserving precision for presentational components like <Amount.Crypto /> and <Amount.Fiat /> to format appropriately.

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-09-12T11:52:39.280Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:18-21
Timestamp: 2025-09-12T11:52:39.280Z
Learning: In WalletConnect dApps integration, gomesalexandre has implemented intentional routing logic where EIP155TransactionConfirmation is typed for EthSignTransactionCallRequest only, while a separate SendTransactionConfirmation component handles EthSendTransactionCallRequest. The WalletConnectModalManager contains conditional logic to route native send transactions to SendTransactionConfirmation and other transaction types to EIP155TransactionConfirmation, creating a clean separation of concerns between signing and sending flows.

Applied to files:

  • src/components/Modals/Send/Form.tsx
📚 Learning: 2025-08-29T07:07:49.332Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10386
File: src/components/MultiHopTrade/components/VerifyAddresses/VerifyAddresses.tsx:272-294
Timestamp: 2025-08-29T07:07:49.332Z
Learning: In UTXO sell address verification flow in VerifyAddresses.tsx, the user wants address verification to be marked as "verified/complete" before starting the change address fetch, not after. The verification step and change address fetch should be treated as separate sequential operations in the UI flow.

Applied to files:

  • src/components/Modals/Send/Form.tsx
📚 Learning: 2025-09-12T12:00:33.924Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns in WalletConnect modals, including side-effects-during-render for error handling (showErrorToast + handleReject), rather than introducing isolated refactors that would make the codebase inconsistent.

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-09-12T12:00:33.924Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns across WalletConnect modal components, including side-effects-during-render for error handling (showErrorToast + handleReject calls before return null), rather than introducing isolated refactors that would create inconsistency in the codebase.

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : All copy/text must use translation keys - never hardcode strings

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:17.804Z
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 **/*.{tsx,jsx} : ALWAYS use `useErrorToast` hook for displaying errors with translated error messages and handle different error types appropriately

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-08T15:00:49.887Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-14T17:56:23.721Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:545-566
Timestamp: 2025-08-14T17:56:23.721Z
Learning: gomesalexandre prefers not to extract helper functions for toast rendering patterns in TransactionRow.tsx (src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx), considering it over-abstraction even when there's code duplication between deposit and withdraw flows.

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to src/assets/translations/en/main.json : Add English copy to `src/assets/translations/en/main.json` (find appropriate section)

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-10-07T03:44:27.350Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10760
File: src/components/ManageHiddenAssets/ManageHiddenAssetsList.tsx:78-84
Timestamp: 2025-10-07T03:44:27.350Z
Learning: In the ShapeShift web codebase, the following are stable references and do not need to be included in useCallback/useMemo dependency arrays:
- `navigate` from `useBrowserRouter()` hook
- Modal control objects (like `walletDrawer`) from `useModal()` hook (including their `isOpen`, `close`, and `open` methods)
- These are backed by stable context providers

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-12-27T16:02:52.792Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11536
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:252-265
Timestamp: 2025-12-27T16:02:52.792Z
Learning: When reviewing bug fixes, especially in shapeshift/web, prefer minimal changes that fix correctness over introducing broader refactors or quality-of-life improvements (e.g., extracting duplicated logic) unless such improvements are essential to the fix. Apply this guideline broadly to TSX files and related components, not just the specific location, to keep changes focused and maintainable.

Applied to files:

  • src/components/Modals/Send/Form.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Import types from `shapeshiftoss/caip` for chain/account/asset IDs

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-14T17:54:32.563Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx:97-108
Timestamp: 2025-08-14T17:54:32.563Z
Learning: In ReusableLpStatus component (src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx), the txAssets dependency is stable from first render because poolAsset, baseAsset, actionSide, and action are all defined first render, making the current txAssetsStatuses initialization pattern safe without needing useEffect synchronization.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-09-04T17:29:59.479Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx:28-33
Timestamp: 2025-09-04T17:29:59.479Z
Learning: In shapeshift/web, the useGetPopularAssetsQuery function in src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx intentionally uses primaryAssets[assetId] instead of falling back to assets[assetId]. The design distributes primary assets across chains by iterating through their related assets and adding the primary asset to each related asset's chain. This ensures primary assets appear in all chains where they have related assets, supporting the grouped asset system.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-21T22:15:25.918Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useFetchBasePortfolio.ts:31-59
Timestamp: 2025-08-21T22:15:25.918Z
Learning: In the ShapeShift web codebase, the maintainer prefers inferred return types for React hooks over explicit return types, particularly for complex hooks that can have intricate return signatures.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-09-08T15:53:09.362Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10442
File: src/components/TradeAssetSearch/components/GroupedAssetList/GroupedAssetList.tsx:34-35
Timestamp: 2025-09-08T15:53:09.362Z
Learning: In DefaultAssetList.tsx, the GroupedAssetList component already receives the activeChainId prop correctly on line ~58, contrary to automated analysis that may flag it as missing.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Use Chakra UI components and conventions

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-07-29T10:27:23.424Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/react-best-practices.mdc:8-14
Timestamp: 2025-07-29T10:27:23.424Z
Learning: The ShapeShift team practices aggressive memoization in React components as documented in .cursor/rules/react-best-practices.mdc. They use useMemo for all transformations, derived values, and conditional values, and useCallback for all event handlers and functions that could be passed as props. This approach was adopted after experiencing performance issues ("had hard time") and is their current established practice, though they acknowledge it may evolve in the future.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:44.637Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/react-best-practices.mdc:0-0
Timestamp: 2025-11-24T21:20:44.637Z
Learning: Applies to **/*.{jsx,tsx} : EXTRACT complex logic into custom hooks

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-10-17T07:51:58.374Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10783
File: src/context/WalletProvider/NewWalletViews/NewWalletViewsSwitch.tsx:344-349
Timestamp: 2025-10-17T07:51:58.374Z
Learning: In the shapeshift/web codebase, Chakra UI's ModalContent component supports the containerProps prop. When using the useModalRegistration hook from ModalStackProvider, spreading {...modalContentProps} directly onto ModalContent is correct and properly applies z-index and pointer-events through containerProps.sx. Do not suggest extracting sx from modalContentProps.containerProps.sx.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-15T07:51:16.374Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10278
File: src/components/AssetHeader/hooks/useQuickBuy.ts:97-99
Timestamp: 2025-08-15T07:51:16.374Z
Learning: The selectPortfolioUserCurrencyBalanceByAssetId selector in src/state/slices/portfolioSlice/selectors.ts accepts a filter object with an assetId property (signature: (state, { assetId })), not a raw AssetId string. Passing a filter object like { assetId: someAssetId } is the correct usage pattern.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-22T12:58:36.070Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/Notifications/RewardDistributionNotification.tsx:33-55
Timestamp: 2025-08-22T12:58:36.070Z
Learning: In RewardDistributionNotification component (src/components/Layout/Header/ActionCenter/components/Notifications/RewardDistributionNotification.tsx), NeOMakinG confirmed that runeAsset is expected to always be defined when the component renders, so defensive guards against undefined runeAsset are not needed.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Account for light/dark mode using `useColorModeValue` hook

Applied to files:

  • src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts
📚 Learning: 2025-07-29T15:04:28.083Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-08T11:41:36.971Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:88-109
Timestamp: 2025-08-08T11:41:36.971Z
Learning: In MultiHopTrade Confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx), the Confirm route does not remount; navigating away goes to the swapper input page. Therefore, persistent deduplication across remounts for quote tracking is unnecessary; a ref-based single-mount dedupe is sufficient.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-08T11:40:55.734Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Use the translation hook: `useTranslate()` from `react-polyglot`

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-09-08T22:00:48.005Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:17.804Z
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 **/*.{ts,tsx} : ALWAYS use custom error classes from `shapeshiftoss/errors` with meaningful error codes for internationalization and relevant details in error objects

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-13T15:50:41.994Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10272
File: src/components/RatingModal.tsx:104-0
Timestamp: 2025-08-13T15:50:41.994Z
Learning: In the ShapeShift web codebase, internal strings like Discord webhook embed content (used for team notifications/feedback) don't need to be translated, only user-facing strings require translation keys. The team distinguishes between internal tooling strings and user-facing UI strings for internationalization purposes.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-11T09:46:41.060Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10219
File: src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx:167-172
Timestamp: 2025-08-11T09:46:41.060Z
Learning: In the shapeshift/web repository, the display cache logic for trade quotes (using `selectUserAvailableTradeQuotes` and `selectUserUnavailableTradeQuotes`) is intentionally kept the same between `TradeInput.tsx` and `TradeQuotes.tsx` components. The `hasQuotes` computation in `TradeInput.tsx` uses these display cache selectors by design, matching the pattern used in `TradeQuotes.tsx`.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:17.804Z
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

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-12-09T21:07:22.474Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11335
File: packages/swapper/src/swappers/CetusSwapper/utils/helpers.ts:3-3
Timestamp: 2025-12-09T21:07:22.474Z
Learning: In packages/swapper/src/swappers/CetusSwapper, mysten/sui types (SuiClient, Transaction) must be imported from the nested path within cetusprotocol/aggregator-sdk (e.g., 'cetusprotocol/aggregator-sdk/node_modules/mysten/sui/client') because the aggregator SDK bundles its own version of mysten/sui. Direct imports from 'mysten/sui' break at runtime even when specified in package.json.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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/*/utils/constants.ts : Define supported chain IDs for each swapper in utils/constants.ts with both 'sell' and 'buy' properties following the pattern: SupportedChainIds type

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-04T16:02:27.360Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T16:02:27.360Z
Learning: In multi-hop swap transactions, last hop sell transactions might not be detected by the swapper (unlike buy transactions which are always known immediately). The conditional stepSource logic for last hop buy transactions (`isLastHopSellTxSeen ? stepSource : undefined`) serves as defensive programming for future multi-hop support with intermediate chains, even though multi-hop functionality is not currently supported in production.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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 filterAssetIdsBySellable method to filter assets by supported chain IDs in the sell property

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-12-17T14:50:01.629Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11449
File: packages/chain-adapters/src/tron/TronChainAdapter.ts:570-596
Timestamp: 2025-12-17T14:50:01.629Z
Learning: In packages/chain-adapters/src/tron/TronChainAdapter.ts, the parseTx method uses `unknown` type for the txHashOrTx parameter intentionally. TRON is a "second-class chain" that works differently from other chains - it accepts either a string hash (to fetch TronTx via unchained client) or a TronTx object directly. The base chain-adapter interface is strongly typed and doesn't accommodate this flexible signature, so `unknown` is used as an appropriate escape hatch rather than a type safety issue.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-10T21:09:25.643Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-15T07:51:16.374Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10278
File: src/components/AssetHeader/hooks/useQuickBuy.ts:97-99
Timestamp: 2025-08-15T07:51:16.374Z
Learning: The selectPortfolioUserCurrencyBalanceByAssetId selector in src/state/slices/portfolioSlice/selectors.ts expects a filter object with an assetId property, not a raw AssetId string. The selector signature is (state: ReduxState, filter) where filter should have an assetId property. This pattern is consistent across portfolio selectors that use selectAssetIdParamFromFilter. Passing a filter object like { assetId: someAssetId } is the correct usage pattern.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-15T07:51:16.374Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10278
File: src/components/AssetHeader/hooks/useQuickBuy.ts:97-99
Timestamp: 2025-08-15T07:51:16.374Z
Learning: The selectPortfolioUserCurrencyBalanceByAssetId selector in src/state/slices/portfolioSlice/selectors.ts accepts a filter object with an assetId property, not a raw AssetId string. The selector signature is (state: ReduxState, filter) where filter is expected to have an assetId property. Passing a filter object like { assetId: someAssetId } is the correct usage pattern.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to src/config.ts : Default values always come from environment variables prefixed with `VITE_FEATURE_`

Applied to files:

  • .env
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: To add a new feature flag: (1) Add to `FeatureFlags` type in `src/state/slices/preferencesSlice/preferencesSlice.ts`, (2) Add environment variable validation in `src/config.ts`, (3) Add to initial state in `preferencesSlice.ts`, (4) Add to test mock in `src/test/mocks/store.ts`, (5) Set appropriate values in `.env`, `.env.development`, and `.env.production`

Applied to files:

  • .env
📚 Learning: 2025-12-03T23:19:39.158Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11275
File: headers/csps/chains/plasma.ts:1-10
Timestamp: 2025-12-03T23:19:39.158Z
Learning: For CSP files in headers/csps/chains/, gomesalexandre prefers using Vite's loadEnv() pattern directly to load environment variables (e.g., VITE_PLASMA_NODE_URL, VITE_MONAD_NODE_URL) for consistency with existing second-class chain CSP files, rather than using getConfig() from src/config.ts, even though other parts of the codebase use validated config values.

Applied to files:

  • .env
📚 Learning: 2025-09-09T06:01:24.130Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10424
File: .env.production:3-3
Timestamp: 2025-09-09T06:01:24.130Z
Learning: In Vite, environment variables have a fallback mechanism where .env.production takes precedence over .env, but variables defined only in .env will still be available in the production environment if not overridden in .env.production.

Applied to files:

  • .env
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to {.env.development,.env.production} : Use `.env.development` for dev-only features and `.env.production` for prod settings

Applied to files:

  • .env
📚 Learning: 2025-11-12T09:00:20.961Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: .env:38-38
Timestamp: 2025-11-12T09:00:20.961Z
Learning: In the shapeshift/web repository, alphabetical ordering of environment variables in .env files is not enforced or required, despite dotenv-linter warnings suggesting otherwise.

Applied to files:

  • .env
📚 Learning: 2025-08-13T13:45:25.748Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10265
File: src/pages/ThorChainLP/queries/hooks/usePools.ts:93-0
Timestamp: 2025-08-13T13:45:25.748Z
Learning: In the ShapeShift web app, inbound addresses data for Thorchain pools requires aggressive caching settings (staleTime: 0, gcTime: 0, refetchInterval: 60_000) to ensure trading status and LP deposit availability are always current. This is intentional business-critical behavior, not a performance issue to be optimized.

Applied to files:

  • .env
🧬 Code graph analysis (3)
src/components/Modals/Send/Form.tsx (1)
src/components/Modals/Send/utils.ts (1)
  • maybeFetchChangeAddress (459-483)
src/components/Modals/Send/views/SendAmountDetails.tsx (6)
src/hooks/useNotificationToast.tsx (1)
  • useNotificationToast (27-70)
src/state/store.ts (1)
  • useAppSelector (144-144)
src/state/slices/portfolioSlice/selectors.ts (1)
  • selectPortfolioAccountMetadataByAccountId (121-126)
src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts (1)
  • useIsStarknetAccountDeployed (27-35)
packages/caip/src/constants.ts (1)
  • starknetChainId (89-89)
src/lib/utils/starknet.ts (1)
  • isStarknetChainAdapter (9-14)
src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts (2)
packages/caip/src/constants.ts (1)
  • starknetChainId (89-89)
src/lib/utils/starknet.ts (1)
  • isStarknetChainAdapter (9-14)
🪛 dotenv-linter (4.0.0)
.env

[warning] 162-162: [UnorderedKey] The VITE_STARKNET_NODE_URL key should go before the VITE_THORCHAIN_NODE_URL key

(UnorderedKey)

🔇 Additional comments (9)
.env (2)

10-10: LGTM!

The new feature flag is correctly positioned alphabetically among other feature flags and defaults to false, aligning with the PR objective of gating Starknet support behind a feature flag.


162-162: LGTM!

The Starknet node URL is correctly positioned alphabetically (between SOLANA and TRON) and uses the Lava RPC endpoint as intended per the PR description.

src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts (1)

27-35: LGTM!

The hook correctly uses React Query with appropriate configuration: enabled guards against undefined accountId, staleTime of 30s is reasonable for deployment status, and refetchInterval: false prevents unnecessary polling.

src/components/Modals/Send/Form.tsx (2)

142-151: LGTM!

The executeSend function cleanly separates transaction execution from post-send flow handling. The null check on line 145 correctly short-circuits when the send fails.


231-247: LGTM!

The refactored handleSubmit correctly orchestrates the send flow: validates wallet, fetches change address for UTXO chains, executes the send, and completes the flow. Dependencies are properly included.

src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx (2)

173-195: LGTM!

The translation logic correctly handles the Starknet deployment state, showing the deploy button text when isStarknetAccountDeployed === false during initializing/previewing states.


224-247: LGTM!

The handleClick flow correctly gates on Starknet deployment status before proceeding with trade submission. The early return after triggering deployment prevents the trade from executing before the account is deployed.

src/components/Modals/Send/views/SendAmountDetails.tsx (2)

182-191: Verify: After successful deployment, user needs to click again.

When deployAccountMutation.mutate() succeeds, onSuccess only calls refetchDeploymentStatus(). The user remains on the same screen and must click the button again to proceed to SendRoutes.Confirm.

If this is intentional UX (giving users confirmation before continuing), this is fine. However, if the intent is to auto-navigate after deployment, the flow should call navigate(SendRoutes.Confirm) in onSuccess.


396-403: LGTM!

The UI correctly shows a warning alert when Starknet account is not deployed, and the button states appropriately reflect deployment progress with loading text and disabled states.

Also applies to: 423-457

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

🧹 Nitpick comments (1)
src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx (1)

104-146: Consider extracting shared logic between failAction and completeAction.

Both callbacks share ~90% of their implementation, differing only in:

  • Action status (Failed vs Complete)
  • Message key
  • Toast status (error vs success)

This duplication could be eliminated by extracting a shared helper that accepts these values as parameters.

🔎 Proposed refactor to reduce duplication
+  const updateActionWithToast = useCallback(
+    (
+      action: ReturnType<typeof selectPendingWalletSendActions>[number],
+      status: ActionStatus,
+      message: string,
+      toastStatus: 'success' | 'error',
+    ) => {
+      const { txHash } = action.transactionMetadata
+
+      dispatch(
+        actionSlice.actions.upsertAction({
+          ...action,
+          status,
+          updatedAt: Date.now(),
+          transactionMetadata: {
+            ...action.transactionMetadata,
+            message,
+          },
+        }),
+      )
+
+      const isActive = toast.isActive(txHash)
+      if (isActive) return
+
+      toast({
+        id: txHash,
+        duration: isDrawerOpen ? 5000 : null,
+        status: toastStatus,
+        render: ({ onClose, ...props }) => {
+          const handleClick = () => {
+            onClose()
+            openActionCenter()
+          }
+          return (
+            <GenericTransactionNotification
+              handleClick={handleClick}
+              actionId={txHash}
+              onClose={onClose}
+              {...props}
+            />
+          )
+        },
+      })
+    },
+    [dispatch, toast, isDrawerOpen, openActionCenter],
+  )
+
   const completeAction = useCallback(
     (action: ReturnType<typeof selectPendingWalletSendActions>[number]) => {
-      const { txHash, accountId, accountIdsToRefetch } = action.transactionMetadata
-
-      dispatch(
-        actionSlice.actions.upsertAction({
-          ...action,
-          status: ActionStatus.Complete,
-          updatedAt: Date.now(),
-          transactionMetadata: {
-            ...action.transactionMetadata,
-            message: 'modals.send.youHaveSent',
-          },
-        }),
+      updateActionWithToast(
+        action,
+        ActionStatus.Complete,
+        'modals.send.youHaveSent',
+        'success',
       )

+      const { accountId, accountIdsToRefetch } = action.transactionMetadata
       const chainId = fromAccountId(accountId).chainId
       const isSecondClassChain = SECOND_CLASS_CHAINS.includes(chainId as KnownChainIds)

       if (isSecondClassChain) {
         // ... existing portfolio refresh logic
       }
-
-      const isActive = toast.isActive(txHash)
-      if (isActive) return
-
-      toast({
-        // ... existing toast logic
-      })
     },
-    [dispatch, toast, isDrawerOpen, openActionCenter],
+    [updateActionWithToast],
   )

   const failAction = useCallback(
     (action: ReturnType<typeof selectPendingWalletSendActions>[number]) => {
-      const { txHash } = action.transactionMetadata
-
-      dispatch(
-        actionSlice.actions.upsertAction({
-          ...action,
-          status: ActionStatus.Failed,
-          updatedAt: Date.now(),
-          transactionMetadata: {
-            ...action.transactionMetadata,
-            message: 'modals.send.sendFailed',
-          },
-        }),
-      )
-
-      const isActive = toast.isActive(txHash)
-      if (isActive) return
-
-      toast({
-        id: txHash,
-        duration: isDrawerOpen ? 5000 : null,
-        status: 'error',
-        render: ({ onClose, ...props }) => {
-          const handleClick = () => {
-            onClose()
-            openActionCenter()
-          }
-          return (
-            <GenericTransactionNotification
-              handleClick={handleClick}
-              actionId={txHash}
-              onClose={onClose}
-              {...props}
-            />
-          )
-        },
-      })
+      updateActionWithToast(
+        action,
+        ActionStatus.Failed,
+        'modals.send.sendFailed',
+        'error',
+      )
     },
-    [dispatch, toast, isDrawerOpen, openActionCenter],
+    [updateActionWithToast],
   )
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6c00d2f and d048189.

📒 Files selected for processing (8)
  • .env
  • .env.development
  • scripts/generateAssetData/generateAssetData.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
  • src/constants/chains.ts
  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/lib/asset-service/service/encodedAssetData.json
  • src/lib/asset-service/service/encodedRelatedAssetIndex.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/constants/chains.ts
  • scripts/generateAssetData/generateAssetData.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{tsx,jsx}: ALWAYS wrap React components in error boundaries and provide user-friendly fallback components with error logging
ALWAYS use useErrorToast hook for displaying errors with translated error messages and handle different error types appropriately

Use PascalCase for React component names and match the component name to the file name

Files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{jsx,tsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless absolutely necessary, and ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components; NEVER use default exports for components
KEEP component files under 200 lines when possible; BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly in async operations
ALWAYS provide user-friendly error messages in error handling
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components using React.lazy for code splitting
ALWAYS use Suspense wrapper for lazy loaded components
USE local state for component-level state; LIFT state up when needed across multiple components; USE Context for avoiding prop drilling; USE Redux only for global state shared across multiple places
Wrap components receiving props with memo for performance optimization

Files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

Ensure TypeScript types are explicit and proper; avoid use of any type

Files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
{.env.development,.env.production}

📄 CodeRabbit inference engine (CLAUDE.md)

Use .env.development for dev-only features and .env.production for prod settings

Files:

  • .env.development
🧠 Learnings (35)
📓 Common learnings
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10376
File: packages/contracts/src/viemClient.ts:39-40
Timestamp: 2025-08-27T09:51:36.901Z
Learning: NeOMakinG confirmed that issues flagged by CodeRabbit that predate the PR changes and are unrelated to the PR's core objective should be addressed separately, not within the current PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/components/Stake/components/StakeSummary.tsx:112-114
Timestamp: 2025-08-22T13:00:44.879Z
Learning: NeOMakinG prefers to keep PR changes minimal and focused on the core objectives, avoiding cosmetic or defensive code improvements that aren't directly related to the PR scope, even when they would improve robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/error-handling.mdc:266-274
Timestamp: 2025-07-29T10:35:22.059Z
Learning: NeOMakinG prefers less nitpicky suggestions on documentation and best practices files, finding overly detailed suggestions on minor implementation details (like console.error vs logger.error) too granular for cursor rules documentation.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/pages/Dashboard/components/AccountList/AccountTable.tsx:60-0
Timestamp: 2025-09-02T08:34:08.157Z
Learning: NeOMakinG prefers code review comments to focus only on actual PR changes, not pre-existing code issues, unless there are critical security or correctness concerns directly related to the new functionality.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:42-86
Timestamp: 2025-08-08T11:41:22.794Z
Learning: NeOMakinG prefers not to include refactors in move-only PRs; such suggestions should be deferred to follow-up issues instead of being applied within the same PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/Table/Table.theme.ts:177-180
Timestamp: 2025-09-02T12:38:46.940Z
Learning: NeOMakinG prefers to defer technical debt and CSS correctness issues (like improper hover selectors) to follow-up PRs when the current PR is already large and focused on major feature implementation, even when the issues are valid from a usability/technical perspective.
📚 Learning: 2025-08-22T15:07:18.021Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx:37-41
Timestamp: 2025-08-22T15:07:18.021Z
Learning: In src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx, kaladinlight prefers not to await the upsertBasePortfolio call in the Base chain handling block, indicating intentional fire-and-forget behavior for Base portfolio upserts in the THORChain LP completion flow.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-08-22T13:16:12.721Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/hooks/useRfoxRewardDistributionActionSubscriber.tsx:104-105
Timestamp: 2025-08-22T13:16:12.721Z
Learning: In src/pages/RFOX/hooks/useRfoxRewardDistributionActionSubscriber.tsx, the guard `if (!actions[actionId]) return` before upserting completed reward distributions is intentional product behavior. NeOMakinG confirmed that the system should only show completion notifications for reward distributions that were previously seen in a pending state, not for distributions the user missed during the pending phase.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-08-25T12:58:39.547Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/Notifications/RewardDistributionNotification.tsx:69-70
Timestamp: 2025-08-25T12:58:39.547Z
Learning: In RewardDistributionNotification component (src/components/Layout/Header/ActionCenter/components/Notifications/RewardDistributionNotification.tsx), NeOMakinG confirmed that action is expected to always be defined when the component renders, so defensive guards against undefined action are not needed.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-08-22T14:59:04.889Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useGenericTransactionSubscriber.tsx:105-111
Timestamp: 2025-08-22T14:59:04.889Z
Learning: In the ShapeShift web Base chain handling, the await pattern inside forEach in useGenericTransactionSubscriber is intentional to delay the entire action completion flow (not just fetchBasePortfolio) for Base chain transactions. The user kaladinlight wants everything below the Base portfolio refresh - including dispatch, query invalidation, and toast notifications - to also be delayed by ~10 seconds to accommodate Base's degraded node state.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-08-22T13:02:58.824Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/hooks/useRfoxRewardDistributionActionSubscriber.tsx:33-41
Timestamp: 2025-08-22T13:02:58.824Z
Learning: In src/pages/RFOX/hooks/useRfoxRewardDistributionActionSubscriber.tsx, NeOMakinG declined optimizing useMemo dependencies to depend on lifetimeRewardDistributionsQuery.data instead of the entire query object, indicating indifference toward this type of performance optimization.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-08-14T17:54:32.563Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx:97-108
Timestamp: 2025-08-14T17:54:32.563Z
Learning: In ReusableLpStatus component (src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx), the txAssets dependency is stable from first render because poolAsset, baseAsset, actionSide, and action are all defined first render, making the current txAssetsStatuses initialization pattern safe without needing useEffect synchronization.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-12-17T14:50:01.629Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11449
File: packages/chain-adapters/src/tron/TronChainAdapter.ts:570-596
Timestamp: 2025-12-17T14:50:01.629Z
Learning: In packages/chain-adapters/src/tron/TronChainAdapter.ts, the parseTx method uses `unknown` type for the txHashOrTx parameter intentionally. TRON is a "second-class chain" that works differently from other chains - it accepts either a string hash (to fetch TronTx via unchained client) or a TronTx object directly. The base chain-adapter interface is strongly typed and doesn't accommodate this flexible signature, so `unknown` is used as an appropriate escape hatch rather than a type safety issue.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-08-22T12:58:26.590Z
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.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Use `useAppDispatch` for Redux actions

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
📚 Learning: 2025-12-27T16:02:52.792Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11536
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:252-265
Timestamp: 2025-12-27T16:02:52.792Z
Learning: When reviewing bug fixes, especially in shapeshift/web, prefer minimal changes that fix correctness over introducing broader refactors or quality-of-life improvements (e.g., extracting duplicated logic) unless such improvements are essential to the fix. Apply this guideline broadly to TSX files and related components, not just the specific location, to keep changes focused and maintainable.

Applied to files:

  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to src/config.ts : Default values always come from environment variables prefixed with `VITE_FEATURE_`

Applied to files:

  • .env
  • .env.development
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: To add a new feature flag: (1) Add to `FeatureFlags` type in `src/state/slices/preferencesSlice/preferencesSlice.ts`, (2) Add environment variable validation in `src/config.ts`, (3) Add to initial state in `preferencesSlice.ts`, (4) Add to test mock in `src/test/mocks/store.ts`, (5) Set appropriate values in `.env`, `.env.development`, and `.env.production`

Applied to files:

  • .env
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to {.env.development,.env.production} : Use `.env.development` for dev-only features and `.env.production` for prod settings

Applied to files:

  • .env
📚 Learning: 2025-09-09T06:01:24.130Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10424
File: .env.production:3-3
Timestamp: 2025-09-09T06:01:24.130Z
Learning: In Vite, environment variables have a fallback mechanism where .env.production takes precedence over .env, but variables defined only in .env will still be available in the production environment if not overridden in .env.production.

Applied to files:

  • .env
📚 Learning: 2025-11-12T09:00:20.961Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: .env:38-38
Timestamp: 2025-11-12T09:00:20.961Z
Learning: In the shapeshift/web repository, alphabetical ordering of environment variables in .env files is not enforced or required, despite dotenv-linter warnings suggesting otherwise.

Applied to files:

  • .env
📚 Learning: 2025-12-03T23:19:39.158Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11275
File: headers/csps/chains/plasma.ts:1-10
Timestamp: 2025-12-03T23:19:39.158Z
Learning: For CSP files in headers/csps/chains/, gomesalexandre prefers using Vite's loadEnv() pattern directly to load environment variables (e.g., VITE_PLASMA_NODE_URL, VITE_MONAD_NODE_URL) for consistency with existing second-class chain CSP files, rather than using getConfig() from src/config.ts, even though other parts of the codebase use validated config values.

Applied to files:

  • .env
  • .env.development
📚 Learning: 2025-07-29T15:04:28.083Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-08-08T11:40:55.734Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-08-04T16:02:27.360Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T16:02:27.360Z
Learning: In multi-hop swap transactions, last hop sell transactions might not be detected by the swapper (unlike buy transactions which are always known immediately). The conditional stepSource logic for last hop buy transactions (`isLastHopSellTxSeen ? stepSource : undefined`) serves as defensive programming for future multi-hop support with intermediate chains, even though multi-hop functionality is not currently supported in production.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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 : Reuse executeEvmTransaction utility for EVM-based swappers instead of implementing custom transaction execution

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-08-08T11:41:36.971Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:88-109
Timestamp: 2025-08-08T11:41:36.971Z
Learning: In MultiHopTrade Confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx), the Confirm route does not remount; navigating away goes to the swapper input page. Therefore, persistent deduplication across remounts for quote tracking is unnecessary; a ref-based single-mount dedupe is sufficient.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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 filterAssetIdsBySellable method to filter assets by supported chain IDs in the sell property

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Import types from `shapeshiftoss/caip` for chain/account/asset IDs

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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/*/utils/constants.ts : Define supported chain IDs for each swapper in utils/constants.ts with both 'sell' and 'buy' properties following the pattern: SupportedChainIds type

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-08-05T23:36:13.214Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10187
File: src/state/slices/preferencesSlice/selectors.ts:21-25
Timestamp: 2025-08-05T23:36:13.214Z
Learning: The AssetId type from 'shapeshiftoss/caip' package is a string type alias, so it can be used directly as a return type for cache key resolvers in re-reselect selectors without needing explicit string conversion.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-10-23T14:27:19.073Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10857
File: src/plugins/walletConnectToDapps/eventsManager/useWalletConnectEventsHandler.ts:101-104
Timestamp: 2025-10-23T14:27:19.073Z
Learning: In WalletConnect wallet_switchEthereumChain and wallet_addEthereumChain requests, the chainId parameter is always present as per the protocol spec. Type guards checking for missing chainId in these handlers (like `if (!evmNetworkIdHex) return`) are solely for TypeScript compiler satisfaction, not real runtime edge cases.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-12-09T21:07:22.474Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11335
File: packages/swapper/src/swappers/CetusSwapper/utils/helpers.ts:3-3
Timestamp: 2025-12-09T21:07:22.474Z
Learning: In packages/swapper/src/swappers/CetusSwapper, mysten/sui types (SuiClient, Transaction) must be imported from the nested path within cetusprotocol/aggregator-sdk (e.g., 'cetusprotocol/aggregator-sdk/node_modules/mysten/sui/client') because the aggregator SDK bundles its own version of mysten/sui. Direct imports from 'mysten/sui' break at runtime even when specified in package.json.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-09-12T09:48:46.305Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/StructuredMessage/StructuredMessage.tsx:0-0
Timestamp: 2025-09-12T09:48:46.305Z
Learning: In WalletConnect signing flows dealing with structured message data (like StructuredField.value in StructuredMessage.tsx), gomesalexandre prefers using `any` type for values representing dynamic Solidity types from external API responses, consistent with their approach to other external API parsing in WalletConnect flows.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-08-26T19:04:38.672Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10369
File: packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts:167-176
Timestamp: 2025-08-26T19:04:38.672Z
Learning: In packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts, when processing assets from data.assets.reduce(), the team prefers using empty catch blocks to gracefully skip any assets that fail processing, rather than specific error type handling, to avoid useless noise and ensure robust asset filtering.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-09-12T13:44:17.019Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:0-0
Timestamp: 2025-09-12T13:44:17.019Z
Learning: gomesalexandre prefers letting chain adapter errors throw naturally in useSimulateEvmTransaction rather than adding explicit error handling for missing adapters, consistent with his fail-fast approach and dismissal of defensive validation as "stale" in WalletConnect transaction simulation flows.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-12-04T22:57:50.850Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 11290
File: packages/chain-adapters/src/utxo/zcash/ZcashChainAdapter.ts:48-51
Timestamp: 2025-12-04T22:57:50.850Z
Learning: In packages/chain-adapters/src/**/*ChainAdapter.ts files, the getName() method uses the pattern `const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.XXX); return Object.keys(ChainAdapterDisplayName)[enumIndex]` to reverse-lookup the enum key from its value. This is the established pattern used consistently across almost all chain adapters (Bitcoin, Ethereum, Litecoin, Dogecoin, Polygon, Arbitrum, Cosmos, etc.) and should be preserved for consistency when adding new chain adapters.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
📚 Learning: 2025-11-12T12:49:17.895Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-125
Timestamp: 2025-11-12T12:49:17.895Z
Learning: In packages/chain-adapters/src/evm/utils.ts, the getErc20Data function already includes a guard that returns an empty string when contractAddress is undefined (line 8: `if (!contractAddress) return ''`). This built-in handling means callers don't need to conditionally invoke getErc20Data—it safely handles both ERC20 tokens and native assets.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
🧬 Code graph analysis (2)
src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx (4)
src/state/slices/actionSlice/selectors.ts (1)
  • selectPendingWalletSendActions (119-124)
src/state/slices/actionSlice/actionSlice.ts (1)
  • actionSlice (11-39)
src/lib/utils/starknet.ts (2)
  • isStarknetChainAdapter (9-14)
  • getStarknetTransactionStatus (29-46)
src/state/slices/txHistorySlice/txHistorySlice.ts (1)
  • txHistory (120-161)
src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx (2)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (91-99)
src/lib/utils/starknet.ts (1)
  • assertGetStarknetChainAdapter (16-27)
🪛 dotenv-linter (4.0.0)
.env

[warning] 164-164: [UnorderedKey] The VITE_STARKNET_NODE_URL key should go before the VITE_THORCHAIN_NODE_URL key

(UnorderedKey)

.env.development

[warning] 73-73: [UnorderedKey] The VITE_STARKNET_NODE_URL key should go before the VITE_THORCHAIN_NODE_URL key

(UnorderedKey)


[warning] 88-88: [UnorderedKey] The VITE_FEATURE_STARKNET key should go before the VITE_FEATURE_SWAPPER_FIAT_RAMPS key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Call / Static
🔇 Additional comments (7)
.env (1)

10-10: Configuration correctly gated and uses appropriate node endpoint.

The feature flag defaults to false for production, and the node URL correctly points to the Lava public RPC endpoint for Starknet. Both changes align with the PR objectives of a feature-gated implementation.

Also applies to: 164-164

.env.development (1)

73-73: Development environment correctly enables Starknet feature.

The feature flag is enabled in development (line 88), and the node URL is consistent with .env (line 73). This allows testing of Starknet functionality during development while keeping it disabled by default in production.

Also applies to: 88-88

src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx (2)

4-9: LGTM! Starknet imports follow established patterns.

The addition of StarknetSignTx type and assertGetStarknetChainAdapter utility follows the same pattern as existing chain implementations (Solana, Sui, etc.). The imports are properly structured and necessary for the new Starknet execution path.

Also applies to: 44-44


617-647: Starknet execution case is properly implemented and follows established patterns.

The implementation is verified as correct:

  • execStarknetTransaction method exists in TradeExecution class with proper signature matching the usage
  • Method validates required swapper methods (getUnsignedStarknetTransaction, executeStarknetTransaction) before execution
  • Follows the same pattern as other chain implementations (Solana, Sui, Tron) via _execWalletAgnostic
  • All required parameters correctly passed from the hook
  • Proper handling of sign/broadcast callback, analytics tracking, and polling cancellation
  • Type safety maintained with properly defined StarknetTransactionExecutionInput
src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx (3)

18-18: LGTM - Starknet utility imports.

The new imports are correctly used in the Starknet polling case below.


204-239: Verify intended behavioral difference from other second-class chains.

Starknet is the only second-class chain that distinguishes between Failed and Confirmed transaction statuses:

  • All other chains (Tron, Sui, Monad, Plasma, HyperEvm, Thorchain, Mayachain) treat TxStatus.Failed the same as TxStatus.Confirmed and call completeAction() for both.
  • Starknet explicitly handles failed transactions with failAction(), which does NOT refresh portfolios.

Potential concerns:

  1. Portfolio refresh on failure: When a Starknet transaction fails after being submitted on-chain, gas fees may have been consumed, changing the account balance. However, failAction() doesn't trigger the portfolio refresh that completeAction() performs for second-class chains (lines 62-74). Should portfolio balances be refreshed on failure?

  2. Consistency: Line 172's comment states "as for now we don't support failed sends lets consider it confirmed". Is this Starknet-specific failure handling intentional product direction, or should other chains also adopt this pattern?

Please confirm:

  1. Portfolio refresh is intentionally skipped for failed Starknet transactions
  2. The behavioral difference from other second-class chains is intentional (Starknet distinguishes failures, others don't)

319-319: LGTM - Dependency array correctly updated.

The addition of failAction to the dependency array is correct since the callback is now invoked within the effect.

Copy link
Contributor

@gomesalexandre gomesalexandre left a comment

Choose a reason for hiding this comment

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

Does the thing!

One thing I spotted here is we'll want to have proper fees for near sends as I'm able to send max balance of STRK, but other than that LGTM with the new flow 🌮

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

🧹 Nitpick comments (1)
src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx (1)

122-126: Consider adding an explicit timeout to waitForTransaction.

While Starknet providers typically have internal timeouts, explicitly specifying a timeout parameter improves code clarity and ensures predictable behavior. This defensive practice helps prevent indefinite hangs in case of network issues or provider changes.

🔎 Add explicit timeout
       await starknetProvider.waitForTransaction(deployTxHash, {
         retryInterval: 2000,
+        timeout: 300000, // 5 minutes
         successStates: ['ACCEPTED_ON_L2', 'ACCEPTED_ON_L1'],
       })
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bf5e929 and fc09eaa.

⛔ Files ignored due to path filters (16)
  • packages/caip/src/adapters/coincap/generated/eip155_1/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_137/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_42161/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_43114/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_56/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/eip155_8453/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coincap/generated/solana_5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_1/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_42161/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_43114/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_56/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/eip155_8453/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/solana_5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/adapter.json is excluded by !**/generated/**
  • public/generated/asset-manifest.json is excluded by !**/generated/**
  • public/generated/generatedAssetData.json is excluded by !**/generated/**
  • public/generated/relatedAssetIndex.json is excluded by !**/generated/**
📒 Files selected for processing (11)
  • packages/caip/src/adapters/coincap/index.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateAssetData/color-map.json
  • scripts/generateAssetData/generateAssetData.ts
  • scripts/generateTradableAssetMap/index.ts
  • src/assets/translations/en/main.json
  • src/components/Modals/Send/views/SendAmountDetails.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/lib/asset-service/service/AssetService.ts
  • src/state/migrations/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/assets/translations/en/main.json
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • src/lib/asset-service/service/AssetService.ts
  • packages/caip/src/adapters/coincap/index.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • src/state/migrations/index.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
  • scripts/generateAssetData/generateAssetData.ts
  • src/components/Modals/Send/views/SendAmountDetails.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • src/lib/asset-service/service/AssetService.ts
  • packages/caip/src/adapters/coincap/index.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • src/state/migrations/index.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
  • scripts/generateAssetData/generateAssetData.ts
  • src/components/Modals/Send/views/SendAmountDetails.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • src/lib/asset-service/service/AssetService.ts
  • packages/caip/src/adapters/coincap/index.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • src/state/migrations/index.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
  • scripts/generateAssetData/generateAssetData.ts
  • src/components/Modals/Send/views/SendAmountDetails.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{tsx,jsx}: ALWAYS wrap React components in error boundaries and provide user-friendly fallback components with error logging
ALWAYS use useErrorToast hook for displaying errors with translated error messages and handle different error types appropriately

Use PascalCase for React component names and match the component name to the file name

Files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{jsx,tsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless absolutely necessary, and ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components; NEVER use default exports for components
KEEP component files under 200 lines when possible; BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly in async operations
ALWAYS provide user-friendly error messages in error handling
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components using React.lazy for code splitting
ALWAYS use Suspense wrapper for lazy loaded components
USE local state for component-level state; LIFT state up when needed across multiple components; USE Context for avoiding prop drilling; USE Redux only for global state shared across multiple places
Wrap components receiving props with memo for performance optimization

Files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

Ensure TypeScript types are explicit and proper; avoid use of any type

Files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
**/swapper{s,}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

ALWAYS use makeSwapErrorRight for swapper errors with TradeQuoteError enum for error codes and provide detailed error information

Files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
packages/swapper/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)

packages/swapper/**/*.ts: Use TypeScript with explicit types (e.g., SupportedChainIds) for all code in the Swapper system
Use camelCase for variable and function names in the Swapper system
Use PascalCase for types, interfaces, and enums in the Swapper system
Use kebab-case for filenames in the Swapper system

Files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
packages/swapper/src/swappers/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)

packages/swapper/src/swappers/**/*.ts: Adhere to the Swapper directory structure: each swapper resides in packages/swapper/src/swappers// with required files (SwapperName.ts, endpoints.ts, types.ts, utils/constants.ts, utils/helpers.ts)
Validate inputs and log errors for debugging in Swapper system implementations
Swapper files must be located in packages/swapper/src/swappers/ directory structure and not placed outside this location
Avoid side effects in swap logic; ensure swap methods are deterministic and stateless

Files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
src/state/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/state/**/*.{ts,tsx}: Use createDeepEqualOutputSelector from @/state/selector-utils for deep equality checks
Use createCachedSelector from re-reselect for parameterized selectors

Files:

  • src/state/migrations/index.ts
🧠 Learnings (67)
📓 Common learnings
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/components/Stake/components/StakeSummary.tsx:112-114
Timestamp: 2025-08-22T13:00:44.879Z
Learning: NeOMakinG prefers to keep PR changes minimal and focused on the core objectives, avoiding cosmetic or defensive code improvements that aren't directly related to the PR scope, even when they would improve robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/error-handling.mdc:266-274
Timestamp: 2025-07-29T10:35:22.059Z
Learning: NeOMakinG prefers less nitpicky suggestions on documentation and best practices files, finding overly detailed suggestions on minor implementation details (like console.error vs logger.error) too granular for cursor rules documentation.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/pages/Dashboard/components/AccountList/AccountTable.tsx:60-0
Timestamp: 2025-09-02T08:34:08.157Z
Learning: NeOMakinG prefers code review comments to focus only on actual PR changes, not pre-existing code issues, unless there are critical security or correctness concerns directly related to the new functionality.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:42-86
Timestamp: 2025-08-08T11:41:22.794Z
Learning: NeOMakinG prefers not to include refactors in move-only PRs; such suggestions should be deferred to follow-up issues instead of being applied within the same PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/Table/Table.theme.ts:177-180
Timestamp: 2025-09-02T12:38:46.940Z
Learning: NeOMakinG prefers to defer technical debt and CSS correctness issues (like improper hover selectors) to follow-up PRs when the current PR is already large and focused on major feature implementation, even when the issues are valid from a usability/technical perspective.
📚 Learning: 2025-11-24T21:20:57.909Z
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 filterAssetIdsBySellable method to filter assets by supported chain IDs in the sell property

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-09-08T15:53:09.362Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10442
File: src/components/TradeAssetSearch/components/GroupedAssetList/GroupedAssetList.tsx:34-35
Timestamp: 2025-09-08T15:53:09.362Z
Learning: In DefaultAssetList.tsx, the GroupedAssetList component already receives the activeChainId prop correctly on line ~58, contrary to automated analysis that may flag it as missing.

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateAssetData/generateAssetData.ts
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-08T15:00:49.887Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Import types from `shapeshiftoss/caip` for chain/account/asset IDs

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • packages/caip/src/adapters/coincap/index.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-10-23T14:27:19.073Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10857
File: src/plugins/walletConnectToDapps/eventsManager/useWalletConnectEventsHandler.ts:101-104
Timestamp: 2025-10-23T14:27:19.073Z
Learning: In WalletConnect wallet_switchEthereumChain and wallet_addEthereumChain requests, the chainId parameter is always present as per the protocol spec. Type guards checking for missing chainId in these handlers (like `if (!evmNetworkIdHex) return`) are solely for TypeScript compiler satisfaction, not real runtime edge cases.

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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/*/utils/constants.ts : Define supported chain IDs for each swapper in utils/constants.ts with both 'sell' and 'buy' properties following the pattern: SupportedChainIds type

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-08-11T09:45:51.174Z
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.

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
📚 Learning: 2025-09-04T17:27:33.328Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/TradeAssetSearch/components/SearchTermAssetList.tsx:88-94
Timestamp: 2025-09-04T17:27:33.328Z
Learning: In shapeshift/web, NFTs never have related assets in the grouping system. The related assets feature is designed for fungible tokens that exist across multiple chains (like USDC on different chains), not for NFTs which are unique. Therefore, checking isNft() for related asset IDs is unnecessary since NFT asset IDs won't be present in the relatedAssetIdsById mapping.

Applied to files:

  • src/lib/asset-service/service/AssetService.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to src/config.ts : Default values always come from environment variables prefixed with `VITE_FEATURE_`

Applied to files:

  • packages/caip/src/adapters/coincap/index.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-12-03T23:19:39.158Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11275
File: headers/csps/chains/plasma.ts:1-10
Timestamp: 2025-12-03T23:19:39.158Z
Learning: For CSP files in headers/csps/chains/, gomesalexandre prefers using Vite's loadEnv() pattern directly to load environment variables (e.g., VITE_PLASMA_NODE_URL, VITE_MONAD_NODE_URL) for consistency with existing second-class chain CSP files, rather than using getConfig() from src/config.ts, even though other parts of the codebase use validated config values.

Applied to files:

  • packages/caip/src/adapters/coincap/index.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-07-29T15:04:28.083Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-08T11:41:36.971Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:88-109
Timestamp: 2025-08-08T11:41:36.971Z
Learning: In MultiHopTrade Confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx), the Confirm route does not remount; navigating away goes to the swapper input page. Therefore, persistent deduplication across remounts for quote tracking is unnecessary; a ref-based single-mount dedupe is sufficient.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-08T11:40:55.734Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : All copy/text must use translation keys - never hardcode strings

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:17.804Z
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 **/*.{tsx,jsx} : ALWAYS use `useErrorToast` hook for displaying errors with translated error messages and handle different error types appropriately

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-14T17:56:23.721Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:545-566
Timestamp: 2025-08-14T17:56:23.721Z
Learning: gomesalexandre prefers not to extract helper functions for toast rendering patterns in TransactionRow.tsx (src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx), considering it over-abstraction even when there's code duplication between deposit and withdraw flows.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to src/assets/translations/en/main.json : Add English copy to `src/assets/translations/en/main.json` (find appropriate section)

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Use the translation hook: `useTranslate()` from `react-polyglot`

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-09-08T22:00:48.005Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:17.804Z
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 **/*.{ts,tsx} : ALWAYS use custom error classes from `shapeshiftoss/errors` with meaningful error codes for internationalization and relevant details in error objects

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-13T15:50:41.994Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10272
File: src/components/RatingModal.tsx:104-0
Timestamp: 2025-08-13T15:50:41.994Z
Learning: In the ShapeShift web codebase, internal strings like Discord webhook embed content (used for team notifications/feedback) don't need to be translated, only user-facing strings require translation keys. The team distinguishes between internal tooling strings and user-facing UI strings for internationalization purposes.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-10-07T03:44:27.350Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10760
File: src/components/ManageHiddenAssets/ManageHiddenAssetsList.tsx:78-84
Timestamp: 2025-10-07T03:44:27.350Z
Learning: In the ShapeShift web codebase, the following are stable references and do not need to be included in useCallback/useMemo dependency arrays:
- `navigate` from `useBrowserRouter()` hook
- Modal control objects (like `walletDrawer`) from `useModal()` hook (including their `isOpen`, `close`, and `open` methods)
- These are backed by stable context providers

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-11T09:46:41.060Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10219
File: src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx:167-172
Timestamp: 2025-08-11T09:46:41.060Z
Learning: In the shapeshift/web repository, the display cache logic for trade quotes (using `selectUserAvailableTradeQuotes` and `selectUserUnavailableTradeQuotes`) is intentionally kept the same between `TradeInput.tsx` and `TradeQuotes.tsx` components. The `hasQuotes` computation in `TradeInput.tsx` uses these display cache selectors by design, matching the pattern used in `TradeQuotes.tsx`.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Use Chakra UI components and conventions

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-21T22:15:25.918Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useFetchBasePortfolio.ts:31-59
Timestamp: 2025-08-21T22:15:25.918Z
Learning: In the ShapeShift web codebase, the maintainer prefers inferred return types for React hooks over explicit return types, particularly for complex hooks that can have intricate return signatures.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:17.804Z
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

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-07-29T10:27:23.424Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/react-best-practices.mdc:8-14
Timestamp: 2025-07-29T10:27:23.424Z
Learning: The ShapeShift team practices aggressive memoization in React components as documented in .cursor/rules/react-best-practices.mdc. They use useMemo for all transformations, derived values, and conditional values, and useCallback for all event handlers and functions that could be passed as props. This approach was adopted after experiencing performance issues ("had hard time") and is their current established practice, though they acknowledge it may evolve in the future.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-12-09T21:07:22.474Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11335
File: packages/swapper/src/swappers/CetusSwapper/utils/helpers.ts:3-3
Timestamp: 2025-12-09T21:07:22.474Z
Learning: In packages/swapper/src/swappers/CetusSwapper, mysten/sui types (SuiClient, Transaction) must be imported from the nested path within cetusprotocol/aggregator-sdk (e.g., 'cetusprotocol/aggregator-sdk/node_modules/mysten/sui/client') because the aggregator SDK bundles its own version of mysten/sui. Direct imports from 'mysten/sui' break at runtime even when specified in package.json.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-10-01T04:16:42.281Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10707
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:104-107
Timestamp: 2025-10-01T04:16:42.281Z
Learning: In the ShapeShift web codebase, React Query expects functions to return at least `null` rather than `undefined`. When implementing quote fetching functions that may not return a value, they should explicitly return `null` instead of implicit `undefined` to ensure proper React Query caching and state management.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-04T16:02:27.360Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T16:02:27.360Z
Learning: In multi-hop swap transactions, last hop sell transactions might not be detected by the swapper (unlike buy transactions which are always known immediately). The conditional stepSource logic for last hop buy transactions (`isLastHopSellTxSeen ? stepSource : undefined`) serves as defensive programming for future multi-hop support with intermediate chains, even though multi-hop functionality is not currently supported in production.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-12-17T14:50:01.629Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11449
File: packages/chain-adapters/src/tron/TronChainAdapter.ts:570-596
Timestamp: 2025-12-17T14:50:01.629Z
Learning: In packages/chain-adapters/src/tron/TronChainAdapter.ts, the parseTx method uses `unknown` type for the txHashOrTx parameter intentionally. TRON is a "second-class chain" that works differently from other chains - it accepts either a string hash (to fetch TronTx via unchained client) or a TronTx object directly. The base chain-adapter interface is strongly typed and doesn't accommodate this flexible signature, so `unknown` is used as an appropriate escape hatch rather than a type safety issue.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-14T17:54:32.563Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx:97-108
Timestamp: 2025-08-14T17:54:32.563Z
Learning: In ReusableLpStatus component (src/pages/ThorChainLP/components/ReusableLpStatus/ReusableLpStatus.tsx), the txAssets dependency is stable from first render because poolAsset, baseAsset, actionSide, and action are all defined first render, making the current txAssetsStatuses initialization pattern safe without needing useEffect synchronization.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • scripts/generateTradableAssetMap/index.ts
  • scripts/generateAssetData/generateAssetData.ts
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-09-12T12:00:33.924Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns across WalletConnect modal components, including side-effects-during-render for error handling (showErrorToast + handleReject calls before return null), rather than introducing isolated refactors that would create inconsistency in the codebase.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-09-12T12:00:33.924Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns in WalletConnect modals, including side-effects-during-render for error handling (showErrorToast + handleReject), rather than introducing isolated refactors that would make the codebase inconsistent.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-10T21:09:25.643Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-15T07:51:16.374Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10278
File: src/components/AssetHeader/hooks/useQuickBuy.ts:97-99
Timestamp: 2025-08-15T07:51:16.374Z
Learning: The selectPortfolioUserCurrencyBalanceByAssetId selector in src/state/slices/portfolioSlice/selectors.ts expects a filter object with an assetId property, not a raw AssetId string. The selector signature is (state: ReduxState, filter) where filter should have an assetId property. This pattern is consistent across portfolio selectors that use selectAssetIdParamFromFilter. Passing a filter object like { assetId: someAssetId } is the correct usage pattern.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-15T07:51:16.374Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10278
File: src/components/AssetHeader/hooks/useQuickBuy.ts:97-99
Timestamp: 2025-08-15T07:51:16.374Z
Learning: The selectPortfolioUserCurrencyBalanceByAssetId selector in src/state/slices/portfolioSlice/selectors.ts accepts a filter object with an assetId property (signature: (state, { assetId })), not a raw AssetId string. Passing a filter object like { assetId: someAssetId } is the correct usage pattern.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-15T07:51:16.374Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10278
File: src/components/AssetHeader/hooks/useQuickBuy.ts:97-99
Timestamp: 2025-08-15T07:51:16.374Z
Learning: The selectPortfolioUserCurrencyBalanceByAssetId selector in src/state/slices/portfolioSlice/selectors.ts accepts a filter object with an assetId property, not a raw AssetId string. The selector signature is (state: ReduxState, filter) where filter is expected to have an assetId property. Passing a filter object like { assetId: someAssetId } is the correct usage pattern.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-08-22T15:07:18.021Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx:37-41
Timestamp: 2025-08-22T15:07:18.021Z
Learning: In src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx, kaladinlight prefers not to await the upsertBasePortfolio call in the Base chain handling block, indicating intentional fire-and-forget behavior for Base portfolio upserts in the THORChain LP completion flow.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
📚 Learning: 2025-12-27T16:02:52.792Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11536
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:252-265
Timestamp: 2025-12-27T16:02:52.792Z
Learning: When reviewing bug fixes, especially in shapeshift/web, prefer minimal changes that fix correctness over introducing broader refactors or quality-of-life improvements (e.g., extracting duplicated logic) unless such improvements are essential to the fix. Apply this guideline broadly to TSX files and related components, not just the specific location, to keep changes focused and maintainable.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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 : Reuse executeEvmTransaction utility for EVM-based swappers instead of implementing custom transaction execution

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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/index.ts : Export unique functions and types from packages/swapper/src/index.ts only if needed for external consumption

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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 : Validate inputs and log errors for debugging in Swapper system implementations

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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/*/endpoints.ts : Reuse checkEvmSwapStatus utility for checking EVM swap status instead of implementing custom status checks

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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 : All swappers must implement the Swapper interface from packages/swapper/src/types.ts

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-08-05T23:36:13.214Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10187
File: src/state/slices/preferencesSlice/selectors.ts:21-25
Timestamp: 2025-08-05T23:36:13.214Z
Learning: The AssetId type from 'shapeshiftoss/caip' package is a string type alias, so it can be used directly as a return type for cache key resolvers in re-reselect selectors without needing explicit string conversion.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-09-04T17:29:59.479Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx:28-33
Timestamp: 2025-09-04T17:29:59.479Z
Learning: In shapeshift/web, the useGetPopularAssetsQuery function in src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx intentionally uses primaryAssets[assetId] instead of falling back to assets[assetId]. The design distributes primary assets across chains by iterating through their related assets and adding the primary asset to each related asset's chain. This ensures primary assets appear in all chains where they have related assets, supporting the grouped asset system.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
  • scripts/generateAssetData/generateAssetData.ts
  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-17T21:53:03.806Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10290
File: scripts/generateAssetData/color-map.json:41-47
Timestamp: 2025-08-17T21:53:03.806Z
Learning: In the ShapeShift web codebase, native assets (using CAIP-19 slip44 namespace like eip155:1/slip44:60, bip122:.../slip44:..., cosmos:.../slip44:...) are manually hardcoded and not generated via the automated asset generation script. Only ERC20/BEP20 tokens go through the asset generation process. The validation scripts should only validate generated assets, not manually added native assets.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
  • scripts/generateAssetData/generateAssetData.ts
📚 Learning: 2025-11-12T12:18:00.863Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-145
Timestamp: 2025-11-12T12:18:00.863Z
Learning: NEAR Intents swapper: The NEAR 1Click API does not provide gas limit estimation logic like other swappers (e.g., magic gasLimit fields). For ERC20 token swaps in getTradeQuote, accurate fee estimation requires token approval and sufficient balance; without these prerequisites, fees may display as 0 or use inaccurate native transfer estimates. This is a known limitation of the NEAR Intents integration.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-09-04T13:22:35.399Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/state/slices/assetsSlice/selectors.ts:45-51
Timestamp: 2025-09-04T13:22:35.399Z
Learning: In shapeshift/web, the isPrimaryAsset function in src/lib/utils/asset.ts is intentionally designed to only treat null relatedAssetKey as primary (not undefined). The asset generation process specifically sets relatedAssetKey to null for primary assets, while undefined means the asset doesn't participate in grouping and should not be considered primary. Only assets with null relatedAssetKey or where relatedAssetKey === assetId are primary assets.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-11-12T12:49:17.895Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-125
Timestamp: 2025-11-12T12:49:17.895Z
Learning: In packages/chain-adapters/src/evm/utils.ts, the getErc20Data function already includes a guard that returns an empty string when contractAddress is undefined (line 8: `if (!contractAddress) return ''`). This built-in handling means callers don't need to conditionally invoke getErc20Data—it safely handles both ERC20 tokens and native assets.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts
📚 Learning: 2025-08-27T13:49:48.668Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10375
File: src/state/migrations/index.ts:214-215
Timestamp: 2025-08-27T13:49:48.668Z
Learning: The clearAssetsMigrations system in the ShapeShift web app works independently of the root persistConfig version. Migration numbers (like 171) don't need to match the root persistConfig version field, and the system has been functioning correctly for months/years without manual version bumps.

Applied to files:

  • src/state/migrations/index.ts
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to src/state/slices/**/*.ts : Migrations are required when changing persisted state structure (see `src/state/migrations/`)

Applied to files:

  • src/state/migrations/index.ts
📚 Learning: 2025-08-27T13:49:48.668Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10375
File: src/state/migrations/index.ts:214-215
Timestamp: 2025-08-27T13:49:48.668Z
Learning: The ShapeShift web app uses an automated versioning system for Redux Persist migrations. The version is calculated as `Math.max(...Object.keys(clearAssetsMigrations).map(Number))`, which automatically uses the highest migration number as the version. This eliminates the need to manually update persistConfig versions when adding new migrations - the system automatically bumps the version when new migration numbers are added to the migration objects.

Applied to files:

  • src/state/migrations/index.ts
📚 Learning: 2025-12-04T11:05:01.146Z
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.

Applied to files:

  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-12-26T15:45:47.558Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11515
File: scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts:100-122
Timestamp: 2025-12-26T15:45:47.558Z
Learning: In scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts, gomesalexandre is comfortable with the fetchBridgedCategoryMappings function lacking try-catch error handling for CoinGecko API calls. He prefers letting the script crash on API failures rather than adding defensive error handling, consistent with his fail-fast approach for asset generation scripts.

Applied to files:

  • scripts/generateTradableAssetMap/index.ts
  • scripts/generateAssetData/generateAssetData.ts
📚 Learning: 2025-11-20T12:00:45.005Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11078
File: src/setupVitest.ts:11-15
Timestamp: 2025-11-20T12:00:45.005Z
Learning: In shapeshift/web, src/setupVitest.ts must redirect 'ethers' to 'ethers5' for shapeshiftoss/hdwallet-trezor (and -trezor-connect), same as ledger and shapeshift-multichain. Removing 'trezor' from the regex causes CI/Vitest failures due to ethers v6 vs v5 API differences.

Applied to files:

  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-08-13T13:45:25.748Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10265
File: src/pages/ThorChainLP/queries/hooks/usePools.ts:93-0
Timestamp: 2025-08-13T13:45:25.748Z
Learning: In the ShapeShift web app, inbound addresses data for Thorchain pools requires aggressive caching settings (staleTime: 0, gcTime: 0, refetchInterval: 60_000) to ensure trading status and LP deposit availability are always current. This is intentional business-critical behavior, not a performance issue to be optimized.

Applied to files:

  • scripts/generateTradableAssetMap/index.ts
📚 Learning: 2025-10-21T17:11:18.087Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10871
File: src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx:426-428
Timestamp: 2025-10-21T17:11:18.087Z
Learning: In src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx, within the handleInputChange function, use .toFixed() without arguments (not .toString()) when converting BigNumber amounts for input field synchronization. This avoids exponential notation in the input while preserving precision for presentational components like <Amount.Crypto /> and <Amount.Fiat /> to format appropriately.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-09-12T10:44:46.723Z
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.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-11-24T21:20:44.637Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/react-best-practices.mdc:0-0
Timestamp: 2025-11-24T21:20:44.637Z
Learning: Applies to **/*.{jsx,tsx} : EXTRACT complex logic into custom hooks

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-10-17T07:51:58.374Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10783
File: src/context/WalletProvider/NewWalletViews/NewWalletViewsSwitch.tsx:344-349
Timestamp: 2025-10-17T07:51:58.374Z
Learning: In the shapeshift/web codebase, Chakra UI's ModalContent component supports the containerProps prop. When using the useModalRegistration hook from ModalStackProvider, spreading {...modalContentProps} directly onto ModalContent is correct and properly applies z-index and pointer-events through containerProps.sx. Do not suggest extracting sx from modalContentProps.containerProps.sx.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
📚 Learning: 2025-08-22T12:58:36.070Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/Notifications/RewardDistributionNotification.tsx:33-55
Timestamp: 2025-08-22T12:58:36.070Z
Learning: In RewardDistributionNotification component (src/components/Layout/Header/ActionCenter/components/Notifications/RewardDistributionNotification.tsx), NeOMakinG confirmed that runeAsset is expected to always be defined when the component renders, so defensive guards against undefined runeAsset are not needed.

Applied to files:

  • src/components/Modals/Send/views/SendAmountDetails.tsx
🧬 Code graph analysis (5)
src/lib/asset-service/service/AssetService.ts (1)
packages/caip/src/constants.ts (1)
  • starknetChainId (89-89)
src/components/MultiHopTrade/components/TradeConfirm/TradeFooterButton.tsx (8)
src/hooks/useNotificationToast.tsx (1)
  • useNotificationToast (27-70)
src/state/store.ts (1)
  • useAppSelector (144-144)
src/state/slices/tradeInputSlice/selectors.ts (1)
  • selectFirstHopSellAccountId (46-46)
src/state/slices/portfolioSlice/selectors.ts (1)
  • selectPortfolioAccountMetadataByAccountId (121-126)
src/hooks/useIsStarknetAccountDeployed/useIsStarknetAccountDeployed.ts (1)
  • useIsStarknetAccountDeployed (27-35)
packages/caip/src/constants.ts (1)
  • starknetChainId (89-89)
src/lib/utils/starknet.ts (1)
  • isStarknetChainAdapter (9-14)
src/components/Text/Text.tsx (1)
  • Text (19-83)
packages/swapper/src/swappers/NearIntentsSwapper/utils/helpers/helpers.ts (3)
packages/types/src/base.ts (1)
  • Asset (88-110)
packages/swapper/src/swappers/NearIntentsSwapper/types.ts (1)
  • chainIdToNearIntentsChain (30-47)
packages/caip/src/constants.ts (1)
  • solanaChainId (86-86)
src/state/migrations/index.ts (1)
src/state/migrations/clearAssets.ts (1)
  • clearAssets (6-8)
scripts/generateAssetData/generateAssetData.ts (2)
packages/caip/src/adapters/coingecko/generated/index.ts (1)
  • starknet (47-47)
packages/utils/src/assetData/baseAssets.ts (1)
  • starknet (423-437)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Call / Static

@NeOMakinG NeOMakinG enabled auto-merge (squash) December 30, 2025 21:14
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: 0

🧹 Nitpick comments (2)
packages/chain-adapters/src/starknet/StarknetChainAdapter.ts (2)

45-50: Consider exporting public constants for reusability.

The STRK_TOKEN_ADDRESS and OPENZEPPELIN_ACCOUNT_CLASS_HASH constants are currently module-scoped. If other parts of the codebase need to reference these values (e.g., for asset generation, UI display, or testing), consider exporting them.

Note: The static analysis warning about line 46 is a false positive—this is a public contract address on Starknet mainnet, not a secret.


77-79: Follow the established enum reverse-lookup pattern for getName().

Most chain adapters use the pattern of reverse-looking up the enum key from the display name value:

const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.Starknet)
return Object.keys(ChainAdapterDisplayName)[enumIndex]

This maintains consistency across the codebase. Based on learnings, this is the established pattern used in Bitcoin, Ethereum, Litecoin, Cosmos, and other chain adapters.

🔎 Proposed fix
  getName() {
-   return 'Starknet'
+   const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.Starknet)
+   return Object.keys(ChainAdapterDisplayName)[enumIndex]
  }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fc09eaa and 523e731.

📒 Files selected for processing (1)
  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
🧠 Learnings (15)
📓 Common learnings
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/components/Stake/components/StakeSummary.tsx:112-114
Timestamp: 2025-08-22T13:00:44.879Z
Learning: NeOMakinG prefers to keep PR changes minimal and focused on the core objectives, avoiding cosmetic or defensive code improvements that aren't directly related to the PR scope, even when they would improve robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/error-handling.mdc:266-274
Timestamp: 2025-07-29T10:35:22.059Z
Learning: NeOMakinG prefers less nitpicky suggestions on documentation and best practices files, finding overly detailed suggestions on minor implementation details (like console.error vs logger.error) too granular for cursor rules documentation.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/pages/Dashboard/components/AccountList/AccountTable.tsx:60-0
Timestamp: 2025-09-02T08:34:08.157Z
Learning: NeOMakinG prefers code review comments to focus only on actual PR changes, not pre-existing code issues, unless there are critical security or correctness concerns directly related to the new functionality.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:42-86
Timestamp: 2025-08-08T11:41:22.794Z
Learning: NeOMakinG prefers not to include refactors in move-only PRs; such suggestions should be deferred to follow-up issues instead of being applied within the same PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/Table/Table.theme.ts:177-180
Timestamp: 2025-09-02T12:38:46.940Z
Learning: NeOMakinG prefers to defer technical debt and CSS correctness issues (like improper hover selectors) to follow-up PRs when the current PR is already large and focused on major feature implementation, even when the issues are valid from a usability/technical perspective.
📚 Learning: 2025-12-04T22:57:50.850Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 11290
File: packages/chain-adapters/src/utxo/zcash/ZcashChainAdapter.ts:48-51
Timestamp: 2025-12-04T22:57:50.850Z
Learning: In packages/chain-adapters/src/**/*ChainAdapter.ts files, the getName() method uses the pattern `const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.XXX); return Object.keys(ChainAdapterDisplayName)[enumIndex]` to reverse-lookup the enum key from its value. This is the established pattern used consistently across almost all chain adapters (Bitcoin, Ethereum, Litecoin, Dogecoin, Polygon, Arbitrum, Cosmos, etc.) and should be preserved for consistency when adding new chain adapters.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
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

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-12-17T14:50:01.629Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11449
File: packages/chain-adapters/src/tron/TronChainAdapter.ts:570-596
Timestamp: 2025-12-17T14:50:01.629Z
Learning: In packages/chain-adapters/src/tron/TronChainAdapter.ts, the parseTx method uses `unknown` type for the txHashOrTx parameter intentionally. TRON is a "second-class chain" that works differently from other chains - it accepts either a string hash (to fetch TronTx via unchained client) or a TronTx object directly. The base chain-adapter interface is strongly typed and doesn't accommodate this flexible signature, so `unknown` is used as an appropriate escape hatch rather than a type safety issue.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-12T13:43:19.770Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts:94-103
Timestamp: 2025-09-12T13:43:19.770Z
Learning: gomesalexandre has implemented a reliable gasLimit flow in WalletConnect dApps where Tenderly simulation provides gas estimates that get written to the form via setValue in GasSelectionMenu.tsx, making customTransactionData.gasLimit the primary reliable source. The sendTransaction.gasLimit fallback is kept as "paranoia" but may rarely be hit in practice due to this simulation-based architecture.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-12T13:43:50.695Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:91-95
Timestamp: 2025-09-12T13:43:50.695Z
Learning: gomesalexandre dismissed gas calculation overflow validation in useSimulateEvmTransaction hook as "stale", preferring to trust Tenderly's simulation data without defensive validation checks, consistent with his established pattern of relying on external service quality over defensive programming in WalletConnect flows.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-11T22:53:19.837Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-10-15T15:57:39.956Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10810
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:212-0
Timestamp: 2025-10-15T15:57:39.956Z
Learning: gomesalexandre uses discriminated union patterns (e.g., `isEIP1559 ? { max_fee_per_gas, max_priority_fee_per_gas } : { gas_price }`) in WalletConnect flows without additional validation guards, trusting that the runtime data structure ensures mutual exclusivity between EIP-1559 and legacy gas pricing fields.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-12-03T23:16:28.342Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11261
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx:117-172
Timestamp: 2025-12-03T23:16:28.342Z
Learning: In TRON transaction confirmation polling (e.g., approval flows in useAllowanceApproval.tsx), gomesalexandre is comfortable with optimistic completion when polling times out after the configured duration (e.g., 60 seconds). He considers the timeout a "paranoia" safety net for unlikely scenarios, expecting normal transactions to complete much faster. He prefers to defer more sophisticated timeout/failure handling as a separate follow-up concern rather than expanding PR scope.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-10T15:35:46.223Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx:55-55
Timestamp: 2025-09-10T15:35:46.223Z
Learning: gomesalexandre prefers fail-fast early returns over graceful degradation when critical data is missing in WalletConnect flows (like peer metadata in EIP155SignTypedDataConfirmation.tsx). He favors "safety first, always double-wrap" approach and believes missing peer metadata indicates bigger problems that should be surfaced explicitly rather than masked with partial UI rendering.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-12T10:35:51.632Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:33-45
Timestamp: 2025-09-12T10:35:51.632Z
Learning: gomesalexandre consistently dismisses CodeRabbit suggestions about replacing console.error/console.warn with structured logging in API integration code, preferring simple console logging for debugging Tenderly transaction simulation APIs in WalletConnect flows.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-12-03T23:21:16.985Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11261
File: src/lib/utils/tron/getAllowance.ts:14-59
Timestamp: 2025-12-03T23:21:16.985Z
Learning: In src/lib/utils/tron/getAllowance.ts, gomesalexandre is not concerned about adding comprehensive error handling (try-catch blocks, custom error classes) for the getTrc20Allowance utility function, because it is used close to the view layer. He prefers simpler error handling for view-layer utilities, letting errors propagate naturally rather than adding defensive guards.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-12T13:43:19.770Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts:94-103
Timestamp: 2025-09-12T13:43:19.770Z
Learning: gomesalexandre has implemented a sophisticated gasLimit management system in WalletConnect dApps using Tenderly simulation. The GasSelectionMenu component automatically adjusts gasLimit via setValue when simulation shows higher gas usage than currently set, handling edge cases like dApps that enforce low gas limits (e.g., 21000) when actual usage is higher (e.g., 23322). This makes customTransactionData.gasLimit highly reliable as the primary source.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-09-12T10:44:46.723Z
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.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
📚 Learning: 2025-08-22T12:58:26.590Z
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.

Applied to files:

  • packages/chain-adapters/src/starknet/StarknetChainAdapter.ts
🪛 Gitleaks (8.30.0)
packages/chain-adapters/src/starknet/StarknetChainAdapter.ts

[high] 46-46: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Call / Static
🔇 Additional comments (4)
packages/chain-adapters/src/starknet/StarknetChainAdapter.ts (4)

324-337: Verify resource bounds safety margins are appropriate.

The code applies 500% multiplier (5x) to gas amounts and 200% multiplier (2x) to gas prices. While conservative safety margins are important for Starknet's resource bounds model, these values seem quite high and could result in users locking up significantly more funds than necessary for transaction execution.

Are these multipliers based on documented best practices or empirical testing? Consider:

  • 5x gas amount means users must have 5x the estimated gas available
  • Combined with 2x price multiplier, this is ~10x the estimated cost
  • This could impact UX for users with limited balances

If these are standard/tested values for Starknet, this is fine. Otherwise, consider reducing to more typical values (e.g., 150-200% for amounts, 110-150% for prices).


905-1007: Fee estimation implementation looks good—past concern addressed.

The current implementation correctly uses a dummy transaction to estimate fees (lines 949-954), with hardcoded fallbacks only when the estimation fails entirely. This addresses the previous review comment about using RPC estimation instead of fixed values.

The fallback values (100,000 for L1 gas amounts) are reasonable defaults for error cases where the estimation service is unavailable, as they prevent the method from throwing while still providing conservative estimates.

Note: The optional chaining in lines 957-974 ensures the fallbacks are used only when feeEstimate fields are missing, not as primary values.


1120-1182: Transfer event parsing logic looks correct for Starknet.

The implementation properly:

  • Identifies Transfer events by selector (line 1118)
  • Reconstructs Uint256 amounts from low/high parts (lines 1129-1131)
  • Normalizes addresses for comparison (lines 1136-1137, 1149-1151)
  • Creates both Send and Receive transfers when the user is involved (lines 1154-1173)

The address normalization prevents issues with inconsistent padding in Starknet addresses.


677-689: Resource bounds multipliers are consistent across the codebase.

The same safety margins (500% for gas amounts, 200% for prices) are applied consistently in both deployAccount and buildSendApiTransaction methods. This ensures predictable behavior across different transaction types.

@NeOMakinG NeOMakinG merged commit 3ec9533 into develop Dec 30, 2025
4 checks passed
@NeOMakinG NeOMakinG deleted the starknet branch December 30, 2025 21:22
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.

2 participants