Skip to content

Conversation

@NeOMakinG
Copy link
Collaborator

@NeOMakinG NeOMakinG commented Jan 27, 2026

Description

Review me with shapeshift/hdwallet#786 and shapeshift/mobile-app#161

Integrates Seeker mobile wallet vault support into ShapeShift Web, enabling users to connect their Seeker mobile wallet vaults (.skr files) directly to the web application. Seeker is a Solana-focused mobile wallet that uses the Solana Mobile Wallet Adapter (MWA) protocol for secure communication between the mobile app and web interface via React Native WebView postMessage.

Key Features

  1. Hardware Wallet Section on Mobile - Added hardware wallet support section to mobile wallet connection view, making Seeker and other hardware wallets accessible on mobile devices.

  2. Direct Connection Flow - Seeker connection now launches instantly without modal navigation, providing a streamlined UX by directly invoking authorization when the user clicks the Seeker option.

  3. Vault Name Display - The wallet connection now displays the actual Seeker vault name (.skr file label) instead of the generic "Seeker" label, giving users better identification of which vault they're connecting.

  4. Platform Abstraction - Implemented message handler interface that abstracts Solana Mobile Wallet Adapter protocol behind a clean API, allowing the HDWallet adapter to work independently of the web environment.

Implementation Details

  • Added @shapeshiftoss/hdwallet-seeker package dependency
  • Integrated Seeker into hardware wallet list with proper icon and availability detection
  • Implemented direct authorization flow in HardwareWalletsSection.tsx
  • Updated wallet types to include SeekerHDWallet in adapter type mappings
  • Made hardware wallet section visible on mobile devices

Issue (if applicable)

N/A - New feature integration

Risk

Medium - Introduces new wallet provider integration

High Risk PRs Require 2 approvals

This PR adds a new wallet connection method and introduces dependencies on the React Native WebView communication layer. While isolated to the Seeker wallet flow, it touches wallet provider infrastructure.

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

Seeker wallet connection and Solana transaction signing via Solana Mobile Wallet Adapter (MWA) protocol.

Testing

Engineering

  • Connect Seeker wallet on mobile device (requires Seeker mobile app with .skr vault)
  • Verify wallet displays vault name instead of generic "Seeker"
  • Verify connection completes without modal navigation
  • Verify hardware wallet section appears on mobile
  • Test Solana transaction signing with connected Seeker wallet
  • Verify wallet disconnection and reconnection flows
  • Test with multiple vaults if available

Operations

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

Note: Testing requires Seeker mobile app with configured vault. Seeker availability detection will show/hide the option automatically based on WebView postMessage availability.

Screenshots (if applicable)

Quite hard to me to show my seeker as I don't have jam installed on it but:

  • Connected successfully using yarn android --device with our mobile app
  • Able to sign TXs (swaps using Relay, send solana and SPL tokens)

🤖 Generated with Claude Code

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

📝 Walkthrough

Walkthrough

This PR adds complete Seeker hardware wallet integration to the application, including npm registry configuration, wallet dependencies, UI components for connection and failure flows, message handlers for wallet communication, routing setup, and integration with the existing wallet provider infrastructure.

Changes

