Skip to content

feat: migrate rainbowkit to reown on swap widget plus support btc and solana#11712

Merged
NeOMakinG merged 33 commits intodevelopfrom
auto-claude/001-feat-switch-widget-to-wallet-connect-and-support-u
Jan 21, 2026
Merged

feat: migrate rainbowkit to reown on swap widget plus support btc and solana#11712
NeOMakinG merged 33 commits intodevelopfrom
auto-claude/001-feat-switch-widget-to-wallet-connect-and-support-u

Conversation

@NeOMakinG
Copy link
Collaborator

@NeOMakinG NeOMakinG commented Jan 17, 2026

Description

This PR migrates the swap widget from RainbowKit to Reown AppKit and adds comprehensive multi-chain wallet support including Bitcoin (UTXO) and Solana. The migration enables a better multi-chain experience with improved wallet connection handling and cross-chain swap capabilities.

Key Changes

1. Multi-Chain Wallet Integration

  • Migrated from RainbowKit to Reown AppKit with support for:
    • EVM chains: Wagmi adapter with all supported EVM networks
    • Bitcoin (UTXO): Bitcoin adapter with Taproot and Native SegWit support
    • Solana: Solana adapter with SPL token support
  • Added useBitcoinSigning hook for Bitcoin wallet interactions (sendTransfer, signPSBT, signMessage)
  • Added useSolanaSigning hook for Solana wallet interactions
  • Implemented async Bitcoin address detection with priority: Taproot (bc1p, purpose 86) → Native SegWit (bc1q, purpose 84) → Payment accounts

