@sodax/wallet-sdk-react 1.5.7-beta → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -145
- package/ai-exported/AGENTS.md +122 -0
- package/ai-exported/integration/README.md +102 -0
- package/ai-exported/integration/ai-rules.md +136 -0
- package/ai-exported/integration/architecture.md +181 -0
- package/ai-exported/integration/examples/01-minimal-evm.tsx +75 -0
- package/ai-exported/integration/examples/02-multi-chain-modal.tsx +169 -0
- package/ai-exported/integration/examples/03-nextjs-app-router.tsx +99 -0
- package/ai-exported/integration/examples/04-walletconnect-setup.tsx +89 -0
- package/ai-exported/integration/examples/README.md +29 -0
- package/ai-exported/integration/recipes/batch-operations.md +223 -0
- package/ai-exported/integration/recipes/bridge-to-sdk.md +164 -0
- package/ai-exported/integration/recipes/chain-detection.md +254 -0
- package/ai-exported/integration/recipes/connect-button.md +156 -0
- package/ai-exported/integration/recipes/multi-chain-modal.md +199 -0
- package/ai-exported/integration/recipes/setup.md +158 -0
- package/ai-exported/integration/recipes/sign-message.md +137 -0
- package/ai-exported/integration/recipes/sub-path-imports.md +95 -0
- package/ai-exported/integration/recipes/switch-chain.md +141 -0
- package/ai-exported/integration/recipes/walletconnect-setup.md +139 -0
- package/ai-exported/integration/reference/api-surface.md +175 -0
- package/ai-exported/integration/reference/chain-support.md +78 -0
- package/ai-exported/integration/reference/connectors.md +74 -0
- package/ai-exported/integration/reference/hooks.md +204 -0
- package/ai-exported/integration/reference/wallet-brands.md +106 -0
- package/ai-exported/migration/README.md +49 -0
- package/ai-exported/migration/ai-rules.md +144 -0
- package/ai-exported/migration/breaking-changes.md +305 -0
- package/ai-exported/migration/checklist.md +159 -0
- package/ai-exported/migration/recipes/connect-button.md +166 -0
- package/ai-exported/migration/recipes/multi-chain-modal.md +244 -0
- package/ai-exported/migration/recipes/ssr-setup.md +162 -0
- package/ai-exported/migration/recipes/walletconnect-migration.md +168 -0
- package/ai-exported/migration/reference/components.md +73 -0
- package/ai-exported/migration/reference/config.md +307 -0
- package/ai-exported/migration/reference/hooks.md +278 -0
- package/ai-exported/migration/reference/imports.md +157 -0
- package/dist/XConnector-B9YQTVJ4.d.ts +146 -0
- package/dist/chunk-2BOUGCJ7.mjs +150 -0
- package/dist/chunk-2BOUGCJ7.mjs.map +1 -0
- package/dist/chunk-66BAUK56.mjs +202 -0
- package/dist/chunk-66BAUK56.mjs.map +1 -0
- package/dist/chunk-7ULB6DW4.mjs +102 -0
- package/dist/chunk-7ULB6DW4.mjs.map +1 -0
- package/dist/chunk-BKJB527E.mjs +125 -0
- package/dist/chunk-BKJB527E.mjs.map +1 -0
- package/dist/chunk-BXJLBR4G.mjs +88 -0
- package/dist/chunk-BXJLBR4G.mjs.map +1 -0
- package/dist/chunk-E5IAZ7E6.mjs +186 -0
- package/dist/chunk-E5IAZ7E6.mjs.map +1 -0
- package/dist/chunk-MAQ47Q52.mjs +33 -0
- package/dist/chunk-MAQ47Q52.mjs.map +1 -0
- package/dist/chunk-MXZVF5HR.mjs +34 -0
- package/dist/chunk-MXZVF5HR.mjs.map +1 -0
- package/dist/chunk-N5A2TMF6.mjs +33 -0
- package/dist/chunk-N5A2TMF6.mjs.map +1 -0
- package/dist/chunk-NY7U7OJW.mjs +64 -0
- package/dist/chunk-NY7U7OJW.mjs.map +1 -0
- package/dist/chunk-PJLEJVAU.mjs +140 -0
- package/dist/chunk-PJLEJVAU.mjs.map +1 -0
- package/dist/chunk-PLCA4ZDJ.mjs +1585 -0
- package/dist/chunk-PLCA4ZDJ.mjs.map +1 -0
- package/dist/chunk-TZMKDXFA.mjs +3 -0
- package/dist/chunk-TZMKDXFA.mjs.map +1 -0
- package/dist/chunk-X2MHIWXO.mjs +100 -0
- package/dist/chunk-X2MHIWXO.mjs.map +1 -0
- package/dist/chunk-XZ7CHO2S.mjs +41 -0
- package/dist/chunk-XZ7CHO2S.mjs.map +1 -0
- package/dist/config-OlnzyEUE.d.ts +146 -0
- package/dist/index.cjs +2784 -1594
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +768 -1498
- package/dist/index.mjs +463 -2004
- package/dist/index.mjs.map +1 -1
- package/dist/xchains/bitcoin/index.cjs +1927 -0
- package/dist/xchains/bitcoin/index.cjs.map +1 -0
- package/dist/xchains/bitcoin/index.d.ts +125 -0
- package/dist/xchains/bitcoin/index.mjs +16 -0
- package/dist/xchains/bitcoin/index.mjs.map +1 -0
- package/dist/xchains/evm/index.cjs +316 -0
- package/dist/xchains/evm/index.cjs.map +1 -0
- package/dist/xchains/evm/index.d.ts +39 -0
- package/dist/xchains/evm/index.mjs +5 -0
- package/dist/xchains/evm/index.mjs.map +1 -0
- package/dist/xchains/icon/index.cjs +311 -0
- package/dist/xchains/icon/index.cjs.map +1 -0
- package/dist/xchains/icon/index.d.ts +37 -0
- package/dist/xchains/icon/index.mjs +7 -0
- package/dist/xchains/icon/index.mjs.map +1 -0
- package/dist/xchains/injective/index.cjs +223 -0
- package/dist/xchains/injective/index.cjs.map +1 -0
- package/dist/xchains/injective/index.d.ts +35 -0
- package/dist/xchains/injective/index.mjs +5 -0
- package/dist/xchains/injective/index.mjs.map +1 -0
- package/dist/xchains/near/index.cjs +190 -0
- package/dist/xchains/near/index.cjs.map +1 -0
- package/dist/xchains/near/index.d.ts +34 -0
- package/dist/xchains/near/index.mjs +6 -0
- package/dist/xchains/near/index.mjs.map +1 -0
- package/dist/xchains/solana/index.cjs +186 -0
- package/dist/xchains/solana/index.cjs.map +1 -0
- package/dist/xchains/solana/index.d.ts +26 -0
- package/dist/xchains/solana/index.mjs +7 -0
- package/dist/xchains/solana/index.mjs.map +1 -0
- package/dist/xchains/stacks/index.cjs +240 -0
- package/dist/xchains/stacks/index.cjs.map +1 -0
- package/dist/xchains/stacks/index.d.ts +36 -0
- package/dist/xchains/stacks/index.mjs +5 -0
- package/dist/xchains/stacks/index.mjs.map +1 -0
- package/dist/xchains/stellar/index.cjs +322 -0
- package/dist/xchains/stellar/index.cjs.map +1 -0
- package/dist/xchains/stellar/index.d.ts +44 -0
- package/dist/xchains/stellar/index.mjs +6 -0
- package/dist/xchains/stellar/index.mjs.map +1 -0
- package/dist/xchains/sui/index.cjs +248 -0
- package/dist/xchains/sui/index.cjs.map +1 -0
- package/dist/xchains/sui/index.d.ts +37 -0
- package/dist/xchains/sui/index.mjs +7 -0
- package/dist/xchains/sui/index.mjs.map +1 -0
- package/docs/ADDING_A_NEW_CHAIN.md +440 -0
- package/docs/ARCHITECTURE.md +291 -0
- package/docs/BATCH_OPERATIONS.md +267 -0
- package/docs/CHAIN_DETECTION.md +216 -0
- package/docs/CONFIGURE_PROVIDER.md +360 -0
- package/docs/CONNECTORS.md +247 -0
- package/docs/CONNECT_FLOW.md +276 -0
- package/docs/EVM_SWITCH_CHAIN.md +161 -0
- package/docs/SIGN_MESSAGE.md +213 -0
- package/docs/SUB_PATH_EXPORTS.md +246 -0
- package/docs/WALLETCONNECT.md +154 -0
- package/docs/WALLET_MODAL.md +331 -0
- package/docs/WALLET_PROVIDER_BRIDGE.md +226 -0
- package/package.json +37 -12
- package/skills/SKILLS.md +84 -0
- package/skills/bridge-to-sdk.md +148 -0
- package/skills/connect-button.md +116 -0
- package/skills/evm-only-walletconnect.md +111 -0
- package/skills/multi-chain-modal.md +178 -0
- package/skills/setup.md +107 -0
- package/dist/index.d.cts +0 -1579
- package/src/Hydrate.ts +0 -65
- package/src/SodaxWalletProvider.tsx +0 -97
- package/src/actions/getXChainType.ts +0 -8
- package/src/actions/getXService.ts +0 -33
- package/src/actions/index.ts +0 -2
- package/src/assets/wallets/hana.svg +0 -6
- package/src/assets/wallets/havah.svg +0 -76
- package/src/assets/wallets/keplr.svg +0 -30
- package/src/assets/wallets/metamask.svg +0 -60
- package/src/assets/wallets/phantom.svg +0 -4
- package/src/assets/wallets/sui.svg +0 -20
- package/src/core/XConnector.ts +0 -54
- package/src/core/XService.ts +0 -85
- package/src/core/index.ts +0 -2
- package/src/hooks/index.ts +0 -11
- package/src/hooks/useEthereumChainId.ts +0 -44
- package/src/hooks/useEvmSwitchChain.ts +0 -91
- package/src/hooks/useWalletProvider.ts +0 -206
- package/src/hooks/useXAccount.ts +0 -51
- package/src/hooks/useXAccounts.ts +0 -56
- package/src/hooks/useXBalances.ts +0 -65
- package/src/hooks/useXConnect.ts +0 -118
- package/src/hooks/useXConnection.ts +0 -72
- package/src/hooks/useXConnectors.ts +0 -72
- package/src/hooks/useXDisconnect.ts +0 -73
- package/src/hooks/useXService.ts +0 -8
- package/src/hooks/useXSignMessage.ts +0 -82
- package/src/index.ts +0 -19
- package/src/types/index.ts +0 -22
- package/src/useXWagmiStore.ts +0 -116
- package/src/utils/index.ts +0 -21
- package/src/xchains/bitcoin/BitcoinXConnector.ts +0 -34
- package/src/xchains/bitcoin/BitcoinXService.ts +0 -40
- package/src/xchains/bitcoin/OKXXConnector.ts +0 -117
- package/src/xchains/bitcoin/UnisatXConnector.ts +0 -117
- package/src/xchains/bitcoin/XverseXConnector.ts +0 -232
- package/src/xchains/bitcoin/index.ts +0 -7
- package/src/xchains/bitcoin/useBitcoinXConnectors.ts +0 -14
- package/src/xchains/evm/EvmXConnector.ts +0 -27
- package/src/xchains/evm/EvmXService.ts +0 -211
- package/src/xchains/evm/index.ts +0 -3
- package/src/xchains/icon/IconHanaXConnector.ts +0 -39
- package/src/xchains/icon/IconXService.ts +0 -117
- package/src/xchains/icon/actions.ts +0 -28
- package/src/xchains/icon/iconex/index.tsx +0 -46
- package/src/xchains/icon/index.ts +0 -2
- package/src/xchains/injective/InjectiveXConnector.ts +0 -60
- package/src/xchains/injective/InjectiveXService.ts +0 -62
- package/src/xchains/injective/actions.ts +0 -32
- package/src/xchains/injective/index.ts +0 -2
- package/src/xchains/near/NearXConnector.ts +0 -42
- package/src/xchains/near/NearXService.ts +0 -46
- package/src/xchains/near/useNearXConnectors.ts +0 -23
- package/src/xchains/solana/SolanaXConnector.ts +0 -26
- package/src/xchains/solana/SolanaXService.ts +0 -46
- package/src/xchains/solana/index.ts +0 -2
- package/src/xchains/stacks/StacksXConnector.ts +0 -63
- package/src/xchains/stacks/StacksXService.ts +0 -59
- package/src/xchains/stacks/constants.ts +0 -42
- package/src/xchains/stacks/index.ts +0 -4
- package/src/xchains/stacks/useStacksXConnectors.ts +0 -7
- package/src/xchains/stellar/CustomSorobanServer.ts +0 -93
- package/src/xchains/stellar/StellarWalletsKitXConnector.ts +0 -53
- package/src/xchains/stellar/StellarXService.ts +0 -93
- package/src/xchains/stellar/actions.ts +0 -24
- package/src/xchains/stellar/index.tsx +0 -2
- package/src/xchains/stellar/useStellarXConnectors.ts +0 -21
- package/src/xchains/stellar/utils.ts +0 -49
- package/src/xchains/sui/SuiXConnector.ts +0 -28
- package/src/xchains/sui/SuiXService.ts +0 -66
- package/src/xchains/sui/index.ts +0 -2
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Recipe: Setup
|
|
2
|
+
|
|
3
|
+
Install and wire `@sodax/wallet-sdk-react` into a React project. **Always do this first** — every other recipe assumes `SodaxWalletProvider` is mounted.
|
|
4
|
+
|
|
5
|
+
**Depends on:** None
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @sodax/wallet-sdk-react @tanstack/react-query
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Peer dependencies:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"react": ">=19",
|
|
20
|
+
"@tanstack/react-query": "5.x"
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Wire `SodaxWalletProvider`
|
|
27
|
+
|
|
28
|
+
Top-level keys on `SodaxWalletConfig` are chain-type slots — **omit a slot to skip mounting that adapter**, pass `{}` to mount with SDK defaults. `<QueryClientProvider>` must wrap `<SodaxWalletProvider>`.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
// providers.tsx
|
|
32
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
33
|
+
import { SodaxWalletProvider, type SodaxWalletConfig } from '@sodax/wallet-sdk-react';
|
|
34
|
+
import { ChainKeys } from '@sodax/types';
|
|
35
|
+
|
|
36
|
+
const queryClient = new QueryClient();
|
|
37
|
+
|
|
38
|
+
const walletConfig: SodaxWalletConfig = {
|
|
39
|
+
EVM: {
|
|
40
|
+
ssr: true, // Next.js — keep true for SSR-safe hydration. Drop for Vite/CRA.
|
|
41
|
+
chains: {
|
|
42
|
+
[ChainKeys.SONIC_MAINNET]: { rpcUrl: 'https://rpc.soniclabs.com' },
|
|
43
|
+
[ChainKeys.ETHEREUM_MAINNET]: { rpcUrl: 'https://ethereum-rpc.publicnode.com' },
|
|
44
|
+
[ChainKeys.BSC_MAINNET]: { rpcUrl: 'https://bsc-dataseed.binance.org' },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
ICON: {
|
|
48
|
+
chains: { [ChainKeys.ICON_MAINNET]: { rpcUrl: 'https://ctz.solidwallet.io/api/v3' } },
|
|
49
|
+
},
|
|
50
|
+
// BITCOIN: {}, // mount with SDK defaults
|
|
51
|
+
// SOLANA: { chains: { [ChainKeys.SOLANA_MAINNET]: { rpcUrl: '...' } } },
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
55
|
+
return (
|
|
56
|
+
<QueryClientProvider client={queryClient}>
|
|
57
|
+
<SodaxWalletProvider config={walletConfig}>{children}</SodaxWalletProvider>
|
|
58
|
+
</QueryClientProvider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Mount point per framework
|
|
66
|
+
|
|
67
|
+
| Framework | Where to mount `<Providers>` | `EVM.ssr` |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Next.js (App Router) | `app/layout.tsx`, inside `<body>`. Mark the providers file `'use client'`. Pair with [`recipes/ssr-setup.md`](../../migration/recipes/ssr-setup.md) if you need wagmi cookie hydration. | `true` |
|
|
70
|
+
| Vite + React | `main.tsx`, wrap `<App />` directly. | omit (defaults `false`) |
|
|
71
|
+
| Create React App | `index.tsx`, wrap `<App />` directly. | omit |
|
|
72
|
+
| Remix / Tanstack Start | Root route component, marked client-only. Same as Next.js. | `true` |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Chain-type slots
|
|
77
|
+
|
|
78
|
+
| Slot | React adapter mounted? | Notes |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `EVM` | ✅ wagmi | One connection across every configured EVM chain. WalletConnect opt-in via `EVM.walletConnect.projectId`. |
|
|
81
|
+
| `SOLANA` | ✅ `@solana/wallet-adapter-react` | `autoConnect` defaults to `true`. |
|
|
82
|
+
| `SUI` | ✅ `@mysten/dapp-kit` | `network` defaults to `'mainnet'`. |
|
|
83
|
+
| `BITCOIN` / `STELLAR` / `ICON` / `INJECTIVE` / `NEAR` / `STACKS` | ❌ no React adapter | Service auto-registered at mount. Connector list shipped per chain. |
|
|
84
|
+
|
|
85
|
+
For chain key constants and per-chain entry shapes, see [`../reference/chain-support.md`](../reference/chain-support.md).
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Enable WalletConnect (optional)
|
|
90
|
+
|
|
91
|
+
Add WalletConnect support for Fireblocks / Ledger Live / mobile-only EVM wallets by setting `EVM.walletConnect.projectId`:
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
const walletConfig: SodaxWalletConfig = {
|
|
95
|
+
EVM: {
|
|
96
|
+
ssr: true,
|
|
97
|
+
walletConnect: {
|
|
98
|
+
projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID!,
|
|
99
|
+
// Optional: showQrModal, metadata, qrModalOptions — see WalletConnectParameters
|
|
100
|
+
},
|
|
101
|
+
chains: { /* ... */ },
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Get a project ID from [cloud.walletconnect.com](https://cloud.walletconnect.com). Omit `walletConnect` entirely to disable — v2 falls back to EIP-6963 injected wallets only. Full pattern in [`walletconnect-setup.md`](./walletconnect-setup.md).
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Config is captured once on mount
|
|
111
|
+
|
|
112
|
+
`SodaxWalletProvider` freezes the `config` prop on first render. Subsequent re-renders with a new reference have **no effect**. To swap config at runtime, remount with a new `key`:
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<SodaxWalletProvider key={configVersion} config={walletConfig}>
|
|
116
|
+
{children}
|
|
117
|
+
</SodaxWalletProvider>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Pair with `@sodax/dapp-kit` (optional)
|
|
123
|
+
|
|
124
|
+
If you also use `@sodax/dapp-kit` for SDK feature hooks, mount `SodaxProvider` outermost:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
<SodaxProvider config={sodaxConfig}>
|
|
128
|
+
<QueryClientProvider client={queryClient}>
|
|
129
|
+
<SodaxWalletProvider config={walletConfig}>{children}</SodaxWalletProvider>
|
|
130
|
+
</QueryClientProvider>
|
|
131
|
+
</SodaxProvider>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`SodaxProvider` (from dapp-kit) wraps the lot. `QueryClientProvider` must wrap `SodaxWalletProvider` because hooks inside use React Query.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Verification
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# 1. Type check
|
|
142
|
+
pnpm checkTs
|
|
143
|
+
|
|
144
|
+
# 2. Provider mounted exactly once
|
|
145
|
+
grep -rn "SodaxWalletProvider" <user-src> --include="*.tsx" | grep -v "import" | wc -l
|
|
146
|
+
# expect 1
|
|
147
|
+
|
|
148
|
+
# 3. QueryClientProvider wraps SodaxWalletProvider
|
|
149
|
+
# (manual — confirm nesting in providers.tsx)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Next steps
|
|
155
|
+
|
|
156
|
+
- [`connect-button.md`](./connect-button.md) — single-chain connect/disconnect button
|
|
157
|
+
- [`multi-chain-modal.md`](./multi-chain-modal.md) — multi-chain headless wallet modal
|
|
158
|
+
- [`bridge-to-sdk.md`](./bridge-to-sdk.md) — pass `walletProvider` to `@sodax/sdk` calls
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Recipe: Sign Message
|
|
2
|
+
|
|
3
|
+
`useXSignMessage` is a single React Query mutation that delegates message signing to the connected wallet's per-chain `signMessage` implementation. The signature shape and encoding rules differ per chain — Bitcoin in particular auto-selects between BIP-322 and ECDSA based on the connected address type.
|
|
4
|
+
|
|
5
|
+
**Depends on:** [`setup.md`](./setup.md), one of [`connect-button.md`](./connect-button.md) / [`multi-chain-modal.md`](./multi-chain-modal.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Hook API
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { useXSignMessage } from '@sodax/wallet-sdk-react';
|
|
13
|
+
|
|
14
|
+
const sign = useXSignMessage();
|
|
15
|
+
|
|
16
|
+
const signature = await sign.mutateAsync({
|
|
17
|
+
xChainType: 'EVM',
|
|
18
|
+
message: 'Sign in to MyDApp\nNonce: abc123',
|
|
19
|
+
});
|
|
20
|
+
// signature: `0x${string}` | Uint8Array | string | undefined
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| Field | Type | Notes |
|
|
24
|
+
|-------|------|-------|
|
|
25
|
+
| `xChainType` | `ChainType` | Which chain to sign with (`'EVM'`, `'BITCOIN'`, …) |
|
|
26
|
+
| `message` | `string` | Plain UTF-8; per-chain wrappers handle encoding |
|
|
27
|
+
|
|
28
|
+
Return type is the discriminated union `` `0x${string}` | Uint8Array | string | undefined `` because each chain returns its native signature shape (hex for EVM, base64 for Stellar, base58 for Solana, etc.). Cast or branch on `xChainType` when consuming.
|
|
29
|
+
|
|
30
|
+
`undefined` is returned (not thrown) when the chain doesn't implement `signMessage` — currently only ICON. A one-time `console.warn` accompanies the `undefined`.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Per-chain support matrix
|
|
35
|
+
|
|
36
|
+
| Chain | Implementation | Signature shape |
|
|
37
|
+
|-------|----------------|-----------------|
|
|
38
|
+
| EVM | `signMessageAsync` from wagmi → personal_sign | `` `0x${string}` `` |
|
|
39
|
+
| Solana | `signMessage` from `@solana/wallet-adapter` | `Uint8Array` |
|
|
40
|
+
| Sui | `signPersonalMessage` from `@mysten/dapp-kit` | `string` (base64 signature + bytes) |
|
|
41
|
+
| Bitcoin | Auto-detect: BIP-322 (P2WPKH/P2TR) or ECDSA (P2SH/P2PKH) | `string` |
|
|
42
|
+
| Stellar | `walletsKit.signMessage` from `@creit.tech/stellar-wallets-kit` | `string` (base64) |
|
|
43
|
+
| Injective | `walletStrategy.signArbitrary` from `@injectivelabs/wallet-base` | `string` |
|
|
44
|
+
| NEAR | NEAR connector's `signMessage` | `string` |
|
|
45
|
+
| Stacks | `signMessage` from `@stacks/connect` | `string` |
|
|
46
|
+
| **ICON** | **Not supported** — Hana wallet does not expose a signing API | `undefined` |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Bitcoin — BIP-322 vs ECDSA auto-detect
|
|
51
|
+
|
|
52
|
+
Bitcoin's signing flow inspects the connected address and picks the right method automatically:
|
|
53
|
+
|
|
54
|
+
| Address type | Signing method | Connectors that support it |
|
|
55
|
+
|--------------|----------------|----------------------------|
|
|
56
|
+
| P2WPKH (native segwit, `bc1q…`) | BIP-322 | Unisat, Xverse, OKX |
|
|
57
|
+
| P2TR (taproot, `bc1p…`) | BIP-322 | Unisat, Xverse, OKX |
|
|
58
|
+
| P2SH (legacy multi-sig, `3…`) | ECDSA | Unisat, Xverse, OKX |
|
|
59
|
+
| P2PKH (legacy, `1…`) | ECDSA | Unisat, Xverse, OKX |
|
|
60
|
+
|
|
61
|
+
If a custom connector implements only one of the two methods, calling `signMessage` from a wrongly-typed address surfaces the error inline.
|
|
62
|
+
|
|
63
|
+
The same logic mirrors the SDK's `BitcoinSpokeProvider.authenticateWithWallet` — the React layer doesn't reinvent the dispatch.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## ICON not supported
|
|
68
|
+
|
|
69
|
+
Hana wallet on ICON exposes account / transaction APIs but no general-purpose `signMessage` endpoint. `sign.mutateAsync({ xChainType: 'ICON' })` returns `undefined` and logs:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
[useXSignMessage] signMessage not supported for chain "ICON"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If you need a signature on ICON for SIWE-style auth, fall back to a transaction-based proof or skip ICON in your auth flow.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Error handling
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
'use client';
|
|
83
|
+
|
|
84
|
+
import { useXSignMessage } from '@sodax/wallet-sdk-react';
|
|
85
|
+
|
|
86
|
+
export function SignButton() {
|
|
87
|
+
const sign = useXSignMessage();
|
|
88
|
+
|
|
89
|
+
const handleSign = async () => {
|
|
90
|
+
try {
|
|
91
|
+
const signature = await sign.mutateAsync({
|
|
92
|
+
xChainType: 'EVM',
|
|
93
|
+
message: 'Sign in',
|
|
94
|
+
});
|
|
95
|
+
if (!signature) {
|
|
96
|
+
// ICON or other unsupported chain
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
submitSignature(signature);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
// User rejection, wallet disconnect mid-sign, address mismatch, etc.
|
|
102
|
+
console.error('sign failed:', error);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<button onClick={handleSign} disabled={sign.isPending}>
|
|
108
|
+
{sign.isPending ? 'Waiting for wallet…' : 'Sign'}
|
|
109
|
+
</button>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Common error messages by chain:
|
|
115
|
+
|
|
116
|
+
| Chain | Typical error |
|
|
117
|
+
|-------|---------------|
|
|
118
|
+
| EVM | `User rejected the request` (MetaMask), `User denied message signature` (Rabby) |
|
|
119
|
+
| Solana | `WalletSignMessageError: User rejected the request` |
|
|
120
|
+
| Sui | `User rejected the signature request` |
|
|
121
|
+
| Bitcoin | `<connector.id> does not support BIP-322 signing` (mismatch with address type), `User canceled the request` |
|
|
122
|
+
| Stellar | `Stellar signature not found` |
|
|
123
|
+
| Injective | `Injective signature not found`, `Injective address not found` |
|
|
124
|
+
|
|
125
|
+
`mutation.error` reflects the latest failure; `mutation.isError` / `mutation.isPending` follow standard React Query semantics.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Verification
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 1. Type check
|
|
133
|
+
pnpm checkTs
|
|
134
|
+
|
|
135
|
+
# 2. Manual — connect wallet, click sign button, approve in wallet, confirm signature in handler
|
|
136
|
+
# 3. Manual — reject the signature, confirm error renders
|
|
137
|
+
```
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Recipe: Sub-Path Imports (Advanced)
|
|
2
|
+
|
|
3
|
+
When and how to use deep imports from `@sodax/wallet-sdk-react/xchains/<chain>`. Default to barrel imports — reach for sub-paths only when you need a concrete class for `instanceof` checks, custom connector lists, or chain-specific utilities not exposed through the public hooks.
|
|
4
|
+
|
|
5
|
+
**Depends on:** [`setup.md`](./setup.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## When you need it
|
|
10
|
+
|
|
11
|
+
The package barrel exports hooks, types, abstractions, and `SodaxWalletProvider`. Concrete chain-specific classes (`XverseXConnector`, `EvmXService`, `IconHanaXConnector`, …) live behind sub-paths to keep the barrel small. Reach for a sub-path import in three cases:
|
|
12
|
+
|
|
13
|
+
| Use case | Example |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Runtime type check on a connector | `if (connector instanceof XverseXConnector) { … }` |
|
|
16
|
+
| Override the default connector list for a chain | Pass `connectors: [new MyConnector()]` to `ChainTypeConfig` |
|
|
17
|
+
| Call a chain-specific method not on `IXConnector` | `xverseConnector.setAddressPurpose('payment')` |
|
|
18
|
+
|
|
19
|
+
If none of the above applies, **stick with barrel imports** — sub-paths are not part of the typical surface.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## `instanceof` check (most common)
|
|
24
|
+
|
|
25
|
+
Tag a connector by class to call methods specific to that wallet:
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { useXConnectors } from '@sodax/wallet-sdk-react';
|
|
29
|
+
import { XverseXConnector } from '@sodax/wallet-sdk-react/xchains/bitcoin';
|
|
30
|
+
|
|
31
|
+
function BitcoinConnectButton() {
|
|
32
|
+
const connectors = useXConnectors({ xChainType: 'BITCOIN' });
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<>
|
|
36
|
+
{connectors.map((connector) => (
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
key={connector.id}
|
|
40
|
+
onClick={async () => {
|
|
41
|
+
// Pre-configure Xverse before connect
|
|
42
|
+
if (connector instanceof XverseXConnector) {
|
|
43
|
+
connector.setAddressPurpose('payment');
|
|
44
|
+
}
|
|
45
|
+
await connector.connect();
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
{connector.name}
|
|
49
|
+
</button>
|
|
50
|
+
))}
|
|
51
|
+
</>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The barrel-typed `IXConnector` exposes only `connect()` / `disconnect()` / metadata fields. To reach `setAddressPurpose` (or any class-specific method), narrow via `instanceof` after a sub-path import.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Custom connector list
|
|
61
|
+
|
|
62
|
+
Override the default connectors a chain ships with by passing `connectors` on the `ChainTypeConfig`:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import type { SodaxWalletConfig } from '@sodax/wallet-sdk-react';
|
|
66
|
+
import { XverseXConnector, UnisatXConnector } from '@sodax/wallet-sdk-react/xchains/bitcoin';
|
|
67
|
+
|
|
68
|
+
const walletConfig: SodaxWalletConfig = {
|
|
69
|
+
BITCOIN: {
|
|
70
|
+
// Only mount Xverse + Unisat — drop the OKX connector that ships by default.
|
|
71
|
+
connectors: [new XverseXConnector(), new UnisatXConnector()],
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Use sparingly — the default lists are tuned per chain. Override only when you need to remove a connector you do not support, or add a custom one you implemented yourself.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Available sub-paths
|
|
81
|
+
|
|
82
|
+
For the per-chain symbol list, see [`../reference/api-surface.md`](../reference/api-surface.md) § "Sub-path exports". That table is the single source of truth — `scripts/check-ai-exported.sh` validates it stays in sync with `src/xchains/`.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Verification
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# 1. Type check
|
|
90
|
+
pnpm checkTs
|
|
91
|
+
|
|
92
|
+
# 2. Sub-path imports must resolve to a real chain folder
|
|
93
|
+
grep -rnE "from '@sodax/wallet-sdk-react/xchains/[a-z]+'" <user-src>
|
|
94
|
+
# Each match's <chain> must be one of: bitcoin, evm, icon, injective, near, solana, stacks, stellar, sui
|
|
95
|
+
```
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Recipe: Switch EVM Chain
|
|
2
|
+
|
|
3
|
+
A single wagmi connection covers **every configured EVM network** (Sonic, Ethereum, Arbitrum, Base, BSC, Optimism, Polygon, Avalanche, etc.). The user picks a wallet once; switching the **active network** is a separate concern handled by `useEvmSwitchChain`.
|
|
4
|
+
|
|
5
|
+
**Depends on:** [`setup.md`](./setup.md), [`connect-button.md`](./connect-button.md) or [`multi-chain-modal.md`](./multi-chain-modal.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
When you call `sodax.swaps.swap({ params: { srcChainKey: ChainKeys.BSC_MAINNET, ... }, walletProvider })`, the wallet provider must be **on BSC at signing time** — wagmi will reject the tx otherwise. But wagmi remembers the last network the user selected, so a user who connected via MetaMask on Ethereum and then opened your dApp's BSC swap form needs to switch first.
|
|
12
|
+
|
|
13
|
+
`useEvmSwitchChain` reads the connected EVM wallet's current chain id, compares against the chain id implied by `srcChainKey`, and exposes:
|
|
14
|
+
|
|
15
|
+
- `isWrongChain: boolean` — render a "Switch to BSC" CTA when `true`
|
|
16
|
+
- `handleSwitchChain()` — triggers wagmi's `switchChain()` (or `wallet_switchEthereumChain` for Injective MetaMask)
|
|
17
|
+
|
|
18
|
+
Without this hook you'd have to import wagmi directly and replicate the logic per-chain.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Hook API
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { useEvmSwitchChain } from '@sodax/wallet-sdk-react';
|
|
26
|
+
import { ChainKeys } from '@sodax/types';
|
|
27
|
+
|
|
28
|
+
const { isWrongChain, handleSwitchChain } = useEvmSwitchChain({
|
|
29
|
+
xChainId: ChainKeys.BSC_MAINNET,
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Field | Type | Behavior |
|
|
34
|
+
|-------|------|----------|
|
|
35
|
+
| `isWrongChain` | `boolean` | `true` when the wallet's active chain id doesn't match `xChainId`. Always `false` for non-EVM/Injective chain ids. |
|
|
36
|
+
| `handleSwitchChain` | `() => void` | Triggers the network switch. No-op for chain ids that aren't EVM or Injective. |
|
|
37
|
+
|
|
38
|
+
The hook never throws — `handleSwitchChain` returns synchronously and lets wagmi (or `wallet_switchEthereumChain`) own the user-rejection error path.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Standard EVM switch flow
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
'use client';
|
|
46
|
+
|
|
47
|
+
import { useEvmSwitchChain, useWalletProvider, useXAccount } from '@sodax/wallet-sdk-react';
|
|
48
|
+
import { ChainKeys } from '@sodax/types';
|
|
49
|
+
|
|
50
|
+
export function BscSwapButton() {
|
|
51
|
+
const account = useXAccount({ xChainType: 'EVM' });
|
|
52
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET });
|
|
53
|
+
const { isWrongChain, handleSwitchChain } = useEvmSwitchChain({
|
|
54
|
+
xChainId: ChainKeys.BSC_MAINNET,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (!account.address || !walletProvider) {
|
|
58
|
+
return <ConnectCta />;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (isWrongChain) {
|
|
62
|
+
return <button onClick={handleSwitchChain}>Switch to BSC</button>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return <button onClick={() => doSwap(walletProvider)}>Swap on BSC</button>;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`useSwitchChain` opens the wallet's network-switch popup; wagmi handles the chain-config-not-added flow (most wallets prompt to add the chain if it's missing).
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Pattern: gate every cross-chain action
|
|
74
|
+
|
|
75
|
+
For dApps where the source chain depends on user input (e.g. a swap form with a "from chain" picker), wire `useEvmSwitchChain` against the **selected** chain id:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
function SwapForm() {
|
|
79
|
+
const [srcChainKey, setSrcChainKey] = useState<SpokeChainKey>(ChainKeys.SONIC_MAINNET);
|
|
80
|
+
const { isWrongChain, handleSwitchChain } = useEvmSwitchChain({ xChainId: srcChainKey });
|
|
81
|
+
const walletProvider = useWalletProvider({ xChainId: srcChainKey });
|
|
82
|
+
|
|
83
|
+
const buttonState =
|
|
84
|
+
!walletProvider ? 'connect' :
|
|
85
|
+
isWrongChain ? 'switch' :
|
|
86
|
+
'swap';
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<>
|
|
90
|
+
<ChainSelect value={srcChainKey} onChange={setSrcChainKey} />
|
|
91
|
+
{buttonState === 'connect' && <ConnectCta />}
|
|
92
|
+
{buttonState === 'switch' && <button onClick={handleSwitchChain}>Switch chain</button>}
|
|
93
|
+
{buttonState === 'swap' && <button onClick={() => doSwap(walletProvider)}>Swap</button>}
|
|
94
|
+
</>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Re-renders on `srcChainKey` change automatically — no manual reset needed.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Injective MetaMask special case
|
|
104
|
+
|
|
105
|
+
Injective offers MetaMask as a wallet option (in addition to Keplr, Leap). When MetaMask is the active Injective wallet, **the underlying Ethereum chain id must be mainnet (`1`)** — Injective uses MetaMask's `personal_sign` infrastructure which is bound to whatever EVM network the wallet is currently on.
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
const { isWrongChain, handleSwitchChain } = useEvmSwitchChain({
|
|
109
|
+
xChainId: ChainKeys.INJECTIVE_MAINNET,
|
|
110
|
+
});
|
|
111
|
+
// isWrongChain === true if user is on Injective via MetaMask AND active EVM chain is not mainnet (1)
|
|
112
|
+
// handleSwitchChain calls wallet_switchEthereumChain to chain id 0x1
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Keplr and Leap on Injective don't have this constraint — `isWrongChain` is `false` for those wallets regardless of network state.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Safe to call when EVM is disabled
|
|
120
|
+
|
|
121
|
+
`useEvmSwitchChain` checks `useEnabledChains()` and returns a no-op result `{ isWrongChain: false, handleSwitchChain: () => {} }` when the EVM slot isn't mounted in `SodaxWalletProvider` config. Calling wagmi's hooks outside a `WagmiProvider` would throw — the early-return lets components opt-in to a "switch chain" CTA without checking EVM-enabled themselves at every call site.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Verification
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# 1. Type check
|
|
129
|
+
pnpm checkTs
|
|
130
|
+
|
|
131
|
+
# 2. Manual — connect MetaMask on Ethereum, open BSC swap form, confirm Switch button appears
|
|
132
|
+
# 3. Manual — click Switch, approve in MetaMask, confirm Swap button replaces it
|
|
133
|
+
# 4. Manual — switch to Polygon manually (in MetaMask), confirm Switch button reappears for BSC form
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Reference
|
|
139
|
+
|
|
140
|
+
- [wagmi `useSwitchChain`](https://wagmi.sh/react/api/hooks/useSwitchChain) — underlying hook
|
|
141
|
+
- [EIP-3326 — `wallet_switchEthereumChain`](https://eips.ethereum.org/EIPS/eip-3326) — RPC method spec
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Recipe: WalletConnect Setup (EVM only)
|
|
2
|
+
|
|
3
|
+
Enable WalletConnect protocol on the EVM slot for partners using enterprise custody (Fireblocks, Ledger Live, mobile-only wallets). Default EVM discovery (EIP-6963) only finds browser-extension wallets — WalletConnect lets users pair via QR / deep-link.
|
|
4
|
+
|
|
5
|
+
**Depends on:** [`setup.md`](./setup.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
| Scenario | Need WalletConnect? |
|
|
12
|
+
|----------|---------------------|
|
|
13
|
+
| MetaMask / Hana / Rabby browser extension | ❌ — EIP-6963 covers them |
|
|
14
|
+
| Enterprise custody wallets (e.g. Fireblocks, Safe) | ✅ |
|
|
15
|
+
| Ledger Live | ✅ |
|
|
16
|
+
| MetaMask Mobile / Trust / Rainbow (paired via QR) | ✅ |
|
|
17
|
+
| Coinbase Smart Wallet | ✅ (fallback path) |
|
|
18
|
+
|
|
19
|
+
If your dApp only targets desktop browser-extension wallets, omit `walletConnect` entirely.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Get a WalletConnect Cloud project id
|
|
24
|
+
|
|
25
|
+
Sign up at [https://cloud.walletconnect.com](https://cloud.walletconnect.com) and copy your project id. Add it to `.env`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
NEXT_PUBLIC_WC_PROJECT_ID=your-project-id
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. Add `walletConnect` to the `EVM` slot
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { type SodaxWalletConfig } from '@sodax/wallet-sdk-react';
|
|
37
|
+
import { ChainKeys } from '@sodax/types';
|
|
38
|
+
|
|
39
|
+
const walletConfig: SodaxWalletConfig = {
|
|
40
|
+
EVM: {
|
|
41
|
+
ssr: true,
|
|
42
|
+
chains: {
|
|
43
|
+
[ChainKeys.SONIC_MAINNET]: { rpcUrl: 'https://rpc.soniclabs.com' },
|
|
44
|
+
[ChainKeys.ARBITRUM_MAINNET]: { rpcUrl: 'https://arb1.arbitrum.io/rpc' },
|
|
45
|
+
},
|
|
46
|
+
walletConnect: {
|
|
47
|
+
projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID!,
|
|
48
|
+
// showQrModal: true is the default — wagmi/WalletConnect own the QR display
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A WalletConnect connector now surfaces alongside EIP-6963 wallets. `useXConnectors({ xChainType: 'EVM' })` returns it with `id === 'walletConnect'`. **No UI changes required** — your existing connect-button or modal already handles it.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 3. Restrict the QR modal to a specific wallet (optional)
|
|
59
|
+
|
|
60
|
+
To show **only** one wallet in the WalletConnect modal (e.g. when integrating with a single enterprise custody provider), filter the WalletConnect Explorer list:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const walletConfig: SodaxWalletConfig = {
|
|
64
|
+
EVM: {
|
|
65
|
+
walletConnect: {
|
|
66
|
+
projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID!,
|
|
67
|
+
qrModalOptions: {
|
|
68
|
+
explorerRecommendedWalletIds: [
|
|
69
|
+
'<target-wallet-id>', // hex from WalletConnect Explorer
|
|
70
|
+
],
|
|
71
|
+
explorerExcludedWalletIds: 'ALL', // hide everything except recommended
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Find wallet IDs at the [WalletConnect Explorer](https://walletconnect.com/explorer) — they're the long hex strings in the URL, not the human names. Default (no `qrModalOptions`) shows the full WalletConnect wallet list.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 4. Hide the Sodax modal during WalletConnect QR
|
|
83
|
+
|
|
84
|
+
When the user picks the WalletConnect connector, wagmi opens its own QR modal — two dialogs would stack. Detect WC by connector id and render `null`:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { useWalletModal } from '@sodax/wallet-sdk-react';
|
|
88
|
+
|
|
89
|
+
const modal = useWalletModal();
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
modal.state.kind === 'connecting' &&
|
|
93
|
+
modal.state.connector.id === 'walletConnect'
|
|
94
|
+
) {
|
|
95
|
+
return null; // wagmi's QR modal owns the screen
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The `useWalletModal` state machine handles the `connecting → success | error` transition normally — only the rendering is conditionally blanked.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Missing `projectId` — silent skip
|
|
104
|
+
|
|
105
|
+
Setting `walletConnect: {}` without a `projectId` (or with an empty string) **silently skips** the WalletConnect connector and logs a warning:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
[wallet-sdk-react] walletConnect.projectId is required — WalletConnect connector skipped.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
EIP-6963 wallets continue to work normally — the dApp degrades gracefully. This intentionally avoids forcing local-dev environments to plumb the env var.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## EVM-only
|
|
116
|
+
|
|
117
|
+
The `walletConnect` field only exists on the `EVM` slot. Solana, Bitcoin, etc. use their own native wallet adapters and don't share the WalletConnect protocol layer. Don't attempt `SOLANA: { walletConnect: ... }` — TypeScript will reject it.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Verification
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# 1. Type check
|
|
125
|
+
pnpm checkTs
|
|
126
|
+
|
|
127
|
+
# 2. Confirm walletConnect projectId is set
|
|
128
|
+
grep -rn "walletConnect" <user-src> | grep -i "projectId"
|
|
129
|
+
# expect at least one match
|
|
130
|
+
|
|
131
|
+
# 3. Manual — open connect modal, confirm WalletConnect option appears alongside extension wallets
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Reference
|
|
137
|
+
|
|
138
|
+
- [wagmi `WalletConnectParameters`](https://wagmi.sh/core/api/connectors/walletConnect) — full options reference
|
|
139
|
+
- [WalletConnect Cloud](https://cloud.walletconnect.com) — get a `projectId`
|