Cohort / File(s) Summary
npm/package configuration
.yarnrc.yml, package.json
Updated npm registry to local proxy (127.0.0.1:4873); added @shapeshiftoss/hdwallet-seeker ^1.62.42 dependency
Icon component
src/components/Icons/SeekerIcon.tsx
Added new 24x24 circular SVG icon component using Chakra UI's createIcon
Translations
src/assets/translations/en/main.json
Added walletProvider.seeker translation keys for connect (header, body, button) and failure (header, body) states
KeyManager enum
src/context/WalletProvider/KeyManager.ts
Added Seeker as new enum member with value 'seeker'
Seeker wallet module
src/context/WalletProvider/Seeker/config.ts, src/context/WalletProvider/Seeker/seekerMessageHandlers.ts, src/context/WalletProvider/Seeker/components/Connect.tsx, src/context/WalletProvider/Seeker/components/Failure.tsx
Created Seeker wallet configuration, message handler wrappers for 7 wallet operations, and connection/failure UI components with authorization flow and state management
Routing
src/context/WalletProvider/NewWalletViews/routes/SeekerRoutes.tsx
Added memoized route container for /seeker/connect and /seeker/failure paths
Integration with wallet provider
src/context/WalletProvider/HardwareWalletsSection.tsx, src/context/WalletProvider/NewWalletViews/NewWalletViewsSwitch.tsx, src/context/WalletProvider/config.ts, src/context/WalletProvider/types.ts
Integrated Seeker availability check and connection handler in HardwareWalletsSection; added SeekerRoutes to NewWalletViewsSwitch; updated SUPPORTED_WALLETS config and wallet adapter mappings; extended AdaptersByKeyManager type

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant App as App<br/>(React)
    participant Seeker as Seeker<br/>(Native)
    participant Redux as Redux<br/>Store
    participant LocalStorage as Local<br/>Storage

    User->>App: Click "Connect Seeker"
    App->>Seeker: checkSeekerAvailability()
    Seeker-->>App: availability result
    App->>App: Render SeekerConnect modal

    User->>App: Click "Pair Device"
    App->>Seeker: seekerAuthorize(cluster)
    Seeker-->>App: authorization token + deviceId
    
    App->>Seeker: Dynamically load SeekerHDWallet
    Seeker-->>App: HDWallet instance
    
    App->>App: Initialize wallet with<br/>messageHandlers
    App->>Redux: dispatch(setWallet)
    Redux-->>App: ✓ wallet set
    
    App->>Redux: dispatch(markConnected)
    Redux-->>App: ✓ connected
    
    App->>Redux: dispatch(unlock)
    Redux-->>App: ✓ unlocked
    
    App->>LocalStorage: Save deviceId & wallet type
    LocalStorage-->>App: ✓ persisted
    
    App->>App: Close modal
    App-->>User: ✓ Seeker wallet connected
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • #11012 — Adds support for a new hardware wallet provider with parallel code-level changes (package dependency, translations, KeyManager enum, types/adapters, SUPPORTED_WALLETS routes, connect/failure components)
  • #11078 — Modifies KeyManager enum to add a new wallet variant, following the same pattern as Seeker integration
  • #11135 — Modifies NewWalletViewsSwitch.tsx routing and mobile wallet view rendering, potential for overlapping changes

Suggested reviewers

  • gomesalexandre

Poem

🐰 wiggles nose with glee
Seeker arrives, and now we see—
Icons sparkle, auth flows dance,
Messages waltz their sweet romance! 💫
Redux states align just right,
Hardware wallets shine so bright! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: seeker vault compatibility' accurately reflects the main change: integrating Seeker wallet vault support as a new feature into the application.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch seeker-vault

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.

- Add Seeker wallet to hardware wallets section in mobile app
- Conditional display based on Seeker vault availability detection
- Display actual vault name (.skr) instead of generic "Seeker"
- Direct connection without modal step for seamless UX
- Add translations for Seeker wallet
- Create Seeker routes, config, and message handlers
- Integrate with @shapeshiftoss/hdwallet-seeker package
- Clean up Butter swap changes (use Relay for swapping)
- Restore original error handling and comments
- Remove temporary Seeker adapter files
- Reset verdaccio versions back to ^1.62.41

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

Co-Authored-By: Claude <noreply@anthropic.com>
npmAuthToken: "${NPM_AUTH-fallback}"

npmRegistryServer: "https://registry.npmjs.org"
npmRegistryServer: "http://127.0.0.1:4873"
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

revert me after review

@NeOMakinG NeOMakinG marked this pull request as ready for review January 28, 2026 05:41
@NeOMakinG NeOMakinG requested a review from a team as a code owner January 28, 2026 05:41
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
src/context/WalletProvider/NewWalletViews/sections/HardwareWalletsSection.tsx (1)

70-159: Guard against concurrent Seeker connects.

This async flow doesn't prevent overlapping auth attempts. Repeated taps launch concurrent authorization flows that can race wallet state updates. Add local in-flight guard with early return and disable the option while connecting.