2. Balance Fetching Enhancements

  • Implemented useMultiChainBalances hook supporting EVM, UTXO, and Solana chains
  • Added Solana public RPC fallback (https://api.mainnet-beta.solana.com) for balance fetching without wallet connection
  • Enhanced Bitcoin balance precision to support up to 8 decimals
  • Migrated balance refresh to React Query's queryClient.invalidateQueries() API for better performance
  • Optimized TokenSelectModal to only refetch current sell/buy asset balances instead of all assets

3. Cross-Chain Swap Support

  • Fixed canExecuteDirectly logic to enable EVM → non-EVM swaps (e.g., Base → Solana with Phantom wallet)
  • Implemented chain-aware default receive address:
    • Uses Bitcoin address for UTXO chain purchases
    • Uses Solana address for Solana chain purchases
    • Uses EVM address for EVM chain purchases
  • Updated buy asset balance tracking to use chain-appropriate wallet address
  • Implemented delayed balance refetch for cross-chain swaps:
    • Sell balance: 3 seconds (source chain)
    • Buy balance (cross-chain): 15 seconds + 30 seconds
    • Buy balance (same-chain): 3 seconds

4. UI/UX Improvements

  • Simplified isButtonDisabled logic with early returns for better readability
  • Added wallet connection state handling for Bitcoin and Solana
  • Enhanced TokenSelectModal to show balances for all connected wallet types
  • Improved loading states for multi-chain balance queries

5. Configuration Updates

  • Added missing EVM chains to AppKit config: Monad, HyperEVM, Plasma, Katana
  • Added Bitcoin and Solana chain configurations
  • Updated types/index.ts with multi-chain types and utilities

Files Modified

Core Components:

  • src/components/SwapWidget.tsx - Main swap logic with multi-chain support
  • src/components/TokenSelectModal.tsx - Token selection with multi-chain balances

Hooks:

  • src/hooks/useBalances.ts - Multi-chain balance fetching
  • src/hooks/useBitcoinSigning.ts - Bitcoin wallet integration (NEW)
  • src/hooks/useSolanaSigning.ts - Solana wallet integration (NEW)

Configuration:

  • src/config/appkit.ts - AppKit configuration with all adapters
  • src/types/index.ts - Multi-chain types and utilities

Technical Details

Bitcoin Integration:

  • Detects and prioritizes Taproot addresses (bc1p, BIP86/purpose 86)
  • Falls back to Native SegWit (bc1q, BIP84/purpose 84)
  • Uses mempool.space API for balance fetching
  • Supports PSBT signing and message signing

Solana Integration:

  • Native SOL balance support
  • SPL token balance support via getTokenAccountsByOwner
  • Public RPC fallback for balance queries without wallet connection

Balance Refresh Strategy:

  • Uses React Query's invalidation API with predicates
  • Query keys: ['multiChainBalance', chainType, address, assetId, ...]
  • Respects staleTime settings (60s for EVM/UTXO, 30s for Solana)

Issue (if applicable)

N/A - Infrastructure improvement for multi-chain support

Risk

Medium Risk

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

This PR affects:

  • Wallet Connection: Migration from RainbowKit to Reown AppKit
  • Balance Fetching: All chains (EVM, Bitcoin, Solana)
  • Swap Execution: Cross-chain swaps (EVM ↔ Bitcoin ↔ Solana)
  • Transaction Signing: Bitcoin PSBT signing, Solana transactions

Risk Mitigation:

  • All EVM functionality remains unchanged (same Wagmi core)
  • Bitcoin and Solana are additive features (no existing functionality removed)
  • Public RPC fallbacks ensure balance fetching works without wallet connection
  • React Query invalidation respects existing cache settings

Testing

Engineering

Local Testing:

cd packages/swap-widget
yarn install
yarn dev

Test Scenarios:

  1. EVM Wallet Connection:

    • Connect MetaMask/WalletConnect
    • Verify balance fetching for EVM tokens
    • Execute EVM → EVM swap (e.g., ETH → USDC)
  2. Bitcoin Wallet Connection:

    • Connect Bitcoin wallet (via AppKit)
    • Verify Taproot address detection (bc1p)
    • Verify balance display with 8 decimal precision
    • Test receive address defaults to Bitcoin address for BTC purchases
  3. Solana Wallet Connection:

    • Connect Phantom wallet
    • Verify SOL and SPL token balances
    • Execute cross-chain swap (e.g., Base → SOL)
    • Verify delayed balance refresh (15s, 30s)
  4. TokenSelectModal:

    • Open token selector after swap
    • Verify only current assets are refetched (check network tab)
    • Verify balances show for all connected wallet types
  5. Cross-Chain Swaps:

    • Test EVM → Solana (Base → SOL)
    • Test EVM → Bitcoin (ETH → BTC)
    • Verify receive addresses are chain-appropriate
    • Verify buy asset balance uses correct wallet address

Integration Points:

  • AppKit wallet adapters (EVM, Bitcoin, Solana)
  • React Query cache invalidation
  • Multi-chain balance queries (useQueries)

Operations

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

User-Facing Changes:

  1. Wallet Connection:

    • Users can now connect Bitcoin and Solana wallets in addition to EVM
    • Wallet modal shows all supported chains
  2. Balance Display:

    • Bitcoin balances show up to 8 decimals
    • Balances refresh automatically after swaps with appropriate timing
    • TokenSelectModal shows balances for all connected wallet types
  3. Cross-Chain Swaps:

    • Users can swap from EVM chains to Solana/Bitcoin
    • Default receive address automatically uses appropriate wallet based on destination chain
    • Balance updates reflect cross-chain swap timing (15-30s for destination)

Test Plan:

  1. Connect various wallet types (MetaMask, Phantom, Bitcoin wallet)
  2. Verify balances display correctly
  3. Execute swaps on different chains
  4. Verify cross-chain swaps work (EVM → Solana, EVM → Bitcoin)
  5. Verify balance refresh after swaps

Screenshots (if applicable)

https://jam.dev/c/612daaf3-478a-430c-85aa-c2b3e9a37a37
https://jam.dev/c/132c2637-599c-4b9b-87db-4c9bda6788c3

Summary by CodeRabbit

  • New Features

    • Full multi-chain swap support (EVM, Bitcoin/UTXO, Solana) with per-chain receive addresses, wallet badges, chain-aware transaction links, and unified cross-chain transaction status monitoring.
    • Cross-chain balance tracking with refreshed balances after swaps.
  • Chores

    • Replaced prior wallet UI with a built-in AppKit-based wallet flow and updated external wallet integration patterns.
    • Updated dependencies to enable Bitcoin and Solana adapters.
  • Documentation

    • Wallet connection docs rewritten for multi-chain usage, renamed sections, and new examples.

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

Minimoi and others added 16 commits January 17, 2026 18:17
…n AppKit migration

- Remove @rainbow-me/rainbowkit dependency
- Add @reown/appkit and adapters for EVM, Bitcoin, and Solana
- Add @solana/wallet-adapter-wallets for Phantom/Solflare support
- Add @solana/web3.js for Solana transaction handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ll three adapters

- Add AppKit initialization with WagmiAdapter, BitcoinAdapter, and SolanaAdapter
- Configure EVM networks (mainnet, polygon, arbitrum, etc.)
- Configure Bitcoin and Solana network support
- Use PhantomWalletAdapter and SolflareWalletAdapter for Solana
- Export helper functions for adapter creation and initialization
- Follow Reown AppKit v1.8.15 patterns with correct import paths

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…export config

- Removed @rainbow-me/rainbowkit dependency (getDefaultConfig)
- Import networks from @reown/appkit/networks instead of wagmi/chains
- Use WagmiAdapter from @reown/appkit-adapter-wagmi
- Removed unsupported chains (monad, hyperEvm, plasma, katana) not available in AppKit networks
- Export createWagmiAdapter() and getWagmiAdapter() for adapter access
- Export createWagmiConfig() for backward compatibility with WagmiProvider

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…instead of RainbowKit

- Replace RainbowKitProvider with AppKit initialization via initializeAppKit()
- Use getWagmiAdapter() to get wagmi config from AppKit adapter
- Replace RainbowKit's ConnectButton.Custom with custom button using useAppKit and useAppKitAccount hooks
- Remove themeMode prop as AppKit handles theming internally
- Add useCallback for handleClick optimization

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…of RainbowKit

- Remove RainbowKit imports (@rainbow-me/rainbowkit, styles)
- Add AppKit imports (useAppKit, useAppKitAccount from @reown/appkit/react)
- Replace RainbowKitProvider with direct AppKit initialization pattern
- Create custom ConnectButton using AppKit's useAppKit hook
- Update DemoContent to use useAppKitAccount instead of useAccount
- Use initializeAppKit and getWagmiAdapter from config/appkit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…on flow

- Remove unused themeMode prop from InternalWalletProvider call
  (AppKit handles theming through createAppKit configuration)
- Add enableWalletConnection={true} to SwapWidgetCore when using
  internal wallet mode to ensure connect button is visible

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ain-agno

Create chain-agnostic transaction status checking service with:
- checkEvmStatus: EVM transaction status using viem publicClient
- checkBitcoinStatus: Bitcoin tx status via mempool.space API
- checkSolanaStatus: Solana signature status via connection
- waitFor* variants for blocking confirmation waits
- Unified checkTransactionStatus function for all chain types

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ified status polling

- Created useTransactionStatus hook for unified transaction status polling UI
- Implements polling for EVM, Bitcoin (UTXO), and Solana transactions
- Uses React Query for state management with configurable poll intervals
- Provides useTransactionWatcher hook for simplified SwapWidget integration
- Follows existing hook patterns from useSwapRates and useBalances

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…transact

Create useBitcoinSigning.ts hook for Bitcoin/UTXO transaction signing using
Reown AppKit's BitcoinAdapter with bip122 namespace.

Features:
- sendTransfer() for simple BTC transfers
- signPsbt() for complex PSBT signing with optional broadcast
- signMessage() for message signing
- getAccountAddresses() to retrieve wallet addresses
- checkTxStatus() for transaction status polling via mempool.space
- Proper error handling for user rejections and failures
- State management for loading/error/txid tracking

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… signing

- Import and use useBitcoinSigning hook for Bitcoin transaction signing
- Add UTXO chain detection using getChainType() === 'utxo'
- Implement Bitcoin signing flow in handleExecuteSwap:
  - Support PSBT signing via signPsbt()
  - Support simple transfers via sendBitcoinTransfer()
- Update button text and disabled state for UTXO chains
- Enable swap rates fetching for UTXO chains
- Display Bitcoin wallet address in sell section header
- Use mempool.space for Bitcoin transaction explorer links
- Update handleButtonClick to handle Bitcoin wallet connection state

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… transac

Create Solana signing hook with:
- useAppKitProvider<Provider>('solana') for wallet provider
- useAppKitConnection() for Solana connection
- sendTransaction() for sending transactions
- signTransaction() for signing without broadcast
- signMessage() for message signing with TextEncoder
- checkTxStatus() and waitForConfirmation() for tx monitoring
- Proper error handling for user rejections
- State management for loading/error/signature tracking

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…in signing flow

- Import and use useSolanaSigning hook for Solana wallet integration
- Add isSellAssetSolana and canExecuteSolana chain type detection
- Implement Solana transaction execution flow in handleExecuteSwap:
  - Get quote from API with Solana addresses
  - Deserialize and send versioned transaction via wallet
  - Handle transaction status updates and error handling
- Update button text and disabled states for Solana flow
- Display Solana address badge when Solana asset is selected
- Add Solscan explorer link for Solana transaction status

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…let prov

Add type definitions for multi-chain wallet provider support:
- Re-export BitcoinConnector from @reown/appkit-adapter-bitcoin
- Re-export SolanaProvider from @reown/appkit-adapter-solana/react
- Add TransactionStatus type for unified tx status tracking
- Add TransactionStatusResult with confirmations and block info
- Add BitcoinTransactionStatus for mempool.space API responses
- Add WalletProviderNamespace type for namespace identification
- Add MultiChainAddress and MultiChainWalletState utility types

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed import sorting with simple-import-sort
- Fixed prettier formatting issues
- Removed unused imports (useAppKitProvider, BitcoinConnector, ChainTypeResult)
- Removed unused variable (queryClient)
- Fixed async functions without await expressions
- Changed getAccountAddresses to sync since no await needed
- Prefixed unused parameter with underscore (_timeoutMs)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…types

- Updated vite.config.ts to replace RainbowKit externals with AppKit packages
- Updated README.md documentation to reflect migration to Reown AppKit
  - Updated props table to mention AppKit multi-chain support
  - Updated wallet connection example to remove RainbowKit import
  - Updated built-in wallet section with multi-chain capabilities
  - Updated Notes section to describe multi-chain swap support
- Verified all RainbowKit references removed from codebase

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

Walkthrough

This PR replaces RainbowKit with Reown AppKit and implements multi-chain swap support (EVM, Bitcoin/UTXO, Solana): new appkit config, adapters, multi-chain balance hooks, Bitcoin/Solana signing hooks, cross-chain transaction status service, UI/provider updates, and build/dependency changes.

Changes

Cohort / File(s) Summary
Docs
packages/swap-widget/README.md
Updated wallet connection docs to use Reown AppKit, renamed sections, added multi-chain guidance and external wallet examples.
Deps / Build
packages/swap-widget/package.json, packages/swap-widget/vite.config.ts
Removed @rainbow-me/rainbowkit; added @reown/appkit + adapters, Solana deps; bumped wagmi; updated lib externals.
AppKit config
packages/swap-widget/src/config/appkit.ts
New module: network lists, adapter factories, initializeAppKit/getters and single-init guard.
Wagmi config
packages/swap-widget/src/config/wagmi.ts
Removed createWagmiConfig export; updated SUPPORTED_CHAINS source/order and pruned chains.
Wallet provider
packages/swap-widget/src/components/WalletProvider.tsx
Replaced RainbowKit UI with appkit flow; removed themeMode prop; simplified Connect button using useAppKit/useAppKitAccount.
Swap core
packages/swap-widget/src/components/SwapWidget.tsx
Multi-chain wiring: useMultiChainBalance(s), Bitcoin & Solana signing paths (executeUtxoSwap/executeSolanaSwap/executeEvmSwap), per-chain addresses, tx links, UI states; passes currentAssetIds to token modal.
Token selector
packages/swap-widget/src/components/TokenSelectModal.tsx
Replaced evm-only balances with useMultiChainBalances; added currentAssetIds prop, bitcoin/solana addresses, refetchSpecific usage, updated fiat formatting.
Balances hooks
packages/swap-widget/src/hooks/useBalances.ts
New multi-chain parsing and hooks: useBitcoinBalance, useSolanaBalance, useMultiChainBalance(s); removed useEvmBalances/useAssetBalance; MEMPOOL and Solana RPC integration; refetchSpecific.
Bitcoin signing
packages/swap-widget/src/hooks/useBitcoinSigning.ts
New hook exposing address, sendTransfer, signPSBT, signMessage, account derivation and tx status utilities.
Solana signing
packages/swap-widget/src/hooks/useSolanaSigning.ts
New hook exposing address, sendTransaction, signTransaction, signMessage, status/wait helpers and connection handling.
Tx status service
packages/swap-widget/src/services/transactionStatus.ts
New cross-chain status/check/wait helpers: checkEvmStatus, checkBitcoinStatus, checkSolanaStatus, waitFor* and unified checkTransactionStatus.
Types & utils
packages/swap-widget/src/types/index.ts, packages/swap-widget/src/utils/addressValidation.ts
Exported Bitcoin/Solana provider types; made formatAmount maxDecimals optional with small-value formatting; added multi-chain wallet and tx status types; updated Solana address hint.
Demo
packages/swap-widget/src/demo/App.tsx
Removed RainbowKit/Wagmi wrappers and connection UI; replaced walletClient usage with walletConnectProjectId.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SwapWidget
    participant SigningHook as Signing Hook (BTC/SOL/EVM)
    participant AppKit as Reown AppKit
    participant Chain as Blockchain Network

    User->>SwapWidget: initiate swap
    SwapWidget->>SigningHook: request sign/broadcast for target chain
    SigningHook->>AppKit: request wallet client / connector / provider
    AppKit-->>SigningHook: return WalletClient / BitcoinConnector / SolanaProvider
    SigningHook->>Chain: build, sign and broadcast tx (PSBT / Solana tx / EVM tx)
    Chain-->>SigningHook: txHash / txid / signature
    SigningHook-->>SwapWidget: tx identifier
    SwapWidget->>Chain: checkTransactionStatus (via service)
    Chain-->>SwapWidget: status (pending / confirmed / failed)
    SwapWidget->>SwapWidget: refresh multi-chain balances
    SwapWidget-->>User: update UI
Loading
sequenceDiagram
    participant User
    participant TokenModal
    participant BalanceHook as useMultiChainBalances
    participant EvmRpc as EVM RPC
    participant Mempool as Mempool API
    participant SolanaRpc as Solana RPC

    User->>TokenModal: open selector
    TokenModal->>BalanceHook: fetch balances (assetIds)
    BalanceHook->>EvmRpc: query ERC20 / getBalance
    BalanceHook->>Mempool: query UTXO balances for BTC
    BalanceHook->>SolanaRpc: query SOL / SPL token accounts
    EvmRpc-->>BalanceHook: evm balances
    Mempool-->>BalanceHook: utxo balances
    SolanaRpc-->>BalanceHook: solana balances
    BalanceHook-->>TokenModal: aggregated balances + refetchSpecific
    TokenModal-->>User: render balances
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Suggested labels

high risk

Suggested reviewers

  • gomesalexandre
  • premiumjibles

Poem

🐇 I hopped from Rainbow to AppKit bright,

Carried BTC, SOL, and EVM light,
I signed PSBTs and Solana cheers,
Refreshed balances across the years,
Hooray—multichain swaps now take flight! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main changes: migrating from RainbowKit to Reown AppKit and adding multi-chain support for Bitcoin and Solana.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch auto-claude/001-feat-switch-widget-to-wallet-connect-and-support-u

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.

@NeOMakinG NeOMakinG changed the title feat: migrate rainbowkit to reown on swap widget feat: migrate rainbowkit to reown on swap widget and support btc and solana Jan 18, 2026
@NeOMakinG NeOMakinG changed the title feat: migrate rainbowkit to reown on swap widget and support btc and solana feat: migrate rainbowkit to reown on swap widget plus support btc and solana Jan 18, 2026
@NeOMakinG NeOMakinG marked this pull request as ready for review January 18, 2026 16:05
@NeOMakinG NeOMakinG requested a review from a team as a code owner January 18, 2026 16:05
@NeOMakinG NeOMakinG force-pushed the auto-claude/001-feat-switch-widget-to-wallet-connect-and-support-u branch from 5fa6340 to bbf3f46 Compare January 18, 2026 16: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: 6

🤖 Fix all issues with AI agents
In `@packages/swap-widget/package.json`:
- Around line 18-21: The package.json has mismatched `@reown/`* versions (most are
^1.8.15 while `@reown/appkit-adapter-solana` is ^1.8.14); align all `@reown`
packages to the same release to avoid peer/type mismatches by changing the
version strings for `@reown/appkit`, `@reown/appkit-adapter-bitcoin`,
`@reown/appkit-adapter-wagmi` (and any other `@reown/`* entries) to match
`@reown/appkit-adapter-solana`’s current published version (^1.8.14) so all `@reown`
packages share the identical X.Y.Z version.

In `@packages/swap-widget/src/components/SwapWidget.tsx`:
- Around line 304-374: executeUtxoSwap currently doesn't verify the user's
wallet has enough balance to cover sellAmountBaseUnit; add a preflight balance
check at the start of executeUtxoSwap (after verifying
isBitcoinConnected/bitcoinAddress and rateToUse) that compares
sellAmountBaseUnit against the user's available sell balance (e.g., sellBalance
or sellBalanceBaseUnit) and if insufficient, setTxStatus to an error (clear
isExecuting) and return early; ensure you do this before resetBitcoinState() and
before making the API quote so you don't clear UI state or call
apiClient.getQuote when funds are inadequate.

