Skip to content

Conversation

@premiumjibles
Copy link
Contributor

@premiumjibles premiumjibles commented Dec 11, 2025

Summary by CodeRabbit

  • New Features

    • Improved wallet UI: clearer wallet & network icons, "Active" badges, per‑wallet connect/disconnect with confirmations, primary‑wallet switching, and "Connect another wallet".
  • Refactor

    • Switched to a dynamic wallet/context model with unified wallet connection, signer handling, and network switching; centralized chain/network configuration and wallet utilities; portfolio, send, and swap flows updated to use the new model.
  • Chores

    • Public env var renamed to VITE_DYNAMIC_ENVIRONMENT_ID; build config and package resolution override added.

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

@vercel
Copy link

vercel bot commented Dec 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
shapeshift-agentic Ready Ready Preview Comment Dec 11, 2025 11:12pm

@coderabbitai
Copy link

coderabbitai bot commented Dec 11, 2025

Warning

Rate limit exceeded

@premiumjibles has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 26 seconds before requesting another review.

⌛ How to resolve this issue?

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

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

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

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

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between d4dc7e6 and 1bbd371.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • .env.example (1 hunks)
  • .env.production (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/components/CustomConnectButton.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (5 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useApprovedChains.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (0 hunks)
  • apps/agentic-chat/src/hooks/useNetworkSwitch.ts (4 hunks)
  • apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (5 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (12 hunks)
  • apps/agentic-chat/src/hooks/useWalletConnection.ts (1 hunks)
  • apps/agentic-chat/src/lib/appkit.ts (0 hunks)
  • apps/agentic-chat/src/lib/chains.ts (1 hunks)
  • apps/agentic-chat/src/lib/networks.ts (0 hunks)
  • apps/agentic-chat/src/lib/solana-config.ts (0 hunks)
  • apps/agentic-chat/src/lib/wagmi-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/walletUtils.ts (1 hunks)
  • apps/agentic-chat/src/types/appkit.d.ts (0 hunks)
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/types.ts (1 hunks)
  • apps/agentic-chat/src/utils/sendExecutor.ts (2 hunks)
  • apps/agentic-chat/src/utils/sendTransaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/swapExecutor.ts (2 hunks)
  • apps/agentic-chat/vite.config.mjs (1 hunks)
  • package.json (1 hunks)
📝 Walkthrough

Walkthrough

Replaces AppKit wallet stack with Dynamic Labs providers/connectors, centralizes EVM/Solana chain config, renames VITE_PROJECT_ID → VITE_DYNAMIC_ENVIRONMENT_ID, migrates Solana signing to signer-based APIs, and rewires wallet UI/hooks, network switching, and transaction/send/swap flows.

Changes

Cohort / File(s) Summary
Environment & build
\.env.example, \.env.production, apps/agentic-chat/vite.config.mjs
Replace VITE_PROJECT_ID with VITE_DYNAMIC_ENVIRONMENT_ID and update comments; add Vite define mapping process.env{}.
Root package
\package.json``
Add top-level overrides forcing @solana/web3.js1.98.1.
App dependencies
**/apps/agentic-chat/package.json
Remove AppKit/Phantom adapters; add @dynamic-labs/* Dynamic Labs packages.
App bootstrap / providers
\apps/agentic-chat/src/app/app.tsx``
Replace AppKit initialization with DynamicContextProvider + DynamicWagmiConnector; rewire Wagmi/Query providers under dynamic context and use DYNAMIC_EVM_NETWORKS.
Chains & networks
\apps/agentic-chat/src/lib/chains.ts`, `apps/agentic-chat/src/lib/networks.ts`, `apps/agentic-chat/src/lib/appkit.ts`, `apps/agentic-chat/src/lib/wagmi-config.ts`, `apps/agentic-chat/src/lib/solana-config.ts``
Add chains.ts with SUPPORTED_EVM_CHAINS, mappings, DYNAMIC_EVM_NETWORKS, SOLANA_CAIP_ID; remove AppKit networks export and solanaAdapter; replace WagmiAdapter with createConfig using new chains/transports; remove projectId usage.
Wallet utilities
\apps/agentic-chat/src/lib/walletUtils.ts``
Add findEvmWallet, findSolanaWallet, filterEvmWallets, filterSolanaWallets helpers with type guards.
Wallet connection hook
\apps/agentic-chat/src/hooks/useWalletConnection.ts``
Rework to return WalletConnectionResult containing isConnected, primaryAddress, evmAddress, solanaAddress, evmWallet, solanaWallet, and approvedChainIds; export wallet-finder helpers.
Approved chains
\apps/agentic-chat/src/hooks/useApprovedChains.ts``
Replace provider/session parsing with wallet-driven approved-chain derivation (per-wallet logic via useUserWallets).
Auto-network hook removal
\apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts``
Remove entire implementation and export.
Network switching
\apps/agentic-chat/src/hooks/useNetworkSwitch.ts``
Replace AppKit maps with dynamic networkNameToChainId; perform primary-wallet switching; call evmWallet.connector.switchNetwork; add Solana fast-path and enhanced error handling and persistence.
Send / Swap execution
\apps/agentic-chat/src/hooks/useSendExecution.ts`, `apps/agentic-chat/src/hooks/useSwapExecution.tsx``
Migrate to dynamic wallet context (useWalletConnection, useDynamicContext, useSwitchWallet); obtain Solana signer via solanaWallet.getSigner(); align primary wallet before actions; use connector.switchNetwork for EVM.
Portfolio & queries
\apps/agentic-chat/src/hooks/usePortfolioQuery.ts`, `apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx``
Use primaryAddress for queries; add per-wallet grouping, connect/disconnect flows, two-step disconnect confirmation, and primary-wallet switching; derive display addresses/icons from primary wallet.
UI: connect button & wallet rows
\apps/agentic-chat/src/components/CustomConnectButton.tsx`, `apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx``
Replace AppKit hooks with dynamic hooks; compute caipChainId, icons and addresses from primaryWallet; NetworkWalletRow adds optional isActive?: boolean, unified clickable row, and propagation-safe copy/disconnect.
Tool UIs
\apps/agentic-chat/src/components/tools/SendUI.tsx`, `apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx``
Remove useAppKitAccount usage; derive sender/sell addresses from component outputs (sendOutput.summary.from, swapOutput.swapData.sellAccount).
Transaction utils (EVM)
\apps/agentic-chat/src/utils/chains/evm/transaction.ts`, `apps/agentic-chat/src/utils/chains/types.ts``
Replace viem extractChain/networks lookup with chainIdToChain mapping; add unsupported-chain error; introduce SolanaWalletSigner type and alias for backward compatibility; rename solanaProvidersolanaSigner in types.
Transaction utils (Solana) & executors
\apps/agentic-chat/src/utils/chains/solana/transaction.ts`, `apps/agentic-chat/src/utils/sendExecutor.ts`, `apps/agentic-chat/src/utils/sendTransaction.ts`, `apps/agentic-chat/src/utils/swapExecutor.ts``
Switch to signer-based signing (signTransaction) and rename option fields/spreads from solanaProvidersolanaSigner; adapt executors to accept and pass SolanaWalletSigner.
Wagmi config
\apps/agentic-chat/src/lib/wagmi-config.ts``
Export wagmiConfig via createConfig using SUPPORTED_EVM_CHAINS and per-chain http transports; remove AppKit networks and environment projectId.
AppKit types / JSX augmentation
\apps/agentic-chat/src/types/appkit.d.ts``
Remove global JSX intrinsic augmentation for appkit-button and module export guard.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant App as App (DynamicContextProvider)
  participant Hook as useWalletConnection
  participant Wallet as Wallets (evmWallet / solanaWallet)
  participant Connector as Connector (evm.connector / solanaSigner)
  participant RPC as Chain RPC / PublicClient

  User->>App: trigger send/swap or network switch
  App->>Hook: resolve primaryWallet, evmWallet, solanaWallet, primaryAddress
  Hook-->>App: return primaryAddress + wallet objects
  App->>Wallet: ensure correct primary (maybe changePrimary)
  alt EVM path
    Wallet->>Connector: connector.switchNetwork(chainId)
    Connector->>RPC: perform chain switch
    RPC-->>Connector: result
  else Solana path
    Wallet->>Connector: getSigner()
    Connector-->>App: signer
  end
  App->>Connector: sign and submit transaction
  Connector->>RPC: submit transaction
  RPC-->>App: tx hash / error
  App-->>User: success / error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • useWalletConnection: resolution priority, new return shape, exported finder helpers
    • useNetworkSwitch: primary-wallet switching, evm.connector.switchNetwork, error/persistence handling
    • useSendExecution / useSwapExecution: Solana signer retrieval and propagation
    • PortfolioDrawer & NetworkWalletRow: UI event propagation, disconnect flows, primary switching
    • chains.ts & wagmi-config: chain metadata correctness and transport wiring

Possibly related PRs

  • #141 — Approved-chain computation and useApprovedChains changes (direct overlap in approvedChainIds logic).
  • #124 — PortfolioDrawer connect/disconnect UI and flow (strong overlap with per-wallet flows and dialogs).
  • #114 — Send-related APIs and types (useSendExecution, sendExecutor, Solana signer rename and wiring).

Poem

🐰 I hopped from kit to dynamic light,

I stitched the chains and signed at night,
Wallets found homes, solana sang,
Connectors leapt — the switches rang,
A joyful rabbit — code takes flight! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.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: migrate from reown to dynamic' directly and clearly summarizes the main objective of the pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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 (13)
apps/agentic-chat/src/utils/chains/solana/transaction.ts (1)

40-42: Consider extracting the window.solana type declaration.

The inline type declaration for window.solana could be extracted to a shared type definition file for better maintainability and reusability.

Consider adding to apps/agentic-chat/src/utils/chains/types.ts:

declare global {
  interface Window {
    solana?: {
      signTransaction: (tx: VersionedTransaction) => Promise<VersionedTransaction>
    }
  }
}

Then simplify this line to:

-    const signer =
-      params.solanaSigner ??
-      (window as { solana?: { signTransaction: (tx: VersionedTransaction) => Promise<VersionedTransaction> } }).solana
+    const signer = params.solanaSigner ?? window.solana
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

45-49: Redundant stopPropagation wrapper around CopyButton.

The CopyButton component already calls e.stopPropagation() internally in its click handler (see CopyButton.tsx lines 17-18). The wrapper div with onClick and onKeyDown stopPropagation is unnecessary.

             {address && (
-              <div onClick={e => e.stopPropagation()} onKeyDown={e => e.stopPropagation()} role="button" tabIndex={0}>
-                <CopyButton value={address} className="text-muted-foreground hover:text-foreground" />
-              </div>
+              <CopyButton value={address} className="text-muted-foreground hover:text-foreground" />
             )}
apps/agentic-chat/src/app/app.tsx (1)

43-52: Consider validating VITE_DYNAMIC_ENVIRONMENT_ID at startup.

If VITE_DYNAMIC_ENVIRONMENT_ID is undefined or empty, the Dynamic SDK may fail silently or with a cryptic error. Consider adding validation or a fallback with a clear error message during development.

const dynamicEnvironmentId = import.meta.env.VITE_DYNAMIC_ENVIRONMENT_ID
if (!dynamicEnvironmentId) {
  throw new Error('VITE_DYNAMIC_ENVIRONMENT_ID environment variable is required')
}
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)

15-16: Redundant context access: primaryWallet is available from useWalletConnection.

useWalletConnection already accesses primaryWallet from useDynamicContext() internally and exposes primaryAddress. Consider exposing primaryWallet from useWalletConnection to avoid duplicate context consumption, or use the existing evmWallet/solanaWallet from useWalletConnection to determine the primary wallet type.

apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

112-132: Consider using a constant or case-insensitive comparison for Solana network check.

The string comparison data.network === 'solana' is case-sensitive and relies on the exact string format. Consider using a constant or normalizing the comparison to prevent issues if the network name format varies:

-    if (data.network === 'solana') {
+    if (data.network.toLowerCase() === 'solana') {
apps/agentic-chat/src/hooks/useSendExecution.ts (1)

187-194: Consider adding error handling for wallet switch.

The changePrimaryWallet call is awaited but not wrapped in try/catch. If the wallet switch fails, the error will propagate to the outer catch block, which may be acceptable, but consider whether a more specific error message would help users understand what failed.

         if (
           chainNamespace === CHAIN_NAMESPACE.Solana &&
           solanaWallet &&
           primaryWallet &&
           !isSolanaWallet(primaryWallet)
         ) {
-          await changePrimaryWallet(solanaWallet.id)
+          try {
+            await changePrimaryWallet(solanaWallet.id)
+          } catch (e) {
+            throw new Error('Failed to switch to Solana wallet')
+          }
         }
apps/agentic-chat/src/lib/wagmi-config.ts (1)

10-13: Consider using custom RPC URLs from chain config.

The http() transport is created without arguments, using wagmi's default RPC URLs. However, SUPPORTED_EVM_CHAINS defines custom rpcUrl for each chain. Consider using those for consistency:

-const transports = Object.fromEntries(SUPPORTED_CHAIN_IDS.map(id => [id, http()])) as Record<
+const transports = Object.fromEntries(
+  SUPPORTED_EVM_CHAINS.map(c => [c.chain.id, http(c.rpcUrl)])
+) as Record<
   (typeof SUPPORTED_CHAIN_IDS)[number],
   ReturnType<typeof http>
 >
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

217-243: Consider extracting shared wallet switching logic.

The wallet switching logic (lines 217-243) is nearly identical to useSendExecution. Consider extracting this to a shared utility to reduce duplication and ensure consistent behavior.

Example shared utility:

// utils/walletSwitch.ts
export async function ensureCorrectPrimaryWallet(
  chainNamespace: string,
  primaryWallet: Wallet | null,
  evmWallet: EthereumWallet | undefined,
  solanaWallet: SolanaWallet | undefined,
  changePrimaryWallet: (id: string) => Promise<void>
): Promise<void> {
  if (chainNamespace === CHAIN_NAMESPACE.Solana) {
    if (solanaWallet && primaryWallet && !isSolanaWallet(primaryWallet)) {
      await changePrimaryWallet(solanaWallet.id)
    }
  } else if (chainNamespace === CHAIN_NAMESPACE.Evm) {
    if (!evmWallet) throw new Error('EVM wallet not connected')
    if (primaryWallet && !isEthereumWallet(primaryWallet)) {
      await changePrimaryWallet(evmWallet.id)
    }
  }
}
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (3)

57-62: Add error handling for removeWallet.

The removeWallet call is fire-and-forget with void. If it fails, the user won't know. Consider adding error handling:

   const handleWalletDisconnect = useCallback(() => {
     if (walletToDisconnect) {
-      void removeWallet(walletToDisconnect)
+      removeWallet(walletToDisconnect).catch(error => {
+        console.error('Failed to disconnect wallet:', error)
+      })
       setWalletToDisconnect(null)
     }
   }, [walletToDisconnect, removeWallet])

85-92: Inefficient wallet filtering in walletGroups computation.

The otherWallets filter calls filterEvmWallets and filterSolanaWallets for each wallet individually, which is O(n²). Consider restructuring:

   const walletGroups = useMemo(
     () => ({
       evmWallets: filterEvmWallets(userWallets),
       solanaWallets: filterSolanaWallets(userWallets),
-      otherWallets: userWallets.filter(w => !filterEvmWallets([w]).length && !filterSolanaWallets([w]).length),
+      otherWallets: userWallets.filter(
+        w => !isEthereumWallet(w) && !isSolanaWallet(w)
+      ),
     }),
     [userWallets]
   )

This requires importing isEthereumWallet and isSolanaWallet from the Dynamic Labs packages, which are already used elsewhere in the codebase.


112-185: Consider extracting repeated wallet group rendering to a component.

The three wallet group blocks (EVM, Solana, Other) have identical structure. Consider extracting to reduce duplication:

const WalletGroup = ({ label, wallets }: { label: string; wallets: Wallet[] }) => {
  if (wallets.length === 0) return null
  return (
    <div className="mb-2">
      <div className="px-2 py-1 text-xs font-medium text-muted-foreground/70 uppercase tracking-wider">
        {label}
      </div>
      {wallets.map(wallet => (
        <div key={wallet.id} className="relative">
          <NetworkWalletRow
            label={wallet.connector.name}
            address={wallet.address}
            icon={getWalletIcon(wallet)}
            isConnected={true}
            isActive={wallet.id === primaryWallet?.id}
            onConnect={() => {
              if (wallet.id !== primaryWallet?.id) {
                void changePrimaryWallet(wallet.id)
              }
            }}
            onDisconnect={() => setWalletToDisconnect(wallet.id)}
          />
        </div>
      ))}
    </div>
  )
}
apps/agentic-chat/src/lib/chains.ts (1)

15-88: Consider externalizing or validating icon URLs.

The icon URLs are hardcoded to Dynamic's CDN (app.dynamic.xyz/assets/networks/). If Dynamic changes their asset paths or the app needs to work offline/in a custom environment, these could break silently.

Consider either:

  1. Using environment variables or a config file for the base URL
  2. Adding a fallback mechanism for missing icons
  3. Documenting that these URLs depend on Dynamic's CDN availability
const DYNAMIC_ICON_BASE = 'https://app.dynamic.xyz/assets/networks'

// Then use:
iconUrl: `${DYNAMIC_ICON_BASE}/eth.svg`,
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)

28-30: Consider adding a fallback icon.

The getWalletIcon function safely handles null/undefined wallet via optional chaining, but callers may need to handle the undefined return value. Consider whether a default fallback icon would be useful.

📜 Review details

Configuration used: CodeRabbit 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 749e9e3 and 59024ea.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • .env.example (1 hunks)
  • .env.production (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/components/CustomConnectButton.tsx (3 hunks)
  • apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (4 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useApprovedChains.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3 hunks)
  • apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (5 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (8 hunks)
  • apps/agentic-chat/src/hooks/useWalletConnection.ts (1 hunks)
  • apps/agentic-chat/src/lib/appkit.ts (0 hunks)
  • apps/agentic-chat/src/lib/chains.ts (1 hunks)
  • apps/agentic-chat/src/lib/networks.ts (1 hunks)
  • apps/agentic-chat/src/lib/solana-config.ts (0 hunks)
  • apps/agentic-chat/src/lib/wagmi-config.ts (1 hunks)
  • apps/agentic-chat/src/types/appkit.d.ts (0 hunks)
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/types.ts (1 hunks)
  • apps/agentic-chat/src/utils/sendExecutor.ts (2 hunks)
  • apps/agentic-chat/src/utils/sendTransaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/swapExecutor.ts (2 hunks)
  • apps/agentic-chat/vite.config.mjs (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (3)
  • apps/agentic-chat/src/lib/appkit.ts
  • apps/agentic-chat/src/lib/solana-config.ts
  • apps/agentic-chat/src/types/appkit.d.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/lib/networks.ts
  • apps/agentic-chat/src/hooks/useSendExecution.ts
🧬 Code graph analysis (14)
apps/agentic-chat/src/utils/sendExecutor.ts (5)
apps/agentic-server/src/lib/schemas/swapSchemas.ts (1)
  • TransactionData (75-75)
apps/agentic-server/src/tools/send.ts (1)
  • SendOutput (137-137)
apps/agentic-server/src/index.ts (1)
  • SendOutput (64-64)
apps/agentic-server/src/lib/schemas/sendSchemas.ts (1)
  • SendOutput (49-49)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/utils/chains/evm/transaction.ts (1)
apps/agentic-chat/src/lib/chains.ts (1)
  • chainIdToChain (99-101)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (3)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/CopyButton.tsx (1)
  • CopyButton (15-41)
apps/agentic-chat/src/components/ui/IconButton.tsx (1)
  • IconButton (22-29)
apps/agentic-chat/src/utils/sendTransaction.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/hooks/useApprovedChains.ts (2)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
  • filterEvmWallets (20-22)
  • filterSolanaWallets (24-26)
apps/agentic-chat/src/lib/chains.ts (2)
  • EVM_CAIP_IDS (108-108)
  • SOLANA_CAIP_ID (90-90)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (2)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/services/portfolioService.ts (1)
  • fetchFullPortfolio (31-102)
apps/agentic-chat/src/utils/chains/types.ts (2)
apps/agentic-chat/src/types/transaction.ts (1)
  • Transaction (1-10)
packages/caip/src/constants.ts (1)
  • ChainId (175-175)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
apps/agentic-chat/src/lib/chains.ts (2)
  • SUPPORTED_EVM_CHAINS (15-88)
  • SUPPORTED_CHAIN_IDS (94-97)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
apps/agentic-chat/src/types/wallet.ts (1)
  • Wallet (1-6)
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)
  • useApprovedChains (8-24)
apps/agentic-chat/src/components/CustomConnectButton.tsx (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
  • useWalletConnection (42-67)
  • getWalletIcon (28-30)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/lib/chains.ts (1)
  • SOLANA_CAIP_ID (90-90)
packages/utils/src/networkIcons.ts (1)
  • NETWORK_ICONS (14-31)
apps/agentic-chat/src/app/app.tsx (2)
apps/agentic-chat/src/lib/chains.ts (1)
  • DYNAMIC_EVM_NETWORKS (110-120)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (15-19)
apps/agentic-chat/src/hooks/useSendExecution.ts (5)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/utils/sendExecutor.ts (1)
  • executeSend (34-40)
apps/agentic-server/src/tools/send.ts (1)
  • executeSend (24-71)
apps/agentic-chat/src/utils/swapExecutor.ts (3)
apps/agentic-server/src/lib/schemas/swapSchemas.ts (2)
  • SwapData (77-77)
  • TransactionData (75-75)
apps/agentic-server/src/tools/initiateSwap.ts (1)
  • InitiateSwapOutput (277-277)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
⏰ 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: main
🔇 Additional comments (37)
apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1)

19-19: LGTM - More accurate address source.

Deriving the address from swapOutput?.swapData.sellAccount is semantically correct as it shows the actual sender of the swap transaction rather than the currently connected wallet. This is especially important for historical transactions where the connected wallet may differ from the transaction initiator.

apps/agentic-chat/src/components/tools/SendUI.tsx (1)

17-17: LGTM - Consistent address source.

Using sendOutput?.summary.from to derive the address is consistent with the approach in InitiateSwapUI.tsx and correctly represents the actual transaction sender rather than the currently connected wallet.

apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (1)

1-5: Verify that callers don't rely on the previous hook behavior.

The hook has been converted to a no-op with network switching delegated to the Dynamic SDK. While this maintains API compatibility, ensure that any code calling useAutoNetworkSwitch doesn't rely on side effects from the previous implementation.

package.json (1)

62-64: @solana/web3.js version 1.98.1 is valid and secure.

The override pins @solana/web3.js to version 1.98.1, which is a stable, non-deprecated release on NPM with no known security vulnerabilities. The version is stricter than the semver range ^1.95.8 specified in the app's package.json, though newer patch versions (1.98.2, 1.98.3, 1.98.4) are available.

apps/agentic-chat/package.json (1)

16-21: The Dynamic Labs SDK packages at version 4.49.0 are compatible with React 19.1.1. The @dynamic-labs/sdk-react-core package explicitly declares React peerDependencies as >=18.0.0 <20.0.0, which includes React 19. No compatibility concerns.

apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

31-34: Verify the intent of row click triggering onConnect.

When connected, clicking the row calls onConnect. Confirm this is intentional for switching/selecting the active wallet rather than an oversight where it should be a no-op or different action for an already-connected wallet.

.env.example (1)

26-27: LGTM!

The environment variable rename from VITE_PROJECT_ID to VITE_DYNAMIC_ENVIRONMENT_ID is clear and aligns with the Dynamic Labs SDK migration.

apps/agentic-chat/src/utils/sendExecutor.ts (1)

4-4: LGTM!

The refactoring from SolanaWalletProvider to SolanaWalletSigner is consistent and aligns with the signer-based wallet interaction pattern introduced in this PR.

Also applies to: 11-11, 28-28

apps/agentic-chat/src/utils/sendTransaction.ts (1)

4-4: LGTM!

Consistent type rename aligning SendTransactionParams with the new SolanaWalletSigner interface.

Also applies to: 13-13

apps/agentic-chat/src/utils/chains/evm/transaction.ts (1)

25-28: LGTM!

Good improvement replacing the extractChain iteration with a direct O(1) map lookup via chainIdToChain. The explicit validation guard with a clear error message is a good defensive addition.

apps/agentic-chat/src/utils/swapExecutor.ts (1)

4-4: LGTM!

Consistent with the sendExecutor.ts refactoring, maintaining symmetry between swap and send transaction flows.

Also applies to: 12-12, 28-28

apps/agentic-chat/src/app/app.tsx (1)

1-13: LGTM on the Dynamic Labs SDK integration.

The provider hierarchy (DynamicContextProviderWagmiProviderQueryClientProviderDynamicWagmiConnector) follows the recommended nesting for Dynamic Labs with Wagmi. The connect-only authentication mode and network merging strategy are appropriate for this use case.

apps/agentic-chat/src/components/CustomConnectButton.tsx (3)

17-19: Potential stale chainId when Solana is the primary wallet.

When the primary wallet is Solana, useChainId() from wagmi may return a stale EVM chain ID (from the last connected EVM wallet) or undefined. This could cause the caipChainId on line 47 to fall through to an EVM chain even when Solana is primary, though the isPrimarySolana check should handle this correctly.

Consider verifying that chainId behavior is expected when no EVM wallet is active.


39-48: LGTM!

The address fallback chain and the conditional CAIP ID derivation based on wallet type are well-structured. The Solana-specific handling using isSolanaWallet ensures the correct network icon is displayed.


50-64: LGTM!

The conditional rendering for wallet and network icons handles missing values gracefully, and the address truncation provides a clean user experience.

apps/agentic-chat/src/hooks/useApprovedChains.ts (1)

14-20: Behavioral change: All EVM chains are now approved if any EVM wallet is connected.

The previous implementation likely extracted specific approved chains from WalletConnect sessions. This new logic includes all EVM_CAIP_IDS when any EVM wallet is present, which may grant broader access than the wallet actually supports.

If chain-specific approvals are needed (e.g., for WalletConnect v2 session namespaces), this simplification may cause issues. Please confirm this is the intended behavior with Dynamic's wallet model.

apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2)

22-31: Behavioral change: Portfolio only fetches for the primary wallet type.

Previously, the portfolio may have fetched for both EVM and Solana addresses. Now it only fetches for the primary wallet's chain type. Users with both EVM and Solana wallets connected will only see the portfolio for whichever wallet is currently primary.

If this is intentional, consider adding a comment explaining this behavior. If users should see their combined portfolio, both addresses should be passed to fetchFullPortfolio.


38-48: LGTM!

The asset filtering logic and return shape are well-structured, maintaining backward compatibility with consumers of this hook.

apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3)

73-99: LGTM!

The hydration logic for persisted state follows a clean pattern, ensuring that tool state is properly restored when the component re-mounts.


167-183: LGTM!

The error handling is comprehensive, properly capturing the error message, updating the state, and persisting the failure for recovery purposes.


139-153: The code pattern here is intentional and appears throughout the codebase (useSwapExecution.tsx, useSendExecution.ts). After changePrimaryWallet(evmWallet.id) switches the primary wallet context, the evmWallet.connector reference remains valid because the connector is tied to the wallet instance itself, not to its primary designation. The pattern is consistent with Dynamic SDK's design where changing primary wallet status doesn't invalidate other wallet instances. No special handling or re-fetching is needed.

apps/agentic-chat/src/lib/networks.ts (1)

1-1: No action needed. The re-export of chainIdToChain and networkNameToChainId from ./chains is correct, and there are no consumers in the codebase using outdated export names.

apps/agentic-chat/src/utils/chains/types.ts (2)

6-13: LGTM! Clean interface design with backward compatibility.

The SolanaWalletSigner interface is appropriately minimal, focusing only on the signing capability needed. The legacy alias preserves backward compatibility during migration.


22-22: LGTM! Parameter rename aligns with signer-based pattern.

The rename from solanaProvider to solanaSigner better reflects the actual usage and aligns with the new Dynamic Labs integration.

apps/agentic-chat/src/hooks/useSendExecution.ts (1)

205-214: LGTM! EVM wallet validation and network switching.

Good defensive check for evmWallet presence before proceeding. The primary wallet switch and network switch sequence is correct.

apps/agentic-chat/src/lib/wagmi-config.ts (1)

15-19: LGTM! Config structure is correct.

Setting multiInjectedProviderDiscovery: false is appropriate since Dynamic Labs handles wallet discovery. The config is properly typed and exported.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (2)

201-205: LGTM! Early signer retrieval is a good pattern.

Obtaining the Solana signer early in the flow, before network switching and transaction execution, ensures it's available when needed and fails fast if there's an issue.


278-286: LGTM! Approval confirmation handles missing public client gracefully.

The if (publicClient) check prevents crashes if the chain isn't properly configured in wagmi.

apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (2)

43-55: LGTM! Proper cleanup on disconnect.

Good pattern: invalidating relevant queries before logout ensures stale data isn't displayed if the user reconnects.


257-268: LGTM! Per-wallet disconnect confirmation.

Good UX to require confirmation before disconnecting individual wallets. The dialog state management using walletToDisconnect is clean.

apps/agentic-chat/src/lib/chains.ts (3)

5-13: Well-structured chain configuration interface.

The ChainConfig interface provides a clean, type-safe structure for chain metadata. This centralizes chain configuration and avoids scattered magic values.


103-106: Clarify the solana: 0 mapping.

Using 0 as the chain ID for Solana is unconventional since Solana doesn't use numeric chain IDs like EVM chains. This could cause issues if code assumes all values in this map are valid EVM chain IDs.

Consider:

  1. Adding a comment explaining why 0 is used (e.g., sentinel value for non-EVM)
  2. Using a separate mapping for non-EVM networks
  3. Using null or a distinct constant like SOLANA_CHAIN_ID_PLACEHOLDER = 0
+// Solana uses 0 as a placeholder since it doesn't have a numeric chain ID like EVM chains
 export const networkNameToChainId: Record<string, number> = {
   ...Object.fromEntries(SUPPORTED_EVM_CHAINS.map(c => [c.networkName, c.chain.id])),
   solana: 0,
 }

110-120: LGTM - Clean transformation to Dynamic's EvmNetwork type.

The mapping from ChainConfig to EvmNetwork is well-structured and correctly maps all required fields including nativeCurrency from viem's chain definition.

apps/agentic-chat/src/hooks/useWalletConnection.ts (4)

20-26: LGTM - Filter functions follow the same pattern as find functions.

These utility functions provide a clean API for filtering wallets by type and are properly typed with type guards.


32-40: Well-defined return type interface.

The WalletConnectionResult interface clearly documents the hook's contract and provides good type safety for consumers.


42-66: Clean wallet resolution logic with sensible priority.

The hook correctly:

  1. Prioritizes primaryWallet when it matches the expected type
  2. Falls back to searching userWallets for each wallet type
  3. Derives addresses from resolved wallets
  4. Computes isConnected from address presence

This approach ensures users with multiple wallets get their primary wallet used preferentially.


10-18: Type cast is appropriate given SDK design, no changes needed.

DynamicWallet (derived from useUserWallets) and Wallet are distinct types from the same SDK package, as evidenced by getWalletIcon accepting both. The w as Wallet cast is intentional type narrowing required because useUserWallets returns a broader union type than the type guards expect. This pattern is consistent across all helper functions and poses no runtime risk—the types are mutually compatible. If the SDK's type definitions change in future updates, this code would require explicit updates regardless, which is normal for external dependency changes.

Copy link

@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

Caution

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

⚠️ Outside diff range comments (1)
apps/agentic-chat/src/hooks/useSendExecution.ts (1)

169-175: Address comparison may fail for Solana addresses.

The lowercase comparison at line 173 works for EVM addresses but Solana addresses are case-sensitive (base58 encoded). This could cause false negatives for Solana transactions.

-      if (currentAddress.toLowerCase() !== tx.from.toLowerCase()) {
+      const addressesMatch = chainNamespace === CHAIN_NAMESPACE.Evm
+        ? currentAddress.toLowerCase() === tx.from.toLowerCase()
+        : currentAddress === tx.from
+      if (!addressesMatch) {
         throw new Error('Wallet address changed. Please re-initiate the transaction.')
       }
♻️ Duplicate comments (2)
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)

9-23: Memoization is ineffective due to unstable userWallets reference.

As flagged in the previous review, useUserWallets() returns a new array reference on each render, causing the useMemo to recalculate every time. Use a stable derived key:

 export function useApprovedChains(): string[] {
   const userWallets = useUserWallets()
+  const walletIds = useMemo(() => userWallets.map(w => w.id).join(','), [userWallets])

   return useMemo(() => {
     const chainIds: string[] = []

     if (filterEvmWallets(userWallets).length > 0) {
       chainIds.push(...EVM_CAIP_IDS)
     }

     if (filterSolanaWallets(userWallets).length > 0) {
       chainIds.push(SOLANA_CAIP_ID)
     }

     return chainIds
-  }, [userWallets])
+  }, [walletIds, userWallets])
 }
apps/agentic-chat/src/hooks/useSendExecution.ts (1)

224-230: Consider using ISolanaSigner type from Dynamic Labs SDK.

The code assigns solanaWallet.getSigner() to SolanaWalletSigner, but Dynamic Labs SDK returns ISolanaSigner. While structurally compatible, using the SDK's type directly would improve type safety and clarity.

Dynamic Labs SDK 4.49.0 ISolanaSigner type definition
🧹 Nitpick comments (7)
apps/agentic-chat/src/utils/chains/solana/transaction.ts (1)

40-42: Extract the inline type annotation for better maintainability.

The inline type annotation for window.solana is verbose and couples the type definition with its usage. Consider extracting it to a type alias or ensuring it aligns with the SolanaWalletSigner interface mentioned in previous reviews.

// At the top of the file or in types.ts
type SolanaWindowProvider = {
  signTransaction: (tx: VersionedTransaction) => Promise<VersionedTransaction>
}

// Then use:
const signer =
  params.solanaSigner ??
  (window as { solana?: SolanaWindowProvider }).solana
apps/agentic-chat/src/components/CustomConnectButton.tsx (1)

39-53: LGTM! Clean integration with Dynamic context.

The address resolution chain and CAIP chain ID construction are well-structured. Minor observation: if walletIcon is falsy (e.g., wallet doesn't provide an icon), the parent div still renders but appears empty. This shouldn't cause visual issues given the network icon overlay, but consider a fallback icon or hiding the container:

-        {walletIcon && <img src={walletIcon} alt={walletName || 'Wallet'} className="w-6 h-6 rounded-full" />}
+        <img src={walletIcon || '/fallback-wallet-icon.svg'} alt={walletName || 'Wallet'} className="w-6 h-6 rounded-full" />
apps/agentic-chat/src/app/app.tsx (1)

43-70: Provider hierarchy looks correct.

The nesting order (DynamicContextProvider → WagmiProvider → QueryClientProvider → DynamicWagmiConnector) aligns with Dynamic Labs integration patterns.

However, VITE_DYNAMIC_ENVIRONMENT_ID at line 46 has no fallback or validation. If this env variable is missing or empty, the app will silently fail to initialize properly. Consider adding a runtime check:

const environmentId = import.meta.env.VITE_DYNAMIC_ENVIRONMENT_ID
if (!environmentId) {
  throw new Error('VITE_DYNAMIC_ENVIRONMENT_ID is required')
}
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (4)

43-55: Consider awaiting invalidateQueries before logout.

The query invalidations are fire-and-forget while handleLogOut is awaited. If logout completes before invalidation finishes, there could be a brief window where stale data persists.

-  const handleDisconnect = useCallback(() => {
-    void queryClient.invalidateQueries({ queryKey: ['portfolio'] })
-    void queryClient.invalidateQueries({ queryKey: ['approvedChains'] })
-
-    handleLogOut()
+  const handleDisconnect = useCallback(async () => {
+    await Promise.all([
+      queryClient.invalidateQueries({ queryKey: ['portfolio'] }),
+      queryClient.invalidateQueries({ queryKey: ['approvedChains'] }),
+    ])
+
+    await handleLogOut()
       .catch(error => {
         console.error('Failed to disconnect wallet:', error)
       })
       .finally(() => {
         setShowDisconnectAlert(false)
         onClose()
       })
   }, [queryClient, handleLogOut, onClose])

57-62: Missing error handling for removeWallet.

removeWallet is called with void but failures are silently ignored. Consider adding error handling to inform users if wallet removal fails.

   const handleWalletDisconnect = useCallback(() => {
     if (walletToDisconnect) {
-      void removeWallet(walletToDisconnect)
+      removeWallet(walletToDisconnect).catch(error => {
+        console.error('Failed to remove wallet:', error)
+      })
       setWalletToDisconnect(null)
     }
   }, [walletToDisconnect, removeWallet])

86-93: Inefficient wallet filtering creates unnecessary intermediate arrays.

filterEvmWallets([w]) and filterSolanaWallets([w]) are called for each wallet in otherWallets computation, creating single-element arrays repeatedly. Use the type guards directly instead.

+import { isEthereumWallet } from '@dynamic-labs/ethereum'
+import { isSolanaWallet } from '@dynamic-labs/solana'
+import type { Wallet } from '@dynamic-labs/sdk-react-core'

   const walletGroups = useMemo(
     () => ({
       evmWallets: filterEvmWallets(userWallets),
       solanaWallets: filterSolanaWallets(userWallets),
-      otherWallets: userWallets.filter(w => !filterEvmWallets([w]).length && !filterSolanaWallets([w]).length),
+      otherWallets: userWallets.filter(w => !isEthereumWallet(w as Wallet) && !isSolanaWallet(w as Wallet)),
     }),
     [userWallets]
   )

113-136: Repetitive wallet row rendering across EVM, Solana, and Other groups.

The three wallet group sections (lines 113-136, 138-161, 163-186) contain nearly identical rendering logic. Consider extracting a reusable component or helper to reduce duplication.

const WalletGroupSection = ({ label, wallets }: { label: string; wallets: typeof walletGroups.evmWallets }) => (
  wallets.length > 0 ? (
    <div className="mb-2">
      <div className="px-2 py-1 text-xs font-medium text-muted-foreground/70 uppercase tracking-wider">
        {label}
      </div>
      {wallets.map(wallet => (
        <div key={wallet.id} className="relative">
          <NetworkWalletRow
            label={wallet.connector.name}
            address={wallet.address}
            icon={getWalletIcon(wallet)}
            isConnected={true}
            isActive={wallet.id === primaryWallet?.id}
            onConnect={() => wallet.id !== primaryWallet?.id && void changePrimaryWallet(wallet.id)}
            onDisconnect={() => setWalletToDisconnect(wallet.id)}
          />
        </div>
      ))}
    </div>
  ) : null
)
📜 Review details

Configuration used: CodeRabbit 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 59024ea and bea0509.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • .env.example (1 hunks)
  • .env.production (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/components/CustomConnectButton.tsx (3 hunks)
  • apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (4 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useApprovedChains.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3 hunks)
  • apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (5 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (8 hunks)
  • apps/agentic-chat/src/hooks/useWalletConnection.ts (1 hunks)
  • apps/agentic-chat/src/lib/appkit.ts (0 hunks)
  • apps/agentic-chat/src/lib/chains.ts (1 hunks)
  • apps/agentic-chat/src/lib/networks.ts (1 hunks)
  • apps/agentic-chat/src/lib/solana-config.ts (0 hunks)
  • apps/agentic-chat/src/lib/wagmi-config.ts (1 hunks)
  • apps/agentic-chat/src/types/appkit.d.ts (0 hunks)
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/types.ts (1 hunks)
  • apps/agentic-chat/src/utils/sendExecutor.ts (2 hunks)
  • apps/agentic-chat/src/utils/sendTransaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/swapExecutor.ts (2 hunks)
  • apps/agentic-chat/vite.config.mjs (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (3)
  • apps/agentic-chat/src/lib/appkit.ts
  • apps/agentic-chat/src/types/appkit.d.ts
  • apps/agentic-chat/src/lib/solana-config.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx
  • apps/agentic-chat/src/utils/chains/types.ts
  • .env.production
  • apps/agentic-chat/vite.config.mjs
  • apps/agentic-chat/src/utils/swapExecutor.ts
  • package.json
  • apps/agentic-chat/src/components/tools/SendUI.tsx
  • apps/agentic-chat/src/lib/chains.ts
  • apps/agentic-chat/src/hooks/useWalletConnection.ts
  • apps/agentic-chat/package.json
  • .env.example
  • apps/agentic-chat/src/utils/sendExecutor.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-16T20:28:23.547Z
Learnt from: premiumjibles
Repo: shapeshift/agentic-chat PR: 68
File: apps/agentic-server/package.json:26-26
Timestamp: 2025-09-16T20:28:23.547Z
Learning: In the ShapeShift agentic-chat codebase, mathjs optimization (lazy-loading or using modular sub-packages) has been noted for future implementation rather than immediate action.

Applied to files:

  • apps/agentic-chat/src/hooks/useApprovedChains.ts
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/lib/networks.ts
  • apps/agentic-chat/src/hooks/useSendExecution.ts
🧬 Code graph analysis (10)
apps/agentic-chat/src/utils/sendTransaction.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/hooks/useApprovedChains.ts (2)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
  • filterEvmWallets (20-22)
  • filterSolanaWallets (24-26)
apps/agentic-chat/src/lib/chains.ts (2)
  • EVM_CAIP_IDS (108-108)
  • SOLANA_CAIP_ID (90-90)
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (4)
  • useWalletConnection (42-67)
  • getWalletIcon (28-30)
  • filterEvmWallets (20-22)
  • filterSolanaWallets (24-26)
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)
  • usePortfolioQuery (14-49)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)
  • NetworkWalletRow (19-72)
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-57)
apps/agentic-chat/src/lib/chains.ts (1)
  • networkNameToChainId (103-106)
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/services/portfolioService.ts (1)
  • fetchFullPortfolio (31-102)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (3)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/CopyButton.tsx (1)
  • CopyButton (15-41)
apps/agentic-chat/src/components/ui/IconButton.tsx (1)
  • IconButton (22-29)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
apps/agentic-chat/src/lib/chains.ts (2)
  • SUPPORTED_EVM_CHAINS (15-88)
  • SUPPORTED_CHAIN_IDS (94-97)
apps/agentic-chat/src/app/app.tsx (2)
apps/agentic-chat/src/lib/chains.ts (1)
  • DYNAMIC_EVM_NETWORKS (110-120)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (15-19)
apps/agentic-chat/src/utils/chains/evm/transaction.ts (1)
apps/agentic-chat/src/lib/chains.ts (1)
  • chainIdToChain (99-101)
⏰ 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: main
🔇 Additional comments (18)
apps/agentic-chat/src/utils/chains/evm/transaction.ts (2)

25-28: Good defensive check for unsupported chains.

The explicit guard and error message for unsupported chain IDs improves debuggability compared to a silent undefined chain.


18-28: [rewritten comment]
[classification tag]

apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (2)

31-34: The clickable row pattern improves wallet selection UX.

Making the connected wallet row clickable to set it as active is intuitive. The propagation handling on child elements correctly prevents unintended activations.


39-41: Active badge styling is clear and non-intrusive.

The badge provides good visual feedback for the currently selected wallet without being overly prominent.

apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (1)

1-5: Approve the hook as-is; it is actively used in the codebase.

The hook is imported and called in apps/agentic-chat/src/app/app.tsx within the AppContent function, so it cannot be removed. The no-op implementation with explanatory comments is appropriate during this migration—Dynamic SDK handles network coordination automatically, and the hook is retained as a call site for potential future network-awareness logic. The current approach maintains API stability without introducing dead code.

apps/agentic-chat/src/lib/networks.ts (1)

1-1: Clean re-export centralizes chain configuration.

The re-export of chainIdToChain and networkNameToChainId from ./chains simplifies the module structure and is appropriate for internal use within the agentic-chat application.

apps/agentic-chat/src/lib/wagmi-config.ts (1)

15-19: The current createConfig implementation is correct and does not need SSR or storage options.

The previous WagmiAdapter setup (from Reown) only configured projectId and networks — it did not include SSR or storage settings. The app is a Vite+React client-side SPA with no SSR framework, so SSR configuration is not applicable. Wallet state persistence is now handled by the Dynamic Labs SDK (@dynamic-labs/wagmi-connector), while app-level state uses Zustand with localStorage (in chatStore.ts). The wagmiConfig itself does not need additional storage or SSR options.

apps/agentic-chat/src/utils/sendTransaction.ts (1)

4-13: LGTM! Clean type migration from provider to signer model.

The parameter rename from solanaProvider to solanaSigner aligns well with the new SolanaWalletSigner interface that exposes only signTransaction, reflecting the narrower API surface from Dynamic Labs.

apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)

18-31: Behavioral change: portfolio now scoped to primary wallet only.

The previous implementation likely fetched portfolios for both connected wallet types. Now only the primary wallet's portfolio is fetched. This appears intentional but worth confirming.

Additionally, evmAddressToFetch and solanaAddressToFetch are captured in the queryFn closure but aren't included in the query key. If these values change mid-query, the query could use stale addresses while React Query thinks the result is still valid for primaryAddress.

Consider including the derived addresses in the query key for consistency:

-  const queryKey = useMemo(() => ['portfolio', primaryAddress] as const, [primaryAddress])
+  const queryKey = useMemo(
+    () => ['portfolio', primaryAddress, evmAddressToFetch, solanaAddressToFetch] as const,
+    [primaryAddress, evmAddressToFetch, solanaAddressToFetch]
+  )
apps/agentic-chat/src/hooks/useSwapExecution.tsx (3)

201-205: Solana signer retrieval looks correct.

The await solanaWallet.getSigner() properly handles the async nature of signer retrieval from Dynamic Labs SDK.


278-280: Good fix: explicit chainId for public client.

Passing chainId: Number(chainReference) ensures the correct chain's public client is used for waiting on transaction receipt, avoiding potential cross-chain issues.


217-243: Wallet switching logic is well-structured and safe.

The pattern of checking wallet type and conditionally switching primary wallet before network operations is correct. The early bail for missing EVM wallet (line 234-236) prevents runtime errors. Wallet references remain stable after changePrimaryWallet — Dynamic Labs SDK updates which wallet is considered primary in its context, but does not mutate or recreate the underlying wallet objects. The evmWallet reference captured at the start of the function continues to be valid for the subsequent switchNetwork call.

apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

139-183: EVM network switching logic is well-structured.

The try-catch pattern with proper state persistence for both success and error cases is solid. The console logging aids debugging.

apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (2)

1-7: Imports look correct for Dynamic Labs migration.

The imports are well-organized, bringing in the necessary Dynamic Labs hooks and utility functions from the local useWalletConnection hook.


258-269: Second disconnect dialog implementation looks good.

The per-wallet disconnect confirmation dialog properly manages state via walletToDisconnect and clears it on cancel/close.

apps/agentic-chat/src/hooks/useSendExecution.ts (3)

1-18: Imports correctly updated for Dynamic Labs SDK.

The imports properly bring in the type guards (isEthereumWallet, isSolanaWallet), context hooks, and the local SolanaWalletSigner type.


186-200: Solana wallet switching logic is correct.

The code properly checks if the primary wallet is not a Solana wallet before switching, avoiding unnecessary wallet switches when already on Solana.


205-214: EVM wallet validation and network switch logic looks good.

The code correctly validates EVM wallet presence and switches primary wallet when needed before performing network switch.

Copy link

@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 (6)
apps/agentic-chat/src/lib/wagmi-config.ts (1)

10-13: Custom RPC URLs from chain config are not being used.

This issue was flagged in a previous review. SUPPORTED_EVM_CHAINS defines custom rpcUrl values (e.g., https://eth.llamarpc.com), but the transports use bare http() which falls back to viem's default public RPCs.

-const transports = Object.fromEntries(SUPPORTED_CHAIN_IDS.map(id => [id, http()])) as Record<
+const transports = Object.fromEntries(
+  SUPPORTED_EVM_CHAINS.map(c => [c.chain.id, http(c.rpcUrl)])
+) as Record<
   (typeof SUPPORTED_CHAIN_IDS)[number],
   ReturnType<typeof http>
 >
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

101-132: Bug: Solana network switching always fails due to falsy chainId check.

This issue was flagged in a previous review. The networkNameToChainId map assigns solana: 0 (from chains.ts). Since 0 is falsy in JavaScript, the check at line 104 (if (!targetChainId)) triggers for Solana before reaching the Solana-specific handling at line 113.

Reorder the checks to handle Solana before the chainId validation, or change the check to targetChainId === undefined:

 const { state } = useToolExecutionEffect(toolCallId, networkData, initialNetworkState, async (data, setState) => {
+    // Handle Solana first (chainId 0 is falsy)
+    if (data.network === 'solana') {
+      if (solanaWallet && primaryWallet && !isSolanaWallet(primaryWallet)) {
+        await changePrimaryWallet(solanaWallet.id)
+      }
+      setState(draft => {
+        draft.phase = 'success'
+      })
+      if (activeConversationId) {
+        const persisted = networkStateToPersistedState(
+          toolCallId,
+          { phase: 'success' },
+          activeConversationId,
+          data.network,
+          data
+        )
+        store.persistTransaction(persisted)
+      }
+      return
+    }
+
     const targetChainId = networkNameToChainId[data.network]

-    if (!targetChainId) {
+    if (targetChainId === undefined) {
       setState(draft => {
         draft.phase = 'error'
         draft.error = `Network "${data.network}" not found`
       })
       return
     }
-
-    // Solana doesn't need network switching in the same way, but we might need to switch primary wallet
-    if (data.network === 'solana') {
-      // ... move this block before the chainId check
-    }
apps/agentic-chat/src/utils/chains/solana/transaction.ts (1)

81-83: Type assertion can be removed.

This was flagged in a previous review. The SolanaWalletSigner interface defines signTransaction as a generic method that correctly infers VersionedTransaction as the return type, making this assertion redundant.

-    const signedTx = await (signer.signTransaction as (tx: VersionedTransaction) => Promise<VersionedTransaction>)(
-      transaction
-    )
+    const signedTx = await signer.signTransaction(transaction)
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)

9-23: useMemo dependency on userWallets is likely ineffective.

useApprovedChains memoizes on userWallets, but useUserWallets() does not guarantee referential stability and may return a new array each render, causing the memo to recompute every time and negating its benefit. The logic is correct; this is mainly about efficiency and intent clarity.

Consider using a stable derived key as the dependency, for example:

  • Derive a wallet IDs key once:
    const walletKey = useMemo(
      () => userWallets.map(w => w.id).join(','),
      [userWallets],
    )
  • Then memoize chain IDs off that:
    return useMemo(() => {
      const chainIds: string[] = []
      if (filterEvmWallets(userWallets).length > 0) chainIds.push(...EVM_CAIP_IDS)
      if (filterSolanaWallets(userWallets).length > 0) chainIds.push(SOLANA_CAIP_ID)
      return chainIds
    }, [walletKey])

This keeps behavior identical while making useMemo actually effective. Based on learnings and prior review notes.

apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

14-16: Remove or fix the extra role="button" wrapper around CopyButton.

The new isActive badge and click/propagation logic look fine, but the CopyButton wrapper here:

{address && (
  <div onClick={e => e.stopPropagation()} onKeyDown={e => e.stopPropagation()} role="button" tabIndex={0}>
    <CopyButton value={address} className="text-muted-foreground hover:text-foreground" />
  </div>
)}

still has the same accessibility issue previously flagged:

  • It declares role="button" and tabIndex={0} but never triggers any action on Enter/Space; it only calls stopPropagation.
  • CopyButton itself already handles e.stopPropagation() on click and is a proper button via IconButton, so this wrapper is redundant and introduces an extra, non-functional focus target.

Suggested fix:

  • Simplest: remove the wrapper and render CopyButton directly, relying on its internal stopPropagation().
  • If a wrapper is required for layout, drop role="button" and tabIndex from the wrapper, or implement proper keyboard activation that forwards to the inner button while still stopping propagation.

Also applies to: 31-49, 55-58

apps/agentic-chat/src/hooks/useSendExecution.ts (1)

1-3: Solana signer typing still diverges from Dynamic Labs’ getSigner() return type.

You’re importing a local SolanaWalletSigner and assigning the result of await solanaWallet.getSigner() to it:

import type { SolanaWalletSigner } from '@/utils/chains/types'
// ...
let solanaSigner: SolanaWalletSigner | undefined
if (chainNamespace === CHAIN_NAMESPACE.Solana && solanaWallet) {
  solanaSigner = await solanaWallet.getSigner()
}

Per earlier review and Dynamic’s v4.49.0 docs, getSigner() returns Dynamic’s own Solana signer type (e.g. ISolanaSigner from @dynamic-labs/solana-core), which exposes additional methods beyond signTransaction. Relying on a narrower, homegrown SolanaWalletSigner interface is structurally valid in TypeScript, but it can drift from the actual SDK type over time and obscure breaking changes.

To keep things aligned while preserving your abstraction, consider either:

  • Importing and using the SDK type directly here (ISolanaSigner), or
  • Making SolanaWalletSigner in @/utils/chains/types a type alias (or extends) of the Dynamic SDK’s signer type, so all call sites stay in sync with the upstream signature.

This is the same concern raised in the previous review; addressing it once will make future Dynamic upgrades safer.

Also applies to: 14-15, 224-231

🧹 Nitpick comments (4)
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (2)

1-8: Dynamic wallet wiring and derived state look solid; small optimization for wallet grouping.

The integration with Dynamic (useDynamicContext, useSwitchWallet, useDynamicModals, useUserWallets, useWalletConnection) plus displayAddress/truncatedAddress and primary/chain‑specific wallet icons is cohesive and matches the rest of the PR. The connect flow (closing the drawer, then either linking a new wallet or starting auth) is also clean.

For walletGroups, you currently recompute EVM/Solana classification inside the otherWallets filter by calling filterEvmWallets([w]) / filterSolanaWallets([w]) per wallet. You could avoid repeated work and keep the classification logic in one place by computing the filtered lists once and deriving “other” from them, e.g.:

const walletGroups = useMemo(() => {
  const evmWallets = filterEvmWallets(userWallets)
  const solanaWallets = filterSolanaWallets(userWallets)
  const evmIds = new Set(evmWallets.map(w => w.id))
  const solanaIds = new Set(solanaWallets.map(w => w.id))

  const otherWallets = userWallets.filter(w => !evmIds.has(w.id) && !solanaIds.has(w.id))

  return { evmWallets, solanaWallets, otherWallets }
}, [userWallets])

This is purely an optimization/readability tweak; current behavior is correct.

Also applies to: 33-55, 64-77, 79-93


57-63: Per‑wallet disconnect UX works; consider handling async errors and avoiding dual‑dialog overlap.

The per‑wallet rows and dialogs are wired correctly: selecting a wallet updates the primary via changePrimaryWallet, and walletToDisconnect + the secondary AlertDialog provide a clear, scoped disconnect flow.

Two small refinements to consider:

  • handleWalletDisconnect calls void removeWallet(walletToDisconnect) and ignores the result. If removeWallet is async and can fail, you may want to await it inside a try/catch (and potentially show a toast) to avoid unhandled rejections and give users feedback when a disconnect fails.
  • Because you now have both a “global logout” dialog (showDisconnectAlert) and a per‑wallet dialog (walletToDisconnect), it’s possible for both to be triggered in quick succession. If that’s not desired, you could, for example, clear walletToDisconnect inside handleDisconnect or disable the global power button while walletToDisconnect is set.

These are UX/resilience polish items; the current logic is otherwise sound.

Also applies to: 110-137, 138-161, 163-186, 189-192, 254-265

apps/agentic-chat/src/hooks/useWalletConnection.ts (2)

10-31: Helper filters/finders are correct; you may be able to drop the extra Wallet cast.

findEvmWallet / findSolanaWallet / filterEvmWallets / filterSolanaWallets are nicely factored and give you strong typing for Ethereum vs Solana wallets.

If useUserWallets() indeed returns Wallet[] from @dynamic-labs/sdk-react-core, your DynamicWallet alias is already compatible with Wallet, and you may be able to invoke the type guards directly:

return wallets.find((w): w is EthereumWallet => isEthereumWallet(w))

instead of casting w as Wallet first. Dropping the cast tightens types slightly and avoids a possible future mismatch if DynamicWallet’s shape diverges from Wallet.


1-6: Avoid the circular dependency between useWalletConnection and useApprovedChains by extracting wallet helpers.

useWalletConnection imports useApprovedChains, and useApprovedChains (per the provided snippet) imports filterEvmWallets / filterSolanaWallets from this same module. This circular dependency is safe today because neither hook is invoked at module top level, but it does couple the modules and can become brittle as more logic is added.

A cleaner structure would be:

  • Move DynamicWallet, findEvmWallet, findSolanaWallet, filterEvmWallets, filterSolanaWallets, and maybe getWalletIcon into a small shared utility module (e.g. walletUtils.ts) or a dedicated shared package, and
  • Have both useWalletConnection and useApprovedChains import from that utility.

That breaks the cycle and keeps wallet‑classification logic in one place, which should scale better as you add more chain types and consumers. Based on learnings, this also aligns with your preference to centralize shared cross‑app logic into dedicated packages/utilities.

Also applies to: 8-9, 32-40, 42-66

📜 Review details

Configuration used: CodeRabbit 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 bea0509 and 034f99a.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • .env.example (1 hunks)
  • .env.production (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/components/CustomConnectButton.tsx (3 hunks)
  • apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (4 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useApprovedChains.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (0 hunks)
  • apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3 hunks)
  • apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (5 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (8 hunks)
  • apps/agentic-chat/src/hooks/useWalletConnection.ts (1 hunks)
  • apps/agentic-chat/src/lib/appkit.ts (0 hunks)
  • apps/agentic-chat/src/lib/chains.ts (1 hunks)
  • apps/agentic-chat/src/lib/networks.ts (0 hunks)
  • apps/agentic-chat/src/lib/solana-config.ts (0 hunks)
  • apps/agentic-chat/src/lib/wagmi-config.ts (1 hunks)
  • apps/agentic-chat/src/types/appkit.d.ts (0 hunks)
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/types.ts (1 hunks)
  • apps/agentic-chat/src/utils/sendExecutor.ts (2 hunks)
  • apps/agentic-chat/src/utils/sendTransaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/swapExecutor.ts (2 hunks)
  • apps/agentic-chat/vite.config.mjs (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (5)
  • apps/agentic-chat/src/lib/appkit.ts
  • apps/agentic-chat/src/lib/solana-config.ts
  • apps/agentic-chat/src/lib/networks.ts
  • apps/agentic-chat/src/types/appkit.d.ts
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx
  • .env.production
  • apps/agentic-chat/src/app/app.tsx
  • apps/agentic-chat/vite.config.mjs
  • apps/agentic-chat/src/lib/chains.ts
  • apps/agentic-chat/src/utils/sendTransaction.ts
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts
  • apps/agentic-chat/src/components/tools/SendUI.tsx
  • .env.example
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-16T20:28:23.547Z
Learnt from: premiumjibles
Repo: shapeshift/agentic-chat PR: 68
File: apps/agentic-server/package.json:26-26
Timestamp: 2025-09-16T20:28:23.547Z
Learning: In the ShapeShift agentic-chat codebase, mathjs optimization (lazy-loading or using modular sub-packages) has been noted for future implementation rather than immediate action.

Applied to files:

  • apps/agentic-chat/src/hooks/useApprovedChains.ts
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/hooks/useSendExecution.ts
🧬 Code graph analysis (12)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
apps/agentic-chat/src/lib/chains.ts (2)
  • SUPPORTED_EVM_CHAINS (15-88)
  • SUPPORTED_CHAIN_IDS (94-97)
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-57)
apps/agentic-chat/src/lib/chains.ts (1)
  • networkNameToChainId (103-106)
apps/agentic-chat/src/utils/sendExecutor.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/components/CustomConnectButton.tsx (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
  • useWalletConnection (42-67)
  • getWalletIcon (28-30)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/lib/chains.ts (1)
  • SOLANA_CAIP_ID (90-90)
packages/utils/src/networkIcons.ts (1)
  • NETWORK_ICONS (14-31)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
apps/agentic-chat/src/types/wallet.ts (1)
  • Wallet (1-6)
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)
  • useApprovedChains (8-24)
apps/agentic-chat/src/hooks/useApprovedChains.ts (2)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
  • filterEvmWallets (20-22)
  • filterSolanaWallets (24-26)
apps/agentic-chat/src/lib/chains.ts (2)
  • EVM_CAIP_IDS (108-108)
  • SOLANA_CAIP_ID (90-90)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (3)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/CopyButton.tsx (1)
  • CopyButton (15-41)
apps/agentic-chat/src/components/ui/IconButton.tsx (1)
  • IconButton (22-29)
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (6)
apps/agentic-chat/src/hooks/useWalletConnection.ts (4)
  • useWalletConnection (42-67)
  • getWalletIcon (28-30)
  • filterEvmWallets (20-22)
  • filterSolanaWallets (24-26)
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)
  • usePortfolioQuery (14-49)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/DropdownMenu.tsx (3)
  • DropdownMenuTrigger (206-206)
  • DropdownMenuContent (207-207)
  • DropdownMenuSeparator (214-214)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)
  • NetworkWalletRow (19-72)
apps/agentic-chat/src/components/ui/AlertDialog.tsx (8)
  • AlertDialog (93-93)
  • AlertDialogContent (97-97)
  • AlertDialogHeader (98-98)
  • AlertDialogTitle (100-100)
  • AlertDialogDescription (101-101)
  • AlertDialogFooter (99-99)
  • AlertDialogCancel (103-103)
  • AlertDialogAction (102-102)
apps/agentic-chat/src/utils/swapExecutor.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (15-19)
apps/agentic-chat/src/hooks/useSendExecution.ts (5)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • useChatStore (69-188)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-server/src/tools/send.ts (1)
  • executeSend (24-71)
apps/agentic-chat/src/utils/chains/types.ts (2)
apps/agentic-chat/src/types/transaction.ts (1)
  • Transaction (1-10)
packages/caip/src/constants.ts (1)
  • ChainId (175-175)
⏰ 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: main
🔇 Additional comments (12)
apps/agentic-chat/package.json (1)

16-21: LGTM!

The Dynamic Labs dependencies are consistently versioned at ^4.49.0, which is appropriate for a coordinated SDK migration. The caret range allows compatible updates while maintaining version alignment across the Dynamic Labs packages.

apps/agentic-chat/src/lib/wagmi-config.ts (1)

15-19: LGTM!

The createConfig setup with multiInjectedProviderDiscovery: false is appropriate when using Dynamic Labs, as Dynamic handles wallet discovery through its own mechanisms.

apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

139-166: LGTM!

The EVM network switching logic correctly handles primary wallet switching when the current wallet is Solana, validates EVM wallet availability, and uses Dynamic's connector for network switching with proper error handling and state persistence.

apps/agentic-chat/src/utils/chains/solana/transaction.ts (1)

40-46: LGTM!

The signer acquisition with fallback to window.solana provides backwards compatibility while supporting the new Dynamic Labs signer pattern. The inline type annotation for window.solana correctly constrains the expected interface.

package.json (1)

62-64: The Solana web3.js version override is intentional and necessary.

The override to 1.98.1 is required because Dynamic Labs packages (v4.49.0) have fixed dependencies on this version. Multiple Dynamic Labs packages (@dynamic-labs/solana, @dynamic-labs/solana-core, @dynamic-labs/embedded-wallet-solana, and @dynamic-labs/waas-svm) explicitly require @solana/[email protected], while the direct dependencies specify ^1.95.8 and ^1.95.2. The override correctly resolves this conflict, as confirmed by the migration commit ("feat: migrate from reown to dynamic"). All API usage (Connection, PublicKey, TransactionMessage, etc.) is compatible across the minor version range.

apps/agentic-chat/src/utils/swapExecutor.ts (1)

4-13: Solana signer wiring in swap executor looks consistent.

ExecuteTransactionOptions and finalTx now correctly carry solanaSigner?: SolanaWalletSigner, matching the updated TransactionParams shape and keeping EVM behavior unchanged when no signer is passed.

Also applies to: 28-32

apps/agentic-chat/src/utils/sendExecutor.ts (1)

4-12: Send executor’s Solana signer integration is consistent.

The solanaSigner?: SolanaWalletSigner option is cleanly threaded into finalTx and only attached when present, preserving existing EVM behavior while enabling Solana signing via the shared transaction adapter.

Also applies to: 21-32

apps/agentic-chat/src/utils/chains/types.ts (1)

6-23: Solana signer abstraction and TransactionParams update look sound.

Defining SolanaWalletSigner with signTransaction and threading it into TransactionParams.solanaSigner? (plus the SolanaWalletProvider alias for back-compat) provides a clear, minimal surface for Solana signing while keeping adapters generic over chain. Internal call sites that pass solanaSigner (send/swap executors) align with this shape.

apps/agentic-chat/src/components/CustomConnectButton.tsx (1)

16-20: Dynamic wallet wiring and CAIP-based network icon look correct.

  • Address selection (primaryWallet?.address ?? evmAddress ?? solanaAddress) gracefully prefers the dynamic primary wallet while still falling back to chain-specific addresses.
  • isPrimarySolana + SOLANA_CAIP_ID vs eip155:${chainId} matches the NETWORK_ICONS CAIP key scheme, so EVM vs Solana network icons should render as expected.
  • setShowAuthFlow(true) is an appropriate replacement for the prior connect flow, and onConnectedClick remains isolated from the connect button via handleOpenAccount.

No functional issues stand out here.

Also applies to: 39-49, 53-58

apps/agentic-chat/src/hooks/useSwapExecution.tsx (2)

18-19: Wallet context and primary-wallet switching integration is coherent.

useSwapExecution now:

  • Pulls evmAddress, solanaAddress, evmWallet, and solanaWallet from useWalletConnection.
  • Reads primaryWallet plus changePrimaryWallet from Dynamic context.

The resulting logic cleanly distinguishes EVM vs Solana flows and ensures a concrete wallet is available before progressing, with primary wallet switching handled explicitly where needed. This keeps the swap-step state machine intact while aligning it with the new Dynamic-based wallet model.

Also applies to: 159-165


201-205: Solana signer acquisition and EVM/Solana execution paths look robust.

Key points in the execution effect:

  • For Solana:

    • Lazily obtains solanaSigner via solanaWallet.getSigner() only when chainNamespace === CHAIN_NAMESPACE.Solana and a Solana wallet exists.
    • Ensures the active address matches swapTx.from before proceeding.
    • Skips the EVM-specific approval confirmation step while still passing solanaSigner to both executeApproval and executeSwap.
  • For EVM:

    • Guards against missing evmWallet before switching networks.
    • If the primary wallet isn’t EVM, switches the primary to evmWallet.id before calling evmWallet.connector.switchNetwork({ networkChainId: sellChainIdNumber }).
    • Uses getPublicClient(wagmiConfig, { chainId: Number(chainReference) }) and waitForTransactionReceipt only for EVM approvals.
  • Shared:

    • Both approval and swap execution now receive { solanaSigner }, which is defined only for Solana, so EVM paths ignore it without behavioral change.

Overall, the signer handling and chain-conditional branching are consistent with the updated SolanaWalletSigner abstraction and avoid obvious race or mismatch conditions.

Also applies to: 217-225, 234-240, 243-244, 254-256, 278-280, 301-303

apps/agentic-chat/src/hooks/useSendExecution.ts (1)

136-141: Network switching and primary‑wallet alignment logic look correct for EVM vs Solana.

Using useWalletConnection() to derive evmAddress/solanaAddress and evmWallet/solanaWallet, then:

  • Verifying currentAddress against tx.from,
  • Switching the primary wallet to Solana when chainNamespace === CHAIN_NAMESPACE.Solana but the current primaryWallet isn’t Solana, and
  • On EVM, ensuring evmWallet exists, promoting it to primaryWallet when necessary, and then calling evmWallet.connector.switchNetwork({ networkChainId }),

gives a coherent story that should prevent mismatches between the active wallet/network and the transaction being executed.

No functional issues stand out here; just ensure the non‑EVM branches you support (currently Solana) remain in sync with how executeSend expects its wallet context.

Also applies to: 184-221

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (5)
apps/agentic-chat/src/utils/chains/solana/transaction.ts (1)

81-83: Remove unnecessary type assertion.

The SolanaWalletSigner interface defines signTransaction as a generic method that infers the return type from the input type. When called with VersionedTransaction, TypeScript automatically infers the return type as Promise<VersionedTransaction>, making the type assertion redundant.

-    const signedTx = await (signer.signTransaction as (tx: VersionedTransaction) => Promise<VersionedTransaction>)(
-      transaction
-    )
+    const signedTx = await signer.signTransaction(transaction)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

34-36: Accessibility issue: Remove wrapper with incomplete button semantics.

The wrapper div has role="button" and tabIndex={0} but only stops propagation on keydown without handling Enter/Space activation. Since CopyButton already handles stopPropagation internally (see CopyButton.tsx line 18), this wrapper is unnecessary and creates an inaccessible button for keyboard users.

         {address && (
-          <div onClick={e => e.stopPropagation()} onKeyDown={e => e.stopPropagation()} role="button" tabIndex={0}>
-            <CopyButton value={address} className="text-muted-foreground hover:text-foreground" />
-          </div>
+          <div onClick={e => e.stopPropagation()}>
+            <CopyButton value={address} className="text-muted-foreground hover:text-foreground" />
+          </div>
         )}
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

102-132: Critical: Solana network switching still fails due to falsy chainId check.

The past review marked this as addressed, but the code still shows the problematic pattern. At line 104, if (!targetChainId) treats chainId 0 (Solana from networkNameToChainId.solana = 0) as falsy, causing the error at lines 105-109 to execute before the Solana-specific handling at lines 113-132.

Reorder to check Solana first, before validating chainId:

 const { state } = useToolExecutionEffect(toolCallId, networkData, initialNetworkState, async (data, setState) => {
+    // Solana doesn't need network switching in the same way, but we might need to switch primary wallet
+    if (data.network === 'solana') {
+      const targetChainId = networkNameToChainId[data.network]
+      if (targetChainId === undefined) {
+        setState(draft => {
+          draft.phase = 'error'
+          draft.error = `Network "${data.network}" not found`
+        })
+        return
+      }
+
+      if (solanaWallet && primaryWallet && !isSolanaWallet(primaryWallet)) {
+        await changePrimaryWallet(solanaWallet.id)
+      }
+
+      setState(draft => {
+        draft.phase = 'success'
+      })
+      if (activeConversationId) {
+        const persisted = networkStateToPersistedState(
+          toolCallId,
+          { phase: 'success' },
+          activeConversationId,
+          data.network,
+          data
+        )
+        store.persistTransaction(persisted)
+      }
+      return
+    }
+
     const targetChainId = networkNameToChainId[data.network]

-    if (!targetChainId) {
+    if (targetChainId === undefined) {
       setState(draft => {
         draft.phase = 'error'
         draft.error = `Network "${data.network}" not found`
       })
       return
     }

-    // Solana doesn't need network switching in the same way...
-    if (data.network === 'solana') {
-      ...
-    }
apps/agentic-chat/src/lib/wagmi-config.ts (1)

10-13: Custom RPC URLs from chain config are still not being used.

SUPPORTED_EVM_CHAINS defines custom rpcUrl values (e.g., https://eth.llamarpc.com), but the transports still use bare http() which falls back to viem's default public RPCs. This may cause rate limiting or reliability issues.

Apply this diff to use the custom RPC URLs:

-const transports = Object.fromEntries(SUPPORTED_CHAIN_IDS.map(id => [id, http()])) as Record<
+const transports = Object.fromEntries(
+  SUPPORTED_EVM_CHAINS.map(c => [c.chain.id, http(c.rpcUrl)])
+) as Record<
   (typeof SUPPORTED_CHAIN_IDS)[number],
   ReturnType<typeof http>
 >
apps/agentic-chat/src/hooks/useSendExecution.ts (1)

224-230: Type annotation uses local SolanaWalletSigner rather than SDK type.

As noted in a previous review, the Dynamic Labs SDK returns ISolanaSigner from getSigner(). While structurally compatible, using the SDK's type would provide stronger type guarantees.

This is the same pattern flagged in useSwapExecution.tsx. Consider importing ISolanaSigner from @dynamic-labs/solana-core for both files.

🧹 Nitpick comments (7)
apps/agentic-chat/src/app/app.tsx (1)

41-51: Consider validating the environment variable.

The VITE_DYNAMIC_ENVIRONMENT_ID is passed directly to DynamicContextProvider without validation. If this environment variable is missing or invalid, the application will fail at runtime with potentially unclear errors.

Add validation before the return statement:

function App() {
  const dynamicEnvironmentId = import.meta.env.VITE_DYNAMIC_ENVIRONMENT_ID
  
  if (!dynamicEnvironmentId) {
    console.error('VITE_DYNAMIC_ENVIRONMENT_ID is not configured')
    return <div>Configuration error: Missing Dynamic environment ID</div>
  }

  return (
    <DynamicContextProvider
      // ...
      settings={{
        environmentId: dynamicEnvironmentId,
        // ...
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (2)

43-55: Consider awaiting query invalidation before logout.

The handleDisconnect function calls invalidateQueries with .catch(console.error) but doesn't await them before calling handleLogOut(). This could lead to a race condition where the logout completes before cache invalidation.

  const handleDisconnect = useCallback(() => {
-   queryClient.invalidateQueries({ queryKey: ['portfolio'] }).catch(console.error)
-   queryClient.invalidateQueries({ queryKey: ['approvedChains'] }).catch(console.error)
-
-   handleLogOut()
+   Promise.all([
+     queryClient.invalidateQueries({ queryKey: ['portfolio'] }),
+     queryClient.invalidateQueries({ queryKey: ['approvedChains'] }),
+   ])
+     .catch(console.error)
+     .then(() => handleLogOut())
      .catch(error => {
        console.error('Failed to disconnect wallet:', error)
      })
      .finally(() => {
        setShowDisconnectAlert(false)
        onClose()
      })
  }, [queryClient, handleLogOut, onClose])

116-186: Consider extracting repeated wallet list rendering into a reusable component.

The rendering logic for EVM, Solana, and Other wallet groups is nearly identical. This could be refactored into a single WalletGroup component to reduce duplication.

// Example extracted component
const WalletGroup = ({ label, wallets, primaryWallet, changePrimaryWallet, setWalletToDisconnect }) => (
  wallets.length > 0 && (
    <div className="mb-2">
      <div className="px-2 py-1 text-xs font-medium text-muted-foreground/70 uppercase tracking-wider">
        {label}
      </div>
      {wallets.map(wallet => (
        <div key={wallet.id} className="relative">
          <NetworkWalletRow
            label={wallet.connector.name}
            address={wallet.address}
            icon={getWalletIcon(wallet)}
            isActive={wallet.id === primaryWallet?.id}
            onConnect={() => {
              if (wallet.id !== primaryWallet?.id) {
                changePrimaryWallet(wallet.id).catch(console.error)
              }
            }}
            onDisconnect={() => setWalletToDisconnect(wallet.id)}
          />
        </div>
      ))}
    </div>
  )
);
apps/agentic-chat/src/lib/chains.ts (2)

15-88: Consider using environment variables or a config service for RPC URLs.

The hardcoded public RPC endpoints (e.g., https://eth.llamarpc.com, https://polygon-rpc.com) may have rate limits in production. Consider making these configurable via environment variables or using a dedicated RPC provider.

  {
    chain: mainnet,
    networkName: 'ethereum',
    caipId: 'eip155:1',
    iconUrl: 'https://app.dynamic.xyz/assets/networks/eth.svg',
    blockExplorerUrl: 'https://etherscan.io/',
-   rpcUrl: 'https://eth.llamarpc.com',
+   rpcUrl: import.meta.env.VITE_ETH_RPC_URL ?? 'https://eth.llamarpc.com',
    vanityName: 'Ethereum',
  },
  // ... similar for other chains

103-106: Using 0 for Solana chain ID is unconventional but acceptable.

The solana: 0 entry in networkNameToChainId uses 0 as a sentinel value since Solana doesn't have an EVM-style numeric chain ID. Document this convention or consider using null/undefined if consumers can handle it.

 export const networkNameToChainId: Record<string, number> = {
   ...Object.fromEntries(SUPPORTED_EVM_CHAINS.map(c => [c.networkName, c.chain.id])),
-  solana: 0,
+  solana: 0, // Sentinel value: Solana is not an EVM chain
 }
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)

32-40: Consider exporting WalletConnectionResult interface.

The interface is well-defined but not exported. If other components need to type their props or state based on this return type, exporting it would improve reusability.

-interface WalletConnectionResult {
+export interface WalletConnectionResult {
   isConnected: boolean
   evmAddress: string | undefined
   solanaAddress: string | undefined
   primaryAddress: string | undefined
   approvedChainIds: string[]
   evmWallet: EthereumWallet | undefined
   solanaWallet: SolanaWallet | undefined
 }
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

201-205: Consider aligning type imports with SDK definitions for consistency.

The code uses the local SolanaWalletSigner interface (which only defines signTransaction) rather than the SDK's ISolanaSigner type from @dynamic-labs/solana-core. While the current approach works since SolanaWalletSigner is a compatible subset, importing ISolanaSigner would align with SDK conventions and provide access to additional signer methods if needed in the future. This same pattern appears in useSendExecution.ts.

📜 Review details

Configuration used: CodeRabbit 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 034f99a and 1ca0b23.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • .env.example (1 hunks)
  • .env.production (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/components/CustomConnectButton.tsx (3 hunks)
  • apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (4 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useApprovedChains.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (0 hunks)
  • apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3 hunks)
  • apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (5 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (8 hunks)
  • apps/agentic-chat/src/hooks/useWalletConnection.ts (1 hunks)
  • apps/agentic-chat/src/lib/appkit.ts (0 hunks)
  • apps/agentic-chat/src/lib/chains.ts (1 hunks)
  • apps/agentic-chat/src/lib/networks.ts (0 hunks)
  • apps/agentic-chat/src/lib/solana-config.ts (0 hunks)
  • apps/agentic-chat/src/lib/wagmi-config.ts (1 hunks)
  • apps/agentic-chat/src/types/appkit.d.ts (0 hunks)
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/types.ts (1 hunks)
  • apps/agentic-chat/src/utils/sendExecutor.ts (2 hunks)
  • apps/agentic-chat/src/utils/sendTransaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/swapExecutor.ts (2 hunks)
  • apps/agentic-chat/vite.config.mjs (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (5)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts
  • apps/agentic-chat/src/lib/networks.ts
  • apps/agentic-chat/src/lib/appkit.ts
  • apps/agentic-chat/src/lib/solana-config.ts
  • apps/agentic-chat/src/types/appkit.d.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/agentic-chat/src/components/tools/SendUI.tsx
  • .env.example
  • apps/agentic-chat/package.json
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-16T20:28:23.547Z
Learnt from: premiumjibles
Repo: shapeshift/agentic-chat PR: 68
File: apps/agentic-server/package.json:26-26
Timestamp: 2025-09-16T20:28:23.547Z
Learning: In the ShapeShift agentic-chat codebase, mathjs optimization (lazy-loading or using modular sub-packages) has been noted for future implementation rather than immediate action.

Applied to files:

  • apps/agentic-chat/src/hooks/useApprovedChains.ts
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/hooks/useSendExecution.ts
🧬 Code graph analysis (15)
apps/agentic-chat/src/utils/chains/types.ts (1)
packages/caip/src/constants.ts (1)
  • ChainId (175-175)
apps/agentic-chat/src/hooks/useApprovedChains.ts (2)
apps/agentic-chat/src/lib/chains.ts (2)
  • EVM_CAIP_IDS (108-108)
  • SOLANA_CAIP_ID (90-90)
apps/agentic-chat/src/types/wallet.ts (1)
  • Wallet (1-6)
apps/agentic-chat/src/utils/sendExecutor.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/utils/sendTransaction.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/utils/swapExecutor.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (4)
  • useWalletConnection (42-67)
  • getWalletIcon (28-30)
  • filterEvmWallets (20-22)
  • filterSolanaWallets (24-26)
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)
  • usePortfolioQuery (14-49)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)
  • NetworkWalletRow (17-52)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (3)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/CopyButton.tsx (1)
  • CopyButton (15-41)
apps/agentic-chat/src/components/ui/IconButton.tsx (1)
  • IconButton (22-29)
apps/agentic-chat/src/hooks/useSendExecution.ts (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/utils/sendExecutor.ts (1)
  • executeSend (34-40)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
apps/agentic-chat/src/lib/chains.ts (2)
  • SUPPORTED_EVM_CHAINS (15-88)
  • SUPPORTED_CHAIN_IDS (94-97)
apps/agentic-chat/src/app/app.tsx (2)
apps/agentic-chat/src/lib/chains.ts (1)
  • DYNAMIC_EVM_NETWORKS (110-120)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (15-19)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
apps/agentic-chat/src/types/wallet.ts (1)
  • Wallet (1-6)
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)
  • useApprovedChains (54-68)
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-57)
apps/agentic-chat/src/lib/chains.ts (1)
  • networkNameToChainId (103-106)
apps/agentic-chat/src/components/CustomConnectButton.tsx (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
  • useWalletConnection (42-67)
  • getWalletIcon (28-30)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/lib/chains.ts (1)
  • SOLANA_CAIP_ID (90-90)
packages/utils/src/networkIcons.ts (1)
  • NETWORK_ICONS (14-31)
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (42-67)
apps/agentic-chat/src/services/portfolioService.ts (1)
  • fetchFullPortfolio (31-102)
⏰ 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: main
🔇 Additional comments (31)
.env.production (1)

25-26: LGTM!

The environment variable rename from VITE_PROJECT_ID to VITE_DYNAMIC_ENVIRONMENT_ID aligns with the migration to Dynamic Labs and is properly documented.

apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

17-51: LGTM with one accessibility concern.

The component refactor simplifies the UI by making the entire row clickable for connection. The Active badge provides clear visual feedback, and the disconnect button properly stops propagation. The structure is clean and the logic is sound, pending resolution of the accessibility issue flagged above.

apps/agentic-chat/src/utils/chains/types.ts (2)

6-13: LGTM!

The SolanaWalletSigner interface provides a clean abstraction for Solana wallet signing, with proper typing for both transaction types. The backward compatibility alias and inline documentation are helpful.


22-22: LGTM!

The parameter rename from solanaProvider to solanaSigner accurately reflects the new interface and improves clarity.

apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

139-183: LGTM!

The EVM network switching logic with Dynamic connector is well-structured. The try-catch block properly handles errors, persists state, and switches wallets when needed. The console logs aid debugging.

apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1)

19-19: LGTM!

Deriving the address from swapOutput?.swapData.sellAccount is more direct and aligns with the migration away from AppKit. The swap data is the authoritative source for the account performing the swap.

apps/agentic-chat/src/utils/chains/solana/transaction.ts (1)

40-46: LGTM!

The signer source now correctly uses params.solanaSigner with a fallback to window.solana, properly typed with the SolanaWalletSigner interface. The validation logic is sound.

apps/agentic-chat/vite.config.mjs (1)

9-12: The process.env stubbing is safe and appropriate for this browser-based application.

The codebase already uses import.meta.env for all environment variable access (e.g., VITE_AGENTIC_SERVER_BASE_URL, VITE_ENABLE_ANALYTICS, VITE_SOLANA_RPC_URL, VITE_DYNAMIC_ENVIRONMENT_ID), which is Vite's standard runtime approach for browser builds. No client-side code or dependencies rely on process.env directly, making the empty object stub safe and correct.

apps/agentic-chat/src/utils/sendTransaction.ts (1)

4-4: LGTM! Type migration is consistent.

The migration from SolanaWalletProvider to SolanaWalletSigner aligns with the broader shift to signer-based APIs. The type interface provides the necessary signTransaction method.

Also applies to: 13-13

apps/agentic-chat/src/utils/swapExecutor.ts (1)

4-4: LGTM! Consistent signer migration.

The type and property changes are consistent with the signer-based approach across transaction utilities.

Also applies to: 12-12, 28-28

apps/agentic-chat/src/utils/sendExecutor.ts (1)

4-4: LGTM! Consistent with other executors.

The migration follows the same signer-based pattern as swapExecutor.ts.

Also applies to: 11-11, 28-28

apps/agentic-chat/src/app/app.tsx (1)

52-68: LGTM! Provider structure is correct.

The provider nesting follows the correct order: DynamicContextProvider → WagmiProvider → QueryClientProvider → DynamicWagmiConnector → App content. This ensures proper initialization and context availability.

apps/agentic-chat/src/components/CustomConnectButton.tsx (1)

18-50: LGTM! Dynamic wallet integration is well-structured.

The component correctly:

  • Uses primaryWallet for primary wallet state
  • Falls back through primaryWallet.addressevmAddresssolanaAddress for address display
  • Determines wallet type for proper CAIP chain ID computation
  • Handles both EVM and Solana wallet icons and network badges
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)

59-65: LGTM! Query key properly addresses referential stability.

Using userWallets.map(w => w.id).join(',') in the query key ensures the query only refetches when wallet identities actually change, which addresses the referential stability concern from earlier reviews.

apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)

18-24: Clarify intent: Is portfolio fetching limited to primary wallet by design?

The current logic only fetches portfolio data for the primary wallet: if the primary wallet is EVM-based, solanaAddressToFetch is undefined, and vice versa. This means users with both EVM and Solana wallets connected will only see the portfolio of their primary wallet.

useWalletConnection exposes both evmAddress and solanaAddress, and the fetchFullPortfolio API endpoint is designed to accept and aggregate data from both chains. If the intent is to display a unified portfolio across all connected wallets, the hook should pass both addresses:

-  // Determine which address type the primary wallet is
-  const isEvmPrimary = primaryWallet && isEthereumWallet(primaryWallet)
-  const isSolanaPrimary = primaryWallet && isSolanaWallet(primaryWallet)
-
-  // Only pass the address that matches the primary wallet type
-  const evmAddressToFetch = isEvmPrimary ? primaryAddress : undefined
-  const solanaAddressToFetch = isSolanaPrimary ? primaryAddress : undefined
+  const { evmAddress, solanaAddress } = useWalletConnection()

Then update the query call to use evmAddress and solanaAddress directly, and adjust the query key accordingly.

Confirm whether primary-wallet-only is the intended behavior or if multi-chain portfolio support is required.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (5)

1-22: Imports look correct for the Dynamic Labs migration.

The imports properly bring in isEthereumWallet, isSolanaWallet, useDynamicContext, useSwitchWallet, and the local SolanaWalletSigner type. The migration from the previous wallet provider to Dynamic Labs SDK is consistent.


159-163: Wallet context destructuring is well-structured.

The hook now correctly retrieves evmAddress, solanaAddress, solanaWallet, and evmWallet from useWalletConnection(), and primaryWallet/changePrimaryWallet from Dynamic context hooks.


217-224: Primary wallet switch for Solana path is well-handled.

The logic correctly detects when Solana is the active chain but the primary wallet is not a Solana wallet, then switches accordingly. This ensures proper wallet alignment before transaction execution.


234-243: EVM network switch logic is correct.

The code properly validates EVM wallet presence, switches primary wallet if needed, and uses the Dynamic Labs connector's switchNetwork method. Error handling for missing EVM wallet is appropriate.


278-280: Public client creation properly includes chainId.

The getPublicClient call now correctly passes the chainId in the configuration object, which is necessary for wagmi to return the correct chain-specific client.

apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (3)

1-7: Imports are appropriate for the Dynamic Labs migration.

All necessary hooks (useDynamicContext, useDynamicModals, useSwitchWallet, useUserWallets) and utilities (filterEvmWallets, filterSolanaWallets, getWalletIcon) are imported correctly.


86-96: Wallet grouping logic is well-structured.

The memoized walletGroups correctly categorizes wallets into EVM, Solana, and Other groups, using a Set for efficient exclusion of already-categorized wallets.


254-265: Per-wallet disconnect confirmation dialog is a good UX addition.

The two-step disconnect flow with a confirmation dialog prevents accidental wallet disconnections. The onOpenChange handler correctly resets state when the dialog is closed.

apps/agentic-chat/src/lib/chains.ts (2)

1-13: Clean interface definition for chain configuration.

The ChainConfig interface provides a well-structured schema for chain metadata including the viem Chain object, network identifiers, URLs, and display names.


110-120: DYNAMIC_EVM_NETWORKS transformation is correct.

The mapping from ChainConfig to EvmNetwork properly populates all required fields for Dynamic Labs network configuration.

apps/agentic-chat/src/hooks/useSendExecution.ts (3)

1-18: Imports align with the Dynamic Labs migration pattern.

The imports mirror useSwapExecution.tsx, maintaining consistency across the codebase for the wallet migration.


136-140: Wallet context destructuring is consistent with swap execution.

The hook correctly retrieves wallet data from useWalletConnection() and Dynamic context hooks.


187-214: Network switch logic correctly handles both Solana and EVM paths.

The Solana path properly switches primary wallet when needed, and the EVM path validates wallet presence before switching networks. Error handling is appropriate.

apps/agentic-chat/src/hooks/useWalletConnection.ts (3)

1-10: Imports and type alias are well-structured.

The Dynamic Labs SDK imports are appropriate, and the DynamicWallet type alias provides a clean abstraction over the useUserWallets return type.


12-30: Helper functions provide clean wallet filtering utilities.

The find* and filter* functions properly use type guards with isEthereumWallet/isSolanaWallet. The getWalletIcon function safely accesses the nested connector metadata.


42-66: Hook implementation correctly prioritizes primary wallet.

The logic properly checks if primaryWallet is an EVM or Solana wallet first, then falls back to finding any available wallet of that type. This ensures the primary wallet is always used when compatible.

Copy link

@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

♻️ Duplicate comments (5)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

34-36: Accessibility: role="button" without keyboard activation.

This wrapper has role="button" and tabIndex={0} but doesn't handle Enter/Space key activation. Since CopyButton already calls stopPropagation internally, this wrapper can be simplified.

         {address && (
-          <div onClick={e => e.stopPropagation()} onKeyDown={e => e.stopPropagation()} role="button" tabIndex={0}>
+          <div onClick={e => e.stopPropagation()}>
             <CopyButton value={address} className="text-muted-foreground hover:text-foreground" />
           </div>
         )}
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)

15-16: Consider adding explicit Dynamic SDK state checks for robustness.

Per Dynamic Labs SDK documentation, primaryWallet can be null during auth resolution or wallet switching even when isConnected is true. The current enabled: isConnected && !!primaryAddress guard works because primaryAddress derives from primaryWallet?.address, but this is implicit.

For clarity and to align with Dynamic's patterns, consider explicit checks:

const { primaryWallet, sdkHasLoaded } = useDynamicContext()
// ...
enabled: isConnected && !!primaryAddress && sdkHasLoaded

Also applies to: 31-31

apps/agentic-chat/src/hooks/useApprovedChains.ts (1)

40-45: Only the first EVM wallet's approved chains are queried.

The comment states "they should all have same session," but this assumption doesn't hold for mixed wallet scenarios. WalletConnect wallets query getSupportedNetworks(), while injected wallets return all EVM_CAIP_IDS. If users connect both types, the first wallet's chain set may not represent complete coverage.

Consider querying all EVM wallets and merging unique chains:

-  const firstEvmWallet = evmWallets[0]
-  if (firstEvmWallet) {
-    // Get approved chains from the first EVM wallet (they should all have same session)
-    const evmChains = await getApprovedChainsForWallet(firstEvmWallet)
-    chainIds.push(...evmChains)
-  }
+  if (evmWallets.length > 0) {
+    const evmChainResults = await Promise.all(
+      evmWallets.map(wallet => getApprovedChainsForWallet(wallet))
+    )
+    const uniqueEvmChains = [...new Set(evmChainResults.flat())]
+    chainIds.push(...uniqueEvmChains)
+  }
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

101-132: Bug: Solana network switching fails due to falsy chainId check.

The networkNameToChainId map assigns solana: 0 (from chains.ts line 105). Since 0 is falsy in JavaScript, the check at line 104 (if (!targetChainId)) will trigger an error for Solana before reaching the Solana-specific handling at line 113.

Reorder the checks to handle Solana before the chainId validation, or use strict equality:

   const { state } = useToolExecutionEffect(toolCallId, networkData, initialNetworkState, async (data, setState) => {
+    // Handle Solana first since chainId 0 is falsy
+    if (data.network === 'solana') {
+      if (solanaWallet && primaryWallet && !isSolanaWallet(primaryWallet)) {
+        await changePrimaryWallet(solanaWallet.id)
+      }
+
+      setState(draft => {
+        draft.phase = 'success'
+      })
+      if (activeConversationId) {
+        const persisted = networkStateToPersistedState(
+          toolCallId,
+          { phase: 'success' },
+          activeConversationId,
+          data.network,
+          data
+        )
+        store.persistTransaction(persisted)
+      }
+      return
+    }
+
     const targetChainId = networkNameToChainId[data.network]

-    if (!targetChainId) {
+    if (targetChainId === undefined) {
       setState(draft => {
         draft.phase = 'error'
         draft.error = `Network "${data.network}" not found`
       })
       return
     }
-
-    // Solana doesn't need network switching in the same way, but we might need to switch primary wallet
-    if (data.network === 'solana') {
-      ...
-    }
apps/agentic-chat/src/hooks/useSendExecution.ts (1)

224-230: Add proper type annotations for Dynamic Labs SDK's SolanaWallet.getSigner() return type.

The code assigns solanaWallet.getSigner() to SolanaWalletSigner, but Dynamic Labs SDK v4.49.0 returns ISolanaSigner (which includes publicKey and methods like signTransaction, signAllTransactions, signAndSendTransaction, signMessage). The type annotation should match the actual SDK return type for clarity and type safety.

Import and use ISolanaSigner from @dynamic-labs/solana-core instead of the local SolanaWalletSigner type:

+import type { ISolanaSigner } from '@dynamic-labs/solana-core'
 import { isSolanaWallet } from '@dynamic-labs/solana'

Then update the type annotation:

-      let solanaSigner: SolanaWalletSigner | undefined
+      let solanaSigner: ISolanaSigner | undefined
       if (chainNamespace === CHAIN_NAMESPACE.Solana && solanaWallet) {
         solanaSigner = await solanaWallet.getSigner()
       }
🧹 Nitpick comments (6)
apps/agentic-chat/src/utils/sendExecutor.ts (1)

10-12: Consider extracting shared ExecuteTransactionOptions type.

This interface is identical to the one in swapExecutor.ts. If the pattern is stable, extracting it to a shared location (e.g., @/utils/chains/types) would reduce duplication.

apps/agentic-chat/src/app/app.tsx (1)

41-70: Provider setup follows Dynamic Labs conventions correctly.

The provider hierarchy (DynamicContextProvider → WagmiProvider → QueryClientProvider → DynamicWagmiConnector) aligns with Dynamic's recommended integration pattern. The initialAuthenticationMode: 'connect-only' is appropriate for wallet connection without embedded authentication.

Consider adding runtime validation for the environment ID to provide a clearer error message during development:

+const dynamicEnvironmentId = import.meta.env.VITE_DYNAMIC_ENVIRONMENT_ID
+if (!dynamicEnvironmentId) {
+  throw new Error('VITE_DYNAMIC_ENVIRONMENT_ID is required')
+}
+
 <DynamicContextProvider
   theme="dark"
   settings={{
-    environmentId: import.meta.env.VITE_DYNAMIC_ENVIRONMENT_ID,
+    environmentId: dynamicEnvironmentId,
apps/agentic-chat/src/components/CustomConnectButton.tsx (1)

39-40: Inconsistent memoization between walletIcon and walletName.

walletName is wrapped in useMemo but walletIcon is not, despite both being derived from primaryWallet?.connector. Either memoize both or neither for consistency. Since both are simple property accesses returning primitives/strings, memoization provides negligible benefit here.

-  const walletIcon = primaryWallet?.connector?.metadata?.icon
-  const walletName = useMemo(() => primaryWallet?.connector?.name, [primaryWallet?.connector?.name])
+  const walletIcon = primaryWallet?.connector?.metadata?.icon
+  const walletName = primaryWallet?.connector?.name
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

201-205: Consider error handling for getSigner() call.

The solanaWallet.getSigner() call is awaited but not wrapped in try/catch. If this throws (e.g., wallet disconnected mid-operation), it could cause an unhandled rejection before the main try block catches it.

       // Get Solana signer if needed - SolanaWallet has getSigner() directly on the class
       let solanaSigner: SolanaWalletSigner | undefined
       if (chainNamespace === CHAIN_NAMESPACE.Solana && solanaWallet) {
-        solanaSigner = await solanaWallet.getSigner()
+        try {
+          solanaSigner = await solanaWallet.getSigner()
+        } catch (e) {
+          throw new Error('Failed to get Solana signer. Please reconnect your wallet.')
+        }
       }
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

142-152: Remove debug console.log statements before production.

Debug logging statements should be removed or replaced with proper logging infrastructure for production code.

       if (evmWallet && primaryWallet && !isEthereumWallet(primaryWallet)) {
-        console.log('[useNetworkSwitch] Switching primary wallet from Solana to EVM:', evmWallet.id)
         await changePrimaryWallet(evmWallet.id)
       }
       ...
-      console.log('[useNetworkSwitch] Switching chain via Dynamic connector to:', targetChainId)
       await evmWallet.connector.switchNetwork({ networkChainId: targetChainId })
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (1)

57-62: Consider handling the case when the disconnected wallet is the primary wallet.

When removing a wallet via removeWallet, if that wallet is the current primary wallet, the user may be left in an inconsistent state. Consider checking if walletToDisconnect === primaryWallet?.id and handling that case (e.g., switching to another wallet first or showing additional confirmation).

   const handleWalletDisconnect = useCallback(() => {
     if (walletToDisconnect) {
+      // If disconnecting the primary wallet and other wallets exist, switch first
+      const otherWallets = userWallets.filter(w => w.id !== walletToDisconnect)
+      if (walletToDisconnect === primaryWallet?.id && otherWallets.length > 0) {
+        changePrimaryWallet(otherWallets[0].id).catch(console.error)
+      }
       removeWallet(walletToDisconnect).catch(console.error)
       setWalletToDisconnect(null)
     }
-  }, [walletToDisconnect, removeWallet])
+  }, [walletToDisconnect, removeWallet, primaryWallet?.id, userWallets, changePrimaryWallet])
📜 Review details

Configuration used: CodeRabbit 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 1ca0b23 and a4768e0.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • .env.example (1 hunks)
  • .env.production (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/components/CustomConnectButton.tsx (3 hunks)
  • apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (5 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useApprovedChains.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (0 hunks)
  • apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3 hunks)
  • apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (5 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (8 hunks)
  • apps/agentic-chat/src/hooks/useWalletConnection.ts (1 hunks)
  • apps/agentic-chat/src/lib/appkit.ts (0 hunks)
  • apps/agentic-chat/src/lib/chains.ts (1 hunks)
  • apps/agentic-chat/src/lib/networks.ts (0 hunks)
  • apps/agentic-chat/src/lib/solana-config.ts (0 hunks)
  • apps/agentic-chat/src/lib/wagmi-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/walletUtils.ts (1 hunks)
  • apps/agentic-chat/src/types/appkit.d.ts (0 hunks)
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/types.ts (1 hunks)
  • apps/agentic-chat/src/utils/sendExecutor.ts (2 hunks)
  • apps/agentic-chat/src/utils/sendTransaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/swapExecutor.ts (2 hunks)
  • apps/agentic-chat/vite.config.mjs (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (5)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts
  • apps/agentic-chat/src/lib/appkit.ts
  • apps/agentic-chat/src/types/appkit.d.ts
  • apps/agentic-chat/src/lib/networks.ts
  • apps/agentic-chat/src/lib/solana-config.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • apps/agentic-chat/package.json
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts
  • .env.example
  • .env.production
  • apps/agentic-chat/src/lib/wagmi-config.ts
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx
  • apps/agentic-chat/src/components/tools/SendUI.tsx
  • package.json
  • apps/agentic-chat/src/utils/sendTransaction.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-16T20:28:23.547Z
Learnt from: premiumjibles
Repo: shapeshift/agentic-chat PR: 68
File: apps/agentic-server/package.json:26-26
Timestamp: 2025-09-16T20:28:23.547Z
Learning: In the ShapeShift agentic-chat codebase, mathjs optimization (lazy-loading or using modular sub-packages) has been noted for future implementation rather than immediate action.

Applied to files:

  • apps/agentic-chat/src/hooks/useApprovedChains.ts
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/hooks/useSendExecution.ts
🧬 Code graph analysis (10)
apps/agentic-chat/src/utils/chains/types.ts (2)
apps/agentic-chat/src/types/transaction.ts (1)
  • Transaction (1-10)
packages/caip/src/constants.ts (1)
  • ChainId (175-175)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (3)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/CopyButton.tsx (1)
  • CopyButton (15-41)
apps/agentic-chat/src/components/ui/IconButton.tsx (1)
  • IconButton (22-29)
apps/agentic-chat/src/utils/swapExecutor.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (5)
apps/agentic-chat/src/hooks/useWalletConnection.ts (3)
  • useWalletConnection (23-48)
  • filterEvmWallets (11-11)
  • filterSolanaWallets (11-11)
apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)
  • usePortfolioQuery (14-49)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/lib/walletUtils.ts (2)
  • filterEvmWallets (21-24)
  • filterSolanaWallets (26-29)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)
  • NetworkWalletRow (17-52)
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-57)
apps/agentic-chat/src/lib/chains.ts (1)
  • networkNameToChainId (103-106)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)
  • useApprovedChains (54-68)
apps/agentic-chat/src/lib/walletUtils.ts (2)
  • findEvmWallet (11-14)
  • findSolanaWallet (16-19)
apps/agentic-chat/src/app/app.tsx (2)
apps/agentic-chat/src/lib/chains.ts (1)
  • DYNAMIC_EVM_NETWORKS (110-120)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (15-19)
apps/agentic-chat/src/components/CustomConnectButton.tsx (4)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/lib/chains.ts (1)
  • SOLANA_CAIP_ID (90-90)
packages/utils/src/networkIcons.ts (1)
  • NETWORK_ICONS (14-31)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/hooks/useSendExecution.ts (5)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/utils/sendExecutor.ts (1)
  • executeSend (34-40)
apps/agentic-server/src/index.ts (1)
  • executeSend (64-64)
⏰ 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: main
🔇 Additional comments (27)
apps/agentic-chat/vite.config.mjs (1)

9-12: LGTM — standard browser polyfill for process.env.

This is a common Vite pattern to prevent runtime errors from libraries that reference process.env. Since Vite uses import.meta.env for environment variables, this empty object shim is appropriate.

apps/agentic-chat/src/utils/swapExecutor.ts (1)

4-4: LGTM — clean migration to signer-based API.

The rename from solanaProvider to solanaSigner and the corresponding type change align with the Dynamic Labs signer pattern. The SolanaWalletSigner interface correctly exposes only the signTransaction method needed for this use case.

Also applies to: 10-13, 28-28

apps/agentic-chat/src/utils/sendExecutor.ts (1)

4-4: LGTM — consistent with the signer migration in swapExecutor.ts.

The changes mirror the swap executor updates. Both files now use the same SolanaWalletSigner type and solanaSigner naming convention.

Also applies to: 10-12, 28-28

apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

17-50: LGTM — cleaner unified row design.

The simplified clickable row approach with proper stopPropagation on child actions is a good pattern. The isActive badge provides clear visual feedback.

apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1)

18-24: Behavior change: portfolio now fetches only the primary wallet's chain.

With this logic, if a user has both EVM and Solana wallets connected but the primary is EVM, only the EVM portfolio is fetched. Previously, both addresses may have been passed. Verify this is the intended UX.

apps/agentic-chat/src/components/CustomConnectButton.tsx (2)

44-49: Network icon lookup may return undefined for unrecognized chains.

If caipChainId doesn't exist in NETWORK_ICONS, networkIcon will be undefined. The UI handles this gracefully (conditional render on line 63), but users on unsupported chains won't see a network indicator. This is acceptable behavior, but worth noting for awareness.


17-35: Wallet connection flow and address derivation look correct.

The migration to setShowAuthFlow(true) for triggering the connection modal and the address fallback chain (primaryWallet?.address → evmAddress → solanaAddress) properly handles both EVM and Solana wallet scenarios.

apps/agentic-chat/src/utils/chains/types.ts (2)

6-13: Type definitions are well-structured.

The SolanaWalletSigner interface correctly uses a generic constraint to preserve the input transaction type through signing. The backward compatibility alias SolanaWalletProvider is a thoughtful addition for gradual migration.


22-22: All usages of solanaProvider have been successfully updated to solanaSigner throughout the codebase—no remaining references detected.

apps/agentic-chat/src/hooks/useApprovedChains.ts (2)

59-61: Query key now uses stable wallet IDs - addresses previous memoization concern.

Using userWallets.map(w => w.id).join(',') in the query key ensures the query only re-runs when wallet identities actually change, not on every render. This properly addresses the referential stability concern from the prior review.


17-32: Error handling in getApprovedChainsForWallet is appropriate.

The try-catch gracefully falls back to EVM_CAIP_IDS if getSupportedNetworks() fails, ensuring the app remains functional even if WalletConnect session queries fail.

apps/agentic-chat/src/lib/walletUtils.ts (1)

11-29: Utility functions are correctly implemented with proper type predicates.

The eslint-disable comments are justified—the Dynamic SDK's type variance between Wallet<any>[] and specific wallet types (explained in the file header) necessitates suppressing the unsafe-argument warning. The type predicate syntax (w): w is EthereumWallet => correctly narrows types for consumers. Both filterEvmWallets and filterSolanaWallets are actively used in PortfolioDrawer.tsx with memoization.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (3)

217-224: LGTM on Solana primary wallet switching.

The logic correctly switches to the Solana wallet when a Solana transaction is needed but the primary wallet is not Solana. The guard conditions are appropriate.


234-243: LGTM on EVM wallet and network switching.

The implementation correctly validates the EVM wallet presence, switches the primary wallet if needed, and uses Dynamic's connector API for network switching.


278-280: LGTM on public client configuration.

The getPublicClient call correctly passes the chainId configuration to get the appropriate chain-specific client.

apps/agentic-chat/src/lib/chains.ts (2)

15-88: LGTM on centralized chain configuration.

The SUPPORTED_EVM_CHAINS array provides a clean, single source of truth for chain configurations. Using viem's chain definitions ensures consistency with the ecosystem.


110-120: LGTM on Dynamic EVM networks transformation.

The DYNAMIC_EVM_NETWORKS array correctly transforms the chain configurations into the EvmNetwork format expected by Dynamic Labs SDK.

apps/agentic-chat/src/hooks/useWalletConnection.ts (2)

23-47: LGTM on wallet connection hook.

The hook provides a clean abstraction over Dynamic Labs wallet state, correctly prioritizing the primary wallet and falling back to any connected wallet of the appropriate type. The return type is well-defined with all necessary fields for downstream consumers.


11-11: Good pattern: Re-exporting wallet utilities.

Re-exporting filterEvmWallets, filterSolanaWallets, findEvmWallet, and findSolanaWallet from this hook module provides a convenient single import point for wallet-related functionality.

apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (3)

43-55: LGTM on disconnect handler with proper cleanup.

The handleDisconnect function correctly invalidates relevant query caches before logging out, ensuring stale data isn't displayed after reconnection.


99-154: LGTM on wallet dropdown with grouped wallets.

The implementation correctly groups EVM and Solana wallets, displays appropriate labels, and handles primary wallet switching with proper guards. The UI provides clear visual feedback for the active wallet.


216-227: LGTM on per-wallet disconnect confirmation dialog.

The implementation follows the same AlertDialog pattern as the main disconnect dialog, providing consistent UX. The onOpenChange handler correctly clears the walletToDisconnect state when the dialog is dismissed.

apps/agentic-chat/src/hooks/useSendExecution.ts (5)

1-3: LGTM! Imports correctly updated for Dynamic Labs migration.

The Dynamic Labs SDK imports (isEthereumWallet, isSolanaWallet, useDynamicContext, useSwitchWallet) are appropriate for the new wallet management approach.


136-140: LGTM! Hook usage correctly migrated to Dynamic Labs context.

The destructuring of solanaWallet and evmWallet from useWalletConnection, along with primaryWallet and changePrimaryWallet from Dynamic Labs hooks, properly supports the new multi-wallet management approach.


205-207: Good error handling for missing EVM wallet.

The explicit check for evmWallet existence with a clear error message prevents runtime failures and provides actionable feedback to users.


209-214: Primary wallet alignment logic mirrors Solana approach.

The code aligns the primary wallet to evmWallet before switching networks, similar to the Solana path. The same verification concerns apply here—ensure changePrimaryWallet() completes successfully before switchNetwork() is called.


187-194: The code is sound. The changePrimaryWallet() call at line 193 is properly awaited, ensuring it completes before the subsequent setState call marks the step complete. Any errors from changePrimaryWallet will be caught by the outer try-catch block (lines 161-242), which persists the error state and tracks the failed step. No race conditions or timing issues exist with this implementation.

Comment on lines 22 to 23
rpcUrl: 'https://eth.llamarpc.com',
vanityName: 'Ethereum',
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

llamarpc rate limits and reliability for production

💡 Result:

Short answer: llama.cpp's RPC (rpc-server / llama-server) has no built‑in API rate‑limiting and is still effectively “experimental” for heavy production use — it can work in production if you design around its limits, but you must expect throughput/latency penalties, memory/transfer failure modes, and operational fragility unless you thoroughly test and harden the setup. [1][2][3][4]

Key points (concise):

  • Rate limits: none provided by the RPC layer — you must enforce request throttling, queues, or concurrency limits at your own API/gateway layer. [1][2]
  • Reliability: documented as proof‑of‑concept/fragile; maintainers and users report crashes when RPC servers are overloaded or when model offload exceeds available RAM, and there are known performance/throughput regressions vs single‑node runs. Test for token throughput, memory pressure, and edge cases. [1][3][4]
  • Network & performance: RPC transfers can be heavy (substantial bytes/token) and introduce significant latency and lower GPU utilization in multi‑node splits — network bandwidth and latency strongly affect token/sec. Monitor per‑token traffic and colocate when possible. [5][4]
  • Security: RPC was explicitly warned as insecure if exposed to open networks; always run behind private networks, firewalls, or VPNs. [1]

Practical recommendations for production:

  • Put a fronting API/gateway (NGINX, Envoy, FastAPI, Kong) to enforce rate limits, concurrency, auth, and circuit breakers. (No built‑in RPC rate limiting.) [1]
  • Capacity test with your exact model, tensor‑split, batch sizes, and network topology; measure tokens/sec, p95 latency, and bytes/token. Use these results to size nodes and set autoscaling thresholds. [3][4][5]
  • Avoid overcommitting RPC server RAM; leave headroom and enable caching where supported. Watch for model‑load crashes when >~75% of server RAM is used (reported). [3]
  • Co‑locate high‑traffic offload servers on the same high‑bandwidth network or use 10Gb+ links; prefer local GPU where feasible to reduce RPC overhead. [4][5]
  • Add health checks, rolling restarts, request timeouts and retries, exponential backoff, and throttling to protect RPC backends from bursts. [1][3]
  • Consider alternatives for critical production: single‑node large‑GPU instances, commercial hosted inference (with SLA/rate limits), or proven multi‑node orchestration layers (that include rate limiting, autoscaling, and monitoring).

Sources:

  • llama.cpp RPC example / README (notes that RPC is experimental, insecure, and intended as proof‑of‑concept). [1]
  • llama.cpp docs / server build & RPC usage references. [2]
  • GitHub issues reporting crashes when offloading large models / memory overcommit. [3]
  • GitHub issue and community reports about GPU utilization and RPC throughput penalties. [4]
  • Community performance reports (per‑token network traffic, Reddit threads) highlighting high bytes/token and practical latency/throughput impacts. [5]

If you want, I can: run a short checklist tailored to your model (size, batch, token rate target, network) and produce concrete capacity numbers and a recommended fronting‑gateway config.


🏁 Script executed:

# Check the full context of the file to understand usage
head -50 apps/agentic-chat/src/lib/chains.ts

Repository: shapeshift/agentic-chat

Length of output: 1564


🏁 Script executed:

# Search for all RPC URL references in the file
rg -n "rpcUrl|https://" apps/agentic-chat/src/lib/chains.ts -A 2 -B 2

Repository: shapeshift/agentic-chat

Length of output: 2480


🏁 Script executed:

# Check if there's any environment variable configuration for RPC URLs
rg -r "process.env|import.*env|\.env" apps/agentic-chat/src/lib/chains.ts

Repository: shapeshift/agentic-chat

Length of output: 49


🌐 Web query:

Ethereum public RPC endpoints rate limits reliability llamarpc

💡 Result:

Short answer

  • eth.llamarpc.com is a widely-used free public Ethereum RPC used by many projects and tools and generally measures fast in independent latency tests, but LlamaRPC does not publish a formal public SLA or clear global per-IP public rate-limit page like some paid providers. [1][2][3]
  • Public RPC endpoints (Cloudflare, PublicNode, Ankr, GetBlock, etc.) each impose different limits (RPS, daily caps, per-method weights) and throttling behaviors; free endpoints are shared resources and can return 429s or intermittent errors under load. Expect modest free-tier limits (tens to a few hundred RPS or method-weighted "credits") or per-IP/day caps depending on provider. Examples: Cloudflare/publicnode entries in public lists and docs. [4][5]
  • Practical guidance: do not rely on a single public endpoint for production—use multiple endpoints + client-side rate limiting, batching, caching, exponential backoff, and (for high-volume/critical apps) a paid RPC provider or self-hosted node for guaranteed throughput. [6][2]

Notes and sources

  • eth.llamarpc.com listed among public RPCs and measured fast in independent comparisons. [2][3]
  • Public RPC catalogs and provider docs summarizing many endpoints and typical rate‑limit patterns (per-second / daily caps / method weights). See aggregated lists and examples. [4][5]
  • Best-practices (multiple endpoints, rate-limiting, backoff, paid plans or own node) referenced in tooling/docs that use eth.llamarpc.com as an endpoint and in RPC-provider docs. [6][2]

Sources

  1. urlscan record / domain metadata for llamarpc.com. [turn2search6]
  2. Chain‑List / public RPC index showing eth.llamarpc.com as an Ethereum mainnet endpoint. [turn0search8]
  3. Independent node-performance comparison showing LlamaRPC latency vs competitors. [turn1search6]
  4. Aggregated public RPC lists (CompareNodes / Chain‑List) and catalogs of public endpoints and notes about availability. [turn0search7][turn0search8]
  5. Examples of provider rate‑limit docs and policies (sample provider pages showing RPS/day or credit systems). [turn0search0][turn0search4]
  6. Tooling/docs recommending multiple endpoints and rate‑limit handling (Ponder, projects that include eth.llamarpc.com as an example). [turn1search0][turn1search2]

If you want, I can:

  • check LlamaRPC for any updated public rate‑limit or status pages right now, or
  • produce a short code snippet showing how to implement multi‑endpoint failover + exponential backoff for ethers/viem.

🌐 Web query:

public RPC endpoints production ethereum rate limiting best practices

💡 Result:

Short checklist — production public Ethereum RPC endpoints rate-limiting best practices:

  • Define limits & quotas per identity: enforce per-API-key and per-IP quotas (short window + burst allowance). [2][3]
  • Use a token‑bucket or sliding‑window algorithm server-side; expose X-RateLimit-Limit / -Remaining / -Reset headers and return 429 on exceed. [1][3]
  • Limit JSON-RPC batch size and expensive methods (set max batch length and per-method cost). [1][3]
  • Client-side throttling: implement a local rate limiter that respects estimated cost units (CU) to avoid 429s. [4]
  • Backoff & retry: require exponential backoff + jitter on 429/5xx; respect any server backoff_seconds field. [3][2]
  • Caching & aggregation: cache frequently-read data, use block-tag caching, and combine requests (batch, multicall) when possible. [5][2]
  • Circuit breaker & health checks: stop routing to failing providers, do health probes, and rotate/blacklist degraded nodes. [5][8]
  • Multi-provider & load‑balance: spread traffic across providers/regions to smooth spikes and reduce single‑point overload. [5][8]
  • Monitoring, alerts & metrics: track RPS, 429 rate, latency, error rates, per-key usage and queue depth; alert before limits hit. [2][5]
  • Security controls: require authentication for higher quotas, IP/referrer whitelists for client keys, and rotate keys. [4][3]
  • Provide developer guidance: publish per-method costs, recommended client limits, and escalation path for quota increases. [2][1]

If you want, I can produce a recommended server-side config (token-bucket params, header formats, sample 429 body) or sample client limiter code (Node/Go).


🏁 Script executed:

# Check for environment configuration or dotenv files
fd -e ".env*" -e "config" apps/agentic-chat/ | head -20

Repository: shapeshift/agentic-chat

Length of output: 444


🏁 Script executed:

# Check if rpcUrl is configurable or used elsewhere in the codebase
rg -r "CHAIN|RPC_URL|process.env" apps/agentic-chat/ --type ts --type js | head -30

Repository: shapeshift/agentic-chat

Length of output: 222


Use environment-configurable RPC URLs and implement fallback/rate-limit handling for production.

Public RPC endpoints (llamarpc, polygon-rpc.com, etc.) enforce rate limits and lack formal SLAs—eth.llamarpc.com specifically does not publish clear per-IP limits. Hardcoding a single RPC per chain risks outages and 429 errors under load. For production, make RPC URLs environment-configurable, implement multi-endpoint failover, add client-side rate limiting and exponential backoff, and consider paid RPC providers for critical operations.

🤖 Prompt for AI Agents
In apps/agentic-chat/src/lib/chains.ts around lines 22-23, the RPC URL is
hardcoded to a public endpoint which risks rate limits and outages; change the
chain RPC configuration to read a prioritized list of RPC endpoints from
environment variables (with sensible defaults to the current URL), implement
client-side multi-endpoint failover (try next endpoint on network error/429),
add a simple rate limiter and exponential backoff/retry strategy for transient
429/5xx responses, and make provider selection/configurable (env var for
provider priority or paid provider URL) so production can override defaults and
avoid single-endpoint failures.

Copy link

@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 (8)
apps/agentic-chat/src/lib/chains.ts (2)

15-88: Consider env‑configurable RPC URLs and optional multi‑endpoint strategy for production

Hardcoding single public RPC URLs (e.g., https://eth.llamarpc.com, https://polygon-rpc.com) is convenient for dev but brittle in production due to rate limits and lack of SLAs. Consider:

  • Reading RPC URLs from environment variables with these as defaults, and
  • (Optionally) supporting multiple RPC URLs per chain plus simple client‑side failover/backoff in your networking layer.

This keeps ChainConfig as the central source of truth while making production setups more resilient.


103-106: solana: 0 sentinel in networkNameToChainId is easy to misuse

Mapping solana to 0 makes any if (!targetChainId) checks treat Solana as “missing”, which is already causing issues in useNetworkSwitch. Either avoid giving Solana a numeric chainId here (and handle it by name elsewhere), or ensure all consumers use an explicit undefined check (targetChainId === undefined) rather than falsy checks.

apps/agentic-chat/src/hooks/useNetworkSwitch.ts (1)

101-121: Bug: Solana network switch path is unreachable due to falsy chainId check

networkNameToChainId['solana'] is 0, so for data.network === 'solana' the if (!targetChainId) block runs first and returns an error before the Solana‑specific branch. As a result, Solana “switches” always fail.

Reorder the Solana handling and make the missing‑network check explicit:

-    const targetChainId = networkNameToChainId[data.network]
-
-    if (!targetChainId) {
+    // Solana doesn't require an EVM network switch, only primary wallet alignment.
+    if (data.network === 'solana') {
+      if (solanaWallet && primaryWallet && !isSolanaWallet(primaryWallet)) {
+        await changePrimaryWallet(solanaWallet.id)
+      }
+
+      setState(draft => {
+        draft.phase = 'success'
+      })
+      persistState({ phase: 'success' })
+      return
+    }
+
+    const targetChainId = networkNameToChainId[data.network]
+
+    if (targetChainId === undefined) {
       const errorState: NetworkSwitchState = { phase: 'error', error: `Network "${data.network}" not found` }
       setState(draft => {
         draft.phase = errorState.phase
         draft.error = errorState.error
       })
       persistState(errorState)
       return
     }
-
-    // Solana doesn't need network switching in the same way, but we might need to switch primary wallet
-    if (data.network === 'solana') {
-      if (solanaWallet && primaryWallet && !isSolanaWallet(primaryWallet)) {
-        await changePrimaryWallet(solanaWallet.id)
-      }
-
-      setState(draft => {
-        draft.phase = 'success'
-      })
-      persistState({ phase: 'success' })
-      return
-    }

This ensures Solana uses the dedicated path and only true “unknown” networks are rejected.

apps/agentic-chat/src/hooks/usePortfolioQuery.ts (2)

19-24: Stale closure in queryFn still present.

As noted in the previous review, evmAddress and solanaAddress are captured in the queryFn closure but aren't included in queryKey. While this is unlikely to cause issues in practice (wallet type changes typically change the address too), it's technically incorrect and could cause stale fetches in multi-wallet scenarios.

The previous review's suggestion to add these to the queryKey or recompute them inline remains valid.


24-24: Consider adding explicit Dynamic SDK state checks.

As noted in the previous review, the query relies on the implicit !!address guard, but doesn't check Dynamic SDK-specific state flags like isLoggedIn or loadingNetwork. While the current implementation works, adding explicit SDK state checks would make the intent clearer and align better with Dynamic Labs' documented patterns.

apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1)

34-36: Accessibility issue persists: role="button" requires keyboard activation handlers.

As noted in the previous review, the wrapper has role="button" and tabIndex={0} but only stops propagation on keydown without handling Enter/Space to trigger the action. Since CopyButton already handles stopPropagation internally, this wrapper may be unnecessary.

The previous review's suggestion to remove the wrapper or add proper keyboard activation handlers remains valid.

apps/agentic-chat/src/lib/wagmi-config.ts (1)

10-13: Custom RPC URLs from chain config are still not being used.

As noted in the previous review, SUPPORTED_EVM_CHAINS defines custom rpcUrl values (e.g., https://eth.llamarpc.com), but the transports use bare http() which falls back to viem's default public RPCs. This may cause rate limiting or reliability issues.

The previous review's suggestion to pass the custom RPC URLs to http() remains valid.

apps/agentic-chat/src/hooks/useSendExecution.ts (1)

224-228: Use Dynamic Labs SDK's ISolanaSigner type instead of local SolanaWalletSigner.

As noted in the previous review, the code uses the local SolanaWalletSigner type, but Dynamic Labs SDK's getSigner() method returns ISolanaSigner. The previous review's suggestion to import and use ISolanaSigner from @dynamic-labs/solana-core remains valid.

🧹 Nitpick comments (2)
apps/agentic-chat/package.json (1)

16-21: Confirm Dynamic package versions and peer-dependency compatibility

All @dynamic-labs/* packages are aligned on ^4.49.0, which is good. Please double‑check against Dynamic’s docs that this version range is compatible with your current wagmi, viem, and React versions and that any required peer deps are satisfied, especially in production builds.

If anything is off, I can help suggest a compatible version matrix.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

213-217: Use Dynamic Labs SDK's ISolanaSigner type instead of local SolanaWalletSigner.

Similar to the issue in useSendExecution.ts, this code uses the local SolanaWalletSigner type, but Dynamic Labs SDK's getSigner() method returns ISolanaSigner. While structurally compatible, using the actual SDK type provides better type safety and documentation.

+import type { ISolanaSigner } from '@dynamic-labs/solana-core'
 
-import type { SolanaWalletSigner } from '@/utils/chains/types'
+import type { SolanaWalletSigner as LocalSolanaWalletSigner } from '@/utils/chains/types'
 
-      let solanaSigner: SolanaWalletSigner | undefined
+      let solanaSigner: ISolanaSigner | undefined
       if (chainNamespace === CHAIN_NAMESPACE.Solana && solanaWallet) {
         solanaSigner = await solanaWallet.getSigner()
       }
📜 Review details

Configuration used: CodeRabbit 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 a4768e0 and d4dc7e6.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • .env.example (1 hunks)
  • .env.production (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/components/CustomConnectButton.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx (5 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useApprovedChains.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts (0 hunks)
  • apps/agentic-chat/src/hooks/useNetworkSwitch.ts (4 hunks)
  • apps/agentic-chat/src/hooks/usePortfolioQuery.ts (1 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (5 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (12 hunks)
  • apps/agentic-chat/src/hooks/useWalletConnection.ts (1 hunks)
  • apps/agentic-chat/src/lib/appkit.ts (0 hunks)
  • apps/agentic-chat/src/lib/chains.ts (1 hunks)
  • apps/agentic-chat/src/lib/networks.ts (0 hunks)
  • apps/agentic-chat/src/lib/solana-config.ts (0 hunks)
  • apps/agentic-chat/src/lib/wagmi-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/walletUtils.ts (1 hunks)
  • apps/agentic-chat/src/types/appkit.d.ts (0 hunks)
  • apps/agentic-chat/src/utils/chains/evm/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/chains/types.ts (1 hunks)
  • apps/agentic-chat/src/utils/sendExecutor.ts (2 hunks)
  • apps/agentic-chat/src/utils/sendTransaction.ts (2 hunks)
  • apps/agentic-chat/src/utils/swapExecutor.ts (2 hunks)
  • apps/agentic-chat/vite.config.mjs (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (5)
  • apps/agentic-chat/src/types/appkit.d.ts
  • apps/agentic-chat/src/lib/networks.ts
  • apps/agentic-chat/src/hooks/useAutoNetworkSwitch.ts
  • apps/agentic-chat/src/lib/appkit.ts
  • apps/agentic-chat/src/lib/solana-config.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • apps/agentic-chat/src/components/tools/SendUI.tsx
  • .env.production
  • apps/agentic-chat/src/utils/sendTransaction.ts
  • apps/agentic-chat/src/lib/walletUtils.ts
  • package.json
  • apps/agentic-chat/src/utils/chains/solana/transaction.ts
  • .env.example
  • apps/agentic-chat/src/components/Portfolio/PortfolioDrawer.tsx
  • apps/agentic-chat/src/hooks/useApprovedChains.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/hooks/useSendExecution.ts
🧬 Code graph analysis (10)
apps/agentic-chat/src/utils/swapExecutor.ts (3)
apps/agentic-server/src/lib/schemas/swapSchemas.ts (2)
  • SwapData (77-77)
  • TransactionData (75-75)
apps/agentic-server/src/tools/initiateSwap.ts (1)
  • InitiateSwapOutput (277-277)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/utils/sendExecutor.ts (1)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
apps/agentic-chat/src/components/CustomConnectButton.tsx (4)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/lib/chains.ts (1)
  • SOLANA_CAIP_ID (90-90)
packages/utils/src/networkIcons.ts (1)
  • NETWORK_ICONS (14-31)
apps/agentic-chat/src/components/ui/Button.tsx (1)
  • Button (55-55)
apps/agentic-chat/src/utils/chains/types.ts (1)
packages/caip/src/constants.ts (1)
  • ChainId (175-175)
apps/agentic-chat/src/hooks/useWalletConnection.ts (2)
apps/agentic-chat/src/hooks/useApprovedChains.ts (1)
  • useApprovedChains (31-57)
apps/agentic-chat/src/lib/walletUtils.ts (2)
  • findEvmWallet (11-14)
  • findSolanaWallet (16-19)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
apps/agentic-chat/src/lib/chains.ts (2)
  • SUPPORTED_EVM_CHAINS (15-88)
  • SUPPORTED_CHAIN_IDS (94-97)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/utils/chains/types.ts (1)
  • SolanaWalletSigner (8-10)
packages/caip/src/constants.ts (1)
  • CHAIN_NAMESPACE (46-54)
apps/agentic-chat/src/app/app.tsx (2)
apps/agentic-chat/src/lib/chains.ts (1)
  • DYNAMIC_EVM_NETWORKS (110-120)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (15-19)
apps/agentic-chat/src/hooks/useNetworkSwitch.ts (3)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-57)
apps/agentic-chat/src/lib/chains.ts (1)
  • networkNameToChainId (103-106)
apps/agentic-chat/src/components/Portfolio/NetworkWalletRow.tsx (3)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/CopyButton.tsx (1)
  • CopyButton (15-41)
apps/agentic-chat/src/components/ui/IconButton.tsx (1)
  • IconButton (22-29)
⏰ 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: main
🔇 Additional comments (6)
apps/agentic-chat/vite.config.mjs (1)

11-11: No action needed. Setting 'process.env': {} in the Vite define config is a standard practice to prevent undefined reference errors in the browser bundle. A search of the codebase found no remaining process.env usages, confirming the migration to import.meta.env is complete or was never applicable for the browser code.

apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1)

19-19: Using swapData.sellAccount for “Received from” looks correct

Deriving address from swapOutput.swapData.sellAccount keeps the header tied to the actual swap source account (including for historical runs) instead of the current wallet hook. This is consistent with the rest of the component’s use of swapOutput and is a safe change.

apps/agentic-chat/src/utils/chains/types.ts (1)

6-23: Signer-based Solana typing and legacy alias look sound

The SolanaWalletSigner interface with signTransaction<T extends Transaction | VersionedTransaction> matches common wallet signer contracts, and the SolanaWalletProvider alias preserves backward compatibility. Updating TransactionParams to solanaSigner?: SolanaWalletSigner keeps the call sites structurally aligned with the new signer model.

apps/agentic-chat/src/utils/swapExecutor.ts (1)

4-13: Swap executor wiring to SolanaWalletSigner is consistent

Threading solanaSigner?: SolanaWalletSigner through ExecuteTransactionOptions and into finalTx aligns with the updated TransactionParams type and keeps the EVM path unchanged. Approval and swap both correctly reuse the shared executeTransaction.

Also applies to: 28-29

apps/agentic-chat/src/utils/sendExecutor.ts (1)

4-12: Send executor’s Solana signer integration matches the shared transaction shape

Using solanaSigner?: SolanaWalletSigner in ExecuteTransactionOptions and conditionally spreading it into finalTx is consistent with the new shared TransactionParams contract and mirrors the swap executor path, so both EVM and Solana sends route through the same abstraction cleanly.

Also applies to: 28-29

apps/agentic-chat/src/utils/chains/evm/transaction.ts (1)

23-28: Chain resolution via chainIdToChain and explicit unsupported‑chain error look good

Looking up the chain with chainIdToChain[chainId] and throwing on missing entries makes unsupported chains fail fast, while keeping the rest of the transaction construction (getAddress, Hex cast, optional gas) intact. This centralizes chain metadata behind your new lib/chains module without changing the external sendEvmTransaction API.

Also applies to: 33-46

@premiumjibles premiumjibles merged commit 9fd2ec8 into main Dec 11, 2025
4 checks passed
@premiumjibles premiumjibles deleted the dynamic-migration branch December 11, 2025 23:13
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