@sodax/wallet-sdk-react 1.5.6-beta → 2.0.0-rc.1

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.
Files changed (211) hide show
  1. package/README.md +103 -145
  2. package/ai-exported/AGENTS.md +122 -0
  3. package/ai-exported/integration/README.md +102 -0
  4. package/ai-exported/integration/ai-rules.md +136 -0
  5. package/ai-exported/integration/architecture.md +181 -0
  6. package/ai-exported/integration/examples/01-minimal-evm.tsx +75 -0
  7. package/ai-exported/integration/examples/02-multi-chain-modal.tsx +169 -0
  8. package/ai-exported/integration/examples/03-nextjs-app-router.tsx +99 -0
  9. package/ai-exported/integration/examples/04-walletconnect-setup.tsx +89 -0
  10. package/ai-exported/integration/examples/README.md +29 -0
  11. package/ai-exported/integration/recipes/batch-operations.md +223 -0
  12. package/ai-exported/integration/recipes/bridge-to-sdk.md +164 -0
  13. package/ai-exported/integration/recipes/chain-detection.md +254 -0
  14. package/ai-exported/integration/recipes/connect-button.md +156 -0
  15. package/ai-exported/integration/recipes/multi-chain-modal.md +199 -0
  16. package/ai-exported/integration/recipes/setup.md +158 -0
  17. package/ai-exported/integration/recipes/sign-message.md +137 -0
  18. package/ai-exported/integration/recipes/sub-path-imports.md +95 -0
  19. package/ai-exported/integration/recipes/switch-chain.md +141 -0
  20. package/ai-exported/integration/recipes/walletconnect-setup.md +139 -0
  21. package/ai-exported/integration/reference/api-surface.md +175 -0
  22. package/ai-exported/integration/reference/chain-support.md +78 -0
  23. package/ai-exported/integration/reference/connectors.md +74 -0
  24. package/ai-exported/integration/reference/hooks.md +204 -0
  25. package/ai-exported/integration/reference/wallet-brands.md +106 -0
  26. package/ai-exported/migration/README.md +49 -0
  27. package/ai-exported/migration/ai-rules.md +144 -0
  28. package/ai-exported/migration/breaking-changes.md +305 -0
  29. package/ai-exported/migration/checklist.md +159 -0
  30. package/ai-exported/migration/recipes/connect-button.md +166 -0
  31. package/ai-exported/migration/recipes/multi-chain-modal.md +244 -0
  32. package/ai-exported/migration/recipes/ssr-setup.md +162 -0
  33. package/ai-exported/migration/recipes/walletconnect-migration.md +168 -0
  34. package/ai-exported/migration/reference/components.md +73 -0
  35. package/ai-exported/migration/reference/config.md +307 -0
  36. package/ai-exported/migration/reference/hooks.md +278 -0
  37. package/ai-exported/migration/reference/imports.md +157 -0
  38. package/dist/XConnector-B9YQTVJ4.d.ts +146 -0
  39. package/dist/chunk-2BOUGCJ7.mjs +150 -0
  40. package/dist/chunk-2BOUGCJ7.mjs.map +1 -0
  41. package/dist/chunk-66BAUK56.mjs +202 -0
  42. package/dist/chunk-66BAUK56.mjs.map +1 -0
  43. package/dist/chunk-7ULB6DW4.mjs +102 -0
  44. package/dist/chunk-7ULB6DW4.mjs.map +1 -0
  45. package/dist/chunk-BKJB527E.mjs +125 -0
  46. package/dist/chunk-BKJB527E.mjs.map +1 -0
  47. package/dist/chunk-BXJLBR4G.mjs +88 -0
  48. package/dist/chunk-BXJLBR4G.mjs.map +1 -0
  49. package/dist/chunk-E5IAZ7E6.mjs +186 -0
  50. package/dist/chunk-E5IAZ7E6.mjs.map +1 -0
  51. package/dist/chunk-MAQ47Q52.mjs +33 -0
  52. package/dist/chunk-MAQ47Q52.mjs.map +1 -0
  53. package/dist/chunk-MXZVF5HR.mjs +34 -0
  54. package/dist/chunk-MXZVF5HR.mjs.map +1 -0
  55. package/dist/chunk-N5A2TMF6.mjs +33 -0
  56. package/dist/chunk-N5A2TMF6.mjs.map +1 -0
  57. package/dist/chunk-NY7U7OJW.mjs +64 -0
  58. package/dist/chunk-NY7U7OJW.mjs.map +1 -0
  59. package/dist/chunk-PJLEJVAU.mjs +140 -0
  60. package/dist/chunk-PJLEJVAU.mjs.map +1 -0
  61. package/dist/chunk-PLCA4ZDJ.mjs +1585 -0
  62. package/dist/chunk-PLCA4ZDJ.mjs.map +1 -0
  63. package/dist/chunk-TZMKDXFA.mjs +3 -0
  64. package/dist/chunk-TZMKDXFA.mjs.map +1 -0
  65. package/dist/chunk-X2MHIWXO.mjs +100 -0
  66. package/dist/chunk-X2MHIWXO.mjs.map +1 -0
  67. package/dist/chunk-XZ7CHO2S.mjs +41 -0
  68. package/dist/chunk-XZ7CHO2S.mjs.map +1 -0
  69. package/dist/config-OlnzyEUE.d.ts +146 -0
  70. package/dist/index.cjs +2784 -1594
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/index.d.ts +768 -1498
  73. package/dist/index.mjs +463 -2004
  74. package/dist/index.mjs.map +1 -1
  75. package/dist/xchains/bitcoin/index.cjs +1927 -0
  76. package/dist/xchains/bitcoin/index.cjs.map +1 -0
  77. package/dist/xchains/bitcoin/index.d.ts +125 -0
  78. package/dist/xchains/bitcoin/index.mjs +16 -0
  79. package/dist/xchains/bitcoin/index.mjs.map +1 -0
  80. package/dist/xchains/evm/index.cjs +316 -0
  81. package/dist/xchains/evm/index.cjs.map +1 -0
  82. package/dist/xchains/evm/index.d.ts +39 -0
  83. package/dist/xchains/evm/index.mjs +5 -0
  84. package/dist/xchains/evm/index.mjs.map +1 -0
  85. package/dist/xchains/icon/index.cjs +311 -0
  86. package/dist/xchains/icon/index.cjs.map +1 -0
  87. package/dist/xchains/icon/index.d.ts +37 -0
  88. package/dist/xchains/icon/index.mjs +7 -0
  89. package/dist/xchains/icon/index.mjs.map +1 -0
  90. package/dist/xchains/injective/index.cjs +223 -0
  91. package/dist/xchains/injective/index.cjs.map +1 -0
  92. package/dist/xchains/injective/index.d.ts +35 -0
  93. package/dist/xchains/injective/index.mjs +5 -0
  94. package/dist/xchains/injective/index.mjs.map +1 -0
  95. package/dist/xchains/near/index.cjs +190 -0
  96. package/dist/xchains/near/index.cjs.map +1 -0
  97. package/dist/xchains/near/index.d.ts +34 -0
  98. package/dist/xchains/near/index.mjs +6 -0
  99. package/dist/xchains/near/index.mjs.map +1 -0
  100. package/dist/xchains/solana/index.cjs +186 -0
  101. package/dist/xchains/solana/index.cjs.map +1 -0
  102. package/dist/xchains/solana/index.d.ts +26 -0
  103. package/dist/xchains/solana/index.mjs +7 -0
  104. package/dist/xchains/solana/index.mjs.map +1 -0
  105. package/dist/xchains/stacks/index.cjs +240 -0
  106. package/dist/xchains/stacks/index.cjs.map +1 -0
  107. package/dist/xchains/stacks/index.d.ts +36 -0
  108. package/dist/xchains/stacks/index.mjs +5 -0
  109. package/dist/xchains/stacks/index.mjs.map +1 -0
  110. package/dist/xchains/stellar/index.cjs +322 -0
  111. package/dist/xchains/stellar/index.cjs.map +1 -0
  112. package/dist/xchains/stellar/index.d.ts +44 -0
  113. package/dist/xchains/stellar/index.mjs +6 -0
  114. package/dist/xchains/stellar/index.mjs.map +1 -0
  115. package/dist/xchains/sui/index.cjs +248 -0
  116. package/dist/xchains/sui/index.cjs.map +1 -0
  117. package/dist/xchains/sui/index.d.ts +37 -0
  118. package/dist/xchains/sui/index.mjs +7 -0
  119. package/dist/xchains/sui/index.mjs.map +1 -0
  120. package/docs/ADDING_A_NEW_CHAIN.md +440 -0
  121. package/docs/ARCHITECTURE.md +291 -0
  122. package/docs/BATCH_OPERATIONS.md +267 -0
  123. package/docs/CHAIN_DETECTION.md +216 -0
  124. package/docs/CONFIGURE_PROVIDER.md +360 -0
  125. package/docs/CONNECTORS.md +247 -0
  126. package/docs/CONNECT_FLOW.md +276 -0
  127. package/docs/EVM_SWITCH_CHAIN.md +161 -0
  128. package/docs/SIGN_MESSAGE.md +213 -0
  129. package/docs/SUB_PATH_EXPORTS.md +246 -0
  130. package/docs/WALLETCONNECT.md +154 -0
  131. package/docs/WALLET_MODAL.md +331 -0
  132. package/docs/WALLET_PROVIDER_BRIDGE.md +226 -0
  133. package/package.json +34 -9
  134. package/skills/SKILLS.md +84 -0
  135. package/skills/bridge-to-sdk.md +148 -0
  136. package/skills/connect-button.md +116 -0
  137. package/skills/evm-only-walletconnect.md +111 -0
  138. package/skills/multi-chain-modal.md +178 -0
  139. package/skills/setup.md +107 -0
  140. package/dist/index.d.cts +0 -1579
  141. package/src/Hydrate.ts +0 -65
  142. package/src/SodaxWalletProvider.tsx +0 -97
  143. package/src/actions/getXChainType.ts +0 -8
  144. package/src/actions/getXService.ts +0 -33
  145. package/src/actions/index.ts +0 -2
  146. package/src/assets/wallets/hana.svg +0 -6
  147. package/src/assets/wallets/havah.svg +0 -76
  148. package/src/assets/wallets/keplr.svg +0 -30
  149. package/src/assets/wallets/metamask.svg +0 -60
  150. package/src/assets/wallets/phantom.svg +0 -4
  151. package/src/assets/wallets/sui.svg +0 -20
  152. package/src/core/XConnector.ts +0 -54
  153. package/src/core/XService.ts +0 -85
  154. package/src/core/index.ts +0 -2
  155. package/src/hooks/index.ts +0 -11
  156. package/src/hooks/useEthereumChainId.ts +0 -44
  157. package/src/hooks/useEvmSwitchChain.ts +0 -91
  158. package/src/hooks/useWalletProvider.ts +0 -206
  159. package/src/hooks/useXAccount.ts +0 -51
  160. package/src/hooks/useXAccounts.ts +0 -56
  161. package/src/hooks/useXBalances.ts +0 -65
  162. package/src/hooks/useXConnect.ts +0 -118
  163. package/src/hooks/useXConnection.ts +0 -72
  164. package/src/hooks/useXConnectors.ts +0 -72
  165. package/src/hooks/useXDisconnect.ts +0 -73
  166. package/src/hooks/useXService.ts +0 -8
  167. package/src/hooks/useXSignMessage.ts +0 -82
  168. package/src/index.ts +0 -19
  169. package/src/types/index.ts +0 -22
  170. package/src/useXWagmiStore.ts +0 -116
  171. package/src/utils/index.ts +0 -21
  172. package/src/xchains/bitcoin/BitcoinXConnector.ts +0 -34
  173. package/src/xchains/bitcoin/BitcoinXService.ts +0 -40
  174. package/src/xchains/bitcoin/OKXXConnector.ts +0 -117
  175. package/src/xchains/bitcoin/UnisatXConnector.ts +0 -117
  176. package/src/xchains/bitcoin/XverseXConnector.ts +0 -232
  177. package/src/xchains/bitcoin/index.ts +0 -7
  178. package/src/xchains/bitcoin/useBitcoinXConnectors.ts +0 -14
  179. package/src/xchains/evm/EvmXConnector.ts +0 -27
  180. package/src/xchains/evm/EvmXService.ts +0 -211
  181. package/src/xchains/evm/index.ts +0 -3
  182. package/src/xchains/icon/IconHanaXConnector.ts +0 -39
  183. package/src/xchains/icon/IconXService.ts +0 -117
  184. package/src/xchains/icon/actions.ts +0 -28
  185. package/src/xchains/icon/iconex/index.tsx +0 -46
  186. package/src/xchains/icon/index.ts +0 -2
  187. package/src/xchains/injective/InjectiveXConnector.ts +0 -60
  188. package/src/xchains/injective/InjectiveXService.ts +0 -62
  189. package/src/xchains/injective/actions.ts +0 -32
  190. package/src/xchains/injective/index.ts +0 -2
  191. package/src/xchains/near/NearXConnector.ts +0 -42
  192. package/src/xchains/near/NearXService.ts +0 -46
  193. package/src/xchains/near/useNearXConnectors.ts +0 -23
  194. package/src/xchains/solana/SolanaXConnector.ts +0 -26
  195. package/src/xchains/solana/SolanaXService.ts +0 -46
  196. package/src/xchains/solana/index.ts +0 -2
  197. package/src/xchains/stacks/StacksXConnector.ts +0 -63
  198. package/src/xchains/stacks/StacksXService.ts +0 -59
  199. package/src/xchains/stacks/constants.ts +0 -42
  200. package/src/xchains/stacks/index.ts +0 -4
  201. package/src/xchains/stacks/useStacksXConnectors.ts +0 -7
  202. package/src/xchains/stellar/CustomSorobanServer.ts +0 -93
  203. package/src/xchains/stellar/StellarWalletsKitXConnector.ts +0 -53
  204. package/src/xchains/stellar/StellarXService.ts +0 -93
  205. package/src/xchains/stellar/actions.ts +0 -24
  206. package/src/xchains/stellar/index.tsx +0 -2
  207. package/src/xchains/stellar/useStellarXConnectors.ts +0 -21
  208. package/src/xchains/stellar/utils.ts +0 -49
  209. package/src/xchains/sui/SuiXConnector.ts +0 -28
  210. package/src/xchains/sui/SuiXService.ts +0 -66
  211. package/src/xchains/sui/index.ts +0 -2