In `@packages/swap-widget/src/components/WalletProvider.tsx`:
- Around line 29-33: Move the side-effect initializeAppKit(projectId) out of the
useMemo and into a useEffect to ensure initialization is performed as an effect
rather than a pure memoized computation: call initializeAppKit(projectId) inside
a useEffect that depends on projectId (and keep its internal guard as-is), and
change the useMemo for wagmiConfig (the variable wagmiConfig returned from
getWagmiAdapter()) to only compute and return adapter?.wagmiConfig without
performing initialization; reference the existing initializeAppKit,
getWagmiAdapter, wagmiConfig, and projectId identifiers when making these edits.

In `@packages/swap-widget/src/config/wagmi.ts`:
- Around line 46-48: Remove the unused exported function createWagmiConfig by
deleting its declaration and export; replace any internal references with
getWagmiAdapter()?.wagmiConfig (as used in appkit.ts) if found, and ensure no
other modules import createWagmiConfig (remove or update those imports). After
removal, run the typecheck/build to confirm there are no dangling references and
update exports if necessary to preserve API surface.

In `@packages/swap-widget/src/hooks/useBalances.ts`:
- Around line 110-127: In fetchBitcoinBalance, the intermediate subtractions can
produce NaN if either operand is undefined; change the calculations to coerce
undefined to 0 before subtracting (e.g., use (data.chain_stats?.funded_txo_sum
?? 0) and (data.chain_stats?.spent_txo_sum ?? 0) for confirmedBalance, and
similarly for mempoolBalance) so confirmedBalance and mempoolBalance are always
numeric before summing and returning totalBalance.toString().