🔧 Suggested fix
-  const [isSeekerAvailable, setIsSeekerAvailable] = useState(false)
+  const [isSeekerAvailable, setIsSeekerAvailable] = useState(false)
+  const [isSeekerConnecting, setIsSeekerConnecting] = useState(false)
@@
-  const handleConnectSeeker = useCallback(async () => {
+  const handleConnectSeeker = useCallback(async () => {
+    if (isSeekerConnecting) return
+    setIsSeekerConnecting(true)
     try {
       const { SEEKER_DEFAULT_CLUSTER } = await import('@/context/WalletProvider/Seeker/config')
@@
       dispatch({ type: WalletActions.SET_WALLET_MODAL, payload: false })
     } catch (error) {
       console.error('Error connecting to Seeker:', error)
+    } finally {
+      setIsSeekerConnecting(false)
     }
-  }, [dispatch, localWallet])
+  }, [dispatch, isSeekerConnecting, localWallet])
🤖 Fix all issues with AI agents
In @.yarnrc.yml:
- Line 5: The .yarnrc.yml currently hardcodes npmRegistryServer:
"http://127.0.0.1:4873", which breaks CI and other contributors; change this to
read from an environment-driven override with the official registry as the
default by replacing the hardcoded value for the npmRegistryServer key with an
env interpolation (e.g., use process/env variable or Yarn-compatible ${ENV_VAR}
reference) that falls back to "https://registry.yarnpkg.com" (or
"https://registry.npmjs.org") so users can override the registry via an
environment variable without forcing localhost.

In `@package.json`:
- Around line 225-226: The package `@shapeshiftoss/hdwallet-seeker`@^1.62.42
cannot be found in the public registry; either pin it to the known working
version (^1.62.41) to match the other hdwallet packages or confirm the intended
source and add the registry configuration; update package.json to replace
"@shapeshiftoss/hdwallet-seeker": "^1.62.42" with the verified version (e.g.,
"^1.62.41") or, if the newer private version is intentional, document the
private registry and add the corresponding .npmrc/registry config and a short
comment in package.json/PR explaining why this package differs.

In `@src/context/WalletProvider/Seeker/components/Connect.tsx`:
- Around line 37-78: The auth-failure throw is hiding the translation set by
setErrorLoading and the catch types are overly broad; after calling
seekerAuthorize and detecting !authResult.success || !authResult.address, return
early (do not throw) so the existing
setErrorLoading('walletProvider.errors.walletNotFound') is preserved; in the
try/catch change the catch signature to catch (e: unknown) and when handling the
error use a safe extraction (e.g. inspect e for message or fallback) and
setErrorLoading('walletProvider.errors.walletNotFound') as the fallback
translation key, while still logging the raw error object (console.error) and
then navigate('/seeker/failure').

In `@src/context/WalletProvider/Seeker/components/Failure.tsx`:
- Around line 1-15: The SeekerFailure component lacks an explicit TypeScript
return type; update the declaration of SeekerFailure to include a return type
(e.g., annotate SeekerFailure as (): JSX.Element or : React.ReactElement) so the
function signature is explicit, leaving the implementation using ModalHeader and
ModalBody unchanged (reference symbol: SeekerFailure).

In `@src/context/WalletProvider/Seeker/config.ts`:
- Around line 1-12: SeekerConfig currently types SeekerConfigType as
Omit<SupportedWalletInfo<any>, 'routes'> which uses any; change it to use the
concrete SeekerHDWallet type to match other configs by replacing any with typeof
SeekerHDWallet (i.e., make SeekerConfigType = Omit<SupportedWalletInfo<typeof
SeekerHDWallet>, 'routes'>), and ensure the dynamic import in SeekerConfig’s
loadAdapter still returns SeekerHDWallet so the types line up with
SupportedWalletInfo and the central registry.

In `@src/context/WalletProvider/Seeker/seekerMessageHandlers.ts`:
- Around line 10-18: Replace all uses of `any` in the message contract types by
`unknown` (e.g., change type Message { cmd: string; [key: string]: any } to use
unknown for payloads and change MessageFromMobileApp.result: any to result:
unknown); then update the code path in `postMessage` to perform explicit runtime
narrowing/type-guarding before resolving or using fields (validate `cmd`, `id`,
and the shape of `result`, use type predicates or runtime checks and only cast
after validation). Ensure `Message`, `MessageFromMobileApp`, and `postMessage`
are updated consistently so no `any` leaks into the public API.