@@ -0,0 +1,89 @@
1
+ /**
2
+ * WalletConnect setup — adds the WalletConnect connector to the EVM modal.
3
+ * For dApps that target users on mobile-only or enterprise custody wallets
4
+ * (Ledger Live, Safe, Fireblocks, ...) which cannot install browser extensions.
5
+ *
6
+ * Get a projectId at https://cloud.walletconnect.com
7
+ *
8
+ * To narrow the WalletConnect modal to ONE specific wallet (e.g. an enterprise
9
+ * custody integration), see the commented `qrModalOptions` block below — fill
10
+ * in the target wallet id from https://walletconnect.com/explorer.
11
+ */
12
+
13
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
14
+ import {
15
+ SodaxWalletProvider,
16
+ type SodaxWalletConfig,
17
+ useWalletModal,
18
+ useXConnectors,
19
+ useXAccount,
20
+ useXDisconnect,
21
+ } from '@sodax/wallet-sdk-react';
22
+ import { ChainKeys } from '@sodax/types';
23
+
24
+ const queryClient = new QueryClient();
25
+
26
+ const walletConfig: SodaxWalletConfig = {
27
+ EVM: {
28
+ ssr: true,
29
+ chains: {
30
+ [ChainKeys.SONIC_MAINNET]: { rpcUrl: 'https://rpc.soniclabs.com' },
31
+ [ChainKeys.ETHEREUM_MAINNET]: { rpcUrl: 'https://ethereum-rpc.publicnode.com' },
32
+ [ChainKeys.ARBITRUM_MAINNET]: { rpcUrl: 'https://arb1.arbitrum.io/rpc' },
33
+ },
34
+ walletConnect: {
35
+ projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID ?? '',
36
+ // Optional — restrict the WalletConnect QR modal to a specific wallet:
37
+ //
38
+ // qrModalOptions: {
39
+ // explorerRecommendedWalletIds: ['<target-wallet-id-from-walletconnect-explorer>'],
40
+ // explorerExcludedWalletIds: 'ALL', // hide everything except recommended
41
+ // },
42
+ },
43
+ },
44
+ };
45
+
46
+ export function App() {
47
+ return (
48
+ <QueryClientProvider client={queryClient}>
49
+ <SodaxWalletProvider config={walletConfig}>
50
+ <ConnectWithWalletConnect />
51
+ </SodaxWalletProvider>
52
+ </QueryClientProvider>
53
+ );
54
+ }
55
+
56
+ function ConnectWithWalletConnect() {
57
+ const modal = useWalletModal();
58
+ const connectors = useXConnectors({ xChainType: 'EVM' });
59
+ const account = useXAccount({ xChainType: 'EVM' });
60
+ const disconnect = useXDisconnect();
61
+
62
+ const wcConnector = connectors.find((c) => c.id === 'walletConnect');
63
+
64
+ // Hide the modal while wagmi/WalletConnect's QR modal owns the screen
65
+ if (modal.state.kind === 'connecting' && modal.state.connector.id === 'walletConnect') {
66
+ return null;
67
+ }
68
+
69
+ if (account.address) {
70
+ return (
71
+ <div>
72
+ <code>{account.address}</code>
73
+ <button type="button" onClick={() => disconnect({ xChainType: 'EVM' })}>
74
+ Disconnect
75
+ </button>
76
+ </div>
77
+ );
78
+ }
79
+
80
+ if (!wcConnector) {
81
+ return <p>WalletConnect not configured — set NEXT_PUBLIC_WC_PROJECT_ID</p>;
82
+ }
83
+
84
+ return (
85
+ <button type="button" onClick={() => modal.selectWallet(wcConnector)}>
86
+ Connect via WalletConnect
87
+ </button>
88
+ );
89
+ }
@@ -0,0 +1,29 @@
1
+ # Examples
2
+
3
+ Copy-paste-runnable code examples. Each file is complete — drop it into a fresh React 19 project with `@sodax/wallet-sdk-react` + `@tanstack/react-query` installed and it works.
4
+
5
+ For narrative + step-by-step explanation, see [`../recipes/`](../recipes/). Examples here are pure code with minimal comments.
6
+
7
+ | File | Use case | Lines |
8
+ |---|---|---|
9
+ | [`01-minimal-evm.tsx`](./01-minimal-evm.tsx) | Smallest working setup — provider + 1 connect button | ~50 |
10
+ | [`02-multi-chain-modal.tsx`](./02-multi-chain-modal.tsx) | Headless wallet modal with chain → connector → connecting flow | ~120 |
11
+ | [`03-nextjs-app-router.tsx`](./03-nextjs-app-router.tsx) | Next.js 15 App Router setup (SSR + `'use client'`) | ~60 |
12
+ | [`04-walletconnect-setup.tsx`](./04-walletconnect-setup.tsx) | WalletConnect connector setup (with optional single-wallet filter) | ~50 |
13
+
14
+ ## Conventions
15
+
16
+ - All files use TypeScript (`.tsx`).
17
+ - All consumer components have `'use client'` (Next.js compatible).
18
+ - `walletConfig` is defined as a **module-level constant** — never created inside a component (the provider freezes config on first render).
19
+ - `QueryClient` is also a module-level constant — one client per app, shared across providers.
20
+ - Examples use `<button>`, `<select>`, `<dialog>` etc. directly — bring your own UI library.
21
+
22
+ ## Running an example
23
+
24
+ ```bash
25
+ pnpm add @sodax/wallet-sdk-react @tanstack/react-query
26
+ # also: react@>=19, react-dom@>=19
27
+ ```
28
+
29
+ Drop the file into your app, mount the provider component at the root, and use the consumer component anywhere below it.
@@ -0,0 +1,223 @@
1
+ # Recipe: Batch Connect / Disconnect
2
+
3
+ `useBatchConnect` and `useBatchDisconnect` orchestrate multi-chain wallet operations sequentially using **wallet brand identifiers** (e.g. `'hana'`, `'phantom'`) instead of individual connectors. Pass an identifier and the hooks discover every chain that wallet supports across the registry, then connect/disconnect them in order.
4
+
5
+ Sequential by design — many extensions share popup singletons, so parallel attempts would race a single popup. Errors are collected, not thrown — `run()` always resolves.
6
+
7
+ **Depends on:** [`setup.md`](./setup.md)
8
+
9
+ ---
10
+
11
+ ## Identifier matching
12
+
13
+ Both batch hooks (and `useIsWalletInstalled`) take a `connectors: readonly string[]` field. Each entry is a **wallet brand identifier** matched **case-insensitive substring** against `connector.id` and `connector.name`:
14
+
15
+ | Identifier | Matches connectors |
16
+ |------------|--------------------|
17
+ | `'hana'` | Hana on EVM (`io.havah.hana`), Hana on ICON (`hana`), Hana on Sui, Hana on Stellar… |
18
+ | `'phantom'` | Phantom on Solana (`phantom`), Phantom on EVM (`app.phantom`) |
19
+ | `'metamask'` | MetaMask on EVM (`io.metamask`), Injective MetaMask connector |
20
+ | `'xverse'` | Xverse on Bitcoin (`xverse`), Xverse on Stacks (`XverseProviders.BitcoinProvider`) |
21
+
22
+ For the full list of known wallet brands and a runtime-discovery snippet (paste-in component that lists every connector available in your app), see [`../reference/wallet-brands.md`](../reference/wallet-brands.md).
23
+
24
+ Earlier identifiers in the array are **higher-priority per chain**. The runner uses **fallback-on-failure**:
25
+
26
+ - If a chain matches `'hana'` but the Hana popup is denied / errors out, the runner tries the next identifier's connector on that same chain (e.g. Phantom).
27
+ - If a chain succeeds on the first identifier, later identifiers for that chain are **silently skipped** — only one popup per chain on the happy path.
28
+ - A chain ends up in `result.failed` only when **every** matched identifier's connector has failed.
29
+
30
+ ```typescript
31
+ // Prefer Hana on every chain it covers; fall back to Phantom either
32
+ // because Hana isn't available (e.g. Solana) OR because its popup failed.
33
+ const { run } = useBatchConnect({ connectors: ['hana', 'phantom'] });
34
+ ```
35
+
36
+ `onProgress` fires per attempt — a chain can emit a `failure` event followed by a `success` event when fallback kicks in. The final outcome lives in `result`.
37
+
38
+ To target a specific connector (not a brand), bypass this API and use `useXConnectors({ xChainType }).find(c => c.id === '...')` + `useXConnect` directly.
39
+
40
+ ---
41
+
42
+ ## `useBatchConnect`
43
+
44
+ Connect every chain where one of the supplied identifiers matches an installed connector. Sequential, never throws, dedupes concurrent runs.
45
+
46
+ ```tsx
47
+ 'use client';
48
+
49
+ import { useBatchConnect } from '@sodax/wallet-sdk-react';
50
+
51
+ export function ConnectAllHana() {
52
+ const { run, status, result, reset } = useBatchConnect({
53
+ connectors: ['hana'],
54
+ skipConnected: true, // skip chains already connected at run() time
55
+ onProgress: event => {
56
+ console.log(`[batch] ${event.chainType}: ${event.outcome}`);
57
+ },
58
+ });
59
+
60
+ return (
61
+ <div>
62
+ <button onClick={run} disabled={status === 'running'}>
63
+ {status === 'running' ? 'Connecting all Hana chains…' : 'Connect with Hana'}
64
+ </button>
65
+ {status === 'done' && result && (
66
+ <div>
67
+ <p>{result.successful.length} connected</p>
68
+ <p>{result.failed.length} failed</p>
69
+ <p>{result.skipped.length} skipped</p>
70
+ <button onClick={reset}>Reset</button>
71
+ </div>
72
+ )}
73
+ </div>
74
+ );
75
+ }
76
+ ```
77
+
78
+ ### Options
79
+
80
+ | Field | Type | Effect |
81
+ |-------|------|--------|
82
+ | `connectors` | `readonly string[]` | Identifiers (required, non-empty) |
83
+ | `skipConnected` | `boolean` | Skip chains already holding an account at `run()` time. Default `false` |
84
+ | `onProgress` | `(event) => void` | Per-target progress event |
85
+
86
+ ### Result shape
87
+
88
+ ```typescript
89
+ type BatchConnectResult = {
90
+ successful: ChainType[];
91
+ failed: Array<{ chainType: ChainType; error: Error }>;
92
+ skipped: ChainType[];
93
+ };
94
+ ```
95
+
96
+ `run()` returns `Promise<BatchConnectResult>` — never rejects.
97
+
98
+ ---
99
+
100
+ ## `useBatchDisconnect`
101
+
102
+ Mirror of `useBatchConnect` for disconnect:
103
+
104
+ ```tsx
105
+ import { useBatchDisconnect } from '@sodax/wallet-sdk-react';
106
+
107
+ function DisconnectAll() {
108
+ const { run, status } = useBatchDisconnect();
109
+ // No `connectors` → disconnect every currently-connected chain regardless of wallet
110
+
111
+ return (
112
+ <button onClick={run} disabled={status === 'running'}>
113
+ {status === 'running' ? 'Disconnecting…' : 'Disconnect all chains'}
114
+ </button>
115
+ );
116
+ }
117
+
118
+ function DisconnectHanaOnly() {
119
+ const { run } = useBatchDisconnect({ connectors: ['hana'] });
120
+ // Only disconnect chains whose CURRENTLY ACTIVE connector matches 'hana'
121
+ return <button onClick={run}>Disconnect Hana</button>;
122
+ }
123
+ ```
124
+
125
+ ### Scope difference vs `useBatchConnect`
126
+
127
+ `useBatchConnect.connectors` is **mandatory** — it picks **which connector** to use on each chain.
128
+
129
+ `useBatchDisconnect.connectors` is **optional** — it filters **which chains** to disconnect by checking the **currently active** connector against the identifiers. Chains where the active connector doesn't match are left untouched.
130
+
131
+ ```typescript
132
+ useBatchDisconnect(); // Disconnect every chain
133
+ useBatchDisconnect({ connectors: ['hana'] }); // Disconnect chains where Hana is active
134
+ useBatchDisconnect({ connectors: ['hana', 'xverse'] }); // Hana OR Xverse
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Wallet install detection — `useIsWalletInstalled`
140
+
141
+ Companion read hook that uses the same identifier matching to detect whether a wallet brand is installed for any (or specific) chain.
142
+
143
+ ```typescript
144
+ import { useIsWalletInstalled } from '@sodax/wallet-sdk-react';
145
+
146
+ // True if any Hana variant is installed across any enabled chain
147
+ const isHanaInstalled = useIsWalletInstalled({ connectors: ['hana'] });
148
+
149
+ // True if any wallet is installed for the given chain
150
+ const hasBitcoinWallet = useIsWalletInstalled({ chainType: 'BITCOIN' });
151
+
152
+ // AND filter — Hana specifically on EVM
153
+ const hanaOnEvm = useIsWalletInstalled({ connectors: ['hana'], chainType: 'EVM' });
154
+ ```
155
+
156
+ The options union enforces at the type level that **at least one** of `connectors` / `chainType` is present. Use this hook to gate an `useBatchConnect` button:
157
+
158
+ ```tsx
159
+ const isInstalled = useIsWalletInstalled({ connectors: ['hana'] });
160
+ const { run } = useBatchConnect({ connectors: ['hana'] });
161
+
162
+ return isInstalled ? (
163
+ <button onClick={run}>Connect Hana</button>
164
+ ) : (
165
+ <a href="https://hana-wallet.com">Install Hana</a>
166
+ );
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Status lifecycle and concurrency
172
+
173
+ | `status` | Meaning |
174
+ |----------|---------|
175
+ | `'idle'` | Initial / after `reset()` |
176
+ | `'running'` | A `run()` is in flight |
177
+ | `'done'` | The last `run()` settled — `result` is populated |
178
+
179
+ **Concurrent `run()` calls are deduped** — the second call returns the existing in-flight promise.
180
+
181
+ **`reset()` does NOT abort an in-flight batch** — there is no cancellation signal. It only clears the observable `status` / `result`. Typical usage: call `reset()` only after `status === 'done'`.
182
+
183
+ ---
184
+
185
+ ## Progress events
186
+
187
+ ```typescript
188
+ const { run } = useBatchConnect({
189
+ connectors: ['hana'],
190
+ onProgress: event => {
191
+ switch (event.outcome) {
192
+ case 'success': toast(`✓ Connected ${event.chainType}`); break;
193
+ case 'failure': toast.error(`✗ ${event.chainType}: ${event.error.message}`); break;
194
+ case 'skipped': toast(`⏭ ${event.chainType} already connected`); break;
195
+ }
196
+ },
197
+ });
198
+ ```
199
+
200
+ `onProgress` is read from a ref each time, so passing an inline arrow function is safe.
201
+
202
+ ---
203
+
204
+ ## When to use the lower-level hooks instead
205
+
206
+ Reach for `useXConnect` / `useXDisconnect` directly when:
207
+
208
+ - **You need a specific connector**, not a brand.
209
+ - **Order is user-driven**, not registry-driven.
210
+ - **You need cancellation** — batch hooks have no cancel signal.
211
+ - **You only have one chain to operate on**.
212
+
213
+ ---
214
+
215
+ ## Verification
216
+
217
+ ```bash
218
+ # 1. Type check
219
+ pnpm checkTs
220
+
221
+ # 2. Manual — install Hana, click batch connect button, confirm sequential popups across chains
222
+ # 3. Manual — confirm result.failed contains chains where Hana isn't available
223
+ ```
@@ -0,0 +1,164 @@
1
+ # Recipe: Bridge to `@sodax/sdk`
2
+
3
+ Pass the user's connected wallet to `@sodax/sdk` calls — `useWalletProvider` returns a typed `IXxxWalletProvider` ready to plug into any SDK method.
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
+ **Requires also:** `pnpm add @sodax/sdk` — this package does not depend on `@sodax/sdk`. Install it separately in the consumer app.
8
+
9
+ ---
10
+
11
+ ## Hooks used
12
+
13
+ | Hook | Purpose |
14
+ |------|---------|
15
+ | `useWalletProvider({ xChainId })` | Typed `IXxxWalletProvider` (chain-narrowed by chain id) |
16
+ | `useWalletProvider({ xChainType })` | Family-level provider (same shape for every chain id in family) |
17
+ | `useXAccount({ xChainId })` | Read connected address |
18
+ | `useXService({ xChainType })` | Lower-level — chain `XService` instance for advanced reads |
19
+
20
+ Pass either `xChainId` (a `SpokeChainKey`) or `xChainType` (a `ChainType`), never both.
21
+
22
+ ---
23
+
24
+ ## Pattern — drive an SDK swap from a connected wallet
25
+
26
+ ```tsx
27
+ import { useWalletProvider, useXAccount } from '@sodax/wallet-sdk-react';
28
+ import { Sodax, ChainKeys } from '@sodax/sdk';
29
+ import type { CreateIntentParams } from '@sodax/sdk';
30
+
31
+ const sodax = new Sodax(); // or hold one in context / pass via @sodax/dapp-kit
32
+
33
+ export function SwapButton({ params }: { params: CreateIntentParams<typeof ChainKeys.BSC_MAINNET> }) {
34
+ const walletProvider = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET });
35
+ const account = useXAccount({ xChainId: ChainKeys.BSC_MAINNET });
36
+
37
+ const handleSwap = async () => {
38
+ if (!walletProvider) return;
39
+ const result = await sodax.swaps.swap({
40
+ params,
41
+ walletProvider, // typed as IEvmWalletProvider — must match BSC src chain
42
+ });
43
+ if (!result.ok) {
44
+ console.error('swap failed:', result.error);
45
+ return;
46
+ }
47
+ console.log('swap submitted:', result.value);
48
+ };
49
+
50
+ return (
51
+ <button onClick={handleSwap} disabled={!walletProvider || !account.address}>
52
+ Swap
53
+ </button>
54
+ );
55
+ }
56
+ ```
57
+
58
+ The pattern works for every SDK feature service:
59
+
60
+ ```typescript
61
+ sodax.swaps.swap({ params, walletProvider });
62
+ sodax.bridge.bridge({ params, walletProvider });
63
+ sodax.moneyMarket.supply({ params, walletProvider });
64
+ sodax.staking.stake({ params, walletProvider });
65
+ sodax.dex.deposit({ params, walletProvider });
66
+ ```
67
+
68
+ ---
69
+
70
+ ## TypeScript narrowing
71
+
72
+ ```typescript
73
+ import { useWalletProvider } from '@sodax/wallet-sdk-react';
74
+ import { ChainKeys } from '@sodax/types';
75
+
76
+ // By chain id — narrowest typing
77
+ const evm = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET });
78
+ // evm: IEvmWalletProvider | undefined
79
+
80
+ const sol = useWalletProvider({ xChainId: ChainKeys.SOLANA_MAINNET });
81
+ // sol: ISolanaWalletProvider | undefined
82
+
83
+ // By chain type — family-level (one wagmi connection covers all EVM chains)
84
+ const evmFamily = useWalletProvider({ xChainType: 'EVM' });
85
+ // evmFamily: IEvmWalletProvider | undefined
86
+ ```
87
+
88
+ Passing the wrong wallet provider type to an SDK call (e.g. `ISolanaWalletProvider` to a `srcChainKey: BSC_MAINNET` swap) is a **compile error**.
89
+
90
+ ---
91
+
92
+ ## EVM — single connection across all networks
93
+
94
+ `useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET })` and `useWalletProvider({ xChainId: ChainKeys.ARBITRUM_MAINNET })` return the **same** `EvmWalletProvider` instance — wagmi maintains one connection across all configured EVM networks. To switch the **active** EVM network:
95
+
96
+ ```tsx
97
+ import { useEvmSwitchChain } from '@sodax/wallet-sdk-react';
98
+ import { ChainKeys } from '@sodax/types';
99
+
100
+ const { isWrongChain, handleSwitchChain } = useEvmSwitchChain({
101
+ xChainId: ChainKeys.BSC_MAINNET,
102
+ });
103
+
104
+ if (isWrongChain) {
105
+ return <button onClick={handleSwitchChain}>Switch to BSC</button>;
106
+ }
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Disabled chains return `undefined`
112
+
113
+ If `xChainType` resolves to a chain not enabled in `SodaxWalletProvider` config, `useWalletProvider` returns `undefined` and logs a one-time warning:
114
+
115
+ ```
116
+ [useWalletProvider] chain "BITCOIN" is not enabled in SodaxWalletProvider config.chains — returning undefined
117
+ ```
118
+
119
+ Always null-check before passing to an SDK call.
120
+
121
+ ---
122
+
123
+ ## Raw transactions — skip the bridge
124
+
125
+ If you only need unsigned transaction data (manual relay, gas estimation, external signing), pass `raw: true` to the SDK and skip `walletProvider`:
126
+
127
+ ```typescript
128
+ const result = await sodax.swaps.createIntent({
129
+ params,
130
+ raw: true, // walletProvider must be absent — compile error if passed
131
+ });
132
+ // result.value.tx is an EvmRawTransaction
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Server / scripts — use `@sodax/wallet-sdk-core` directly
138
+
139
+ For Node.js scripts / bots, skip wallet-sdk-react entirely:
140
+
141
+ ```typescript
142
+ import { Sodax } from '@sodax/sdk';
143
+ import { EvmWalletProvider } from '@sodax/wallet-sdk-core';
144
+ import { ChainKeys } from '@sodax/types';
145
+
146
+ const sodax = new Sodax();
147
+ const walletProvider = new EvmWalletProvider({
148
+ privateKey: process.env.PRIVATE_KEY!,
149
+ chainId: ChainKeys.BSC_MAINNET,
150
+ rpcUrl: 'https://bsc-dataseed.binance.org',
151
+ });
152
+ const result = await sodax.swaps.swap({ params, walletProvider });
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Verification
158
+
159
+ ```bash
160
+ # 1. Type check
161
+ pnpm checkTs
162
+
163
+ # 2. Manual — connect wallet, click SDK action button, confirm transaction prompts in wallet
164
+ ```