@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,247 @@
1
+ # Connectors
2
+
3
+ A connector is the adapter between a specific wallet (Hana, MetaMask, Phantom, Xverse…) and the SODAX store. Every connector implements `IXConnector`, the public contract every hook in `wallet-sdk-react` consumes. The base abstract class `XConnector` provides default `isInstalled` / `installUrl` semantics that subclasses override per wallet.
4
+
5
+ Concrete connector and service classes are **not** exported from the package barrel — they live behind sub-path imports under `@sodax/wallet-sdk-react/xchains/<chain>` to prevent accidental coupling.
6
+
7
+ ## Table of contents
8
+
9
+ 1. [`IXConnector` interface](#ixconnector-interface)
10
+ 2. [`XConnector` abstract base](#xconnector-abstract-base)
11
+ 3. [Sub-path imports — concrete classes](#sub-path-imports--concrete-classes)
12
+ 4. [Per-chain connector reference](#per-chain-connector-reference)
13
+ 5. [Discovery — EIP-6963 vs adapter vs window probe](#discovery--eip-6963-vs-adapter-vs-window-probe)
14
+ 6. [`sortConnectors` — display ordering](#sortconnectors--display-ordering)
15
+ 7. [Custom connectors](#custom-connectors)
16
+
17
+ ---
18
+
19
+ ## `IXConnector` interface
20
+
21
+ Defined in [`src/types/interfaces.ts`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/src/types/interfaces.ts):
22
+
23
+ ```typescript
24
+ export interface IXConnector {
25
+ readonly xChainType: ChainType;
26
+ readonly name: string; // 'Hana', 'MetaMask', 'Xverse', …
27
+ readonly _id: string; // unique connector id (e.g. 'io.metamask')
28
+ readonly _icon?: string; // raw icon URL (or undefined)
29
+
30
+ readonly id: string; // public getter — same as _id
31
+ readonly icon: string | undefined; // public getter
32
+
33
+ readonly isInstalled: boolean; // wallet extension presence (read at getter call time)
34
+ readonly installUrl: string | undefined;
35
+
36
+ connect(): Promise<XAccount | undefined>;
37
+ disconnect(): Promise<void>;
38
+ }
39
+ ```
40
+
41
+ Consumer code should depend on **`IXConnector`** (the interface), not the concrete `XConnector` class — this keeps your code chain-implementation-agnostic and allows custom connectors to slot in without inheriting from the abstract base.
42
+
43
+ `isInstalled` reads `window.*` at getter-call time — no extra subscription is installed. Components get fresh values through normal React render triggers (store updates, parent re-renders).
44
+
45
+ ---
46
+
47
+ ## `XConnector` abstract base
48
+
49
+ The default class subclasses extend ([`src/core/XConnector.ts`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/src/core/XConnector.ts)):
50
+
51
+ ```typescript
52
+ export abstract class XConnector implements IXConnector {
53
+ public readonly xChainType: ChainType;
54
+ public readonly name: string;
55
+ public readonly _id: string;
56
+ public readonly _icon?: string;
57
+
58
+ constructor(xChainType: ChainType, name: string, id: string) { ... }
59
+
60
+ abstract connect(): Promise<XAccount | undefined>;
61
+ abstract disconnect(): Promise<void>;
62
+
63
+ get id(): string { return this._id; }
64
+ get icon(): string | undefined { return this._icon; }
65
+
66
+ /** Default: true. Override in subclasses backed by extension injection. */
67
+ get isInstalled(): boolean { return true; }
68
+ get installUrl(): string | undefined { return undefined; }
69
+ }
70
+ ```
71
+
72
+ The `isInstalled = true` default is correct for **provider-managed chains** (EVM via EIP-6963, Solana via wallet-adapter discovery, Sui via dapp-kit) — if the connector exists in the store, the underlying extension was found by the native SDK.
73
+
74
+ Browser-extension chains (Bitcoin, ICON, Stacks) override `isInstalled` with a `window.unisat` / `window.hanaWallet` / `window.LeatherProvider` probe, plus an `installUrl` to point users to the Chrome Web Store entry.
75
+
76
+ ---
77
+
78
+ ## Sub-path imports — concrete classes
79
+
80
+ The package barrel `@sodax/wallet-sdk-react` deliberately omits concrete classes — only types/interfaces and hooks are exported. To get a concrete class for `instanceof` checks or chain-specific methods, deep-import:
81
+
82
+ ```typescript
83
+ // ✅ Normal usage — barrel
84
+ import { useXConnect, useXAccount, type IXConnector } from '@sodax/wallet-sdk-react';
85
+
86
+ // ✅ Advanced — concrete class
87
+ import { XverseXConnector } from '@sodax/wallet-sdk-react/xchains/bitcoin';
88
+
89
+ if (connector instanceof XverseXConnector) {
90
+ connector.setAddressPurpose('payment');
91
+ }
92
+ ```
93
+
94
+ The `package.json` `exports` field maps `./xchains/*` to `dist/xchains/*/index.{mjs,cjs}` and `typesVersions` adds the `node` resolution fallback.
95
+
96
+ ### Sub-path map
97
+
98
+ | Sub-path | Exports |
99
+ |----------|---------|
100
+ | `@sodax/wallet-sdk-react/xchains/evm` | `EvmXService`, `EvmXConnector`, `createWagmiConfig` (alias `createWagmi`) |
101
+ | `@sodax/wallet-sdk-react/xchains/solana` | `SolanaXService`, `SolanaXConnector` |
102
+ | `@sodax/wallet-sdk-react/xchains/sui` | `SuiXService`, `SuiXConnector` |
103
+ | `@sodax/wallet-sdk-react/xchains/bitcoin` | `BitcoinXService`, `BitcoinXConnector`, `UnisatXConnector`, `XverseXConnector`, `OKXXConnector`, `useBitcoinXConnectors`, type `BtcWalletAddressType` |
104
+ | `@sodax/wallet-sdk-react/xchains/stellar` | `StellarXService`, `StellarWalletsKitXConnector` |
105
+ | `@sodax/wallet-sdk-react/xchains/injective` | `InjectiveXService`, `InjectiveXConnector` |
106
+ | `@sodax/wallet-sdk-react/xchains/icon` | `IconXService`, `IconHanaXConnector`, `CHAIN_INFO`, `SupportedChainId` |
107
+ | `@sodax/wallet-sdk-react/xchains/near` | `NearXService`, `NearXConnector` |
108
+ | `@sodax/wallet-sdk-react/xchains/stacks` | `StacksXService`, `StacksXConnector`, `STACKS_PROVIDERS`, `useStacksXConnectors`, type `StacksProviderConfig` |
109
+
110
+ `StellarXService`, `XverseXConnector`, `BtcWalletAddressType` are **also** re-exported from the barrel as `export type` (no runtime class) — those imports work either way.
111
+
112
+ ---
113
+
114
+ ## Per-chain connector reference
115
+
116
+ | Chain | Connector class(es) | Discovery | Native SDK |
117
+ |-------|---------------------|-----------|------------|
118
+ | EVM | `EvmXConnector` | EIP-6963 + wagmi connectors | `wagmi` + `viem` |
119
+ | Solana | `SolanaXConnector` | `@solana/wallet-adapter-react` | `@solana/web3.js` |
120
+ | Sui | `SuiXConnector` | `@mysten/dapp-kit` | `@mysten/sui` |
121
+ | Stellar | `StellarWalletsKitXConnector` | async — `walletsKit.getSupportedWallets()` | `@creit.tech/stellar-wallets-kit` |
122
+ | Injective | `InjectiveXConnector` × 3 (MetaMask, Keplr, Leap) | wallet-base wallet types | `@injectivelabs/sdk-ts` |
123
+ | ICON | `IconHanaXConnector` | `window.hanaWallet` probe | `icon-sdk-js` |
124
+ | Bitcoin | `UnisatXConnector`, `XverseXConnector`, `OKXXConnector` | `window.unisat`, `window.XverseProviders`, `window.okxwallet.bitcoin` | `sats-connect` (Xverse), connector-specific (Unisat, OKX) |
125
+ | NEAR | `NearXConnector` | `@hot-labs/near-connect` | `near-api-js` |
126
+ | Stacks | `StacksXConnector` × N (one per registered provider) | provider list + `window.LeatherProvider` probe | `@stacks/connect` |
127
+
128
+ The `BitcoinXConnector` is an abstract base — concrete subclasses (Unisat, Xverse, OKX) implement `signEcdsaMessage` / `signBip322Message` per wallet's API. See [`SIGN_MESSAGE.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/SIGN_MESSAGE.md) for the dispatch logic.
129
+
130
+ ---
131
+
132
+ ## Discovery — EIP-6963 vs adapter vs window probe
133
+
134
+ Connectors land in the store via three discovery patterns:
135
+
136
+ **Synchronous default list** (most chains) — `chainRegistry.<CHAIN>.defaultConnectors()` returns a static array at `initChainServices()` time. Bitcoin always registers Unisat + Xverse + OKX; Injective registers MetaMask + Keplr + Leap.
137
+
138
+ **Async discovery** — Stellar's connectors come from `walletsKit.getSupportedWallets()` which probes for installed Stellar wallets at runtime. Implemented via `chainRegistry.STELLAR.discoverConnectors`, called as a side-effect during init.
139
+
140
+ **Native SDK adapter** — EVM, Solana, Sui delegate to wagmi / wallet-adapter / dapp-kit. The adapter discovers wallets via EIP-6963 announcements (EVM) or vendor-specific extension protocols, and the chain's Hydrator reads the discovered list and writes it to the store.
141
+
142
+ Once in the store, all three patterns surface uniformly through `useXConnectors({ xChainType })` — consumers can't tell them apart.
143
+
144
+ ---
145
+
146
+ ## `sortConnectors` — display ordering
147
+
148
+ Pure utility for ranking connectors in lists. Stable sort by:
149
+
150
+ 1. Position in `preferred[]` (earlier wins)
151
+ 2. `isInstalled === true`
152
+ 3. Original index
153
+
154
+ ```typescript
155
+ import { useXConnectors, sortConnectors } from '@sodax/wallet-sdk-react';
156
+
157
+ const PREFERRED = ['hana', 'metamask'];
158
+
159
+ function ConnectorList() {
160
+ const raw = useXConnectors({ xChainType: 'EVM' });
161
+ const sorted = sortConnectors(raw, { preferred: PREFERRED });
162
+ // Hana first if present, then MetaMask, then any other installed wallets, then uninstalled.
163
+ }
164
+ ```
165
+
166
+ `preferred` matches by exact `connector.id`. For substring/case-insensitive matching across chains (matches the batch-operation API), use [`useIsWalletInstalled`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CHAIN_DETECTION.md#useiswalletinstalled--install-detection) instead.
167
+
168
+ ---
169
+
170
+ ## Custom connectors
171
+
172
+ Two ways to plug in a wallet the SDK doesn't ship:
173
+
174
+ ### Option 1 — extend `XConnector`
175
+
176
+ ```typescript
177
+ import { XConnector } from '@sodax/wallet-sdk-react'; // base class is exported from barrel
178
+ import type { XAccount } from '@sodax/wallet-sdk-react';
179
+
180
+ class MyEvmConnector extends XConnector {
181
+ constructor() {
182
+ super('EVM', 'My Wallet', 'com.mycompany.wallet');
183
+ }
184
+
185
+ override get isInstalled(): boolean {
186
+ return typeof window !== 'undefined' && 'mywallet' in window;
187
+ }
188
+
189
+ override get installUrl(): string {
190
+ return 'https://chrome.google.com/webstore/detail/...';
191
+ }
192
+
193
+ async connect(): Promise<XAccount | undefined> {
194
+ const accounts = await window.mywallet.request({ method: 'eth_requestAccounts' });
195
+ return accounts[0]
196
+ ? { address: accounts[0], xChainType: 'EVM' }
197
+ : undefined;
198
+ }
199
+
200
+ async disconnect(): Promise<void> {
201
+ await window.mywallet.request({ method: 'wallet_revokePermissions' });
202
+ }
203
+ }
204
+ ```
205
+
206
+ Pass it via `SodaxWalletConfig.<CHAIN>.connectors`:
207
+
208
+ ```typescript
209
+ const config: SodaxWalletConfig = {
210
+ EVM: {
211
+ connectors: [new MyEvmConnector(), /* …or omit and the registry's defaults run instead */],
212
+ },
213
+ };
214
+ ```
215
+
216
+ The `connectors` field on a chain-type slot **replaces** the registry defaults for that chain. Include the SDK's defaults in the array if you want them alongside your custom one.
217
+
218
+ ### Option 2 — implement `IXConnector` directly
219
+
220
+ Skip `XConnector` if you already have a class hierarchy and don't want the abstract base. Just implement every property/method on `IXConnector`. The SDK never does an `instanceof XConnector` check on user-supplied connectors — it only relies on the interface.
221
+
222
+ ```typescript
223
+ class MyConnector implements IXConnector {
224
+ readonly xChainType = 'EVM';
225
+ readonly name = 'My Wallet';
226
+ readonly _id = 'com.mycompany.wallet';
227
+ readonly id = this._id;
228
+ readonly icon = undefined;
229
+ get isInstalled() { /* … */ }
230
+ get installUrl() { /* … */ }
231
+ async connect() { /* … */ }
232
+ async disconnect() { /* … */ }
233
+ }
234
+ ```
235
+
236
+ For chains with custom `signMessage` requirements (Bitcoin, Injective), implement the chain-specific extra methods (`signBip322Message` / `signEcdsaMessage` for Bitcoin) — `chainRegistry` checks for them via type guards at dispatch time.
237
+
238
+ ---
239
+
240
+ ## Related docs
241
+
242
+ - [Configure SodaxWalletProvider](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONFIGURE_PROVIDER.md) — `connectors` slot field for overriding defaults
243
+ - [Connect Flow](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONNECT_FLOW.md) — how `useXConnectors` returns these connectors
244
+ - [Sign Message](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/SIGN_MESSAGE.md) — Bitcoin connector subclass dispatch (BIP-322 vs ECDSA)
245
+ - [Batch Operations](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/BATCH_OPERATIONS.md) — identifier-based connector matching
246
+ - [Wallet Modal](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/WALLET_MODAL.md) — `selectWallet(connector)` consumes `IXConnector`
247
+ - [SDK Wallet Providers Reference](https://github.com/icon-project/sodax-sdks/blob/main/packages/sdk/docs/WALLET_PROVIDERS.md) — the `IXxxWalletProvider` interfaces these connectors back into
@@ -0,0 +1,276 @@
1
+ # Connect Flow
2
+
3
+ The connect flow covers the full wallet lifecycle in `@sodax/wallet-sdk-react`: discover available connectors → connect to a wallet → read connected account state → disconnect. Every hook reads from the central Zustand store — no direct chain-SDK hook usage in user code.
4
+
5
+ The canonical hook surface is exported from [`src/hooks/index.ts`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/src/hooks/index.ts).
6
+
7
+ ## Table of contents
8
+
9
+ 1. [Lifecycle overview](#lifecycle-overview)
10
+ 2. [Discover connectors](#discover-connectors)
11
+ 3. [Connect a wallet](#connect-a-wallet)
12
+ 4. [Read connected account state](#read-connected-account-state)
13
+ 5. [Disconnect](#disconnect)
14
+ 6. [Provider-managed chains caveat](#provider-managed-chains-caveat)
15
+ 7. [Persisted connections](#persisted-connections)
16
+ 8. [Error handling](#error-handling)
17
+
18
+ ---
19
+
20
+ ## Lifecycle overview
21
+
22
+ ```
23
+ useXConnectors → user picks a connector → useXConnect.mutateAsync(connector)
24
+ │ │
25
+ │ ↓
26
+ │ ChainActions.connect(connectorId)
27
+ │ │
28
+ │ ↓
29
+ │ setXConnection(xChainType, { xAccount, xConnectorId })
30
+ │ │
31
+ ↓ ↓
32
+ useXAccount(xChainType) ←───────────── Zustand store ─────────────→ useXConnection(xChainType)
33
+
34
+
35
+ useXDisconnect({ xChainType })
36
+
37
+
38
+ ChainActions.disconnect()
39
+
40
+
41
+ clearXConnection(xChainType)
42
+ ```
43
+
44
+ **Single store, single source of truth** — every hook subscribes to the same Zustand slice. Connect mutations write through `setXConnection`; reads (`useXAccount`, `useXConnection`) reflect that immediately. Provider-managed chains (EVM/Solana/Sui) write via their Hydrator components instead of inside the mutation — see [Provider-managed chains caveat](#provider-managed-chains-caveat).
45
+
46
+ ---
47
+
48
+ ## Discover connectors
49
+
50
+ ### `useXConnectors({ xChainType })` — connectors for one chain type
51
+
52
+ Returns the list of available connectors for a single chain family. Pass `xChainType` (`'EVM' | 'SOLANA' | 'BITCOIN' | …`).
53
+
54
+ ```typescript
55
+ import { useXConnectors } from '@sodax/wallet-sdk-react';
56
+
57
+ function EvmWalletList() {
58
+ const connectors = useXConnectors({ xChainType: 'EVM' });
59
+ // connectors: IXConnector[] with { id, name, icon, isInstalled, installUrl, xChainType }
60
+ }
61
+ ```
62
+
63
+ If the chain isn't enabled in `SodaxWalletProvider` config, `useXConnectors` returns `[]` and logs a one-time warning per chain.
64
+
65
+ `connector.isInstalled` reads `window.*` at render time (no extra subscription) — values stay fresh through normal React render triggers (store updates, parent re-renders).
66
+
67
+ ### `useXConnectorsByChain()` — all chains at once
68
+
69
+ Returns connectors grouped by chain type. Useful for multi-chain wallet pickers.
70
+
71
+ ```typescript
72
+ import { useXConnectorsByChain } from '@sodax/wallet-sdk-react';
73
+
74
+ function MultiChainPicker() {
75
+ const byChain = useXConnectorsByChain();
76
+ // byChain: Partial<Record<ChainType, IXConnector[]>>
77
+ // e.g. { EVM: [...], SOLANA: [...], BITCOIN: [...] }
78
+ }
79
+ ```
80
+
81
+ ### `sortConnectors(connectors, { preferred })` — display ordering
82
+
83
+ Pure utility that sorts a connector list **stably** by:
84
+ 1. Position in `preferred[]` (earlier wins)
85
+ 2. `isInstalled === true`
86
+ 3. Original order
87
+
88
+ ```typescript
89
+ import { useXConnectors, sortConnectors } from '@sodax/wallet-sdk-react';
90
+
91
+ const PREFERRED = ['hana', 'metamask'] as const;
92
+
93
+ function ConnectorList() {
94
+ const raw = useXConnectors({ xChainType: 'EVM' });
95
+ const connectors = sortConnectors(raw, { preferred: PREFERRED });
96
+ // Hana first if installed, then MetaMask, then any other installed wallets, then uninstalled.
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Connect a wallet
103
+
104
+ `useXConnect()` returns a React Query mutation. Pass an `IXConnector` to `mutate` / `mutateAsync` — the hook delegates to the chain's `ChainActions.connect()` and writes the connection state into the store on success.
105
+
106
+ ```tsx
107
+ import { useXConnect, useXConnectors, useXAccount } from '@sodax/wallet-sdk-react';
108
+
109
+ function ConnectButton() {
110
+ const connectors = useXConnectors({ xChainType: 'EVM' });
111
+ const { mutateAsync: connect, isPending, error } = useXConnect();
112
+ const account = useXAccount({ xChainType: 'EVM' });
113
+
114
+ if (account.address) {
115
+ return <span>Connected: {account.address}</span>;
116
+ }
117
+
118
+ return (
119
+ <div>
120
+ {connectors.map(connector => (
121
+ <button
122
+ key={connector.id}
123
+ onClick={() => connect(connector)}
124
+ disabled={isPending}
125
+ >
126
+ {connector.icon && <img src={connector.icon} alt="" width={20} height={20} />}
127
+ {connector.name}
128
+ </button>
129
+ ))}
130
+ {error && <p style={{ color: 'red' }}>{error.message}</p>}
131
+ </div>
132
+ );
133
+ }
134
+ ```
135
+
136
+ The mutation throws `Error('Chain "<X>" is not enabled or ChainActions not registered')` if the connector's chain type isn't mounted in `SodaxWalletProvider` config.
137
+
138
+ ---
139
+
140
+ ## Read connected account state
141
+
142
+ Four read hooks expose the same store data at different granularities:
143
+
144
+ | Hook | Returns | Use case |
145
+ |------|---------|----------|
146
+ | `useXAccount({ xChainId })` | `XAccount` for the chain's family (resolves chain id → chain type) | Signing/reading at chain-id level (e.g. `useXAccount({ xChainId: ChainKeys.BSC_MAINNET })`) |
147
+ | `useXAccount({ xChainType })` | `XAccount` for that family | Family-level UI (e.g. EVM badge — one wagmi connection covers all 12 EVM chains) |
148
+ | `useXAccounts()` | `Partial<Record<ChainType, XAccount>>` for every enabled chain | Account list / multi-chain dashboard |
149
+ | `useXConnection({ xChainType })` | `XConnection \| undefined` | When you also need `xConnectorId` (e.g. to drive disconnect UX) |
150
+ | `useXConnections()` | `Partial<Record<ChainType, XConnection>>` | Aggregate UIs that care about connector identity per chain |
151
+
152
+ ```typescript
153
+ import { useXAccount, useXAccounts, useXConnection } from '@sodax/wallet-sdk-react';
154
+ import { ChainKeys } from '@sodax/types';
155
+
156
+ // By chain id — narrows to EVM family
157
+ const evmAccount = useXAccount({ xChainId: ChainKeys.BSC_MAINNET });
158
+ // evmAccount: { address: '0x...' | undefined, xChainType: 'EVM', publicKey?: string }
159
+
160
+ // By chain type — same data, family-level UI
161
+ const solanaAccount = useXAccount({ xChainType: 'SOLANA' });
162
+
163
+ // All connected accounts at once
164
+ const accounts = useXAccounts();
165
+ // accounts.EVM, accounts.SOLANA, accounts.BITCOIN, ...
166
+
167
+ // With connector identity (for disconnect button labels, etc.)
168
+ const evmConnection = useXConnection({ xChainType: 'EVM' });
169
+ // evmConnection: { xAccount: XAccount, xConnectorId: string } | undefined
170
+ ```
171
+
172
+ **`xChainId` vs `xChainType`** — `useXAccount` and `useWalletProvider` accept either, never both. `xChainId` (a `SpokeChainKey` like `ChainKeys.BSC_MAINNET`) is resolved to its family via `getXChainType()` internally. For EVM, the family-level view is correct because wagmi maintains a single connection across all configured EVM networks (see [`EVM_SWITCH_CHAIN.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/EVM_SWITCH_CHAIN.md)).
173
+
174
+ When no wallet is connected, `useXAccount` returns `{ address: undefined, xChainType }` (not `undefined`) so consumers don't need to null-check before reading `xChainType`.
175
+
176
+ ---
177
+
178
+ ## Disconnect
179
+
180
+ `useXDisconnect()` returns a callback. Invoke with the chain type to disconnect:
181
+
182
+ ```tsx
183
+ import { useXDisconnect } from '@sodax/wallet-sdk-react';
184
+
185
+ function DisconnectButton() {
186
+ const disconnect = useXDisconnect();
187
+ return <button onClick={() => disconnect({ xChainType: 'EVM' })}>Disconnect EVM</button>;
188
+ }
189
+ ```
190
+
191
+ The callback delegates to `ChainActions.disconnect()`. If no actions are registered (chain not enabled in config), it logs a warning and resolves silently — no throw. Connection state is cleared by the chain's action implementation (provider-managed) or by the store side-effect (non-provider).
192
+
193
+ ---
194
+
195
+ ## Provider-managed chains caveat
196
+
197
+ EVM, Solana, and Sui mount their native React adapters (wagmi, `@solana/wallet-adapter`, `@mysten/dapp-kit`) and use a **Provider/Hydrator/Actions trio**:
198
+
199
+ - `<ChainProvider>` — wraps native adapter context.
200
+ - `<ChainHydrator>` — sole writer of connection state into the store, watching native adapter hooks.
201
+ - `<ChainActions>` — registers `ChainActions.connect/disconnect` that trigger native SDK operations only.
202
+
203
+ Because of this split, **`useXConnect.mutateAsync(connector)` resolves with `undefined`** for EVM/Solana/Sui — connection state lands asynchronously when the Hydrator observes the wallet adapter's status flip from `disconnected` → `connected`. Read the connected account via `useXAccount` / `useXConnection` instead:
204
+
205
+ ```typescript
206
+ const { mutateAsync: connect } = useXConnect();
207
+ const account = useXAccount({ xChainType: 'EVM' });
208
+
209
+ await connect(connector); // may resolve before account.address is populated
210
+ // Don't read connect's return value — read account.address from the next render.
211
+ ```
212
+
213
+ Non-provider chains (Bitcoin, ICON, Injective, Stellar, NEAR, Stacks) write the connection state inside the mutation, so the resolved `XAccount` is reliable for those chains. Code defensively if you support both.
214
+
215
+ ---
216
+
217
+ ## Persisted connections
218
+
219
+ Connection state is persisted to `localStorage` (key: `xwagmi-store`) by Zustand's `persist` middleware. On page reload:
220
+
221
+ - **Provider-managed chains** — wagmi/wallet-adapter/dapp-kit auto-reconnect from their own persistence layer; the Hydrator observes and re-writes the store.
222
+ - **Non-provider chains** — `useInitChainServices` calls `reconnectIcon()` / `reconnectInjective()` / `reconnectStellar()` after hydration. ICON, Injective, and Stellar attempt to reconnect to the previously-connected wallet automatically.
223
+ - **Bitcoin** — `BitcoinXConnector.recreateWalletProvider` rebuilds the provider from `window.*` + the persisted `XAccount` (no popup), so signing works after reload without a reconnect call.
224
+ - **NEAR / Stacks** — no auto-reconnect. The user must re-connect manually after a reload.
225
+ - **Cleanup** — connections for chains no longer in `SodaxWalletProvider` config are removed via `cleanupDisabledConnections()` after persist hydration completes.
226
+
227
+ To detect when persisted state is ready (avoid disconnect flash on first paint), use [`useConnectedChains`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CHAIN_DETECTION.md) and gate UI on `status === 'ready'`.
228
+
229
+ ---
230
+
231
+ ## Error handling
232
+
233
+ `useXConnect` errors fall into two categories:
234
+
235
+ **Configuration errors** — chain type isn't enabled. Message: `Chain "<X>" is not enabled or ChainActions not registered`. Fix by adding the slot to `SodaxWalletProvider` config.
236
+
237
+ **Wallet/runtime errors** — propagated from the underlying wallet SDK. Examples:
238
+
239
+ | Source | Message style |
240
+ |--------|---------------|
241
+ | User rejects in wallet popup | Wallet-specific (`"User rejected the request"`, `"User denied account authorization"`, etc.) |
242
+ | Wallet not installed | `"Wallet extension not detected"` (varies by chain) |
243
+ | Network mismatch | `"Chain not configured"` (wagmi) |
244
+
245
+ Read `mutation.error.message` and surface to UI; for install CTA, fall back to `connector.installUrl`:
246
+
247
+ ```tsx
248
+ const { mutateAsync: connect, error } = useXConnect();
249
+
250
+ return (
251
+ <>
252
+ <button onClick={() => connect(connector).catch(() => {})}>Connect</button>
253
+ {error && (
254
+ <div>
255
+ {error.message}
256
+ {!connector.isInstalled && connector.installUrl && (
257
+ <a href={connector.installUrl}>Install {connector.name}</a>
258
+ )}
259
+ </div>
260
+ )}
261
+ </>
262
+ );
263
+ ```
264
+
265
+ For multi-chain modal flows that wrap connect with status + retry semantics, see [`WALLET_MODAL.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/WALLET_MODAL.md).
266
+
267
+ ---
268
+
269
+ ## Related docs
270
+
271
+ - [Configure SodaxWalletProvider](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONFIGURE_PROVIDER.md) — chain-type slots, opt-in mounting
272
+ - [Wallet Provider Bridge](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/WALLET_PROVIDER_BRIDGE.md) — `useWalletProvider` → typed `IXxxWalletProvider` for SDK calls
273
+ - [Wallet Modal](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/WALLET_MODAL.md) — headless state machine (chainSelect → walletSelect → connecting → success | error)
274
+ - [Chain Detection](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CHAIN_DETECTION.md) — aggregate connected-chain views + hydration status
275
+ - [EVM Switch Chain](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/EVM_SWITCH_CHAIN.md) — single wagmi connection across EVM networks
276
+ - [Connectors](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONNECTORS.md) — `IXConnector` contract, deep imports for concrete classes