npmAuthToken: "${NPM_AUTH-fallback}"

npmRegistryServer: "https://registry.npmjs.org"
npmRegistryServer: "http://127.0.0.1:4873"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid hardcoding a localhost npm registry.

Pointing to 127.0.0.1:4873 will break installs in CI and for contributors without a local registry. Prefer an env-driven override with the official registry as the default.

🛠️ Proposed fix
-npmRegistryServer: "http://127.0.0.1:4873"
+npmRegistryServer: "${NPM_REGISTRY_SERVER:-https://registry.npmjs.org}"
📝 Committable suggestion

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

Suggested change
npmRegistryServer: "http://127.0.0.1:4873"
npmRegistryServer: "${NPM_REGISTRY_SERVER:-https://registry.npmjs.org}"
🤖 Prompt for AI Agents
In @.yarnrc.yml at line 5, The .yarnrc.yml currently hardcodes
npmRegistryServer: "http://127.0.0.1:4873", which breaks CI and other
contributors; change this to read from an environment-driven override with the
official registry as the default by replacing the hardcoded value for the
npmRegistryServer key with an env interpolation (e.g., use process/env variable
or Yarn-compatible ${ENV_VAR} reference) that falls back to
"https://registry.yarnpkg.com" (or "https://registry.npmjs.org") so users can
override the registry via an environment variable without forcing localhost.

Comment on lines +225 to +226
"wouter": "^3.6.0",
"@shapeshiftoss/hdwallet-seeker": "^1.62.42"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for all hdwallet packages in package.json to see their versions
rg "@shapeshiftoss/hdwallet" --type json -A 0 -B 0

Repository: shapeshift/web

Length of output: 1573


🌐 Web query:

@shapeshiftoss/hdwallet-seeker npm registry version 1.62.42

💡 Result:

I couldn’t find any public npm registry listing for @shapeshiftoss/hdwallet-seeker (and therefore no evidence that version 1.62.42 exists/published). The ShapeShift maintainer profile that lists many @shapeshiftoss/hdwallet-* packages does not show hdwallet-seeker. [1]

If you have access to the registry you expect it on (public npm vs a private/proxy registry), the fastest verification is:

npm view `@shapeshiftoss/hdwallet-seeker` versions --json
# or (for that exact version)
npm view `@shapeshiftoss/hdwallet-seeker`@1.62.42 version

Source(s):
[1] (npmjs.com)

Citations:


@shapeshiftoss/hdwallet-seeker@1.62.42 cannot be verified in the public npm registry—this package may not exist or may require a private registry configuration.

All 18 other hdwallet packages are pinned to ^1.62.41, but this new dependency is at ^1.62.42. The web search found no public npm listing for @shapeshiftoss/hdwallet-seeker, and the version cannot be verified. Either this package is in a private registry (which requires configuration), it's a typo, or the version doesn't exist. Clarify the package source and ensure yarn install will succeed. If this is intentional, confirm it exists and explain why it differs from the rest of the hdwallet suite.

🤖 Prompt for AI Agents
In `@package.json` around lines 225 - 226, The package
`@shapeshiftoss/hdwallet-seeker`@^1.62.42 cannot be found in the public registry;
either pin it to the known working version (^1.62.41) to match the other
hdwallet packages or confirm the intended source and add the registry
configuration; update package.json to replace "@shapeshiftoss/hdwallet-seeker":
"^1.62.42" with the verified version (e.g., "^1.62.41") or, if the newer private
version is intentional, document the private registry and add the corresponding
.npmrc/registry config and a short comment in package.json/PR explaining why
this package differs.

