@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,1585 @@
1
+ import { StellarWalletsKitXConnector, StellarXService } from './chunk-66BAUK56.mjs';
2
+ import { SuiXService } from './chunk-7ULB6DW4.mjs';
3
+ import { EvmXService } from './chunk-E5IAZ7E6.mjs';
4
+ import { IconHanaXConnector, IconXService, CHAIN_INFO } from './chunk-2BOUGCJ7.mjs';
5
+ import { assert, isRecord, hasFunctionProperty } from './chunk-MAQ47Q52.mjs';
6
+ import { InjectiveXConnector, InjectiveXService } from './chunk-BKJB527E.mjs';
7
+ import { NearXService, NearXConnector } from './chunk-BXJLBR4G.mjs';
8
+ import { BITCOIN_DEFAULT_RPC_URL, WALLET_METADATA } from './chunk-MXZVF5HR.mjs';
9
+ import { SolanaXService } from './chunk-XZ7CHO2S.mjs';
10
+ import { isNativeToken, getEntryDefaults, getRpcUrl } from './chunk-NY7U7OJW.mjs';
11
+ import { STACKS_PROVIDERS, StacksXService, StacksXConnector } from './chunk-PJLEJVAU.mjs';
12
+ import { XConnector, XService } from './chunk-X2MHIWXO.mjs';
13
+ import { ChainTypeArr, baseChainInfo, ChainKeys, detectBitcoinAddressType, CHAIN_KEYS } from '@sodax/types';
14
+ import { AddressPurpose, MessageSigningProtocols } from 'sats-connect';
15
+ import { createContext, useMemo, useSyncExternalStore, useCallback, useState, useRef, useContext, useEffect } from 'react';
16
+ import { create } from 'zustand';
17
+ import { devtools, persist, createJSONStorage } from 'zustand/middleware';
18
+ import { immer } from 'zustand/middleware/immer';
19
+ import { StacksWalletProvider, NearWalletProvider, IconWalletProvider, StellarWalletProvider, InjectiveWalletProvider } from '@sodax/wallet-sdk-core';
20
+ import { Wallet } from '@injectivelabs/wallet-base';
21
+ import { getEthereumAddress } from '@injectivelabs/sdk-ts';
22
+ import { useMutation } from '@tanstack/react-query';
23
+ import { useAccount, useSwitchChain } from 'wagmi';
24
+ import { mainnet } from 'viem/chains';
25
+
26
+ // src/xchains/bitcoin/BitcoinXService.ts
27
+ var BitcoinXService = class _BitcoinXService extends XService {
28
+ static instance;
29
+ rpcUrl;
30
+ constructor(rpcUrl = BITCOIN_DEFAULT_RPC_URL) {
31
+ super("BITCOIN");
32
+ this.rpcUrl = rpcUrl;
33
+ }
34
+ static getInstance(rpcUrl) {
35
+ if (!_BitcoinXService.instance) {
36
+ _BitcoinXService.instance = new _BitcoinXService(rpcUrl);
37
+ } else if (rpcUrl && rpcUrl !== _BitcoinXService.instance.rpcUrl) {
38
+ _BitcoinXService.instance.rpcUrl = rpcUrl;
39
+ }
40
+ return _BitcoinXService.instance;
41
+ }
42
+ async getBalance(address, xToken) {
43
+ if (!address) return 0n;
44
+ try {
45
+ if (isNativeToken(xToken)) {
46
+ const response = await fetch(`${this.rpcUrl}/address/${address}/utxo`);
47
+ if (!response.ok) return 0n;
48
+ const utxos = await response.json();
49
+ const totalBalance = utxos.reduce((sum, utxo) => sum + utxo.value, 0);
50
+ return BigInt(totalBalance);
51
+ }
52
+ } catch {
53
+ return 0n;
54
+ }
55
+ return 0n;
56
+ }
57
+ };
58
+
59
+ // src/xchains/bitcoin/BitcoinXConnector.ts
60
+ var BitcoinXConnector = class extends XConnector {
61
+ defaults;
62
+ constructor(name, id, defaults) {
63
+ super("BITCOIN", name, id);
64
+ this.defaults = defaults;
65
+ }
66
+ getXService() {
67
+ return BitcoinXService.getInstance();
68
+ }
69
+ };
70
+ var UnisatWalletProvider = class {
71
+ chainType = "BITCOIN";
72
+ cachedAddress;
73
+ defaults;
74
+ constructor(address, defaults) {
75
+ this.cachedAddress = address;
76
+ this.defaults = defaults;
77
+ }
78
+ // Lazy resolve so the provider can be constructed before the extension finishes injecting `window.unisat` (post-refresh rehydrate path).
79
+ get unisat() {
80
+ const u = window.unisat;
81
+ if (!u) throw new Error("Unisat wallet not available");
82
+ return u;
83
+ }
84
+ async getWalletAddress() {
85
+ try {
86
+ const accounts = await this.unisat.getAccounts();
87
+ if (accounts[0]) this.cachedAddress = accounts[0];
88
+ } catch {
89
+ }
90
+ return this.cachedAddress;
91
+ }
92
+ async getPublicKey() {
93
+ return this.unisat.getPublicKey();
94
+ }
95
+ async getAddressType(_address) {
96
+ const address = await this.getWalletAddress();
97
+ return detectBitcoinAddressType(address);
98
+ }
99
+ async signTransaction(psbtBase64, finalize) {
100
+ const effectiveFinalize = finalize ?? this.defaults?.defaultFinalize ?? false;
101
+ const psbtHex = Buffer.from(psbtBase64, "base64").toString("hex");
102
+ const signedHex = await this.unisat.signPsbt(psbtHex, { autoFinalized: effectiveFinalize });
103
+ return signedHex;
104
+ }
105
+ async signEcdsaMessage(message) {
106
+ return this.unisat.signMessage(message, "ecdsa");
107
+ }
108
+ async signBip322Message(message) {
109
+ return this.unisat.signMessage(message, "bip322-simple");
110
+ }
111
+ async sendBitcoin(toAddress, satoshis) {
112
+ if (satoshis > BigInt(Number.MAX_SAFE_INTEGER)) {
113
+ throw new Error(`Amount ${satoshis} satoshis exceeds safe integer range`);
114
+ }
115
+ return this.unisat.sendBitcoin(toAddress, Number(satoshis));
116
+ }
117
+ };
118
+ var UnisatXConnector = class _UnisatXConnector extends BitcoinXConnector {
119
+ walletProvider;
120
+ constructor(defaults) {
121
+ super("Unisat", "unisat", defaults);
122
+ }
123
+ static isAvailable() {
124
+ return typeof window !== "undefined" && !!window.unisat;
125
+ }
126
+ get isInstalled() {
127
+ return _UnisatXConnector.isAvailable();
128
+ }
129
+ get installUrl() {
130
+ return WALLET_METADATA.unisat.installUrl;
131
+ }
132
+ get icon() {
133
+ return WALLET_METADATA.unisat.icon;
134
+ }
135
+ async connect() {
136
+ if (!window.unisat) {
137
+ throw new Error("Unisat wallet is not installed");
138
+ }
139
+ const accounts = await window.unisat.requestAccounts();
140
+ const address = accounts[0];
141
+ if (!address) {
142
+ console.warn("[UnisatXConnector] connect: requestAccounts returned no address");
143
+ return void 0;
144
+ }
145
+ this.walletProvider = new UnisatWalletProvider(address, this.defaults);
146
+ return {
147
+ address,
148
+ xChainType: "BITCOIN"
149
+ };
150
+ }
151
+ async disconnect() {
152
+ this.walletProvider = void 0;
153
+ }
154
+ getWalletProvider() {
155
+ return this.walletProvider;
156
+ }
157
+ recreateWalletProvider(xAccount) {
158
+ if (!xAccount.address) return void 0;
159
+ return new UnisatWalletProvider(xAccount.address, this.defaults);
160
+ }
161
+ };
162
+ var XverseWalletProvider = class {
163
+ chainType = "BITCOIN";
164
+ address;
165
+ publicKey;
166
+ defaults;
167
+ constructor(address, publicKey, defaults) {
168
+ this.address = address;
169
+ this.publicKey = publicKey;
170
+ this.defaults = defaults;
171
+ }
172
+ async getWalletAddress() {
173
+ return this.address;
174
+ }
175
+ async getPublicKey() {
176
+ return this.publicKey;
177
+ }
178
+ async getAddressType(_address) {
179
+ return detectBitcoinAddressType(this.address);
180
+ }
181
+ /**
182
+ * Parse a base64-encoded PSBT to count the number of inputs.
183
+ * Reads the unsigned transaction from the PSBT global section.
184
+ */
185
+ countPsbtInputs(psbtBase64) {
186
+ const data = Buffer.from(psbtBase64, "base64");
187
+ let offset = 5;
188
+ const keyLen = data[offset++] ?? 0;
189
+ if (keyLen !== 1 || data[offset++] !== 0) {
190
+ return 1;
191
+ }
192
+ const firstByte = data[offset++] ?? 0;
193
+ if (firstByte === 253) offset += 2;
194
+ else if (firstByte === 254) offset += 4;
195
+ else if (firstByte === 255) offset += 8;
196
+ offset += 4;
197
+ const inputByte = data[offset] ?? 0;
198
+ if (inputByte < 253) return inputByte;
199
+ return 1;
200
+ }
201
+ async signTransaction(psbtBase64, finalize) {
202
+ const effectiveFinalize = finalize ?? this.defaults?.defaultFinalize ?? false;
203
+ const { request } = await import('sats-connect');
204
+ const inputCount = this.countPsbtInputs(psbtBase64);
205
+ const signingIndexes = Array.from({ length: inputCount }, (_, i) => i);
206
+ const response = await request("signPsbt", {
207
+ psbt: psbtBase64,
208
+ broadcast: false,
209
+ signInputs: {
210
+ [this.address]: signingIndexes
211
+ }
212
+ });
213
+ if (response.status === "error") {
214
+ throw new Error(response.error?.message || "Xverse PSBT signing failed");
215
+ }
216
+ const result = response.result;
217
+ if (effectiveFinalize) {
218
+ return Buffer.from(result.psbt, "base64").toString("hex");
219
+ }
220
+ return result.psbt;
221
+ }
222
+ async signEcdsaMessage(message) {
223
+ const { request } = await import('sats-connect');
224
+ const response = await request("signMessage", {
225
+ address: this.address,
226
+ message,
227
+ protocol: MessageSigningProtocols.ECDSA
228
+ });
229
+ if (response.status === "error") {
230
+ throw new Error(response.error?.message || "Xverse ECDSA signing failed");
231
+ }
232
+ return response.result.signature;
233
+ }
234
+ async signBip322Message(message) {
235
+ const { request } = await import('sats-connect');
236
+ const response = await request("signMessage", {
237
+ address: this.address,
238
+ message,
239
+ protocol: MessageSigningProtocols.BIP322
240
+ });
241
+ if (response.status === "error") {
242
+ throw new Error(response.error?.message || "Xverse BIP322 signing failed");
243
+ }
244
+ return response.result.signature;
245
+ }
246
+ async sendBitcoin(toAddress, satoshis) {
247
+ const { request } = await import('sats-connect');
248
+ const response = await request("sendTransfer", {
249
+ recipients: [
250
+ {
251
+ address: toAddress,
252
+ amount: Number(satoshis)
253
+ }
254
+ ]
255
+ });
256
+ if (response.status === "error") {
257
+ throw new Error(response.error?.message || "Xverse sendTransfer failed");
258
+ }
259
+ return response.result.txid;
260
+ }
261
+ };
262
+ var XVERSE_ADDRESS_TYPE_KEY = "xverse-address-type";
263
+ var XverseXConnector = class _XverseXConnector extends BitcoinXConnector {
264
+ walletProvider;
265
+ /** Address purpose used when connecting. Taproot (Ordinals) by default to match Radfi. */
266
+ addressPurpose;
267
+ constructor(defaults) {
268
+ super("Xverse", "xverse", defaults);
269
+ const saved = typeof window !== "undefined" ? localStorage.getItem(XVERSE_ADDRESS_TYPE_KEY) : null;
270
+ this.addressPurpose = saved === "segwit" ? AddressPurpose.Payment : AddressPurpose.Ordinals;
271
+ }
272
+ /** Set address purpose and persist to localStorage. */
273
+ setAddressPurpose(type) {
274
+ this.addressPurpose = type === "taproot" ? AddressPurpose.Ordinals : AddressPurpose.Payment;
275
+ if (typeof window !== "undefined") {
276
+ localStorage.setItem(XVERSE_ADDRESS_TYPE_KEY, type);
277
+ }
278
+ }
279
+ static isAvailable() {
280
+ return typeof window !== "undefined" && !!window.BitcoinProvider;
281
+ }
282
+ get isInstalled() {
283
+ return _XverseXConnector.isAvailable();
284
+ }
285
+ get installUrl() {
286
+ return WALLET_METADATA.xverse.installUrl;
287
+ }
288
+ get icon() {
289
+ return WALLET_METADATA.xverse.icon;
290
+ }
291
+ async connect() {
292
+ if (!_XverseXConnector.isAvailable()) {
293
+ throw new Error("Xverse wallet is not installed");
294
+ }
295
+ const { request } = await import('sats-connect');
296
+ const response = await request("getAccounts", {
297
+ purposes: [this.addressPurpose],
298
+ message: "Connect to Sodax"
299
+ });
300
+ if (response.status === "error") {
301
+ throw new Error(response.error?.message || "Xverse connection failed");
302
+ }
303
+ const accounts = response.result;
304
+ const paymentAccount = accounts.find((a) => a.purpose === this.addressPurpose) || accounts[0];
305
+ if (!paymentAccount) return void 0;
306
+ this.walletProvider = new XverseWalletProvider(
307
+ paymentAccount.address,
308
+ paymentAccount.publicKey,
309
+ this.defaults
310
+ );
311
+ return {
312
+ address: paymentAccount.address,
313
+ publicKey: paymentAccount.publicKey,
314
+ xChainType: "BITCOIN"
315
+ };
316
+ }
317
+ async disconnect() {
318
+ this.walletProvider = void 0;
319
+ }
320
+ getWalletProvider() {
321
+ return this.walletProvider;
322
+ }
323
+ recreateWalletProvider(xAccount) {
324
+ if (!xAccount.address || !xAccount.publicKey) return void 0;
325
+ return new XverseWalletProvider(xAccount.address, xAccount.publicKey, this.defaults);
326
+ }
327
+ };
328
+ var OKXWalletProvider = class {
329
+ chainType = "BITCOIN";
330
+ cachedAddress;
331
+ defaults;
332
+ constructor(address, defaults) {
333
+ this.cachedAddress = address;
334
+ this.defaults = defaults;
335
+ }
336
+ // Lazy resolve so the provider can be constructed before the extension finishes injecting `window.okxwallet` (post-refresh rehydrate path).
337
+ get okx() {
338
+ const o = window.okxwallet?.bitcoin;
339
+ if (!o) throw new Error("OKX wallet not available");
340
+ return o;
341
+ }
342
+ async getWalletAddress() {
343
+ try {
344
+ const accounts = await this.okx.getAccounts();
345
+ if (accounts[0]) this.cachedAddress = accounts[0];
346
+ } catch {
347
+ }
348
+ return this.cachedAddress;
349
+ }
350
+ async getPublicKey() {
351
+ return this.okx.getPublicKey();
352
+ }
353
+ async getAddressType(_address) {
354
+ const address = await this.getWalletAddress();
355
+ return detectBitcoinAddressType(address);
356
+ }
357
+ async signTransaction(psbtBase64, finalize) {
358
+ const effectiveFinalize = finalize ?? this.defaults?.defaultFinalize ?? false;
359
+ const psbtHex = Buffer.from(psbtBase64, "base64").toString("hex");
360
+ return this.okx.signPsbt(psbtHex, { autoFinalized: effectiveFinalize });
361
+ }
362
+ async signEcdsaMessage(message) {
363
+ return this.okx.signMessage(message, "ecdsa");
364
+ }
365
+ async signBip322Message(message) {
366
+ return this.okx.signMessage(message, "bip322-simple");
367
+ }
368
+ async sendBitcoin(toAddress, satoshis) {
369
+ if (satoshis > BigInt(Number.MAX_SAFE_INTEGER)) {
370
+ throw new Error(`Amount ${satoshis} satoshis exceeds safe integer range`);
371
+ }
372
+ return this.okx.sendBitcoin(toAddress, Number(satoshis));
373
+ }
374
+ };
375
+ var OKXXConnector = class _OKXXConnector extends BitcoinXConnector {
376
+ walletProvider;
377
+ constructor(defaults) {
378
+ super("OKX Wallet", "okx-bitcoin", defaults);
379
+ }
380
+ static isAvailable() {
381
+ return typeof window !== "undefined" && !!window.okxwallet?.bitcoin;
382
+ }
383
+ get isInstalled() {
384
+ return _OKXXConnector.isAvailable();
385
+ }
386
+ get installUrl() {
387
+ return WALLET_METADATA.okx.installUrl;
388
+ }
389
+ get icon() {
390
+ return WALLET_METADATA.okx.icon;
391
+ }
392
+ async connect() {
393
+ const okx = window.okxwallet?.bitcoin;
394
+ if (!okx) {
395
+ throw new Error("OKX wallet is not installed");
396
+ }
397
+ const { address } = await okx.connect();
398
+ if (!address) {
399
+ console.warn("[OKXXConnector] connect: okx.connect() returned no address");
400
+ return void 0;
401
+ }
402
+ this.walletProvider = new OKXWalletProvider(address, this.defaults);
403
+ return {
404
+ address,
405
+ xChainType: "BITCOIN"
406
+ };
407
+ }
408
+ async disconnect() {
409
+ this.walletProvider = void 0;
410
+ }
411
+ getWalletProvider() {
412
+ return this.walletProvider;
413
+ }
414
+ recreateWalletProvider(xAccount) {
415
+ if (!xAccount.address) return void 0;
416
+ return new OKXWalletProvider(xAccount.address, this.defaults);
417
+ }
418
+ };
419
+ function getXChainType(xChainId) {
420
+ if (!xChainId) {
421
+ return void 0;
422
+ }
423
+ return baseChainInfo[xChainId].type;
424
+ }
425
+
426
+ // src/xchains/bitcoin/bitcoinSignGuards.ts
427
+ function hasSignBip322(c) {
428
+ return "signBip322Message" in c && typeof c.signBip322Message === "function";
429
+ }
430
+ function hasSignEcdsa(c) {
431
+ return "signEcdsaMessage" in c && typeof c.signEcdsaMessage === "function";
432
+ }
433
+
434
+ // src/chainRegistry.ts
435
+ function defineChain(factory) {
436
+ return factory;
437
+ }
438
+ function narrowConnectors(items, chainType) {
439
+ return items.filter((item) => {
440
+ if (!(item instanceof XConnector)) {
441
+ console.warn(
442
+ `[chainRegistry] ${chainType} connector "${item.id}" must extend XConnector \u2014 skipping. Implement the abstract XConnector class instead of raw IXConnector for full SDK support.`
443
+ );
444
+ return false;
445
+ }
446
+ return true;
447
+ });
448
+ }
449
+ function readConnectorsOverride(chainType, walletConfig) {
450
+ return walletConfig?.[chainType]?.connectors;
451
+ }
452
+ function hasChainOfType(chainType, walletConfig) {
453
+ return walletConfig[chainType] !== void 0;
454
+ }
455
+ var createDefaultActions = (chainType, service, getStore) => ({
456
+ connect: async (xConnectorId) => {
457
+ const connector = service.getXConnectorById(xConnectorId);
458
+ return connector?.connect();
459
+ },
460
+ disconnect: async () => {
461
+ const store = getStore();
462
+ const connectorId = store.xConnections[chainType]?.xConnectorId;
463
+ const connector = connectorId ? service.getXConnectorById(connectorId) : void 0;
464
+ try {
465
+ await connector?.disconnect();
466
+ } finally {
467
+ store.unsetXConnection(chainType);
468
+ }
469
+ },
470
+ getConnectors: () => getStore().xConnectorsByChain[chainType] ?? [],
471
+ getConnection: () => getStore().xConnections[chainType]
472
+ });
473
+ var chainRegistry = {
474
+ EVM: defineChain({
475
+ createService: () => EvmXService.getInstance(),
476
+ displayName: "EVM",
477
+ defaultConnectors: () => [],
478
+ providerManaged: true
479
+ }),
480
+ SUI: defineChain({
481
+ createService: () => SuiXService.getInstance(),
482
+ displayName: "Sui",
483
+ defaultConnectors: () => [],
484
+ providerManaged: true
485
+ }),
486
+ SOLANA: defineChain({
487
+ createService: () => SolanaXService.getInstance(),
488
+ displayName: "Solana",
489
+ defaultConnectors: () => [],
490
+ providerManaged: true
491
+ }),
492
+ BITCOIN: defineChain({
493
+ createService: (walletConfig) => BitcoinXService.getInstance(getRpcUrl(walletConfig?.BITCOIN?.chains?.[ChainKeys.BITCOIN_MAINNET])),
494
+ displayName: "Bitcoin",
495
+ defaultConnectors: (walletConfig) => {
496
+ const defaults = getEntryDefaults(
497
+ walletConfig?.BITCOIN?.chains?.[ChainKeys.BITCOIN_MAINNET]
498
+ );
499
+ return [new UnisatXConnector(defaults), new XverseXConnector(defaults), new OKXXConnector(defaults)];
500
+ },
501
+ providerManaged: false,
502
+ createActions: (service, getStore) => ({
503
+ ...createDefaultActions("BITCOIN", service, getStore),
504
+ signMessage: async (message) => {
505
+ const store = getStore();
506
+ const connection = store.xConnections.BITCOIN;
507
+ const connector = connection?.xConnectorId ? service.getXConnectorById(connection.xConnectorId) : void 0;
508
+ if (!(connector instanceof BitcoinXConnector)) {
509
+ throw new Error("Bitcoin wallet not connected");
510
+ }
511
+ const address = connection?.xAccount.address;
512
+ if (!address) throw new Error("Bitcoin address not found");
513
+ const addressType = detectBitcoinAddressType(address);
514
+ switch (addressType) {
515
+ case "P2WPKH":
516
+ case "P2TR": {
517
+ if (!hasSignBip322(connector)) {
518
+ throw new Error(`${connector.id} does not support BIP-322 signing`);
519
+ }
520
+ return connector.signBip322Message(message);
521
+ }
522
+ case "P2SH":
523
+ case "P2PKH": {
524
+ if (!hasSignEcdsa(connector)) {
525
+ throw new Error(`${connector.id} does not support ECDSA signing`);
526
+ }
527
+ return connector.signEcdsaMessage(message);
528
+ }
529
+ default: {
530
+ const _exhaustiveCheck = addressType;
531
+ throw new Error(`Unhandled Bitcoin address type: ${_exhaustiveCheck}`);
532
+ }
533
+ }
534
+ }
535
+ }),
536
+ createWalletProvider: (service, getStore) => {
537
+ const store = getStore();
538
+ const connection = store.xConnections.BITCOIN;
539
+ if (!connection?.xConnectorId) return void 0;
540
+ const connector = service.getXConnectorById(connection.xConnectorId);
541
+ if (!(connector instanceof BitcoinXConnector)) return void 0;
542
+ return connector.recreateWalletProvider(connection.xAccount);
543
+ }
544
+ }),
545
+ INJECTIVE: defineChain({
546
+ createService: (walletConfig) => InjectiveXService.getInstance(walletConfig?.INJECTIVE?.chains?.[ChainKeys.INJECTIVE_MAINNET]),
547
+ displayName: "Injective",
548
+ defaultConnectors: () => [
549
+ new InjectiveXConnector("MetaMask", Wallet.Metamask),
550
+ new InjectiveXConnector("Keplr", Wallet.Keplr),
551
+ new InjectiveXConnector("Leap", Wallet.Leap)
552
+ ],
553
+ providerManaged: false,
554
+ createActions: (service, getStore) => ({
555
+ ...createDefaultActions("INJECTIVE", service, getStore),
556
+ signMessage: async (message) => {
557
+ const store = getStore();
558
+ const address = store.xConnections.INJECTIVE?.xAccount.address;
559
+ if (!address) throw new Error("Injective address not found");
560
+ const ethereumAddress = getEthereumAddress(address);
561
+ const walletStrategy = service.walletStrategy;
562
+ const res = await walletStrategy.signArbitrary(
563
+ walletStrategy.getWallet() === Wallet.Metamask ? ethereumAddress : address,
564
+ message
565
+ );
566
+ if (!res) throw new Error("Injective signature not found");
567
+ return res;
568
+ }
569
+ }),
570
+ createWalletProvider: (service, getStore) => {
571
+ if (!service) return void 0;
572
+ const defaults = getEntryDefaults(
573
+ getStore().walletConfig?.INJECTIVE?.chains?.[ChainKeys.INJECTIVE_MAINNET]
574
+ );
575
+ return new InjectiveWalletProvider({ msgBroadcaster: service.msgBroadcaster, defaults });
576
+ }
577
+ }),
578
+ STELLAR: defineChain({
579
+ createService: (walletConfig) => {
580
+ const stellarRpc = walletConfig?.STELLAR?.chains?.[ChainKeys.STELLAR_MAINNET];
581
+ return StellarXService.getInstance(stellarRpc?.horizonRpcUrl, stellarRpc?.sorobanRpcUrl);
582
+ },
583
+ displayName: "Stellar",
584
+ defaultConnectors: () => [],
585
+ providerManaged: false,
586
+ discoverConnectors: async (service, getStore) => {
587
+ const STELLAR_DISCOVER_DELAYS_MS = [0, 100, 500];
588
+ let lastIds = "";
589
+ for (const delay of STELLAR_DISCOVER_DELAYS_MS) {
590
+ if (delay) await new Promise((r) => setTimeout(r, delay));
591
+ const wallets = await service.walletsKit.getSupportedWallets();
592
+ const connectors = wallets.filter((w) => w.isAvailable).map((w) => new StellarWalletsKitXConnector(w));
593
+ const ids = connectors.map((c) => c.id).sort().join(",");
594
+ if (ids === lastIds) break;
595
+ lastIds = ids;
596
+ service.setXConnectors(connectors);
597
+ getStore().setXConnectors("STELLAR", connectors);
598
+ }
599
+ },
600
+ createActions: (service, getStore) => ({
601
+ ...createDefaultActions("STELLAR", service, getStore),
602
+ signMessage: async (message) => {
603
+ const res = await service.walletsKit.signMessage(message);
604
+ return res.signedMessage;
605
+ }
606
+ }),
607
+ createWalletProvider: (service, getStore) => {
608
+ if (!service?.walletsKit) return void 0;
609
+ const defaults = getEntryDefaults(
610
+ getStore().walletConfig?.STELLAR?.chains?.[ChainKeys.STELLAR_MAINNET]
611
+ );
612
+ return new StellarWalletProvider({
613
+ type: "BROWSER_EXTENSION",
614
+ walletsKit: service.walletsKit,
615
+ network: "PUBLIC",
616
+ defaults
617
+ });
618
+ }
619
+ }),
620
+ // ICON: signMessage not implemented — Hana wallet does not expose a signing API.
621
+ // connect/disconnect use createDefaultActions (no createActions override needed).
622
+ ICON: defineChain({
623
+ createService: (walletConfig) => IconXService.getInstance(getRpcUrl(walletConfig?.ICON?.chains?.[ChainKeys.ICON_MAINNET])),
624
+ displayName: "ICON",
625
+ defaultConnectors: () => [new IconHanaXConnector()],
626
+ providerManaged: false,
627
+ createWalletProvider: (_service, getStore) => {
628
+ const store = getStore();
629
+ const address = store.xConnections.ICON?.xAccount.address;
630
+ if (!address) return void 0;
631
+ const chainInfo = CHAIN_INFO[1 /* MAINNET */];
632
+ if (!chainInfo) throw new Error("ICON mainnet chain info not found");
633
+ const defaults = getEntryDefaults(
634
+ store.walletConfig?.ICON?.chains?.[ChainKeys.ICON_MAINNET]
635
+ );
636
+ return new IconWalletProvider({
637
+ walletAddress: address,
638
+ rpcUrl: chainInfo.APIEndpoint,
639
+ defaults
640
+ });
641
+ }
642
+ }),
643
+ NEAR: defineChain({
644
+ createService: (walletConfig) => NearXService.getInstance(getRpcUrl(walletConfig?.NEAR?.chains?.[ChainKeys.NEAR_MAINNET])),
645
+ displayName: "NEAR",
646
+ defaultConnectors: () => [],
647
+ providerManaged: false,
648
+ discoverConnectors: async (service, getStore) => {
649
+ await service.walletSelector.whenManifestLoaded;
650
+ const connectors = service.walletSelector.availableWallets.map((w) => new NearXConnector(w));
651
+ service.setXConnectors(connectors);
652
+ getStore().setXConnectors("NEAR", connectors);
653
+ },
654
+ createActions: (service, getStore) => ({
655
+ ...createDefaultActions("NEAR", service, getStore),
656
+ disconnect: async () => {
657
+ try {
658
+ service.walletSelector.disconnect();
659
+ } finally {
660
+ getStore().unsetXConnection("NEAR");
661
+ }
662
+ }
663
+ }),
664
+ createWalletProvider: (service, getStore) => {
665
+ if (!service?.walletSelector) return void 0;
666
+ const defaults = getEntryDefaults(
667
+ getStore().walletConfig?.NEAR?.chains?.[ChainKeys.NEAR_MAINNET]
668
+ );
669
+ return new NearWalletProvider({ wallet: service.walletSelector, defaults });
670
+ }
671
+ }),
672
+ STACKS: defineChain({
673
+ createService: (walletConfig) => StacksXService.getInstance(walletConfig?.STACKS?.chains?.[ChainKeys.STACKS_MAINNET]),
674
+ displayName: "Stacks",
675
+ defaultConnectors: () => STACKS_PROVIDERS.map((c) => new StacksXConnector(c)),
676
+ providerManaged: false,
677
+ createWalletProvider: (service, getStore) => {
678
+ const store = getStore();
679
+ const connection = store.xConnections.STACKS;
680
+ const address = connection?.xAccount.address;
681
+ if (!address) return void 0;
682
+ const connector = connection?.xConnectorId ? service.getXConnectorById(connection.xConnectorId) : void 0;
683
+ const provider = connector instanceof StacksXConnector ? connector.getProvider() : void 0;
684
+ const defaults = getEntryDefaults(
685
+ store.walletConfig?.STACKS?.chains?.[ChainKeys.STACKS_MAINNET]
686
+ );
687
+ return new StacksWalletProvider({ address, provider, defaults });
688
+ }
689
+ })
690
+ };
691
+ var createChainServices = (walletConfig, getStore) => {
692
+ const xServices = {};
693
+ const xConnectorsByChain = {};
694
+ const enabledChains = [];
695
+ const chainActions = {};
696
+ for (const chainType of ChainTypeArr) {
697
+ if (!hasChainOfType(chainType, walletConfig)) continue;
698
+ const factory = chainRegistry[chainType];
699
+ if (!factory) continue;
700
+ const service = factory.createService(walletConfig);
701
+ xServices[chainType] = service;
702
+ enabledChains.push(chainType);
703
+ if (!factory.providerManaged) {
704
+ const override = readConnectorsOverride(chainType, walletConfig);
705
+ const connectors = override ? narrowConnectors(override, chainType) : factory.defaultConnectors(walletConfig);
706
+ service.setXConnectors(connectors);
707
+ xConnectorsByChain[chainType] = connectors;
708
+ chainActions[chainType] = factory.createActions ? factory.createActions(service, getStore) : createDefaultActions(chainType, service, getStore);
709
+ if (factory.discoverConnectors) {
710
+ factory.discoverConnectors(service, getStore).catch((err) => {
711
+ console.warn(`[wallet-sdk-react] discoverConnectors failed for ${chainType}:`, err);
712
+ });
713
+ }
714
+ }
715
+ }
716
+ return { xServices, xConnectorsByChain, enabledChains, chainActions };
717
+ };
718
+
719
+ // src/useXWalletStore.ts
720
+ var useXWalletStore = create()(
721
+ devtools(
722
+ persist(
723
+ immer((set, get) => ({
724
+ xServices: {},
725
+ xConnections: {},
726
+ xConnectorsByChain: {},
727
+ enabledChains: [],
728
+ chainActions: {},
729
+ walletProviders: {},
730
+ walletConfig: void 0,
731
+ userDisconnected: {},
732
+ setXConnection: (xChainType, xConnection) => {
733
+ set((state) => {
734
+ state.xConnections[xChainType] = xConnection;
735
+ });
736
+ const factory = chainRegistry[xChainType]?.createWalletProvider;
737
+ if (factory) {
738
+ const service = get().xServices[xChainType];
739
+ if (service) {
740
+ const provider = factory(service, () => get());
741
+ get().setWalletProvider(xChainType, provider);
742
+ }
743
+ }
744
+ },
745
+ unsetXConnection: (xChainType) => {
746
+ set((state) => {
747
+ delete state.xConnections[xChainType];
748
+ delete state.walletProviders[xChainType];
749
+ });
750
+ },
751
+ setXConnectors: (xChainType, connectors) => {
752
+ set((state) => {
753
+ state.xConnectorsByChain[xChainType] = connectors;
754
+ });
755
+ },
756
+ registerChainActions: (xChainType, actions) => {
757
+ set((state) => {
758
+ state.chainActions[xChainType] = actions;
759
+ });
760
+ },
761
+ setWalletProvider: (xChainType, provider) => {
762
+ set((state) => {
763
+ if (provider) {
764
+ state.walletProviders[xChainType] = provider;
765
+ } else {
766
+ delete state.walletProviders[xChainType];
767
+ }
768
+ });
769
+ },
770
+ getWalletProvider: (xChainType) => {
771
+ if (!xChainType) return void 0;
772
+ return get().walletProviders[xChainType];
773
+ },
774
+ initChainServices: (walletConfig) => {
775
+ const result = createChainServices(walletConfig, () => get());
776
+ set((state) => {
777
+ state.xServices = result.xServices;
778
+ state.enabledChains = result.enabledChains;
779
+ Object.assign(state.xConnectorsByChain, result.xConnectorsByChain);
780
+ Object.assign(state.chainActions, result.chainActions);
781
+ });
782
+ set({ walletConfig });
783
+ },
784
+ cleanupDisabledConnections: () => {
785
+ set((state) => {
786
+ for (const chainType of ChainTypeArr) {
787
+ if (state.xConnections[chainType] && !state.enabledChains.includes(chainType)) {
788
+ delete state.xConnections[chainType];
789
+ delete state.walletProviders[chainType];
790
+ }
791
+ }
792
+ });
793
+ },
794
+ markUserDisconnected: (xChainType) => {
795
+ set((state) => {
796
+ state.userDisconnected[xChainType] = true;
797
+ });
798
+ },
799
+ clearUserDisconnected: (xChainType) => {
800
+ set((state) => {
801
+ delete state.userDisconnected[xChainType];
802
+ });
803
+ }
804
+ })),
805
+ {
806
+ // key kept as 'xwagmi-store' for backward compat — existing users won't lose persisted connections on upgrade
807
+ name: "xwagmi-store",
808
+ storage: createJSONStorage(() => localStorage),
809
+ partialize: (state) => ({
810
+ xConnections: state.xConnections,
811
+ userDisconnected: state.userDisconnected
812
+ })
813
+ }
814
+ ),
815
+ { name: "xwagmi-store" }
816
+ )
817
+ );
818
+
819
+ // src/actions/getXService.ts
820
+ function getXService(xChainType) {
821
+ const service = useXWalletStore.getState().xServices[xChainType];
822
+ if (!service) {
823
+ throw new Error(`XService for chain type "${xChainType}" is not initialized. Is the chain enabled in config?`);
824
+ }
825
+ return service;
826
+ }
827
+
828
+ // src/hooks/useXConnection.ts
829
+ function useXConnection({ xChainType } = {}) {
830
+ return useXWalletStore((state) => xChainType ? state.xConnections?.[xChainType] : void 0);
831
+ }
832
+
833
+ // src/hooks/useXAccount.ts
834
+ function useXAccount({ xChainId, xChainType }) {
835
+ assert(!(xChainId && xChainType), "[useXAccount] pass either xChainId or xChainType, not both");
836
+ assert(xChainId || xChainType, "[useXAccount] pass xChainId or xChainType");
837
+ const target = xChainType ?? getXChainType(xChainId);
838
+ const xConnection = useXConnection({ xChainType: target });
839
+ return useMemo(
840
+ () => xConnection?.xAccount ?? { address: void 0, xChainType: target },
841
+ [target, xConnection]
842
+ );
843
+ }
844
+
845
+ // src/hooks/useEnabledChains.ts
846
+ function useEnabledChains() {
847
+ return useXWalletStore((state) => state.enabledChains);
848
+ }
849
+
850
+ // src/hooks/useXConnections.ts
851
+ function useXConnections() {
852
+ return useXWalletStore((state) => state.xConnections);
853
+ }
854
+
855
+ // src/hooks/useXAccounts.ts
856
+ function useXAccounts() {
857
+ const enabledChains = useEnabledChains();
858
+ const xConnections = useXConnections();
859
+ return useMemo(() => {
860
+ const result = {};
861
+ for (const xChainType of enabledChains) {
862
+ const xConnection = xConnections[xChainType];
863
+ result[xChainType] = xConnection?.xAccount ?? { address: void 0, xChainType };
864
+ }
865
+ return result;
866
+ }, [enabledChains, xConnections]);
867
+ }
868
+ function useXConnect() {
869
+ const setXConnection = useXWalletStore((state) => state.setXConnection);
870
+ const actionsRegistry = useXWalletStore((state) => state.chainActions);
871
+ return useMutation({
872
+ mutationFn: async (xConnector) => {
873
+ const chainActions = actionsRegistry[xConnector.xChainType];
874
+ if (!chainActions) {
875
+ throw new Error(`Chain "${xConnector.xChainType}" is not enabled or ChainActions not registered`);
876
+ }
877
+ const xAccount = await chainActions.connect(xConnector.id);
878
+ if (xAccount) {
879
+ setXConnection(xConnector.xChainType, {
880
+ xAccount,
881
+ xConnectorId: xConnector.id
882
+ });
883
+ }
884
+ return xAccount;
885
+ }
886
+ });
887
+ }
888
+
889
+ // src/hooks/useXConnectors.ts
890
+ var warnedChains = /* @__PURE__ */ new Set();
891
+ function useXConnectors({ xChainType } = {}) {
892
+ return useXWalletStore((state) => {
893
+ if (!xChainType) return [];
894
+ if (!state.enabledChains.includes(xChainType) && !warnedChains.has(xChainType)) {
895
+ warnedChains.add(xChainType);
896
+ console.warn(
897
+ `[useXConnectors] chain "${xChainType}" is not enabled in SodaxWalletProvider config.chains \u2014 returning empty list`
898
+ );
899
+ }
900
+ return state.xConnectorsByChain[xChainType] ?? [];
901
+ });
902
+ }
903
+
904
+ // src/hooks/useXConnectorsByChain.ts
905
+ function useXConnectorsByChain() {
906
+ return useXWalletStore((state) => state.xConnectorsByChain);
907
+ }
908
+
909
+ // src/utils/matchConnectorIdentifier.ts
910
+ var SHORT_IDENTIFIER_THRESHOLD = 3;
911
+ var warnedShortIdentifiers = /* @__PURE__ */ new Set();
912
+ function matchesConnectorIdentifier(connector, identifier) {
913
+ const needle = identifier.toLowerCase();
914
+ if (needle.length > 0 && needle.length < SHORT_IDENTIFIER_THRESHOLD && !warnedShortIdentifiers.has(needle)) {
915
+ warnedShortIdentifiers.add(needle);
916
+ console.warn(
917
+ `[matchesConnectorIdentifier] identifier "${identifier}" is ${needle.length} chars \u2014 substring matching on short strings frequently hits unintended connectors. Use a more distinctive wallet brand name, or match a single connector via useXConnectors(chainType).find(c => c.id === '...') directly.`
918
+ );
919
+ }
920
+ return connector.id.toLowerCase().includes(needle) || connector.name.toLowerCase().includes(needle);
921
+ }
922
+
923
+ // src/hooks/useIsWalletInstalled.ts
924
+ function useIsWalletInstalled(options) {
925
+ const xConnectorsByChain = useXWalletStore((s) => s.xConnectorsByChain);
926
+ return isAnyConnectorInstalled(options, xConnectorsByChain);
927
+ }
928
+ function isAnyConnectorInstalled(options, xConnectorsByChain) {
929
+ const { connectors: identifiers, chainType } = options;
930
+ if (identifiers === void 0 && chainType === void 0) {
931
+ console.warn(
932
+ "[useIsWalletInstalled] called without `connectors` or `chainType` \u2014 returning `false`. Supply at least one filter."
933
+ );
934
+ return false;
935
+ }
936
+ if (identifiers && identifiers.length === 0) return false;
937
+ const chainsToScan = chainType ? [xConnectorsByChain[chainType]] : Object.values(xConnectorsByChain);
938
+ for (const chainConnectors of chainsToScan) {
939
+ if (!chainConnectors) continue;
940
+ for (const connector of chainConnectors) {
941
+ if (!connector.isInstalled) continue;
942
+ if (!identifiers) return true;
943
+ if (identifiers.some((id) => matchesConnectorIdentifier(connector, id))) return true;
944
+ }
945
+ }
946
+ return false;
947
+ }
948
+
949
+ // src/utils/chainOrder.ts
950
+ function compareChainByOrder(a, b, order) {
951
+ const ia = order.indexOf(a);
952
+ const ib = order.indexOf(b);
953
+ if (ia === -1 && ib === -1) return a.localeCompare(b);
954
+ if (ia === -1) return 1;
955
+ if (ib === -1) return -1;
956
+ return ia - ib;
957
+ }
958
+
959
+ // src/hooks/useChainGroups.ts
960
+ function getSpokeChainKeysByType(chainType) {
961
+ const ids = [];
962
+ for (const chainKey of CHAIN_KEYS) {
963
+ if (baseChainInfo[chainKey].type === chainType) ids.push(chainKey);
964
+ }
965
+ return ids;
966
+ }
967
+ function buildChainGroups(enabledChains, xConnections, registry = chainRegistry, order) {
968
+ const chains = order ? [...enabledChains].sort((a, b) => compareChainByOrder(a, b, order)) : enabledChains;
969
+ return chains.map((chainType) => {
970
+ const factory = registry[chainType];
971
+ const connection = xConnections[chainType];
972
+ return {
973
+ chainType,
974
+ chainIds: getSpokeChainKeysByType(chainType),
975
+ displayName: factory?.displayName ?? chainType,
976
+ iconUrl: factory?.iconUrl,
977
+ isConnected: !!connection?.xAccount.address,
978
+ account: connection?.xAccount,
979
+ connectorId: connection?.xConnectorId
980
+ };
981
+ });
982
+ }
983
+ function useChainGroups({ order } = {}) {
984
+ const enabledChains = useEnabledChains();
985
+ const xConnections = useXConnections();
986
+ return useMemo(
987
+ () => buildChainGroups(enabledChains, xConnections, chainRegistry, order),
988
+ [enabledChains, xConnections, order]
989
+ );
990
+ }
991
+ function buildConnectedChains(xConnections, xConnectorsByChain, isReady = true, order) {
992
+ const chains = [];
993
+ for (const chainType of ChainTypeArr) {
994
+ const connection = xConnections[chainType];
995
+ if (!connection?.xAccount.address) continue;
996
+ const connectors = xConnectorsByChain[chainType] ?? [];
997
+ const connector = connectors.find((c) => c.id === connection.xConnectorId);
998
+ chains.push({
999
+ chainType,
1000
+ account: connection.xAccount,
1001
+ connectorId: connection.xConnectorId,
1002
+ connectorName: connector?.name,
1003
+ connectorIcon: connector?.icon
1004
+ });
1005
+ }
1006
+ if (order) {
1007
+ chains.sort((a, b) => compareChainByOrder(a.chainType, b.chainType, order));
1008
+ }
1009
+ return {
1010
+ chains,
1011
+ total: chains.length,
1012
+ status: isReady ? "ready" : "loading"
1013
+ };
1014
+ }
1015
+ function subscribeHydration(onChange) {
1016
+ const unsubHydrate = useXWalletStore.persist.onHydrate(onChange);
1017
+ const unsubFinish = useXWalletStore.persist.onFinishHydration(onChange);
1018
+ return () => {
1019
+ unsubHydrate();
1020
+ unsubFinish();
1021
+ };
1022
+ }
1023
+ function useConnectedChains({ order } = {}) {
1024
+ const xConnections = useXConnections();
1025
+ const xConnectorsByChain = useXConnectorsByChain();
1026
+ const isReady = useSyncExternalStore(
1027
+ subscribeHydration,
1028
+ () => useXWalletStore.persist.hasHydrated(),
1029
+ () => false
1030
+ );
1031
+ return useMemo(
1032
+ () => buildConnectedChains(xConnections, xConnectorsByChain, isReady, order),
1033
+ [xConnections, xConnectorsByChain, isReady, order]
1034
+ );
1035
+ }
1036
+ function useXDisconnect() {
1037
+ const actionsRegistry = useXWalletStore((state) => state.chainActions);
1038
+ return useCallback(
1039
+ async ({ xChainType }) => {
1040
+ const chainActions = actionsRegistry[xChainType];
1041
+ if (chainActions) {
1042
+ await chainActions.disconnect();
1043
+ } else {
1044
+ console.warn(
1045
+ `[useXDisconnect] No chain actions registered for "${xChainType}". Is it enabled in config.chains?`
1046
+ );
1047
+ }
1048
+ },
1049
+ [actionsRegistry]
1050
+ );
1051
+ }
1052
+
1053
+ // src/hooks/useConnectionFlow.ts
1054
+ function useConnectionFlow() {
1055
+ const mutation = useXConnect();
1056
+ const disconnect = useXDisconnect();
1057
+ const [error, setError] = useState(null);
1058
+ const [activeConnector, setActiveConnector] = useState(null);
1059
+ const lastConnectorRef = useRef(null);
1060
+ const connect = useCallback(
1061
+ async (connector) => {
1062
+ lastConnectorRef.current = connector;
1063
+ setActiveConnector(connector);
1064
+ setError(null);
1065
+ try {
1066
+ return await mutation.mutateAsync(connector);
1067
+ } catch (raw) {
1068
+ setError(raw instanceof Error ? raw : new Error(String(raw)));
1069
+ return void 0;
1070
+ }
1071
+ },
1072
+ [mutation]
1073
+ );
1074
+ const retry = useCallback(async () => {
1075
+ const last = lastConnectorRef.current;
1076
+ if (!last) return void 0;
1077
+ return connect(last);
1078
+ }, [connect]);
1079
+ const reset = useCallback(() => {
1080
+ mutation.reset();
1081
+ setError(null);
1082
+ setActiveConnector(null);
1083
+ lastConnectorRef.current = null;
1084
+ }, [mutation]);
1085
+ const status = error ? "error" : mutation.isPending ? "connecting" : mutation.isSuccess ? "success" : "idle";
1086
+ return {
1087
+ status,
1088
+ error,
1089
+ activeConnector,
1090
+ activeChainType: activeConnector?.xChainType ?? null,
1091
+ connect,
1092
+ disconnect,
1093
+ retry,
1094
+ reset
1095
+ };
1096
+ }
1097
+ function resolveBatchTargets(connectors, connectorsByChain) {
1098
+ const targets = [];
1099
+ for (const chainType of ChainTypeArr) {
1100
+ const chainConnectors = connectorsByChain[chainType];
1101
+ if (!chainConnectors?.length) continue;
1102
+ for (const identifier of connectors) {
1103
+ const match = chainConnectors.find((c) => matchesConnectorIdentifier(c, identifier));
1104
+ if (match) targets.push({ chainType, connector: match });
1105
+ }
1106
+ }
1107
+ return targets;
1108
+ }
1109
+ async function runBatchConnect(targets, helpers) {
1110
+ const successful = [];
1111
+ const failed = [];
1112
+ const skipped = [];
1113
+ const finalized = /* @__PURE__ */ new Set();
1114
+ const pendingError = /* @__PURE__ */ new Map();
1115
+ const emit = (event) => {
1116
+ if (!helpers.onProgress) return;
1117
+ try {
1118
+ helpers.onProgress(event);
1119
+ } catch (err) {
1120
+ console.error("[useBatchConnect] onProgress threw:", err);
1121
+ }
1122
+ };
1123
+ for (const target of targets) {
1124
+ if (finalized.has(target.chainType)) continue;
1125
+ if (helpers.skipConnected && helpers.isConnected(target.chainType)) {
1126
+ skipped.push(target.chainType);
1127
+ finalized.add(target.chainType);
1128
+ emit({ chainType: target.chainType, outcome: "skipped" });
1129
+ continue;
1130
+ }
1131
+ try {
1132
+ await helpers.connect(target.connector);
1133
+ successful.push(target.chainType);
1134
+ finalized.add(target.chainType);
1135
+ pendingError.delete(target.chainType);
1136
+ emit({ chainType: target.chainType, outcome: "success" });
1137
+ } catch (raw) {
1138
+ const error = raw instanceof Error ? raw : new Error(String(raw));
1139
+ pendingError.set(target.chainType, error);
1140
+ emit({ chainType: target.chainType, outcome: "failure", error });
1141
+ }
1142
+ }
1143
+ for (const [chainType, error] of pendingError) {
1144
+ if (!finalized.has(chainType)) failed.push({ chainType, error });
1145
+ }
1146
+ return { successful, failed, skipped };
1147
+ }
1148
+ function useBatchConnect({
1149
+ connectors,
1150
+ skipConnected = false,
1151
+ onProgress
1152
+ }) {
1153
+ assert(Array.isArray(connectors), "useBatchConnect: connectors must be an array");
1154
+ const { mutateAsync: connect } = useXConnect();
1155
+ const xConnectorsByChain = useXConnectorsByChain();
1156
+ const xConnections = useXConnections();
1157
+ const [status, setStatus] = useState("idle");
1158
+ const [result, setResult] = useState(null);
1159
+ const inFlightRef = useRef(null);
1160
+ const onProgressRef = useRef(onProgress);
1161
+ onProgressRef.current = onProgress;
1162
+ const run = useCallback(async () => {
1163
+ if (inFlightRef.current) return inFlightRef.current;
1164
+ const batchPromise = (async () => {
1165
+ setStatus("running");
1166
+ const targets = resolveBatchTargets(connectors, xConnectorsByChain);
1167
+ const finalResult = await runBatchConnect(targets, {
1168
+ connect,
1169
+ isConnected: (chainType) => !!xConnections[chainType]?.xAccount.address,
1170
+ skipConnected,
1171
+ onProgress: (event) => onProgressRef.current?.(event)
1172
+ });
1173
+ setResult(finalResult);
1174
+ setStatus("done");
1175
+ return finalResult;
1176
+ })();
1177
+ inFlightRef.current = batchPromise;
1178
+ try {
1179
+ return await batchPromise;
1180
+ } finally {
1181
+ inFlightRef.current = null;
1182
+ }
1183
+ }, [connect, connectors, xConnectorsByChain, xConnections, skipConnected]);
1184
+ const reset = useCallback(() => {
1185
+ setStatus("idle");
1186
+ setResult(null);
1187
+ }, []);
1188
+ return { run, status, result, reset };
1189
+ }
1190
+ function resolveDisconnectTargets(connectors, xConnections, xConnectorsByChain) {
1191
+ const targets = [];
1192
+ for (const chainType of ChainTypeArr) {
1193
+ const connection = xConnections[chainType];
1194
+ if (!connection?.xAccount.address) continue;
1195
+ if (!connectors) {
1196
+ targets.push(chainType);
1197
+ continue;
1198
+ }
1199
+ const activeConnector = xConnectorsByChain[chainType]?.find((c) => c.id === connection.xConnectorId);
1200
+ if (!activeConnector) continue;
1201
+ if (connectors.some((identifier) => matchesConnectorIdentifier(activeConnector, identifier))) {
1202
+ targets.push(chainType);
1203
+ }
1204
+ }
1205
+ return targets;
1206
+ }
1207
+ async function runBatchDisconnect(chainTypes, disconnect, onProgress) {
1208
+ const successful = [];
1209
+ const failed = [];
1210
+ const emit = (event) => {
1211
+ if (!onProgress) return;
1212
+ try {
1213
+ onProgress(event);
1214
+ } catch (err) {
1215
+ console.error("[useBatchDisconnect] onProgress threw:", err);
1216
+ }
1217
+ };
1218
+ for (const chainType of chainTypes) {
1219
+ try {
1220
+ await disconnect({ xChainType: chainType });
1221
+ successful.push(chainType);
1222
+ emit({ chainType, outcome: "success" });
1223
+ } catch (raw) {
1224
+ const error = raw instanceof Error ? raw : new Error(String(raw));
1225
+ failed.push({ chainType, error });
1226
+ emit({ chainType, outcome: "failure", error });
1227
+ }
1228
+ }
1229
+ return { successful, failed };
1230
+ }
1231
+ function useBatchDisconnect({
1232
+ connectors,
1233
+ onProgress
1234
+ } = {}) {
1235
+ const disconnect = useXDisconnect();
1236
+ const xConnections = useXConnections();
1237
+ const xConnectorsByChain = useXConnectorsByChain();
1238
+ const [status, setStatus] = useState("idle");
1239
+ const [result, setResult] = useState(null);
1240
+ const inFlightRef = useRef(null);
1241
+ const onProgressRef = useRef(onProgress);
1242
+ onProgressRef.current = onProgress;
1243
+ const run = useCallback(async () => {
1244
+ if (inFlightRef.current) return inFlightRef.current;
1245
+ const batchPromise = (async () => {
1246
+ setStatus("running");
1247
+ const targets = resolveDisconnectTargets(connectors, xConnections, xConnectorsByChain);
1248
+ const finalResult = await runBatchDisconnect(targets, disconnect, (event) => onProgressRef.current?.(event));
1249
+ setResult(finalResult);
1250
+ setStatus("done");
1251
+ return finalResult;
1252
+ })();
1253
+ inFlightRef.current = batchPromise;
1254
+ try {
1255
+ return await batchPromise;
1256
+ } finally {
1257
+ inFlightRef.current = null;
1258
+ }
1259
+ }, [connectors, disconnect, xConnections, xConnectorsByChain]);
1260
+ const reset = useCallback(() => {
1261
+ setStatus("idle");
1262
+ setResult(null);
1263
+ }, []);
1264
+ return { run, status, result, reset };
1265
+ }
1266
+ var useWalletModalStore = create()(
1267
+ devtools(
1268
+ immer((set) => ({
1269
+ walletModal: { kind: "closed" },
1270
+ open: () => {
1271
+ set((state) => {
1272
+ state.walletModal = { kind: "chainSelect" };
1273
+ });
1274
+ },
1275
+ close: () => {
1276
+ set((state) => {
1277
+ state.walletModal = { kind: "closed" };
1278
+ });
1279
+ },
1280
+ back: () => {
1281
+ set((state) => {
1282
+ const current = state.walletModal;
1283
+ switch (current.kind) {
1284
+ case "walletSelect":
1285
+ state.walletModal = { kind: "chainSelect" };
1286
+ return;
1287
+ case "connecting":
1288
+ case "error":
1289
+ state.walletModal = { kind: "walletSelect", chainType: current.chainType };
1290
+ return;
1291
+ case "success":
1292
+ state.walletModal = { kind: "closed" };
1293
+ return;
1294
+ }
1295
+ });
1296
+ },
1297
+ selectChain: (chainType) => {
1298
+ set((state) => {
1299
+ state.walletModal = { kind: "walletSelect", chainType };
1300
+ });
1301
+ },
1302
+ setConnecting: (chainType, connector) => {
1303
+ set((state) => {
1304
+ state.walletModal = { kind: "connecting", chainType, connector };
1305
+ });
1306
+ },
1307
+ setSuccess: (chainType, connector, account) => {
1308
+ set((state) => {
1309
+ state.walletModal = { kind: "success", chainType, connector, account };
1310
+ });
1311
+ },
1312
+ setError: (chainType, connector, error) => {
1313
+ set((state) => {
1314
+ state.walletModal = { kind: "error", chainType, connector, error };
1315
+ });
1316
+ }
1317
+ })),
1318
+ { name: "wallet-modal-store" }
1319
+ )
1320
+ );
1321
+
1322
+ // src/hooks/useWalletModal.ts
1323
+ var DEFAULT_HYDRATION_TIMEOUT_MS = 5e3;
1324
+ function waitForXConnection(chainType, expectedConnectorId, timeoutMs = DEFAULT_HYDRATION_TIMEOUT_MS) {
1325
+ return new Promise((resolve) => {
1326
+ let settled = false;
1327
+ const matches = (connection) => connection?.xConnectorId === expectedConnectorId && !!connection?.xAccount?.address;
1328
+ const finish = (account) => {
1329
+ if (settled) return;
1330
+ settled = true;
1331
+ clearTimeout(timer);
1332
+ unsubscribe();
1333
+ resolve(account);
1334
+ };
1335
+ const timer = setTimeout(() => finish(void 0), timeoutMs);
1336
+ const unsubscribe = useXWalletStore.subscribe((state) => {
1337
+ const connection = state.xConnections[chainType];
1338
+ if (matches(connection)) finish(connection?.xAccount);
1339
+ });
1340
+ const initial = useXWalletStore.getState().xConnections[chainType];
1341
+ if (matches(initial)) finish(initial?.xAccount);
1342
+ });
1343
+ }
1344
+ function useWalletModal({
1345
+ onConnected,
1346
+ hydrationTimeoutMs
1347
+ } = {}) {
1348
+ const state = useWalletModalStore((s) => s.walletModal);
1349
+ const open = useWalletModalStore((s) => s.open);
1350
+ const close = useWalletModalStore((s) => s.close);
1351
+ const back = useWalletModalStore((s) => s.back);
1352
+ const selectChain = useWalletModalStore((s) => s.selectChain);
1353
+ const setConnecting = useWalletModalStore((s) => s.setConnecting);
1354
+ const setSuccess = useWalletModalStore((s) => s.setSuccess);
1355
+ const setError = useWalletModalStore((s) => s.setError);
1356
+ const { mutateAsync: connect } = useXConnect();
1357
+ const inFlightRef = useRef(null);
1358
+ const selectWallet = useCallback(
1359
+ async (connector) => {
1360
+ if (inFlightRef.current?.connector === connector) {
1361
+ return inFlightRef.current.promise;
1362
+ }
1363
+ if (!connector.isInstalled) {
1364
+ const installHint = connector.installUrl ? " Install the extension and reload the page." : "";
1365
+ setError(
1366
+ connector.xChainType,
1367
+ connector,
1368
+ new Error(`${connector.name} is not installed.${installHint}`)
1369
+ );
1370
+ return void 0;
1371
+ }
1372
+ const isStillCurrent = () => {
1373
+ const current = useWalletModalStore.getState().walletModal;
1374
+ return current.kind === "connecting" && current.connector === connector;
1375
+ };
1376
+ const promise = (async () => {
1377
+ setConnecting(connector.xChainType, connector);
1378
+ try {
1379
+ const direct = await connect(connector);
1380
+ if (!isStillCurrent()) return void 0;
1381
+ const account = direct?.address ? direct : await waitForXConnection(connector.xChainType, connector.id, hydrationTimeoutMs);
1382
+ if (!isStillCurrent()) return void 0;
1383
+ if (account?.address) {
1384
+ setSuccess(connector.xChainType, connector, account);
1385
+ try {
1386
+ await onConnected?.(connector.xChainType, account);
1387
+ } catch (callbackError) {
1388
+ console.error("[useWalletModal] onConnected threw \u2014 connection is still successful:", callbackError);
1389
+ }
1390
+ return account;
1391
+ }
1392
+ setError(
1393
+ connector.xChainType,
1394
+ connector,
1395
+ new Error("Connection did not complete. Did you close the wallet popup?")
1396
+ );
1397
+ return void 0;
1398
+ } catch (raw) {
1399
+ if (!isStillCurrent()) return void 0;
1400
+ const error = raw instanceof Error ? raw : new Error(String(raw));
1401
+ setError(connector.xChainType, connector, error);
1402
+ return void 0;
1403
+ } finally {
1404
+ if (inFlightRef.current?.connector === connector) {
1405
+ inFlightRef.current = null;
1406
+ }
1407
+ }
1408
+ })();
1409
+ inFlightRef.current = { connector, promise };
1410
+ return promise;
1411
+ },
1412
+ [connect, onConnected, hydrationTimeoutMs, setConnecting, setError, setSuccess]
1413
+ );
1414
+ const retry = useCallback(async () => {
1415
+ if (state.kind !== "error") return void 0;
1416
+ return selectWallet(state.connector);
1417
+ }, [state, selectWallet]);
1418
+ return { state, open, close, back, selectChain, selectWallet, retry };
1419
+ }
1420
+
1421
+ // src/hooks/useXService.ts
1422
+ function useXService({ xChainType } = {}) {
1423
+ const xService = useXWalletStore((state) => xChainType ? state.xServices[xChainType] : void 0);
1424
+ return xService;
1425
+ }
1426
+
1427
+ // src/hooks/useXServices.ts
1428
+ function useXServices() {
1429
+ return useXWalletStore((state) => state.xServices);
1430
+ }
1431
+ var WalletConfigContext = createContext(null);
1432
+ var WalletConfigProvider = WalletConfigContext.Provider;
1433
+ function useWalletConfig() {
1434
+ const config = useContext(WalletConfigContext);
1435
+ if (!config) {
1436
+ throw new Error("useWalletConfig must be used within SodaxWalletProvider");
1437
+ }
1438
+ return config;
1439
+ }
1440
+ function useIsChainEnabled(chainType) {
1441
+ const config = useWalletConfig();
1442
+ return config[chainType] !== void 0;
1443
+ }
1444
+ function useEnabledChainTypes() {
1445
+ const config = useWalletConfig();
1446
+ return Object.keys(config).filter((t) => config[t] !== void 0);
1447
+ }
1448
+ function useEthereumChainId() {
1449
+ const xService = useXService({ xChainType: "INJECTIVE" });
1450
+ const injectiveXService = xService instanceof InjectiveXService ? xService : void 0;
1451
+ const [ethereumChainId, setEthereumChainId] = useState(null);
1452
+ useEffect(() => {
1453
+ if (!injectiveXService?.walletStrategy?.getWallet()) return;
1454
+ const walletStrategy = injectiveXService.walletStrategy;
1455
+ if (walletStrategy.getWallet() !== Wallet.Metamask) return;
1456
+ const getEthereumChainId = async () => {
1457
+ try {
1458
+ const chainId = await walletStrategy.getEthereumChainId();
1459
+ setEthereumChainId(Number.parseInt(chainId));
1460
+ } catch (error) {
1461
+ console.warn("Failed to get Ethereum chain ID:", error);
1462
+ }
1463
+ };
1464
+ getEthereumChainId();
1465
+ try {
1466
+ const strategy = walletStrategy.getStrategy();
1467
+ const isEvmStrategy = isRecord(strategy) && hasFunctionProperty(strategy, "onChainIdChanged");
1468
+ assert(isEvmStrategy, "[useEthereumChainId] walletStrategy.getStrategy() is not an EvmWalletStrategy");
1469
+ strategy.onChainIdChanged(getEthereumChainId);
1470
+ } catch (error) {
1471
+ console.warn("Failed to subscribe to chain ID changes:", error);
1472
+ }
1473
+ }, [injectiveXService?.walletStrategy]);
1474
+ return ethereumChainId;
1475
+ }
1476
+ var EVM_DISABLED_RESULT = { isWrongChain: false, handleSwitchChain: () => {
1477
+ } };
1478
+ var isEip1193Provider = (value) => {
1479
+ return isRecord(value) && hasFunctionProperty(value, "request") && hasFunctionProperty(value, "on");
1480
+ };
1481
+ var getInjectedEthereumProvider = () => {
1482
+ const maybeEthereum = window.ethereum;
1483
+ assert(isEip1193Provider(maybeEthereum), "[useEvmSwitchChain] window.ethereum is not an EIP-1193 provider");
1484
+ return maybeEthereum;
1485
+ };
1486
+ var switchEthereumChain = async () => {
1487
+ const metamaskProvider = getInjectedEthereumProvider();
1488
+ return await Promise.race([
1489
+ metamaskProvider.request({
1490
+ method: "wallet_switchEthereumChain",
1491
+ params: [{ chainId: "0x1" }]
1492
+ }),
1493
+ new Promise((resolve) => {
1494
+ const handler = (chainId) => {
1495
+ if (chainId === "0x1") {
1496
+ metamaskProvider.removeListener("chainChanged", handler);
1497
+ resolve();
1498
+ }
1499
+ };
1500
+ metamaskProvider.on("chainChanged", handler);
1501
+ })
1502
+ ]);
1503
+ };
1504
+ function useEvmSwitchChain({ xChainId }) {
1505
+ const evmEnabled = useIsChainEnabled("EVM");
1506
+ if (!evmEnabled) {
1507
+ return EVM_DISABLED_RESULT;
1508
+ }
1509
+ return useEvmSwitchChainInner({ xChainId });
1510
+ }
1511
+ function useEvmSwitchChainInner({ xChainId }) {
1512
+ const xChainType = getXChainType(xChainId);
1513
+ const expectedChainId = baseChainInfo[xChainId].chainId;
1514
+ if (xChainType === "EVM") {
1515
+ assert(typeof expectedChainId === "number", "[useEvmSwitchChain] EVM chain must have numeric chainId");
1516
+ }
1517
+ const xService = useXService({ xChainType: "INJECTIVE" });
1518
+ const injectiveXService = xService instanceof InjectiveXService ? xService : void 0;
1519
+ const ethereumChainId = useEthereumChainId();
1520
+ const { chainId } = useAccount();
1521
+ const isWrongChain = useMemo(() => {
1522
+ return xChainType === "EVM" && chainId !== expectedChainId || xChainType === "INJECTIVE" && injectiveXService !== void 0 && injectiveXService.walletStrategy.getWallet() === Wallet.Metamask && ethereumChainId !== mainnet.id;
1523
+ }, [xChainType, chainId, expectedChainId, ethereumChainId, injectiveXService]);
1524
+ const { switchChain } = useSwitchChain();
1525
+ const handleSwitchChain = useCallback(() => {
1526
+ if (xChainType === "INJECTIVE") {
1527
+ switchEthereumChain();
1528
+ } else if (xChainType === "EVM" && typeof expectedChainId === "number") {
1529
+ switchChain({ chainId: expectedChainId });
1530
+ }
1531
+ }, [switchChain, expectedChainId, xChainType]);
1532
+ return useMemo(
1533
+ () => ({
1534
+ isWrongChain,
1535
+ handleSwitchChain
1536
+ }),
1537
+ [isWrongChain, handleSwitchChain]
1538
+ );
1539
+ }
1540
+
1541
+ // src/hooks/useWalletProvider.ts
1542
+ var warnedChains2 = /* @__PURE__ */ new Set();
1543
+ function useWalletProvider({
1544
+ xChainId,
1545
+ xChainType
1546
+ } = {}) {
1547
+ assert(!(xChainId && xChainType), "[useWalletProvider] pass either xChainId or xChainType, not both");
1548
+ const target = xChainType ?? (xChainId ? getXChainType(xChainId) : void 0);
1549
+ return useXWalletStore((state) => {
1550
+ if (!target) return void 0;
1551
+ if (!state.enabledChains.includes(target) && !warnedChains2.has(target)) {
1552
+ warnedChains2.add(target);
1553
+ console.warn(
1554
+ `[useWalletProvider] chain "${target}" is not enabled in SodaxWalletProvider config.chains \u2014 returning undefined`
1555
+ );
1556
+ }
1557
+ return state.getWalletProvider(target);
1558
+ });
1559
+ }
1560
+ function useXSignMessage() {
1561
+ const actionsRegistry = useXWalletStore((state) => state.chainActions);
1562
+ return useMutation({
1563
+ mutationFn: async ({ xChainType, message }) => {
1564
+ const chainActions = actionsRegistry[xChainType];
1565
+ if (!chainActions?.signMessage) {
1566
+ console.warn(`[useXSignMessage] signMessage not supported for chain "${xChainType}"`);
1567
+ return void 0;
1568
+ }
1569
+ return await chainActions.signMessage(message);
1570
+ }
1571
+ });
1572
+ }
1573
+
1574
+ // src/xchains/bitcoin/useBitcoinXConnectors.ts
1575
+ function useBitcoinXConnectors() {
1576
+ const xService = useXService({ xChainType: "BITCOIN" });
1577
+ return useMemo(() => {
1578
+ const connectors = xService?.getXConnectors() ?? [];
1579
+ return connectors.filter((c) => c instanceof BitcoinXConnector);
1580
+ }, [xService]);
1581
+ }
1582
+
1583
+ export { BitcoinXConnector, BitcoinXService, OKXXConnector, UnisatXConnector, WalletConfigProvider, XverseXConnector, chainRegistry, getXChainType, getXService, useBatchConnect, useBatchDisconnect, useBitcoinXConnectors, useChainGroups, useConnectedChains, useConnectionFlow, useEnabledChainTypes, useEnabledChains, useEvmSwitchChain, useIsChainEnabled, useIsWalletInstalled, useWalletConfig, useWalletModal, useWalletProvider, useXAccount, useXAccounts, useXConnect, useXConnection, useXConnections, useXConnectors, useXConnectorsByChain, useXDisconnect, useXService, useXServices, useXSignMessage, useXWalletStore };
1584
+ //# sourceMappingURL=chunk-PLCA4ZDJ.mjs.map
1585
+ //# sourceMappingURL=chunk-PLCA4ZDJ.mjs.map