-
Notifications
You must be signed in to change notification settings - Fork 198
feat: walletconnect connect to specific wallet programatically #10879
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add UGLY red button below WalletConnect pair button - Create useDirectConnect hook for UGLY direct wallet connections - Implement UGLY direct MetaMask connection without modal - Uses display_uri event to capture UGLY WalletConnect URI - Deep links directly to wallets (UGLY but works!) - Desktop shows UGLY alert with URI (QR code POC) This is an intentionally UGLY proof of concept to demonstrate programmatic wallet connection via WalletConnect without the modal. 🚨 WARNING: This is UGLY test code - DO NOT use in production! 🚨 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
📝 WalkthroughWalkthroughIntroduces WalletConnect V2 direct connection feature allowing users to connect to specific wallets (MetaMask, Trust, Zerion) without showing the modal. Adds feature flag configuration, new components for wallet buttons, connection hook with deep-linking support, and comprehensive documentation. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as WalletConnectDirectRow
participant Hook as useDirectWalletConnect
participant Provider as WalletConnect V2<br/>EthereumProvider
participant Wallet as Wallet App
participant State as Redux State
User->>UI: Click wallet button
activate UI
UI->>UI: Set loading state
UI->>Hook: connect(walletId)
deactivate UI
activate Hook
Hook->>Provider: Create provider<br/>(showQrModal: false)
activate Provider
Hook->>Provider: Subscribe to display_uri
Provider-->>Hook: Emit display_uri event
Hook->>Wallet: Open deep link
deactivate Provider
Wallet->>Wallet: User approves connection
Wallet->>Provider: Respond to connection request
activate Provider
Provider-->>Hook: Connection established
deactivate Provider
Hook->>State: setWallet() - Update<br/>wallet state
Hook->>State: Store deviceId &<br/>persist wallet
Hook->>State: Close modal
Hook-->>UI: Connection complete
deactivate Hook
UI->>UI: Clear loading state
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Multiple new components and hooks with state management integration, feature flag wiring across config/state layers, and new control flow logic for provider initialization and deep-linking. Changes are additive and follow established patterns but span several concerns and introduce non-trivial wallet connection orchestration. Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Improvements to direct WalletConnect connection POC: - Add third wallet button for Zerion (zerion://wc?uri=) - Implement separate loading states per wallet button - Auto-close modal on successful connection - Remove toast notifications for cleaner UX - Add comprehensive documentation explaining the hack - Fix type naming to avoid confusion (WalletConnectWalletId) - Document deep link references with sources The hack: We bypass the WalletConnect modal by setting showQrModal: false and manually constructing deep links, while maintaining full WalletConnect v2 functionality through the relay servers. See docs/walletconnect-direct-connection.md for detailed explanation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The modal was closing before the deep link even opened the wallet app. Fixed by removing all manual SET_WALLET_MODAL dispatches and letting the parent component handle modal lifecycle. Now the flow is: 1. Click UGLY button 2. Deep link opens wallet app (modal stays open) 3. User approves in wallet 4. Connection completes 5. Modal closes via parent component logic This matches the standard WalletConnect flow timing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- MetaMask: Just UGLY (baseline ugliness) - Trust: SUPER UGLY (elevated ugliness) - Zerion: F**KING UGLY (maximum ugliness achieved) Updated button labels and badges to reflect the proper UGLY hierarchy as requested. The ugliness now escalates appropriately from wallet to wallet. UGLY POC continues to be UGLY, but now with proper gradation! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Button text changes: - Removed "POC: Connect WC" prefix - Now just show wallet names: METAMASK, TRUST, ZERION Badge improvements: - All badges positioned on the right (was broken on Trust) - Maintain UGLY hierarchy: UGLY! → SUPER UGLY! → FUCKING UGLY! - Removed censorship: F**KING → FUCKING (it's Australian!) Removed features: - Attempted spinning animation (didn't work, fuck it) Updated docs with all latest changes and complete implementation journey. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changed "FUCKING UGLY!" to "FUARKIN UGLY!" in the Zerion badge. FUARKIN means thick, solid, tight - not a bad word, trust me bro. Updated docs to reflect proper aesthetic terminology. We're all gonna make it! 💪 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Check provider.session and provider.accounts instead of non-existent provider.connected - Remove premature modal closes from useDirectConnect - Let button polling be single source of truth for modal closing - Loading state now persists until wallet is actually connected 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove "(UGLY DIRECT)" suffix from wallet name - Now shows as just "WalletConnect" like regular connection - Better UX - users don't see implementation details 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove all UGLY references from comments and code - Remove all console.log statements - Clean up variable names (uglyProvider -> walletConnectProvider, etc) - Keep the visual joke with button badges intact (UGLY!, SUPER UGLY!, FUARKIN UGLY!) - Simplify component documentation - The joke has lasted long enough in the code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unnecessary empty event listeners (disconnect, session_event) - Extract shared wallet registration logic to reduce duplication - Remove unused currentUri state - Add constants for polling interval and timeout values - Cleaner, more maintainable code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace loud UGLY styling with clean icon + name layout - Use Flex layout with 3 buttons horizontally - Show wallet icons from WalletConnect Explorer API - Add small WalletConnect badge in corner - Icons: MetaMask (custom SVG), Trust & Zerion (from WC API) - Update docs with WalletConnect Explorer API instructions for adding new wallets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Move WC icon from corner to next to wallet name (aligned horizontally) - Style WC icon with blue circle background and white icon - Increase icon size to 64px for better visibility - Rename "Trust Wallet" to "Trust" - Add minHeight and justify='center' for better alignment - Use WalletConnectCurrentColorIcon for proper color control 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace icon with spinner when loading (same 64px size for alignment) - Use isDisabled instead of isLoading on button for cleaner state - Spinner matches icon size exactly to prevent layout shifts - Remove unused spinnerElement memoization - Clean up unused imports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Wrap MetaMask SVG icon in Flex container for consistent sizing - Ensures all icons occupy same 64px space with centered content - Fixes vertical alignment discrepancy between SVG and image icons 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Document that we're using WalletConnect provider directly without modal - this is the key insight that makes the whole feature work 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Auto-fixed by eslint 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Add VITE_FEATURE_WC_DIRECT_CONNECTION flag to control direct wallet connection buttons: - OFF by default (.env) - ON in development environments (.env.development) - Wired up in config validator and FeatureFlags type - WalletConnectDirectRow only renders when flag is enabled Confirmed: gome.shapeshift.com uses BUILD_MODE=development, so flag will be ON there 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Move from docs/ to src/context/WalletProvider/WalletConnectV2/README.md for better discoverability. Cleaned up to be concise and actionable: - Removed UGLY POC narrative and outdated content - Updated code examples to match current implementation - Documented feature flag (VITE_FEATURE_WC_DIRECT_CONNECTION) - Focused on protocol basics, app implementation, and how to extend - Serves as comprehensive docs for entire WalletConnectV2 module Now covers: protocol basics, app implementation, direct connection feature, and adding new wallets. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Use cleaner pattern with base type and never types for better type safety: - Extract common properties (id, name) to WalletConfigBase - Use intersection with union for discriminating properties - Add runtime check for IconComponent to satisfy TypeScript Also clarify ShapeShift vs wallet app terminology in README. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
localhost works fine for desktop WalletConnect (QR codes). Deep links are mobile-only and require: - Real mobile device with wallet apps - Deployed environment (local IPs rejected by WalletConnect relay) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this 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 (8)
src/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx (1)
79-91: Render the direct row via PairBody.secondaryContent for cohesion.Keeps layout/theming consistent and avoids extra fragment wrappers.
- return ( - <> - <PairBody + return ( + <PairBody icon={icon} headerTranslation='walletProvider.walletConnect.connect.header' bodyTranslation='walletProvider.walletConnect.connect.body' buttonTranslation='walletProvider.walletConnect.connect.button' isLoading={loading} error={error} onPairDeviceClick={pairDevice} - /> - {isWcDirectConnectionEnabled && <WalletConnectDirectRow />} - </> + secondaryContent={isWcDirectConnectionEnabled ? <WalletConnectDirectRow /> : null} + />src/context/WalletProvider/WalletConnectV2/constants.ts (1)
165-171: Use a string enum for wallet IDs per guidelines.Improves discoverability and avoids typos across callers.
-export type WalletConnectWalletId = 'metamask' | 'trust' | 'zerion' +export enum WalletConnectWalletId { + MetaMask = 'metamask', + Trust = 'trust', + Zerion = 'zerion', +} -type WalletConfigBase = { - id: WalletConnectWalletId +type WalletConfigBase = { + id: WalletConnectWalletId name: string } export const WALLET_CONFIGS: WalletConfig[] = [ { - id: 'metamask', + id: WalletConnectWalletId.MetaMask, name: 'MetaMask', IconComponent: MetaMaskIcon, }, { - id: 'trust', + id: WalletConnectWalletId.Trust, name: 'Trust', imageUrl: TrustWalletIcon, }, { - id: 'zerion', + id: WalletConnectWalletId.Zerion, name: 'Zerion', imageUrl: ZerionWalletIcon, }, ]Also applies to: 178-194
src/context/WalletProvider/WalletConnectV2/README.md (1)
18-31: Docs are solid; fix fenced-code languages and a small grammar nit.Adds language tags for lint, and clarifies the mobile testing note. Optional: mention universal link fallbacks for better iOS UX.
-``` +```text ShapeShift (dApp) → WalletConnect SDK → Relay Server ← User's Wallet App-
+text
wc:94caa59c77dae0dd234b5818fb7292540d017b27d41f7f387ee75b22b9738c94@2?relay-protocol=irn&symKey=...-``` +```text src/context/WalletProvider/WalletConnectV2/ ├── README.md # This file ├── config.ts # Provider configs ├── constants.ts # Wallet configs, types ├── useDirectConnect.ts # Direct connection hook ├── useWalletConnectV2EventHandler.ts # Provider event handlers └── components/ ├── Connect.tsx # Standard modal flow └── WalletConnectDirectRow.tsx # Direct connection buttons-
typescript +ts
// Create provider without modal
const provider = await EthereumProvider.init({
...walletConnectV2DirectProviderConfig, // showQrModal: false
})// Intercept URI and build custom deep link
provider.on('display_uri', (uri: string) => {
const deepLink =${walletId}://wc?uri=${encodeURIComponent(uri)}
window.open(deepLink, '_blank')
})// Wait for connection (promise survives app switch!)
await provider.enable()// Register wallet in ShapeShift state
await setWallet(provider, dispatch, localWallet)-```bash +```bash curl "https://explorer-api.walletconnect.com/v3/wallets?projectId=YOUR_PROJECT_ID&search=rainbow"-
typescript +ts
// Add to type
export type WalletConnectWalletId = 'metamask' | 'trust' | 'zerion' | 'rainbow'// Import icon
import RainbowWalletIcon from '@/assets/rainbow-wallet.png'// Add to configs
export const WALLET_CONFIGS: WalletConfig[] = [
// ... existing wallets
{
id: 'rainbow',
name: 'Rainbow',
imageUrl: RainbowWalletIcon,
},
]-Deep links require actual mobile devices with wallet apps installed. Testing requires: -- ✅ Deploy to remote domain (`*.shapeshift.com`) -- ❌ Local IP addresses (`192.168.x.x`) - WalletConnect relay rejects them -- Must use ephemeral environment (gome, private, etc.) to test on phone +Deep links require actual mobile devices with wallet apps installed. Testing requires: +- ✅ Deploy to remote domain (`*.shapeshift.com`) +- ❌ Local IP addresses (`192.168.x.x`) — WalletConnect relay rejects them +- ✅ Use an ephemeral environment (e.g., gome, private) to test on a phone + +Optional: +- Use universal-link fallbacks when available (e.g., MetaMask `https://metamask.app.link/wc?uri=...`) to improve iOS behavior.Also applies to: 38-49, 92-111, 154-190, 208-213
src/context/WalletProvider/WalletConnectV2/config.ts (1)
118-122: Type the config with provider’s options and drop redundant property.Looks good. Two small tweaks:
- Omit qrModalOptions since showQrModal is false.
- Re-export this object typed to @walletconnect/ethereum-provider’s EthereumProviderOptions so we can remove the
as anycast at init.Apply locally here:
-import type { EthereumProviderOptions } from './constants' +import type { EthereumProviderOptions as WcEthereumProviderOptions } from '@walletconnect/ethereum-provider' … -export const walletConnectV2DirectProviderConfig: EthereumProviderOptions = { +export const walletConnectV2DirectProviderConfig: WcEthereumProviderOptions = { ...walletConnectV2ProviderConfig, showQrModal: false, - qrModalOptions: undefined, }And in useDirectConnect.ts replace the cast:
-const provider = await EthereumProvider.init(walletConnectV2DirectProviderConfig as any) +const provider = await EthereumProvider.init(walletConnectV2DirectProviderConfig)Also ensure VITE_WALLET_CONNECT_WALLET_PROJECT_ID is required at config load (fail fast). Based on learnings.
src/context/WalletProvider/WalletConnectV2/useDirectConnect.ts (2)
81-87: Avoidas any; pass properly typed options.Once config exports WcEthereumProviderOptions, this cast can be removed.
-const provider = await EthereumProvider.init(walletConnectV2DirectProviderConfig as any) +const provider = await EthereumProvider.init(walletConnectV2DirectProviderConfig)
83-87: Use a one-time listener and clean up to prevent duplicate deep links.Switch to once() if available, or unregister after first fire.
-// Intercept the URI and open the wallet directly via deep link -provider.on('display_uri', (uri: string) => openDeepLink(walletId, uri)) +const onDisplayUri = (uri: string) => { + openDeepLink(walletId, uri) + provider.off?.('display_uri', onDisplayUri) +} +provider.once ? provider.once('display_uri', onDisplayUri) : provider.on('display_uri', onDisplayUri)src/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsx (2)
22-37: Memoize button and add alt text for accessibility.
- Wrap DirectWalletButton with React.memo to avoid unnecessary re-renders.
- Provide alt text on Image.
-import { useCallback, useMemo, useState } from 'react' +import { memo, useCallback, useMemo, useState } from 'react' … -const DirectWalletButton = ({ wallet, isLoading, onConnect }: DirectWalletButtonProps) => { +const DirectWalletButton = memo(({ wallet, isLoading, onConnect }: DirectWalletButtonProps) => { … - return <Image src={wallet.imageUrl} boxSize='64px' borderRadius='lg' /> + return <Image src={wallet.imageUrl} alt={`${wallet.name} logo`} boxSize='64px' borderRadius='lg' /> }, [isLoading, wallet]) … -} +})
75-77: Use structured logging and user-facing error toast.Replace console.error with app logger and show a translated toast via useErrorToast.
Happy to wire this with your project’s logger and useErrorToast; confirm the import path you prefer.
📜 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.
⛔ Files ignored due to path filters (2)
src/assets/trust-wallet.pngis excluded by!**/*.pngsrc/assets/zerion-wallet.pngis excluded by!**/*.png
📒 Files selected for processing (11)
.env(1 hunks).env.development(1 hunks)src/config.ts(1 hunks)src/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx(3 hunks)src/context/WalletProvider/WalletConnectV2/README.md(1 hunks)src/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsx(1 hunks)src/context/WalletProvider/WalletConnectV2/config.ts(1 hunks)src/context/WalletProvider/WalletConnectV2/constants.ts(2 hunks)src/context/WalletProvider/WalletConnectV2/useDirectConnect.ts(1 hunks)src/state/slices/preferencesSlice/preferencesSlice.ts(2 hunks)src/test/mocks/store.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
**/*.{ts,tsx}: ALWAYS use Result<T, E> pattern for error handling in swappers and APIs
ALWAYS use Ok() and Err() from @sniptt/monads for monadic error handling
ALWAYS use custom error classes from @shapeshiftoss/errors
ALWAYS provide meaningful error codes for internationalization
ALWAYS include relevant details in error objects
ALWAYS wrap async operations in try-catch blocks
ALWAYS use AsyncResultOf utility for converting promises to Results
ALWAYS provide fallback error handling
ALWAYS use timeoutMonadic for API calls
ALWAYS provide appropriate timeout values for API calls
ALWAYS handle timeout errors gracefully
ALWAYS validate inputs before processing
ALWAYS provide clear validation error messages
ALWAYS use early returns for validation failures
ALWAYS log errors for debugging
ALWAYS use structured logging for errors
ALWAYS include relevant context in error logs
Throwing errors instead of using monadic patterns is an anti-pattern
Missing try-catch blocks for async operations is an anti-pattern
Generic error messages without context are an anti-pattern
Not handling specific error types is an anti-pattern
Missing timeout handling is an anti-pattern
No input validation is an anti-pattern
Poor error logging is an anti-pattern
Using any for error types is an anti-pattern
Missing error codes for internationalization is an anti-pattern
No fallback error handling is an anti-pattern
Console.error without structured logging is an anti-pattern
**/*.{ts,tsx}: ALWAYS use camelCase for variables, functions, and methods
ALWAYS use descriptive names that explain the purpose for variables and functions
ALWAYS use verb prefixes for functions that perform actions
ALWAYS use PascalCase for types, interfaces, and enums
ALWAYS use descriptive names that indicate the structure for types, interfaces, and enums
ALWAYS use suffixes like Props, State, Config, Type when appropriate for types and interfaces
ALWAYS use UPPER_SNAKE_CASE for constants and configuration values
ALWAYS use d...
Files:
src/context/WalletProvider/WalletConnectV2/config.tssrc/config.tssrc/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsxsrc/test/mocks/store.tssrc/context/WalletProvider/WalletConnectV2/constants.tssrc/context/WalletProvider/WalletConnectV2/useDirectConnect.tssrc/state/slices/preferencesSlice/preferencesSlice.tssrc/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx
**/*
📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)
**/*: ALWAYS use appropriate file extensions
Flag files without kebab-case
Files:
src/context/WalletProvider/WalletConnectV2/config.tssrc/context/WalletProvider/WalletConnectV2/README.mdsrc/config.tssrc/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsxsrc/test/mocks/store.tssrc/context/WalletProvider/WalletConnectV2/constants.tssrc/context/WalletProvider/WalletConnectV2/useDirectConnect.tssrc/state/slices/preferencesSlice/preferencesSlice.tssrc/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)
USE Redux only for global state shared across multiple places
Files:
src/context/WalletProvider/WalletConnectV2/config.tssrc/config.tssrc/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsxsrc/test/mocks/store.tssrc/context/WalletProvider/WalletConnectV2/constants.tssrc/context/WalletProvider/WalletConnectV2/useDirectConnect.tssrc/state/slices/preferencesSlice/preferencesSlice.tssrc/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
**/*.tsx: ALWAYS wrap components in error boundaries
ALWAYS provide user-friendly fallback components in error boundaries
ALWAYS log errors for debugging in error boundaries
ALWAYS use useErrorToast hook for displaying errors
ALWAYS provide translated error messages in error toasts
ALWAYS handle different error types appropriately in error toasts
Missing error boundaries in React components is an anti-pattern
**/*.tsx: ALWAYS use PascalCase for React component names
ALWAYS use descriptive names that indicate the component's purpose
ALWAYS match the component name to the file name
Flag components without PascalCase
Flag default exports for components
Files:
src/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsxsrc/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)
**/*.{tsx,jsx}: ALWAYS useuseMemofor expensive computations, object/array creations, and filtered data
ALWAYS useuseMemofor derived values and computed properties
ALWAYS useuseMemofor conditional values and simple transformations
ALWAYS useuseCallbackfor event handlers and functions passed as props
ALWAYS useuseCallbackfor any function that could be passed as a prop or dependency
ALWAYS include all dependencies inuseEffect,useMemo,useCallbackdependency arrays
NEVER use// eslint-disable-next-line react-hooks/exhaustive-depsunless absolutely necessary
ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components
NEVER use default exports for components
KEEP component files under 200 lines when possible
BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
USE local state for component-level state
LIFT state up when needed across multiple components
USE Context for avoiding prop drilling
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly
ALWAYS provide user-friendly error messages
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components
ALWAYS use React.lazy for code splitting
Components receiving props are wrapped withmemo
Files:
src/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsxsrc/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx
**/use*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)
**/use*.{ts,tsx}: ALWAYS use use prefix for custom hooks
ALWAYS use descriptive names that indicate the hook's purpose
ALWAYS use camelCase after the use prefix for custom hooks
Files:
src/context/WalletProvider/WalletConnectV2/useDirectConnect.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: gomesalexandre
PR: shapeshift/web#10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
PR: shapeshift/web#10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
PR: shapeshift/web#10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
PR: shapeshift/web#10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
🧬 Code graph analysis (5)
src/context/WalletProvider/WalletConnectV2/config.ts (1)
src/context/WalletProvider/WalletConnectV2/constants.ts (1)
EthereumProviderOptions(150-163)
src/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsx (2)
src/context/WalletProvider/WalletConnectV2/constants.ts (3)
WalletConfig(172-176)WalletConnectWalletId(165-165)WALLET_CONFIGS(178-194)src/context/WalletProvider/WalletConnectV2/useDirectConnect.ts (1)
useDirectWalletConnect(62-104)
src/context/WalletProvider/WalletConnectV2/useDirectConnect.ts (4)
src/context/WalletProvider/WalletConnectV2/constants.ts (1)
WalletConnectWalletId(165-165)src/context/WalletProvider/actions.ts (1)
ActionTypes(36-119)src/context/WalletProvider/local-wallet.ts (1)
useLocalWallet(12-47)src/context/WalletProvider/WalletConnectV2/config.ts (2)
WalletConnectV2Config(24-35)walletConnectV2DirectProviderConfig(118-122)
src/state/slices/preferencesSlice/preferencesSlice.ts (1)
src/config.ts (1)
getConfig(209-211)
src/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx (2)
src/context/WalletProvider/NewWalletViews/components/PairBody.tsx (1)
PairBody(22-64)src/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsx (1)
WalletConnectDirectRow(64-95)
🪛 LanguageTool
src/context/WalletProvider/WalletConnectV2/README.md
[grammar] ~212-~212: Ensure spelling is correct
Context: ... them - Must use ephemeral environment (gome, private, etc.) to test on phone ## Re...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
src/context/WalletProvider/WalletConnectV2/README.md
9-9: Link fragments should be valid
(MD051, link-fragments)
18-18: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
28-28: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
38-38: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (7)
.env (1)
21-21: Flag added consistently; LGTM.Matches config validator and preferences initialization. No action.
.env.development (1)
76-76: Dev override enabled; LGTM.Correctly gates direct-connect to dev only.
src/config.ts (1)
97-97: Validator added; LGTM.VITE_FEATURE_WC_DIRECT_CONNECTION default false aligns with feature-flag pattern here.
src/test/mocks/store.ts (1)
119-121: Mocks updated; LGTM.New WcDirectConnection flag present in mock store so tests won’t crash on selector reads.
src/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx (1)
27-27: Flag gate looks correct; confirm modal closes on direct-connect success.Ensure WalletConnectDirectRow path dispatches SET_WALLET_MODAL false after success to mirror pairDevice().
src/state/slices/preferencesSlice/preferencesSlice.ts (1)
47-48: Feature flag thread complete; LGTM.Type added and initial state wired from getConfig(). No gaps.
Also applies to: 172-173
src/context/WalletProvider/WalletConnectV2/constants.ts (1)
1-4: Verify image module declarations exist.Ensure a global.d.ts (e.g., declare module '*.png') is present so TS recognizes these imports.
src/context/WalletProvider/WalletConnectV2/components/WalletConnectDirectRow.tsx
Show resolved
Hide resolved
NeOMakinG
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirming it works super well on mobile
I've been able to connect to MM, zerion and trust on my mobile using my browser!
src/context/WalletProvider/NewWalletViews/routes/WalletConnectV2Routes.tsx
Show resolved
Hide resolved
- Fix terminology: "Deep Link via WalletConnect Modal" for mobile web - Clarify mobile app supports both paste link and deep link - Add PR #10879 as initial direct connection implementation - Note iOS wallet detection is a spike in progress - Add demo video link for direct connection feature 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
* wip: wc docs * [skip ci] feat: kiss * docs: add comprehensive WalletConnect feature documentation Add simplified documentation for WalletConnect features: - WalletConnect Wallet: Connect external wallets to ShapeShift - Current: QR code connection - Coming: Direct connection (mobile web) - PR #10912 - Future: iOS wallet detection - #10893 - WalletConnect to dApps: Connect ShapeShift wallet to DApps - Paste connection links - Deep link support (app.shapeshift.com/wc) - Works across desktop, mobile web, and mobile app Docs focused on what we support and how it works, with minimal fluff and clear platform support matrices. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: clarify WalletConnect modal already has wallet buttons on mobile The WalletConnect modal already shows wallet buttons on mobile web that deep link to wallet apps - this is already live. The "Direct Connection" feature is about skipping the WalletConnect modal entirely by showing wallet buttons directly in ShapeShift's UI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: fix WalletConnect to dApps details - Use "Connect dApp" button (not Settings menu) - Note: only works with native wallet currently - Remove fluff "What You Can Do" section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: remove session management fluff from WalletConnect to dApps 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: fix mobile app WalletConnect to dApps support Mobile app supports both paste link and deep link methods, not just deep link only. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: final WalletConnect documentation updates - Fix terminology: "Deep Link via WalletConnect Modal" for mobile web - Clarify mobile app supports both paste link and deep link - Add PR #10879 as initial direct connection implementation - Note iOS wallet detection is a spike in progress - Add demo video link for direct connection feature 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: use shorter GitHub URL for direct connection demo video 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: update * feat: update * feat: clarify deep link methods in WalletConnect DApps docs Updated the WalletConnect DApps documentation to clarify deep linking methods for both desktop and mobile applications, including notes on the status of the apps. * feat: revise WalletConnect feature documentation Updated WalletConnect documentation for clarity and added links for further details. * feat: revise WalletConnect documentation overview section Updated the WalletConnect documentation to improve clarity and structure. * feat: update --------- Co-authored-by: Claude <noreply@anthropic.com>
Description
Update: confirmed working 🎉
Note: This is by no means intended to be a fully working flow, nor the final flow - it's mostly a PoC, hacked under the WC "Pair" button (under flag!) for beard to make it look pretty and UX - core functionality is there!
Probably nothing - just vibing around with an ugly red div to see how we can push the limits of escape-hatching WC (wallet) modal.TODO:
spike if we can detect installed wallets like Zapper does, detecting wallets who declarefollow-up spikewc:intentspike if we can have the app redirect to the wallet when using WC and having a sign Tx req (not introduced by this PR, but super annoying tbh)follow-up spikeIssue (if applicable)
closes #10877
Risk
Low - under flag and temp work for @reallybeard to wire design ups in
Testing
Engineering
Operations
Screenshots (if applicable)
Regression test
https://jam.dev/c/a2202c9b-90a3-4c28-8bb2-b114013c80fe
Direction connection buttons test
wc.direct.mov
Summary by CodeRabbit
New Features
Documentation