Comment on lines +37 to +78
try {
const authResult = await seekerAuthorize(SEEKER_DEFAULT_CLUSTER)

if (!authResult.success || !authResult.address) {
setErrorLoading('walletProvider.errors.walletNotFound')
throw new Error('Seeker authorization failed or returned no address')
}

const { SeekerHDWallet } = await import('@shapeshiftoss/hdwallet-seeker')

const messageHandler = {
checkAvailability: checkSeekerAvailability,
authorize: seekerAuthorize,
deauthorize: seekerDeauthorize,
getAddress: seekerGetAddress,
getStatus: seekerGetStatus,
signTransaction: seekerSignTransaction,
signAndSendTransaction: seekerSignAndSendTransaction,
}

const deviceId = `seeker-${Date.now()}`
const wallet = new SeekerHDWallet(deviceId, authResult.address, messageHandler)

const { icon } = SeekerConfig
const name = authResult.label || SeekerConfig.name
await wallet.initialize()

dispatch({
type: WalletActions.SET_WALLET,
payload: { wallet, name, icon, deviceId, connectedType: KeyManager.Seeker },
})
dispatch({
type: WalletActions.SET_IS_CONNECTED,
payload: true,
})
dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false })
localWallet.setLocalWallet({ type: KeyManager.Seeker, deviceId })
dispatch({ type: WalletActions.SET_WALLET_MODAL, payload: false })
} catch (e: any) {
console.error(e, 'Seeker Connect: There was an error initializing the wallet')
setErrorLoading(e.message)
navigate('/seeker/failure')
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check for translation keys in main.json
rg -A 5 '"walletProvider"' src/assets/translations/en/main.json | head -50

Repository: shapeshift/web

Length of output: 347


🏁 Script executed:

# Find all Connect.tsx files in WalletProvider to compare patterns
fd -n "Connect.tsx" src/context/WalletProvider/

Repository: shapeshift/web

Length of output: 288


🏁 Script executed:

# Check the specific Seeker Connect.tsx file structure
cat -n src/context/WalletProvider/Seeker/components/Connect.tsx | head -100

Repository: shapeshift/web

Length of output: 3846


🏁 Script executed:

# Check for generic error key
rg "walletProvider.*generic|errors.*generic" src/assets/translations/en/main.json

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Look at other Connect.tsx implementations for comparison
fd "Connect.tsx" src/context/WalletProvider/ --exec cat {} +

Repository: shapeshift/web

Length of output: 38130


🏁 Script executed:

# Check for seeker-specific error keys
rg "walletProvider.*seeker" src/assets/translations/en/main.json -i

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Check what error keys exist for wallet providers in general
rg '"(walletProvider|errors)"' src/assets/translations/en/main.json | head -30

Repository: shapeshift/web

Length of output: 373


🏁 Script executed:

# Check all available walletProvider.errors keys
rg '"walletProvider":\s*{\s*"errors"' src/assets/translations/en/main.json -A 10

Repository: shapeshift/web

Length of output: 193


🏁 Script executed:

# Check if there's a generic error key elsewhere or what patterns other wallets use for unknown errors
rg 'walletProvider\.(.*?)\.errors\.(unknown|generic)' src/assets/translations/en/main.json

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Get the full walletProvider.errors section
rg -A 20 '"walletProvider": {' src/assets/translations/en/main.json | grep -A 15 '"errors"'

Repository: shapeshift/web

Length of output: 159


🏁 Script executed:

# Search for all unknown error keys pattern
rg "\.errors\.unknown" src/assets/translations/en/main.json

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Read the translations file and find the walletProvider.errors section
cat src/assets/translations/en/main.json | jq '.walletProvider.errors' 2>/dev/null || head -100 src/assets/translations/en/main.json | grep -A 10 "walletProvider"

Repository: shapeshift/web

Length of output: 281


🏁 Script executed:

# Search for unknown errors in all wallet providers
grep -r "unknown" src/assets/translations/en/main.json

Repository: shapeshift/web

Length of output: 688


🏁 Script executed:

# Check if there are seeker-specific translations for errors
rg "seeker" src/assets/translations/en/main.json -i

Repository: shapeshift/web

Length of output: 295


Use early return to preserve auth failure error and type catch as unknown.

The auth failure correctly sets walletProvider.errors.walletNotFound, but the throw funnels into the catch and overwrites it with e.message. Instead, return early after the auth failure check. For the catch block, type the error as unknown and use a valid translation key for the fallback—walletProvider.errors.generic does not exist in the translation file. Since Seeker has no wallet-specific error namespace, reuse walletProvider.errors.walletNotFound as the fallback when catching unexpected errors.

🛠️ Suggested fix
       if (!authResult.success || !authResult.address) {
         setErrorLoading('walletProvider.errors.walletNotFound')
+        navigate('/seeker/failure')
+        return
       }

-      const { SeekerHDWallet } = await import('@shapeshiftoss/hdwallet-seeker')
+      const { SeekerHDWallet } = await import('@shapeshiftoss/hdwallet-seeker')
@@
-    } catch (e: any) {
+    } catch (e: unknown) {
       console.error(e, 'Seeker Connect: There was an error initializing the wallet')
-      setErrorLoading(e.message)
+      setErrorLoading(e instanceof Error ? e.message : 'walletProvider.errors.walletNotFound')
       navigate('/seeker/failure')
🤖 Prompt for AI Agents
In `@src/context/WalletProvider/Seeker/components/Connect.tsx` around lines 37 -
78, The auth-failure throw is hiding the translation set by setErrorLoading and
the catch types are overly broad; after calling seekerAuthorize and detecting
!authResult.success || !authResult.address, return early (do not throw) so the
existing setErrorLoading('walletProvider.errors.walletNotFound') is preserved;
in the try/catch change the catch signature to catch (e: unknown) and when
handling the error use a safe extraction (e.g. inspect e for message or
fallback) and setErrorLoading('walletProvider.errors.walletNotFound') as the
fallback translation key, while still logging the raw error object
(console.error) and then navigate('/seeker/failure').

Comment on lines +1 to +15
import { ModalBody, ModalHeader } from '@chakra-ui/react'
import { Text } from '@/components/Text'

export const SeekerFailure = () => {
return (
<>
<ModalHeader>
<Text translation='walletProvider.seeker.failure.header' />
</ModalHeader>
<ModalBody>
<Text translation='walletProvider.seeker.failure.body' />
</ModalBody>
</>
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check the SeekerFailure component file itself
cat -n src/context/WalletProvider/Seeker/components/Failure.tsx

Repository: shapeshift/web

Length of output: 543


🏁 Script executed:

# Find where SeekerFailure is used/imported
rg -n "SeekerFailure" src/

Repository: shapeshift/web

Length of output: 778


🏁 Script executed:

# Check for error boundaries in the wallet provider/routes structure
rg -n "ErrorBoundary" src/context/WalletProvider/

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Check the SeekerRoutes file structure
cat -n src/context/WalletProvider/Seeker/routes/SeekerRoutes.tsx 2>/dev/null || rg -n "." src/context/WalletProvider/Seeker/routes/ --type tsx --type ts

Repository: shapeshift/web

Length of output: 85


🏁 Script executed:

# Search for ErrorBoundary in the routes file
rg -A 10 "SeekerRoutes" src/context/WalletProvider/NewWalletViews/routes/SeekerRoutes.tsx | head -40

Repository: shapeshift/web

Length of output: 414


🏁 Script executed:

# Check if error boundaries exist anywhere in the wallet provider structure
fd "ErrorBoundary" src/context/WalletProvider/ 2>/dev/null || rg "ErrorBoundary|error.*boundary" src/context/WalletProvider/ -i --type ts --type tsx -l

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Check the full SeekerRoutes file structure
head -50 src/context/WalletProvider/NewWalletViews/routes/SeekerRoutes.tsx

Repository: shapeshift/web

Length of output: 625


🏁 Script executed:

# Look at how seekerFailureElement is used in the routes
rg -B 5 -A 5 "seekerFailureElement" src/context/WalletProvider/NewWalletViews/routes/SeekerRoutes.tsx

Repository: shapeshift/web

Length of output: 543


🏁 Script executed:

# Check if SeekerConnect has similar structure
cat -n src/context/WalletProvider/Seeker/components/Connect.tsx | head -20

Repository: shapeshift/web

Length of output: 882


🏁 Script executed:

# Check if any other wallet Connect components have explicit return types
rg "export const.*Connect = \(\)" src/context/WalletProvider/ -A 2 | head -30

Repository: shapeshift/web

Length of output: 2516


🏁 Script executed:

# Verify the coding guidelines requirement - check if this is enforced elsewhere
rg ": (JSX\.Element|React\.FC|React\.ReactNode)" src/context/WalletProvider/ --type tsx -c | head -10

Repository: shapeshift/web

Length of output: 85


🏁 Script executed:

# Check if explicit return types are actually used in similar presentational components
rg "export const.*= \(\): (JSX\.Element|React\.FC)" src/context/WalletProvider/ --type ts -c

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Verify SeekerFailure is only a presentational component with no complex logic
cat -n src/context/WalletProvider/Seeker/components/Failure.tsx

Repository: shapeshift/web

Length of output: 543


🏁 Script executed:

# Check if the parent route/modal wrapper has error handling
rg -B 10 -A 10 "seekerFailureElement\|/seeker/failure" src/context/WalletProvider/config.ts | head -50

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Check if SeekerConnect (similar component) also lacks explicit return type
head -10 src/context/WalletProvider/Seeker/components/Connect.tsx | grep -A 2 "export const"

Repository: shapeshift/web

Length of output: 40


🏁 Script executed:

# Verify the broader pattern - check random other presentational components
rg "export const.*= \(\)" src/components/ -A 1 | head -30

Repository: shapeshift/web

Length of output: 2177


🏁 Script executed:

# Check if lazy loaded components have error boundaries at the config level
grep -B 5 -A 15 "SeekerFailure" src/context/WalletProvider/config.ts

Repository: shapeshift/web

Length of output: 1280


Add explicit return type annotation.

The component should include an explicit return type following TypeScript guidelines.

Fix
-export const SeekerFailure = () => {
+export const SeekerFailure = (): JSX.Element => {
🤖 Prompt for AI Agents
In `@src/context/WalletProvider/Seeker/components/Failure.tsx` around lines 1 -
15, The SeekerFailure component lacks an explicit TypeScript return type; update
the declaration of SeekerFailure to include a return type (e.g., annotate
SeekerFailure as (): JSX.Element or : React.ReactElement) so the function
signature is explicit, leaving the implementation using ModalHeader and
ModalBody unchanged (reference symbol: SeekerFailure).

Comment on lines +1 to +12
import type { SupportedWalletInfo } from '@/context/WalletProvider/config'
import { SeekerIcon } from '@/components/Icons/SeekerIcon'

type SeekerConfigType = Omit<SupportedWalletInfo<any>, 'routes'>

export const SeekerConfig: SeekerConfigType = {
adapters: [
{
loadAdapter: async () => {
const { SeekerHDWallet } = await import('@shapeshiftoss/hdwallet-seeker')
return SeekerHDWallet as any
},
Copy link
Contributor

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

🏁 Script executed:

# Check how other wallet configs type SupportedWalletInfo
rg -n "SupportedWalletInfo<" src/context/WalletProvider --max-count 20 -A 2 -B 1

Repository: shapeshift/web

Length of output: 6633


🏁 Script executed:

# Check if other wallet config files exist and how they structure adapter loading
fd "config.ts" src/context/WalletProvider -x cat -n {}

Repository: shapeshift/web

Length of output: 38459


🏁 Script executed:

# Search for loadAdapter patterns in other wallet configs
rg -n "loadAdapter" src/context/WalletProvider -g 'config.ts' -A 3 -B 1

Repository: shapeshift/web

Length of output: 5687


Replace any in SeekerConfigType with typeof SeekerHDWallet to match other wallet configs.

Seeker is the only wallet config using SupportedWalletInfo<any>. All other wallet adapters (Coinbase, Keplr, Phantom, Trezor, MetaMask, WalletConnectV2, Vultisig, KeepKey, GridPlus, Native, Ledger) use explicit types like typeof AdapterName. Additionally, the central config registry at src/context/WalletProvider/config.ts:388 already declares the expected type as SupportedWalletInfo<typeof SeekerHDWallet>, so this is a straightforward consistency fix.

♻️ Suggested refactor
-import type { SupportedWalletInfo } from '@/context/WalletProvider/config'
+import type { SeekerHDWallet } from '@shapeshiftoss/hdwallet-seeker'
+import type { SupportedWalletInfo } from '@/context/WalletProvider/config'
@@
-type SeekerConfigType = Omit<SupportedWalletInfo<any>, 'routes'>
+type SeekerConfigType = Omit<SupportedWalletInfo<typeof SeekerHDWallet>, 'routes'>
@@
-        return SeekerHDWallet as any
+        return SeekerHDWallet
📝 Committable suggestion

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

Suggested change
import type { SupportedWalletInfo } from '@/context/WalletProvider/config'
import { SeekerIcon } from '@/components/Icons/SeekerIcon'
type SeekerConfigType = Omit<SupportedWalletInfo<any>, 'routes'>
export const SeekerConfig: SeekerConfigType = {
adapters: [
{
loadAdapter: async () => {
const { SeekerHDWallet } = await import('@shapeshiftoss/hdwallet-seeker')
return SeekerHDWallet as any
},
import type { SeekerHDWallet } from '@shapeshiftoss/hdwallet-seeker'
import type { SupportedWalletInfo } from '@/context/WalletProvider/config'
import { SeekerIcon } from '@/components/Icons/SeekerIcon'
type SeekerConfigType = Omit<SupportedWalletInfo<typeof SeekerHDWallet>, 'routes'>
export const SeekerConfig: SeekerConfigType = {
adapters: [
{
loadAdapter: async () => {
const { SeekerHDWallet } = await import('@shapeshiftoss/hdwallet-seeker')
return SeekerHDWallet
},
🤖 Prompt for AI Agents
In `@src/context/WalletProvider/Seeker/config.ts` around lines 1 - 12,
SeekerConfig currently types SeekerConfigType as Omit<SupportedWalletInfo<any>,
'routes'> which uses any; change it to use the concrete SeekerHDWallet type to
match other configs by replacing any with typeof SeekerHDWallet (i.e., make
SeekerConfigType = Omit<SupportedWalletInfo<typeof SeekerHDWallet>, 'routes'>),
and ensure the dynamic import in SeekerConfig’s loadAdapter still returns
SeekerHDWallet so the types line up with SupportedWalletInfo and the central
registry.

Comment on lines +10 to +18
type Message = {
cmd: string
[key: string]: any
}

type MessageFromMobileApp = {
id: string
result: any
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "seekerMessageHandlers.ts" -o -name "mobileMessageHandlers.ts" | head -20

Repository: shapeshift/web

Length of output: 185


🏁 Script executed:

cat -n src/context/WalletProvider/Seeker/seekerMessageHandlers.ts 2>/dev/null | head -50

Repository: shapeshift/web

Length of output: 1791


🏁 Script executed:

cat -n src/context/WalletProvider/MobileWallet/mobileMessageHandlers.ts 2>/dev/null | head -50

Repository: shapeshift/web

Length of output: 1515


Avoid any in message contracts.

any leaks type-safety into the public API. Use unknown and narrow inside postMessage before resolving.

🔧 Suggested update
 type Message = {
   cmd: string
-  [key: string]: any
+  [key: string]: unknown
 }
 
 type MessageFromMobileApp = {
   id: string
-  result: any
+  result: unknown
 }
📝 Committable suggestion

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

Suggested change
type Message = {
cmd: string
[key: string]: any
}
type MessageFromMobileApp = {
id: string
result: any
}
type Message = {
cmd: string
[key: string]: unknown
}
type MessageFromMobileApp = {
id: string
result: unknown
}
🤖 Prompt for AI Agents
In `@src/context/WalletProvider/Seeker/seekerMessageHandlers.ts` around lines 10 -
18, Replace all uses of `any` in the message contract types by `unknown` (e.g.,
change type Message { cmd: string; [key: string]: any } to use unknown for
payloads and change MessageFromMobileApp.result: any to result: unknown); then
update the code path in `postMessage` to perform explicit runtime
narrowing/type-guarding before resolving or using fields (validate `cmd`, `id`,
and the shape of `result`, use type predicates or runtime checks and only cast
after validation). Ensure `Message`, `MessageFromMobileApp`, and `postMessage`
are updated consistently so no `any` leaks into the public API.

@NeOMakinG NeOMakinG marked this pull request as draft January 28, 2026 08:34
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