In `@packages/swap-widget/src/hooks/useBitcoinSigning.ts`:
- Around line 90-103: The comparisons in taprootByPurpose and
nativeSegwitAccount assume purpose can be numeric but AccountAddress.purpose is
typed as string | undefined; fix by normalizing the value to a string before
comparing (e.g., read purpose via const purpose = String(account.purpose) or
guard typeof account.purpose === 'string') and then compare against '86' and
'84' respectively, or update the AccountAddress type to include number if you
prefer; update the taprootByPurpose and nativeSegwitAccount predicates to use
the normalized purpose variable when testing equality so TS2367 is resolved.
🧹 Nitpick comments (9)
packages/swap-widget/src/config/appkit.ts (1)

74-79: Avoid as any for Solana wallet adapters.

This discards type-safety around adapter capabilities. Prefer a typed wallets array so mismatches are caught at compile time.

♻️ Suggested typing for wallet adapters
-import { PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets'
+import { PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets'
+import type { WalletAdapter } from '@solana/wallet-adapter-base'
-    solanaAdapter = new SolanaAdapter({
-      wallets: [new PhantomWalletAdapter(), new SolflareWalletAdapter()] as any,
-    })
+    const wallets: WalletAdapter[] = [new PhantomWalletAdapter(), new SolflareWalletAdapter()]
+    solanaAdapter = new SolanaAdapter({ wallets })

As per coding guidelines, avoid any when a concrete adapter type is available.

packages/swap-widget/src/hooks/useBalances.ts (3)

272-325: useBitcoinBalance uses useQueries unnecessarily for a single query.

Using useQueries with a single-element array and then accessing query[0] adds unnecessary complexity. Consider using useQuery directly for cleaner code.

Suggested simplification
-  const query = useQueries({
-    queries: [
-      {
-        queryKey: ['utxoBalance', address, assetId],
-        queryFn: async () => {
+  const query = useQuery({
+    queryKey: ['utxoBalance', address, assetId],
+    queryFn: async () => {
           if (!address || !assetId || !isUtxo) return null
           try {
             const balance = await fetchBitcoinBalance(address)
             return {
               assetId,
               balance,
               precision,
             }
           } catch {
             return null
           }
         },
-        enabled: !!address && !!assetId && isUtxo,
-        staleTime: 60_000,
-        refetchOnWindowFocus: false,
-      },
-    ],
-  })
+    enabled: !!address && !!assetId && isUtxo,
+    staleTime: 60_000,
+    refetchOnWindowFocus: false,
+  })

755-814: refetchSpecific has complex query key matching logic.

The predicate function performs deep equality checks on query keys with multiple chain-type branches. This is functional but verbose. Consider extracting the key-matching logic or using a simpler approach like storing assetId directly in the query key for easier matching.


373-374: Use structured parsing for SPL token balance.

The hardcoded byte offsets are actually correct for the SPL token account layout, but manually slicing binary data is less maintainable than using a structured approach. Use connection.getTokenAccountBalance(tokenAccountPubkey) (available via @solana/web3.js) to retrieve the amount, decimals, and pre-formatted uiAmount in a single RPC call. Alternatively, if you need the full account structure, use @solana/spl-token's getAccount() helper to deserialize the account data.

Note: The current code also returns raw balance without accounting for token decimals, which may not be suitable for UI display.

packages/swap-widget/src/components/SwapWidget.tsx (4)

417-417: Unsafe any cast for Solana transaction metadata.

Line 417 uses (innerStep as any)?.solanaTransactionMetadata which bypasses type safety. Consider defining a proper type for the step structure or using a type guard.

Suggested type improvement
type SolanaTransactionMetadata = {
  instructions: Array<{
    keys: Array<{ pubkey: string; isSigner: boolean; isWritable: boolean }>
    programId: string
    data: { data: number[] }
  }>
}

type StepWithSolanaMetadata = {
  solanaTransactionMetadata?: SolanaTransactionMetadata
}

const solanaTransactionMetadata = (innerStep as StepWithSolanaMetadata | undefined)?.solanaTransactionMetadata

433-449: Dynamic import of @solana/web3.js inside callback could cause issues.

The dynamic import await import('@solana/web3.js') on line 433 is executed every time executeSolanaSwap runs. This is unnecessary overhead since PublicKey and Connection are already imported at the top of useBalances.ts. Consider importing these at module level or memoizing the import.


781-814: isButtonDisabled doesn't check for wallet connection for EVM.

For EVM swaps, the button is not disabled when !walletClient && canExecuteDirectly, but clicking it triggers onConnectWallet. This is inconsistent with UTXO/Solana paths where the button is disabled when wallet is not connected. Consider aligning the behavior.


1129-1139: Transaction link IIFE in JSX is functional but verbose.

The inline IIFE for generating explorer links works but reduces readability. Consider extracting to a memoized value.

Suggested extraction
const txExplorerLink = useMemo(() => {
  if (!txStatus?.txHash) return undefined
  if (isSellAssetUtxo) return `https://mempool.space/tx/${txStatus.txHash}`
  if (isSellAssetSolana) return `https://solscan.io/tx/${txStatus.txHash}`
  return `${sellAsset.explorerTxLink ?? 'https://etherscan.io/tx/'}${txStatus.txHash}`
}, [txStatus?.txHash, isSellAssetUtxo, isSellAssetSolana, sellAsset.explorerTxLink])
packages/swap-widget/src/services/transactionStatus.ts (1)

253-287: _timeoutMs parameter is unused.

The _timeoutMs parameter on line 257 is prefixed with underscore indicating it's intentionally unused, but connection.confirmTransaction has its own timeout mechanism via lastValidBlockHeight. Consider either removing the parameter or documenting why it's kept for API consistency.

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

🤖 Fix all issues with AI agents
In `@packages/swap-widget/src/hooks/useBitcoinSigning.ts`:
- Around line 216-247: In signMessage, guard against a missing/empty address and
empty signatures: before calling provider.signMessage in the signMessage
function, verify address is non-empty and if not setState to isLoading:false and
error (e.g., 'Missing wallet address') and throw; after receiving signatureStr,
validate it's a non-empty string and if empty setState to isLoading:false and
error (e.g., 'Empty signature returned') and throw; ensure provider.signMessage
is only invoked with a validated address and preserve existing error/isLoading
state updates in both success and failure paths.
🧹 Nitpick comments (1)
packages/swap-widget/src/hooks/useBitcoinSigning.ts (1)

282-284: Add explicit return type to checkTxStatus.
Helps align with the project’s explicit typing guideline.

♻️ Suggested change
-  const checkTxStatus = useCallback((txid: string, network: 'mainnet' | 'testnet' = 'mainnet') => {
-    return checkBitcoinStatus(txid, network)
-  }, [])
+  const checkTxStatus = useCallback(
+    (txid: string, network: 'mainnet' | 'testnet' = 'mainnet'): ReturnType<typeof checkBitcoinStatus> => {
+      return checkBitcoinStatus(txid, network)
+    },
+    [],
+  )
As per coding guidelines, please keep explicit return types for functions in TS.

@NeOMakinG
Copy link
Collaborator Author

@coderabbitai can you create 2 issues:

{
    "rates": [
        {
            "swapperName": "THORChain",
            "rate": "0",
            "buyAmountCryptoBaseUnit": "0",
            "sellAmountCryptoBaseUnit": "100000",
            "steps": 0,
            "affiliateBps": "55",
            "error": {
                "code": "UnsupportedChain",
                "message": "Unsupported chain"
            }
        },
        {
            "swapperName": "0x",
            "rate": "0",
            "buyAmountCryptoBaseUnit": "0",
            "sellAmountCryptoBaseUnit": "100000",
            "steps": 0,
            "affiliateBps": "55",
            "error": {
                "code": "UnsupportedChain",
                "message": "unsupported chainId"
            }
        },
        {
            "swapperName": "CoW Swap",
            "rate": "0",
            "buyAmountCryptoBaseUnit": "0",
            "sellAmountCryptoBaseUnit": "100000",
            "steps": 0,
            "affiliateBps": "55",
            "error": {
                "code": "UnsupportedChain",
                "message": "[CowSwap: assertValidTrade] - unsupported chainId"
            }
        },
        {
            "swapperName": "Jupiter",
            "rate": "0",
            "buyAmountCryptoBaseUnit": "0",
            "sellAmountCryptoBaseUnit": "100000",
            "steps": 0,
            "affiliateBps": "55",
            "error": {
                "code": "UnsupportedChain",
                "message": "unsupported chainId"
            }
        },
        {
            "swapperName": "ButterSwap",
            "rate": "0",
            "buyAmountCryptoBaseUnit": "0",
            "sellAmountCryptoBaseUnit": "100000",
            "steps": 0,
            "affiliateBps": "55",
            "error": {
                "code": "UnsupportedChain",
                "message": "BTC sells are currently unsupported"
            }
        },
        {
            "swapperName": "Bebop",
            "rate": "0",
            "buyAmountCryptoBaseUnit": "0",
            "sellAmountCryptoBaseUnit": "100000",
            "steps": 0,
            "affiliateBps": "55",
            "error": {
                "code": "UnsupportedChain",
                "message": "unsupported chainId"
            }
        }
    ],
    "timestamp": 1768750058234,
    "expiresAt": 1768750088234
}
  • We will need a swap status endpoint to verify if the swap is successful or not, so the widget will be able to poll to update statuses

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 18, 2026

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Create Issue 1: BTC quotes not returning from API
gh issue create \
  --title "BTC quotes API not returning valid quotes - all swappers return UnsupportedChain errors" \
  --body "## Description
The BTC quotes API is not returning valid quotes. All swappers are returning errors, primarily \"UnsupportedChain\" errors.

## API Endpoint
\`https://api.shapeshift.com/v1/swap/rates?sellAssetId=bip122%3A000000000019d6689c085ae165831e93%2Fslip44%3A0&buyAssetId=eip155%3A42161%2Fslip44%3A60&sellAmountCryptoBaseUnit=100000\`

## Example Response
All swappers (THORChain, 0x, CoW Swap, Jupiter, ButterSwap, Bebop) return rate \"0\" with errors:
- Most return: \"UnsupportedChain\" / \"unsupported chainId\"
- ButterSwap specifically returns: \"BTC sells are currently unsupported\"

## Context
This issue was identified during testing of PR `#11712` which adds Bitcoin support to the swap widget.

## Related
- PR: `#11712`
- Reported by: `@NeOMakinG`" \
  --assignee NeOMakinG

echo "---"

# Create Issue 2: Need swap status endpoint
gh issue create \
  --title "Implement swap status endpoint for widget polling" \
  --body "## Description
The swap widget needs a swap status endpoint to verify if swaps are successful or not. This will enable the widget to poll for status updates and provide real-time feedback to users.

## Requirements
- Endpoint should accept a transaction/swap identifier
- Should return the current status of the swap (pending, confirmed, failed, etc.)
- Should support multi-chain swaps (EVM, Bitcoin, Solana)
- Should be optimized for polling (efficient, rate-limited if necessary)

## Context
This functionality is needed to complete the multi-chain swap support added in PR `#11712`, which introduces Bitcoin and Solana wallet integration alongside EVM chains.

## Related
- PR: `#11712`
- Reported by: `@NeOMakinG`" \
  --assignee NeOMakinG

Length of output: 155


@NeOMakinG, I wasn't able to create the issues directly due to GitHub CLI authentication not being configured in the sandbox environment. However, I've prepared both issue templates for you below that you can create manually:

Issue 1: BTC Quotes API Problem

Title: BTC quotes API not returning valid quotes - all swappers return UnsupportedChain errors

Body:

## Description
The BTC quotes API is not returning valid quotes. All swappers are returning errors, primarily "UnsupportedChain" errors.

## API Endpoint
`https://api.shapeshift.com/v1/swap/rates?sellAssetId=bip122%3A000000000019d6689c085ae165831e93%2Fslip44%3A0&buyAssetId=eip155%3A42161%2Fslip44%3A60&sellAmountCryptoBaseUnit=100000`

## Example Response
All swappers (THORChain, 0x, CoW Swap, Jupiter, ButterSwap, Bebop) return rate "0" with errors:
- Most return: "UnsupportedChain" / "unsupported chainId"
- ButterSwap specifically returns: "BTC sells are currently unsupported"

## Context
This issue was identified during testing of PR `#11712` which adds Bitcoin support to the swap widget.

## Related
- PR: `#11712`
- Reported by: `@NeOMakinG`

Assignee: NeOMakinG


Issue 2: Swap Status Endpoint

Title: Implement swap status endpoint for widget polling

Body:

## Description
The swap widget needs a swap status endpoint to verify if swaps are successful or not. This will enable the widget to poll for status updates and provide real-time feedback to users.

## Requirements
- Endpoint should accept a transaction/swap identifier
- Should return the current status of the swap (pending, confirmed, failed, etc.)
- Should support multi-chain swaps (EVM, Bitcoin, Solana)
- Should be optimized for polling (efficient, rate-limited if necessary)

## Context
This functionality is needed to complete the multi-chain swap support added in PR `#11712`, which introduces Bitcoin and Solana wallet integration alongside EVM chains.

## Related
- PR: `#11712`
- Reported by: `@NeOMakinG`

Assignee: NeOMakinG


You can create these issues directly on GitHub. Would you like me to help with anything else related to these issues?


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

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 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.

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.

- Align all @reown/* package versions to 1.8.14
- Move initializeAppKit side effect from useMemo to useEffect
- Remove unused createWagmiConfig function
- Fix Bitcoin balance calculation to handle undefined operands
- Add balance validation to executeUtxoSwap before execution
- Guard signMessage against missing address and empty signatures
The downgrade to 1.8.14 caused 'Invalid chain id' errors when signing
Solana transactions. Updated all @reown/* packages to latest stable
version 1.8.17 which has the Solana adapter fix.
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

🤖 Fix all issues with AI agents
In `@packages/swap-widget/src/components/SwapWidget.tsx`:
- Around line 685-692: The redirectToShapeShift callback opens a new tab with
window.open without noopener/noreferrer which allows reverse-tabnabbing; update
redirectToShapeShift to supply the third window.open parameter with
'noopener,noreferrer' (and for extra safety set newWindow.opener = null after
opening if a reference is returned) so the opened page cannot access the opener;
refer to redirectToShapeShift and the window.open call when making the change.
- Around line 225-241: The effectiveReceiveAddress useMemo currently falls back
to walletAddress for all chains which can prefill invalid EVM addresses for
UTXO/Solana; update the logic in the effectiveReceiveAddress computation so that
walletAddress is only used when buyChainType === 'evm' (or when explicitly
appropriate), and return an empty string ('') for UTXO/Solana when no
chain-specific address exists; adjust the final return branch accordingly in the
useMemo that references customReceiveAddress, defaultReceiveAddress,
buyChainType, bitcoinAddress, solanaAddress, and walletAddress.

In `@packages/swap-widget/src/config/wagmi.ts`:
- Around line 32-41: The singleton createWagmiAdapter currently reuses
wagmiAdapterInstance without validating the incoming projectId; modify
createWagmiAdapter to store the projectId of the created instance (e.g.,
cachedProjectId) and on each call compare the new projectId to
cachedProjectId—if they differ either reinitialize wagmiAdapterInstance with the
new projectId (creating a new WagmiAdapter using SUPPORTED_CHAINS and the new
projectId) or throw a clear error indicating a projectId mismatch; ensure the
function returns the (possibly reinitialized) wagmiAdapterInstance.

- Fix effectiveReceiveAddress to not fall back to EVM address for UTXO/Solana
- Add noopener,noreferrer to window.open for security
Track cached projectId and reinitialize adapter if projectId changes
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.

Reviewed by Claude Code (Opus 4.5)

Summary

This PR migrates the swap widget from RainbowKit to Reown AppKit and adds Bitcoin/Solana wallet support. The feature scope is reasonable but the implementation has issues ranging from a real bug to significant code quality concerns.

🚨 Critical Bug (Not in diff - existing code touched by this PR)

Number precision issue in TokenSelectModal.tsx:372

(Number(balance.balance) / Math.pow(10, asset.precision)) * Number(marketData[asset.assetId].price)

Number.MAX_SAFE_INTEGER is ~9e15. Any balance exceeding this in base units will silently lose precision. 1000 ETH in wei = 1e21 → corrupted display. This affects display only, not actual swap amounts.

Fix: Use bnOrZero from @shapeshiftoss/utils.

🔴 Serious Issues

  • Dead code: useTransactionStatus.ts (224 lines) is never imported anywhere
  • Duplicate function: createWagmiAdapter exists in both appkit.ts and wagmi.ts with different chain support
  • Missing validation: executeSolanaSwap lacks balance validation (unlike executeUtxoSwap)
  • Reinventing wheel: Custom getChainType() in types/index.ts:238 just remaps ChainNamespace from CAIP to slightly different strings, then code redundantly checks both

⚠️ Code Quality (Tech Debt)

  • Same error detection logic copy-pasted 7 times across signing hooks
  • Magic numbers for setTimeout delays throughout
  • Empty strings '' used instead of undefined
  • Slippage conversion copy-pasted 3 times
  • any type casts instead of proper typing

Blocker Assessment

If it works functionally: The Number/Math.pow bug is the main real issue that will manifest (whale balance display corruption). Everything else is tech debt.

Recommendation: Can merge with follow-up ticket for the Number precision fix. See inline comments for specific locations.

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.

Stamparaooni sandwich for the sake of progression - comments/review issues to tackle in this PR before mergy or in a follow-up PR

https://jam.dev/c/ff41c109-66fc-4b7d-aa96-7cd351d14064

Was able to:

  • Connect Solana through Phantom
  • Trade to/from Solana
  • Trade from SOL to BTC happy
  • Trade from BTC to SOL not happy (see around the end of jam)

Spotted issues:

  • Able to click swap without a receive address
Image
  • The "Receive address" modal when connected with EVM only wrongly populates with EVM addy on Solana side
Image
  • "Enter Base58 address" isn't a very hooman-frenly placeholder
Image
  • Seeing "Swap Succesful" on Tx initiated
Image
  • The "Swap succesful" thingie doesn't go away on input change
Image

Generally speaking, think we'll need a trade execution flow, similar to the one in Yield or e.g the swapper one in app but cleaner and simpler

  • We probably should handle the "Add xyz wallet" functionality from reown in app if possible i.e something somewhere, if wallet supports e.g SOL and I'm receiving SOL, should be able to click connect or add and trigger the same method as reown modal does
Image
  • Able to "execute" swap with more than balance (and most likely invalid/no quote)
Image
  • Explorer link is explorer Tx link, not swapper one which can be confusing i.e swapping SOL -> BTC but looks like I wrongly got USDC
Image Image

- Fix Number precision issue using bnOrZero instead of Number/Math.pow
- Add balance validation to executeSolanaSwap and executeEvmSwap
- Disable swap button when no receive address is available
- Fix receive address modal to use chain-specific wallet address
- Change 'Swap successful' to 'Transaction submitted' for clarity
- Reset txStatus on sell amount input change
- Change Solana placeholder from 'Base58 address' to 'Enter Solana address'
- Remove dead code: useTransactionStatus.ts hook (never imported)
- Remove duplicate createWagmiAdapter from wagmi.ts (kept in appkit.ts)
- Resolve yarn.lock conflict from develop
@NeOMakinG NeOMakinG force-pushed the auto-claude/001-feat-switch-widget-to-wallet-connect-and-support-u branch from b59cebe to cbe931b Compare January 21, 2026 12:32
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

🤖 Fix all issues with AI agents
In `@packages/swap-widget/src/components/SwapWidget.tsx`:
- Line 461: The line creating a Buffer from ix.data.data can throw if ix.data or
ix.data.data is undefined; update the handling around the Buffer creation in
SwapWidget (the const data = Buffer.from(ix.data.data) site) to first validate
ix.data and ix.data.data, and either skip/continue when missing or provide a
safe default (e.g., an empty array/Buffer) before calling Buffer.from; ensure
any downstream logic expects the default or early-return so no runtime exception
occurs.
♻️ Duplicate comments (3)
packages/swap-widget/src/components/SwapWidget.tsx (3)

323-323: Slippage conversion duplicated across swap functions.

This parseFloat(slippage) / 100 pattern appears in executeUtxoSwap, executeSolanaSwap, and executeEvmSwap. As noted in a previous review, consider extracting to a utility using bn instead of parseFloat for consistency with the codebase's BigNumber patterns.


746-751: Silent return without user feedback persists.

When UTXO/Solana wallet is not connected, clicking the button silently returns. While buttonText shows "Connect Bitcoin/Solana Wallet", the button click does nothing. Consider triggering the AppKit wallet connection modal or showing a toast.


1173-1183: Hardcoded explorer URLs noted in previous review.

As flagged previously, consider using existing getExplorerTxLink helper instead of hardcoding mempool.space and solscan.io. For cross-chain swaps, the current approach using sell asset's explorer is correct since the transaction originates on the sell chain.

🧹 Nitpick comments (1)
packages/swap-widget/src/components/SwapWidget.tsx (1)

436-436: Avoid any type for Solana transaction metadata.

Using any bypasses TypeScript type checking. Consider defining a proper type for solanaTransactionMetadata to catch potential runtime errors at compile time.

Example type definition
type SolanaInstructionKey = {
  pubkey: string
  isSigner: boolean
  isWritable: boolean
}

type SolanaInstruction = {
  keys: SolanaInstructionKey[]
  programId: string
  data: { data: number[] }
}

type SolanaTransactionMetadata = {
  instructions: SolanaInstruction[]
}

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

🤖 Fix all issues with AI agents
In `@packages/swap-widget/src/components/SwapWidget.tsx`:
- Line 1232: currentAssetIds is being passed as a fresh array literal on every
render which creates a new reference and can trigger unnecessary re-renders in
TokenSelectModal and its refetchSpecific effect; fix it by memoizing the array
using React.useMemo inside the SwapWidget component (e.g. compute a stable
currentAssetIdsMemo from sellAsset.assetId and buyAsset.assetId) and pass that
memoized value to the currentAssetIds prop so the reference stays stable across
renders unless either assetId changes.
- Line 354: The call signPsbt({ psbt, signInputs: {}, broadcast: true }) may
fail for wallets that require explicit input indices; update the signing logic
in SwapWidget (where signPsbt is called and psbt is available) to build
signInputs from the PSBT's input list (e.g., map psbt.inputs to an object with
input indices true/required keys) and pass that populated signInputs instead of
an empty object, and add fallback error handling to catch a signing rejection
and surface a user-friendly message indicating the wallet requires explicit
input specification.

In `@packages/swap-widget/src/components/TokenSelectModal.tsx`:
- Around line 167-171: The effect in TokenSelectModal uses optional chaining on
refetchSpecific and an unstable array dependency currentAssetIds; remove the
unnecessary optional chaining on refetchSpecific (it is always returned by
useMultiChainBalances) and replace the array dependency with a stable string key
(e.g., join or JSON.stringify of currentAssetIds) so the useEffect callback only
runs when the actual asset IDs change; update the useEffect that references
refetchSpecific and currentAssetIds accordingly to call
refetchSpecific(currentAssetIds) when isOpen is true and the stable key
indicates a change.
♻️ Duplicate comments (4)
packages/swap-widget/src/components/SwapWidget.tsx (4)

323-323: Slippage conversion duplicated and uses parseFloat.

This pattern appears 3 times (lines 323, 424, 551). Per coding guidelines, prefer bn over parseFloat for numeric conversions and extract to a utility.

Suggested refactor
// At module level or in a utils file
const toSlippageDecimal = (slippage: string): string => 
  bn(slippage).div('100').toString()

// Then replace all occurrences:
const slippageDecimal = toSlippageDecimal(slippage)

1173-1183: Hardcoded explorer URLs - consider using asset's explorerTxLink.

The UTXO and Solana explorers are hardcoded. For consistency and maintainability, consider using the asset's explorerTxLink property when available, with fallbacks.

Also note: for cross-chain swaps, this uses the sell asset's chain type, but the transaction hash might correspond to a different chain depending on the swap stage.


454-468: Add defensive check for instruction data before Buffer.from.

If ix.data or ix.data.data is undefined, Buffer.from(undefined) will throw. The API response structure should be validated.

Suggested fix
       const instructions = solanaTransactionMetadata.instructions.map((ix: any) => {
+        if (!ix.data?.data) {
+          throw new Error(`Invalid instruction data for programId: ${ix.programId}`)
+        }
+
         const keys = ix.keys.map((key: any) => ({
           pubkey: new PublicKey(key.pubkey),
           isSigner: key.isSigner,
           isWritable: key.isWritable,
         }))

         const data = Buffer.from(ix.data.data)

746-751: Silent failure when UTXO/Solana wallet not connected.

When the user clicks the swap button but UTXO/Solana wallet isn't connected, the function returns silently with no feedback. The button text says "Connect Bitcoin/Solana Wallet" but clicking doesn't trigger connection.

Consider opening the wallet connect modal or showing an error toast.

@NeOMakinG
Copy link
Collaborator Author

CodeRabbit Comments Addressed

All CodeRabbit review comments have been addressed:

Comment Status
SwapWidget.tsx:383 - executeUtxoSwap missing balance validation ✅ Fixed in previous commit
WalletProvider.tsx - Side effect in useMemo ✅ Already fixed
wagmi.ts - Duplicate createWagmiAdapter ✅ Removed in previous commit
useBalances.ts:129 - Bitcoin balance calculation ✅ Already fixed
useBitcoinSigning.ts:103 - TS2367 purpose type ✅ Already handles string/number
useBitcoinSigning.ts:257 - signMessage guards ✅ Already has address & empty signature checks
SwapWidget.tsx:241 - EVM address fallback for UTXO/Solana ✅ Fixed in previous commit
SwapWidget.tsx:716 - noopener/noreferrer ✅ Already present
SwapWidget.tsx:461 - Solana ix.data.data validation ✅ Fixed in bef4da8

@NeOMakinG
Copy link
Collaborator Author

@coderabbitai #11712 (review)

Create issues for anything that we didn't tackle in this comment (check in the codebase to understand if we fixed it or not)

@NeOMakinG NeOMakinG force-pushed the auto-claude/001-feat-switch-widget-to-wallet-connect-and-support-u branch from 3bf57c5 to f5f9b20 Compare January 21, 2026 13:17
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the specific PR review comments
gh pr view 11712 --json reviews --jq '.reviews[] | select(.id == "PRR_kwDOEbHHYM6gxXQw")' || gh api repos/shapeshift/web/pulls/11712/reviews | jq '.[] | select(.id == 3686759664)'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get all review comments from the PR to find the specific review
gh api repos/shapeshift/web/pulls/11712/reviews | jq '.[] | {id: .id, submitted_at: .submitted_at, state: .state, user: .user.login, body: .body}' | head -50

Length of output: 14805


🏁 Script executed:

#!/bin/bash
# Try to get review comments with a different approach
gh pr view 11712 --json reviews --jq '.reviews[] | {id: .id, author: .author.login, state: .state, submittedAt: .submittedAt, body: .body}' | grep -A 20 -B 5 "coderabbitai"

Length of output: 31632


🏁 Script executed:

#!/bin/bash
# Check SwapWidget.tsx for redirectToShapeShift and window.open usage
rg -n "redirectToShapeShift|window\.open" packages/swap-widget/src/components/SwapWidget.tsx -A 3 -B 3

Length of output: 705


🏁 Script executed:

#!/bin/bash
# Check effectiveReceiveAddress logic in SwapWidget.tsx
rg -n "effectiveReceiveAddress" packages/swap-widget/src/components/SwapWidget.tsx -A 10 -B 2

Length of output: 8040


🏁 Script executed:

#!/bin/bash
# Check wagmi.ts for createWagmiAdapter and projectId handling
cat packages/swap-widget/src/config/wagmi.ts

Length of output: 472


🏁 Script executed:

#!/bin/bash
# Check appkit.ts for createWagmiAdapter and projectId handling
rg -n "createWagmiAdapter" packages/swap-widget/src/config/appkit.ts -A 15 -B 3

Length of output: 941


🏁 Script executed:

#!/bin/bash
# Also check if there are any other mentions of projectId validation issues
rg -n "projectId|cachedProjectId" packages/swap-widget/src/config/appkit.ts -C 5

Length of output: 992


🏁 Script executed:

#!/bin/bash
# Create GitHub issue for createWagmiAdapter projectId validation
gh issue create \
  --title "createWagmiAdapter doesn't validate projectId changes" \
  --body "## Description
The \`createWagmiAdapter\` function in \`packages/swap-widget/src/config/appkit.ts\` uses a singleton pattern but doesn't validate that the \`projectId\` passed in subsequent calls matches the one used to create the initial instance. This could lead to unexpected behavior if the function is called with different project IDs.

## Current Implementation
\`\`\`typescript
export const createWagmiAdapter = (projectId: string): WagmiAdapter => {
  if (!wagmiAdapter) {
    wagmiAdapter = new WagmiAdapter({
      networks: [...EVM_NETWORKS],
      projectId,
    })
  }
  return wagmiAdapter
}
\`\`\`

## Issue
If \`createWagmiAdapter\` is called multiple times with different \`projectId\` values, the first \`projectId\` is used and subsequent calls are ignored, potentially causing configuration mismatches.

## Suggested Fix
Add validation to either:
1. Throw an error if a different \`projectId\` is provided
2. Store the cached \`projectId\` and recreate the adapter if it changes
3. Document that only the first call's \`projectId\` is used

## Context
This issue was identified during review of PR `#11712` which adds multi-chain wallet support to the swap widget.

## Related
- PR: `#11712`
- Review: https://github.com/shapeshift/web/pull/11712#pullrequestreview-3686759664
- Reported by: `@NeOMakinG`" \
  --assignee NeOMakinG

Length of output: 46


@NeOMakinG, I've reviewed all the items from the review comment and here's the status:

✅ Already Fixed (2 items)

  1. redirectToShapeShift noopener/noreferrer (Line 685-692 in review)

    • Status: ✅ Fixed
    • Line 714-717 now has 'noopener,noreferrer' parameter
  2. effectiveReceiveAddress fallback logic (Line 225-241 in review)

    • Status: ✅ Fixed
    • Lines 225-234 now correctly check buyChainType and only use walletAddress for EVM
    • Returns empty string for UTXO/Solana when no chain-specific address exists

🆕 Issue Created (1 item)

  1. createWagmiAdapter projectId validation (wagmi.ts line 32-41 in review)
    • Status: ❌ Not addressed
    • Created issue: #11756
    • Location: Now in packages/swap-widget/src/config/appkit.ts lines 57-65
    • Problem: The singleton pattern doesn't validate that subsequent calls use the same projectId, which could cause configuration mismatches

All review items have been addressed! Two were already fixed in previous commits, and I've created a follow-up issue for the remaining item.


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

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

Learnt from: 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.

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

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 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.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10751
File: src/Routes/RoutesCommon.tsx:190-190
Timestamp: 2025-10-13T11:55:57.439Z
Learning: In the shapeshift/web codebase, there are multiple independent claim systems: Arbitrum bridge claims (removed in PR `#10751`), RFOX claims (in src/pages/RFOX/components/Claim/), and TCY claims (in src/pages/TCY/). Each has its own routes, components, and logic. When reviewing claim-related changes, distinguish which system is being modified and avoid suggesting changes to unrelated claim systems.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11536
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:252-265
Timestamp: 2025-12-27T16:02:59.817Z
Learning: When fixing critical bugs in shapeshift/web, gomesalexandre prefers to keep changes minimal and focused on correctness rather than combining bug fixes with code quality improvements like extracting duplicated logic, even when duplication is present.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10136
File: src/lib/asset-service/service/encodedRelatedAssetIndex.json:1-1
Timestamp: 2025-07-29T10:22:27.037Z
Learning: PRs with titles starting with "feat: regenerate asset data" are routine daily asset updates that don't need detailed code analysis. Users prefer to skip automated reviews for these maintenance PRs using coderabbitai ignore.

Learnt from: premiumjibles
Repo: shapeshift/web PR: 10361
File: src/pages/Markets/components/CardWithSparkline.tsx:83-92
Timestamp: 2025-08-25T23:32:13.876Z
Learning: In shapeshift/web PR `#10361`, premiumjibles considered the nested button accessibility issue (ChartErrorFallback retry Button inside Card rendered as Button in CardWithSparkline.tsx) out of scope for the error boundaries feature PR, consistent with deferring minor a11y improvements to follow-up PRs.

Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10073
File: src/components/Layout/Header/ActionCenter/components/Details/ClaimDetails.tsx:10-11
Timestamp: 2025-07-24T21:05:13.642Z
Learning: In the ShapeShift web repository, translation workflow follows a two-step process: 1) First PR adds only English translations to src/assets/translations/en/main.json, 2) Globalization team handles follow-up PRs to add keys to remaining language files (de, es, fr, id, ja, ko, pt, ru, tr, uk, zh). Don't suggest verifying all locale files simultaneously during initial feature PRs.

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

…at-switch-widget-to-wallet-connect-and-support-u
@NeOMakinG NeOMakinG enabled auto-merge (squash) January 21, 2026 13:23
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

🤖 Fix all issues with AI agents
In `@packages/swap-widget/src/services/transactionStatus.ts`:
- Around line 191-222: Wrap the body of waitForEvmConfirmation in a try/catch
and validate the chain before creating the client (don’t silently fall back to
mainnet like checkEvmStatus); lookup chain via EVM_CHAINS_BY_ID[chainId] and if
missing return a TransactionStatusResult with status 'failed' and a descriptive
error (e.g., 'unsupported chain'); inside try call
client.waitForTransactionReceipt as before and on receipt.status === 'success'
return 'confirmed', otherwise return 'failed' with the revert error; in catch
return a TransactionStatusResult with status 'pending' or 'failed' depending on
the error (e.g., timeout -> 'pending', network/other -> 'failed') and include
the caught error.message in the error field.
- Around line 51-57: The code silently falls back to mainnet when
EVM_CHAINS_BY_ID[chainId] is missing; change the logic to detect unsupported
chain IDs and fail explicitly: check EVM_CHAINS_BY_ID[chainId] (using the
chainId variable) before calling createPublicClient, and if it's undefined (and
no existingClient was provided) either throw an Error or return a clearly typed
error status from the surrounding function (instead of defaulting to mainnet);
update references around createPublicClient, client, and mainnet so callers know
they must handle the error condition.
- Around line 119-124: Wrap the secondary block height fetch and JSON parse
(currentBlockResponse and currentBlockHeight) in its own try/catch and check
response.ok before reading json; on any fetch/parse error or non-OK response log
the error and fall back to a safe default for confirmations (e.g., set
confirmations = 1 when data.block_height exists) so a failed height lookup
doesn’t incorrectly mark a transaction as confirmed; update the code in
transactionStatus.ts around
currentBlockResponse/currentBlockHeight/confirmations to implement these checks
and fallback behavior.
♻️ Duplicate comments (2)
packages/swap-widget/src/components/SwapWidget.tsx (2)

1235-1235: Memoize currentAssetIds to keep the prop stable.
The array literal creates a new reference each render and can trigger unnecessary downstream effects. As per coding guidelines, memoize derived arrays.

♻️ Suggested refactor
+  const currentAssetIds = useMemo(
+    () => [sellAsset.assetId, buyAsset.assetId],
+    [sellAsset.assetId, buyAsset.assetId],
+  )
...
-        currentAssetIds={[sellAsset.assetId, buyAsset.assetId]}
+        currentAssetIds={currentAssetIds}

347-355: Populate PSBT signInputs for stricter wallets.
Some wallets require explicit input indices; an empty object can cause signing to fail. Consider deriving signInputs from the PSBT (or your existing PSBT parser) before calling signPsbt, or surface a targeted error if the wallet rejects auto‑detection.

💡 Possible fix
-      if (psbt) {
-        txid = await signPsbt({ psbt, signInputs: {}, broadcast: true })
-      } else if (recipientAddress) {
+      if (psbt) {
+        const { Psbt } = await import('bitcoinjs-lib')
+        const decoded = Psbt.fromBase64(psbt)
+        const signInputs = Object.fromEntries(
+          decoded.data.inputs.map((_, index) => [index, true]),
+        )
+        txid = await signPsbt({ psbt, signInputs, broadcast: true })
+      } else if (recipientAddress) {
🧹 Nitpick comments (2)
packages/swap-widget/src/components/SwapWidget.tsx (2)

435-456: Avoid any for Solana instruction metadata.
Using any here removes type safety across the transaction build. Consider introducing explicit types (or unknown + type guard) for solanaTransactionMetadata and instructions. As per coding guidelines, avoid any in TSX.

♻️ Suggested typing
+type SolanaInstructionKey = {
+  pubkey: string
+  isSigner: boolean
+  isWritable: boolean
+}
+type SolanaInstruction = {
+  programId: string
+  keys: SolanaInstructionKey[]
+  data: { data: string }
+}
+type SolanaTransactionMetadata = {
+  instructions: SolanaInstruction[]
+}
-      const solanaTransactionMetadata = (innerStep as any)?.solanaTransactionMetadata
+      const solanaTransactionMetadata =
+        (innerStep as { solanaTransactionMetadata?: SolanaTransactionMetadata })
+          ?.solanaTransactionMetadata
-      const instructions = solanaTransactionMetadata.instructions.map((ix: any) => {
+      const instructions = solanaTransactionMetadata.instructions.map((ix: SolanaInstruction) => {

771-820: Move new button text to i18n keys.
These newly added user‑facing strings are hardcoded. Please route them through useTranslate() with translation keys for consistency. As per coding guidelines, all copy should use i18n keys.

@NeOMakinG NeOMakinG merged commit 86f34e6 into develop Jan 21, 2026
3 checks passed
@NeOMakinG NeOMakinG deleted the auto-claude/001-feat-switch-widget-to-wallet-connect-and-support-u branch January 21, 2026 15:31
@coderabbitai coderabbitai bot mentioned this pull request Feb 16, 2026
1 task
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