@sodax/wallet-sdk-react 1.5.7-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
package/dist/index.cjs CHANGED
@@ -1,41 +1,40 @@
1
1
  'use strict';
2
2
 
3
3
  var types = require('@sodax/types');
4
- var nearConnect = require('@hot-labs/near-connect');
5
- var nearApiJs = require('near-api-js');
6
- var transactions = require('@stacks/transactions');
7
- var network = require('@stacks/network');
8
- var satsConnect = require('sats-connect');
9
- var React2 = require('react');
10
- var dappKit = require('@mysten/dapp-kit');
11
- var walletAdapterReact = require('@solana/wallet-adapter-react');
12
- var wagmi = require('wagmi');
13
4
  var zustand = require('zustand');
14
5
  var middleware = require('zustand/middleware');
15
6
  var immer = require('zustand/middleware/immer');
7
+ var walletSdkCore = require('@sodax/wallet-sdk-core');
8
+ var walletBase = require('@injectivelabs/wallet-base');
9
+ var sdkTs = require('@injectivelabs/sdk-ts');
16
10
  var viem = require('viem');
17
11
  var actions = require('wagmi/actions');
18
- var chains = require('wagmi/chains');
19
- var networks = require('@injectivelabs/networks');
20
- var sdkTs = require('@injectivelabs/sdk-ts');
21
- var tsTypes = require('@injectivelabs/ts-types');
22
- var walletCore = require('@injectivelabs/wallet-core');
23
- var walletStrategy = require('@injectivelabs/wallet-strategy');
24
- var walletBase = require('@injectivelabs/wallet-base');
25
- var walletCosmos = require('@injectivelabs/wallet-cosmos');
12
+ var wagmi = require('wagmi');
13
+ var chains$1 = require('wagmi/chains');
26
14
  var web3_js = require('@solana/web3.js');
27
15
  var splToken = require('@solana/spl-token');
28
16
  var stellarWalletsKit = require('@creit.tech/stellar-wallets-kit');
29
17
  var StellarSdk = require('@stellar/stellar-sdk');
30
18
  var IconSdkRaw = require('icon-sdk-js');
31
- var connect = require('@stacks/connect');
19
+ var networks = require('@injectivelabs/networks');
20
+ var tsTypes = require('@injectivelabs/ts-types');
21
+ var walletCore = require('@injectivelabs/wallet-core');
22
+ var walletStrategy = require('@injectivelabs/wallet-strategy');
23
+ var walletCosmos = require('@injectivelabs/wallet-cosmos');
24
+ var satsConnect = require('sats-connect');
25
+ var react = require('react');
32
26
  var reactQuery = require('@tanstack/react-query');
33
- var chains$1 = require('viem/chains');
34
- var walletSdkCore = require('@sodax/wallet-sdk-core');
27
+ var chains = require('viem/chains');
28
+ var nearConnect = require('@hot-labs/near-connect');
29
+ var nearApiJs = require('near-api-js');
30
+ var transactions = require('@stacks/transactions');
31
+ var network = require('@stacks/network');
32
+ var connect = require('@stacks/connect');
33
+ var connectors = require('wagmi/connectors');
34
+ var jsxRuntime = require('react/jsx-runtime');
35
+ var walletAdapterReact = require('@solana/wallet-adapter-react');
36
+ var dappKit = require('@mysten/dapp-kit');
35
37
  var client = require('@mysten/sui/client');
36
- var walletAdapterWallets = require('@solana/wallet-adapter-wallets');
37
-
38
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
39
38
 
40
39
  function _interopNamespace(e) {
41
40
  if (e && e.__esModule) return e;
@@ -55,7 +54,6 @@ function _interopNamespace(e) {
55
54
  return Object.freeze(n);
56
55
  }
57
56
 
58
- var React2__default = /*#__PURE__*/_interopDefault(React2);
59
57
  var StellarSdk__namespace = /*#__PURE__*/_interopNamespace(StellarSdk);
60
58
  var IconSdkRaw__namespace = /*#__PURE__*/_interopNamespace(IconSdkRaw);
61
59
 
@@ -69,9 +67,11 @@ function getXChainType(xChainId) {
69
67
 
70
68
  // src/core/XService.ts
71
69
  var XService = class {
70
+ /** The blockchain type this service handles */
71
+ xChainType;
72
+ /** Available wallet connectors for this chain */
73
+ xConnectors = [];
72
74
  constructor(xChainType) {
73
- /** Available wallet connectors for this chain */
74
- this.xConnectors = [];
75
75
  this.xChainType = xChainType;
76
76
  }
77
77
  /**
@@ -122,106 +122,17 @@ var XService = class {
122
122
  return this.getXConnectors().find((xConnector) => xConnector.id === xConnectorId);
123
123
  }
124
124
  };
125
- var NearXService = class _NearXService extends XService {
126
- constructor() {
127
- super("NEAR");
128
- this.walletSelector = new nearConnect.NearConnector({
129
- network: "mainnet",
130
- logger: console,
131
- autoConnect: true,
132
- excludedWallets: ["okx-wallet"]
133
- });
134
- }
135
- static getInstance() {
136
- if (!_NearXService.instance) {
137
- _NearXService.instance = new _NearXService();
138
- }
139
- return _NearXService.instance;
140
- }
141
- async getBalance(address, xToken) {
142
- const url = "https://1rpc.io/near";
143
- const provider = new nearApiJs.JsonRpcProvider({ url });
144
- if (xToken.symbol === "NEAR") {
145
- const account = await provider.viewAccount({ accountId: address ?? "" });
146
- return BigInt(account.amount);
147
- }
148
- const res = await provider.callFunction({ contractId: xToken.address, method: "ft_balance_of", args: { account_id: address } });
149
- return BigInt(res ?? 0);
150
- }
151
- };
152
- var StacksXService = class _StacksXService extends XService {
153
- constructor() {
154
- super("STACKS");
155
- this.network = network.networkFrom("mainnet");
156
- }
157
- static getInstance() {
158
- if (!_StacksXService.instance) {
159
- _StacksXService.instance = new _StacksXService();
160
- }
161
- return _StacksXService.instance;
162
- }
163
- async getBalance(address, xToken) {
164
- if (!address) return 0n;
165
- if (xToken.symbol === "STX") {
166
- const url = `${this.network?.client.baseUrl}/extended/v1/address/${address}/balances`;
167
- try {
168
- const response = await fetch(url);
169
- if (!response.ok) {
170
- throw new Error(`Error fetching data: ${response.statusText}`);
171
- }
172
- const data = await response.json();
173
- return BigInt(data.stx.balance);
174
- } catch (error) {
175
- console.error("Error fetching STX balance:", error);
176
- return 0n;
177
- }
178
- }
179
- const [contractAddress, contractName] = xToken.address.split(".");
180
- try {
181
- const result = await transactions.fetchCallReadOnlyFunction({
182
- contractAddress,
183
- contractName,
184
- functionName: "get-balance",
185
- functionArgs: [transactions.Cl.principal(address)],
186
- network: this.network,
187
- senderAddress: address
188
- });
189
- return result.value.value;
190
- } catch (error) {
191
- console.error("Error fetching token balance:", error);
192
- return 0n;
193
- }
194
- }
195
- };
196
-
197
- // src/actions/getXService.ts
198
- function getXService(xChainType) {
199
- switch (xChainType) {
200
- case "BITCOIN":
201
- return BitcoinXService.getInstance();
202
- case "EVM":
203
- return EvmXService.getInstance();
204
- case "SUI":
205
- return SuiXService.getInstance();
206
- case "SOLANA":
207
- return SolanaXService.getInstance();
208
- case "ICON":
209
- return IconXService.getInstance();
210
- case "INJECTIVE":
211
- return InjectiveXService.getInstance();
212
- case "STELLAR":
213
- return StellarXService.getInstance();
214
- case "NEAR":
215
- return NearXService.getInstance();
216
- case "STACKS":
217
- return StacksXService.getInstance();
218
- default:
219
- throw new Error(`Unsupported chain type: ${xChainType}`);
220
- }
221
- }
222
125
 
223
126
  // src/core/XConnector.ts
224
127
  var XConnector = class {
128
+ /** The blockchain type this connector supports */
129
+ xChainType;
130
+ /** Display name of the wallet provider */
131
+ name;
132
+ /** Unique identifier for the connector */
133
+ _id;
134
+ /** Optional icon URL for the wallet provider */
135
+ _icon;
225
136
  constructor(xChainType, name, id) {
226
137
  this.xChainType = xChainType;
227
138
  this.name = name;
@@ -235,7 +146,55 @@ var XConnector = class {
235
146
  get icon() {
236
147
  return this._icon;
237
148
  }
149
+ /**
150
+ * True when the wallet extension backing this connector is installed.
151
+ * Default: true (for provider-managed chains where connector presence already
152
+ * implies install — EVM via EIP-6963, Solana/Sui via adapter discovery).
153
+ * Subclasses backed by extension injection (Bitcoin, ICON, Stacks) override
154
+ * this with a window probe.
155
+ */
156
+ get isInstalled() {
157
+ return true;
158
+ }
159
+ /** URL to install the wallet extension when missing. Subclasses override. */
160
+ get installUrl() {
161
+ return void 0;
162
+ }
238
163
  };
164
+ function getEntryDefaults(entry) {
165
+ if (!entry || typeof entry === "string") return void 0;
166
+ return entry.defaults;
167
+ }
168
+ function getRpcUrl(entry) {
169
+ if (!entry || typeof entry === "string") return void 0;
170
+ return entry.rpcUrl;
171
+ }
172
+ function resolveEvmDefaults(activeChainId, evmChains) {
173
+ const key = types.getEvmChainKeyByChainId(activeChainId);
174
+ if (!key || !evmChains) return void 0;
175
+ return evmChains[key]?.defaults;
176
+ }
177
+
178
+ // src/utils/sortConnectors.ts
179
+ function sortConnectors(connectors, options = {}) {
180
+ const { preferred = [] } = options;
181
+ const preferredIndex = new Map(preferred.map((id, i) => [id, i]));
182
+ return [...connectors].map((connector, originalIndex) => ({ connector, originalIndex })).sort((a, b) => {
183
+ const aPref = preferredIndex.get(a.connector.id);
184
+ const bPref = preferredIndex.get(b.connector.id);
185
+ if (aPref !== bPref) {
186
+ if (aPref === void 0) return 1;
187
+ if (bPref === void 0) return -1;
188
+ return aPref - bPref;
189
+ }
190
+ if (a.connector.isInstalled !== b.connector.isInstalled) {
191
+ return a.connector.isInstalled ? -1 : 1;
192
+ }
193
+ return a.originalIndex - b.originalIndex;
194
+ }).map(({ connector }) => connector);
195
+ }
196
+
197
+ // src/utils/index.ts
239
198
  var isNativeToken = (xToken) => {
240
199
  const nativeAddresses = [
241
200
  "cx0000000000000000000000000000000000000000",
@@ -255,516 +214,716 @@ var isNativeToken = (xToken) => {
255
214
  return nativeAddresses.includes(xToken.address);
256
215
  };
257
216
  var getWagmiChainId = (xChainId) => {
258
- return types.baseChainInfo[xChainId].chainId;
217
+ const chainId = types.baseChainInfo[xChainId].chainId;
218
+ if (typeof chainId !== "number") {
219
+ throw new Error(`[wallet-sdk-react] getWagmiChainId: expected numeric chainId, got ${typeof chainId}`);
220
+ }
221
+ return chainId;
259
222
  };
260
-
261
- // src/xchains/bitcoin/BitcoinXService.ts
262
- var BitcoinXService = class _BitcoinXService extends XService {
263
- constructor(rpcUrl = "https://mempool.space/api") {
264
- super("BITCOIN");
265
- this.rpcUrl = rpcUrl;
223
+ var hyper = /* @__PURE__ */ viem.defineChain({
224
+ id: 999,
225
+ name: "HyperEVM",
226
+ nativeCurrency: {
227
+ decimals: 18,
228
+ name: "HYPE",
229
+ symbol: "HYPE"
230
+ },
231
+ rpcUrls: {
232
+ default: { http: ["https://rpc.hyperliquid.xyz/evm"] }
233
+ },
234
+ blockExplorers: {
235
+ default: {
236
+ name: "HyperEVMScan",
237
+ url: "https://hyperevmscan.io/"
238
+ }
239
+ },
240
+ contracts: {
241
+ multicall3: {
242
+ address: "0xcA11bde05977b3631167028862bE2a173976CA11",
243
+ blockCreated: 13051
244
+ }
266
245
  }
267
- static getInstance(rpcUrl) {
268
- if (!_BitcoinXService.instance) {
269
- _BitcoinXService.instance = new _BitcoinXService(rpcUrl);
270
- } else if (rpcUrl && rpcUrl !== _BitcoinXService.instance.rpcUrl) {
271
- _BitcoinXService.instance.rpcUrl = rpcUrl;
246
+ });
247
+ var createWagmiConfig = (evmChains, options) => {
248
+ return wagmi.createConfig({
249
+ chains: [
250
+ chains$1.mainnet,
251
+ chains$1.avalanche,
252
+ chains$1.arbitrum,
253
+ chains$1.base,
254
+ chains$1.bsc,
255
+ chains$1.sonic,
256
+ chains$1.optimism,
257
+ chains$1.polygon,
258
+ hyper,
259
+ chains$1.lightlinkPhoenix,
260
+ chains$1.kaia,
261
+ chains$1.redbellyMainnet
262
+ ],
263
+ connectors: options?.connectors ?? [],
264
+ ssr: options?.ssr,
265
+ transports: {
266
+ [chains$1.mainnet.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.ETHEREUM_MAINNET])),
267
+ [chains$1.avalanche.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.AVALANCHE_MAINNET])),
268
+ [chains$1.arbitrum.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.ARBITRUM_MAINNET])),
269
+ [chains$1.base.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.BASE_MAINNET])),
270
+ [chains$1.bsc.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.BSC_MAINNET])),
271
+ [chains$1.sonic.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.SONIC_MAINNET])),
272
+ [chains$1.optimism.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.OPTIMISM_MAINNET])),
273
+ [chains$1.polygon.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.POLYGON_MAINNET])),
274
+ [hyper.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.HYPEREVM_MAINNET])),
275
+ [chains$1.lightlinkPhoenix.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.LIGHTLINK_MAINNET])),
276
+ [chains$1.redbellyMainnet.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.REDBELLY_MAINNET])),
277
+ [chains$1.kaia.id]: wagmi.http(getRpcUrl(evmChains?.[types.ChainKeys.KAIA_MAINNET]))
278
+ },
279
+ storage: wagmi.createStorage({
280
+ storage: wagmi.cookieStorage,
281
+ key: "sodax"
282
+ })
283
+ });
284
+ };
285
+ var EvmXService = class _EvmXService extends XService {
286
+ static instance;
287
+ wagmiConfig;
288
+ constructor() {
289
+ super("EVM");
290
+ }
291
+ static getInstance() {
292
+ if (!_EvmXService.instance) {
293
+ _EvmXService.instance = new _EvmXService();
272
294
  }
273
- return _BitcoinXService.instance;
295
+ return _EvmXService.instance;
296
+ }
297
+ // get erc20 token balance in a chain (evm chain only)
298
+ async _getTokenBalance(address, chainId, tokenAddress) {
299
+ const publicClient = actions.getPublicClient(this.wagmiConfig, { chainId });
300
+ if (!publicClient) throw new Error("Public client not found");
301
+ const balance = await publicClient.readContract({
302
+ abi: viem.erc20Abi,
303
+ address: tokenAddress,
304
+ functionName: "balanceOf",
305
+ args: [address]
306
+ });
307
+ return balance || 0n;
308
+ }
309
+ //get native balance of the chain (evm chain only)
310
+ async _getChainBalance(address, chainId) {
311
+ const balance = await actions.getPublicClient(this.wagmiConfig, { chainId })?.getBalance({
312
+ address
313
+ });
314
+ return balance || 0n;
274
315
  }
275
316
  async getBalance(address, xToken) {
276
317
  if (!address) return 0n;
277
- try {
278
- if (isNativeToken(xToken)) {
279
- const response = await fetch(`${this.rpcUrl}/address/${address}/utxo`);
280
- if (!response.ok) return 0n;
281
- const utxos = await response.json();
282
- const totalBalance = utxos.reduce((sum, utxo) => sum + utxo.value, 0);
283
- return BigInt(totalBalance);
284
- }
285
- } catch {
286
- return 0n;
318
+ if (!this.wagmiConfig) return 0n;
319
+ const chainId = getWagmiChainId(xToken.chainKey);
320
+ if (isNativeToken(xToken)) {
321
+ return this._getChainBalance(address, chainId);
287
322
  }
288
- return 0n;
323
+ throw new Error(`Unsupported token: ${xToken.symbol}`);
324
+ }
325
+ async getBalances(address, xTokens) {
326
+ if (!address) return {};
327
+ if (!this.wagmiConfig) return {};
328
+ const nativeTokenBalancePromises = xTokens.filter((xToken) => isNativeToken(xToken)).map(async (xToken) => {
329
+ const balance = await this.getBalance(address, xToken);
330
+ return { symbol: xToken.symbol, address: xToken.address, balance };
331
+ });
332
+ const nativeTokenBalances = await Promise.all(nativeTokenBalancePromises);
333
+ const tokenMap = nativeTokenBalances.reduce(
334
+ (map, { address: address2, balance }) => {
335
+ if (balance) map[address2] = balance;
336
+ return map;
337
+ },
338
+ {}
339
+ );
340
+ const nonNativeXTokens = xTokens.filter((xToken) => !isNativeToken(xToken));
341
+ const firstToken = xTokens[0];
342
+ if (!firstToken) return tokenMap;
343
+ const chainKey = firstToken.chainKey;
344
+ const viemChain = this.wagmiConfig.chains.find((chain) => chain.id === getWagmiChainId(chainKey));
345
+ const chainId = getWagmiChainId(chainKey);
346
+ const publicClient = actions.getPublicClient(this.wagmiConfig, { chainId });
347
+ if (!publicClient) throw new Error("Public client not found");
348
+ if (viemChain?.contracts?.multicall3) {
349
+ const result = await publicClient.multicall({
350
+ contracts: nonNativeXTokens.map((token) => ({
351
+ abi: viem.erc20Abi,
352
+ address: token.address,
353
+ functionName: "balanceOf",
354
+ args: [address]
355
+ }))
356
+ });
357
+ return nonNativeXTokens.reduce((acc, token, index) => {
358
+ const resultValue = result?.[index]?.result;
359
+ acc[token.address] = resultValue !== void 0 && resultValue !== null ? BigInt(resultValue) : 0n;
360
+ return acc;
361
+ }, tokenMap);
362
+ }
363
+ const nonNativeTokenBalances = await Promise.all(
364
+ nonNativeXTokens.map((token) => this._getTokenBalance(address, chainId, token.address))
365
+ );
366
+ return nonNativeXTokens.reduce((acc, token, idx) => {
367
+ acc[token.address] = nonNativeTokenBalances[idx] ?? 0n;
368
+ return acc;
369
+ }, tokenMap);
289
370
  }
290
371
  };
291
372
 
292
- // src/xchains/bitcoin/BitcoinXConnector.ts
293
- var BitcoinXConnector = class extends XConnector {
294
- constructor(name, id) {
295
- super("BITCOIN", name, id);
373
+ // src/xchains/evm/EvmXConnector.ts
374
+ var WALLETCONNECT_ICON = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cpath fill='%233B99FC' d='M9.58 11.58c3.55-3.47 9.29-3.47 12.84 0l.43.42a.44.44 0 0 1 0 .63l-1.46 1.43a.23.23 0 0 1-.32 0l-.59-.57a6.72 6.72 0 0 0-9.36 0l-.63.61a.23.23 0 0 1-.32 0L8.71 12.7a.44.44 0 0 1 0-.63l.87-.5Zm15.87 2.95 1.3 1.28a.44.44 0 0 1 0 .63l-5.87 5.74a.46.46 0 0 1-.64 0l-4.17-4.08a.11.11 0 0 0-.16 0l-4.17 4.08a.46.46 0 0 1-.64 0l-5.87-5.74a.44.44 0 0 1 0-.63l1.3-1.28a.46.46 0 0 1 .64 0l4.17 4.08a.11.11 0 0 0 .16 0l4.17-4.08a.46.46 0 0 1 .64 0l4.17 4.08a.11.11 0 0 0 .16 0l4.17-4.08a.46.46 0 0 1 .64 0Z'/%3E%3C/svg%3E";
375
+ var EvmXConnector = class extends XConnector {
376
+ connector;
377
+ constructor(connector) {
378
+ super("EVM", connector.name, connector.id);
379
+ this.connector = connector;
296
380
  }
297
- getXService() {
298
- return BitcoinXService.getInstance();
381
+ async connect() {
382
+ return;
299
383
  }
300
- };
301
- var UnisatWalletProvider = class {
302
- constructor(unisat, address) {
303
- this.unisat = unisat;
304
- this.cachedAddress = address;
384
+ async disconnect() {
385
+ return;
305
386
  }
306
- async getWalletAddress() {
307
- try {
308
- const accounts = await this.unisat.getAccounts();
309
- if (accounts[0]) this.cachedAddress = accounts[0];
310
- } catch {
311
- }
312
- return this.cachedAddress;
313
- }
314
- async getPublicKey() {
315
- return this.unisat.getPublicKey();
316
- }
317
- async getAddressType(_address) {
318
- const address = await this.getWalletAddress();
319
- return types.detectBitcoinAddressType(address);
320
- }
321
- async signTransaction(psbtBase64, finalize = false) {
322
- const psbtHex = Buffer.from(psbtBase64, "base64").toString("hex");
323
- const signedHex = await this.unisat.signPsbt(psbtHex, { autoFinalized: finalize });
324
- return signedHex;
325
- }
326
- async signEcdsaMessage(message) {
327
- return this.unisat.signMessage(message, "ecdsa");
328
- }
329
- async signBip322Message(message) {
330
- return this.unisat.signMessage(message, "bip322-simple");
387
+ get id() {
388
+ return this.connector.id;
331
389
  }
332
- async sendBitcoin(toAddress, satoshis) {
333
- if (satoshis > BigInt(Number.MAX_SAFE_INTEGER)) {
334
- throw new Error(`Amount ${satoshis} satoshis exceeds safe integer range`);
390
+ get icon() {
391
+ if (!this.connector.icon && this.connector.type === "walletConnect") {
392
+ return WALLETCONNECT_ICON;
335
393
  }
336
- return this.unisat.sendBitcoin(toAddress, Number(satoshis));
394
+ return this.connector.icon;
337
395
  }
338
396
  };
339
- var UnisatXConnector = class extends BitcoinXConnector {
397
+ var SolanaXService = class _SolanaXService extends XService {
398
+ static instance;
399
+ connection;
400
+ wallet;
340
401
  constructor() {
341
- super("Unisat", "unisat");
342
- }
343
- static isAvailable() {
344
- return typeof window !== "undefined" && !!window.unisat;
345
- }
346
- get icon() {
347
- return "https://avatars.githubusercontent.com/u/125119198?s=200&v=4";
402
+ super("SOLANA");
348
403
  }
349
- async connect() {
350
- if (!window.unisat) {
351
- throw new Error("Unisat wallet is not installed");
404
+ static getInstance() {
405
+ if (!_SolanaXService.instance) {
406
+ _SolanaXService.instance = new _SolanaXService();
352
407
  }
353
- const accounts = await window.unisat.requestAccounts();
354
- const address = accounts[0];
355
- if (!address) return void 0;
356
- this.walletProvider = new UnisatWalletProvider(window.unisat, address);
357
- return {
358
- address,
359
- xChainType: "BITCOIN"
360
- };
361
- }
362
- async disconnect() {
363
- this.walletProvider = void 0;
364
- }
365
- getWalletProvider() {
366
- return this.walletProvider;
408
+ return _SolanaXService.instance;
367
409
  }
368
- recreateWalletProvider(xAccount) {
369
- if (!window.unisat || !xAccount.address) return void 0;
370
- return new UnisatWalletProvider(window.unisat, xAccount.address);
410
+ async getBalance(address, xToken) {
411
+ if (!address) return BigInt(0);
412
+ const connection = this.connection;
413
+ if (!connection) {
414
+ return BigInt(0);
415
+ }
416
+ try {
417
+ if (isNativeToken(xToken)) {
418
+ const newBalance = await connection.getBalance(new web3_js.PublicKey(address));
419
+ return BigInt(newBalance);
420
+ }
421
+ const tokenAccountPubkey = splToken.getAssociatedTokenAddressSync(new web3_js.PublicKey(xToken.address), new web3_js.PublicKey(address));
422
+ const tokenAccount = await splToken.getAccount(connection, tokenAccountPubkey);
423
+ return BigInt(tokenAccount.amount);
424
+ } catch {
425
+ return BigInt(0);
426
+ }
371
427
  }
372
428
  };
373
- var XverseWalletProvider = class {
374
- constructor(address, publicKey) {
375
- this.address = address;
376
- this.publicKey = publicKey;
377
- }
378
- async getWalletAddress() {
379
- return this.address;
380
- }
381
- async getPublicKey() {
382
- return this.publicKey;
383
- }
384
- async getAddressType(_address) {
385
- return types.detectBitcoinAddressType(this.address);
429
+
430
+ // src/shared/guards.ts
431
+ function isRecord(value) {
432
+ return typeof value === "object" && value !== null;
433
+ }
434
+ function hasStringProperty(value, key) {
435
+ return isRecord(value) && typeof value[key] === "string";
436
+ }
437
+ function hasOptionalStringProperty(value, key) {
438
+ return isRecord(value) && (value[key] === void 0 || typeof value[key] === "string");
439
+ }
440
+ function hasBooleanProperty(value, key) {
441
+ return isRecord(value) && typeof value[key] === "boolean";
442
+ }
443
+ function hasFunctionProperty(value, key) {
444
+ return isRecord(value) && typeof value[key] === "function";
445
+ }
446
+ function assert(condition, message) {
447
+ if (!condition) {
448
+ throw new Error(message);
386
449
  }
387
- /**
388
- * Parse a base64-encoded PSBT to count the number of inputs.
389
- * Reads the unsigned transaction from the PSBT global section.
390
- */
391
- countPsbtInputs(psbtBase64) {
392
- const data = Buffer.from(psbtBase64, "base64");
393
- let offset = 5;
394
- const keyLen = data[offset++] ?? 0;
395
- if (keyLen !== 1 || data[offset++] !== 0) {
396
- return 1;
397
- }
398
- const firstByte = data[offset++] ?? 0;
399
- if (firstByte === 253) offset += 2;
400
- else if (firstByte === 254) offset += 4;
401
- else if (firstByte === 255) offset += 8;
402
- offset += 4;
403
- const inputByte = data[offset] ?? 0;
404
- if (inputByte < 253) return inputByte;
405
- return 1;
450
+ }
451
+ function assertSuiProviderShape(caller, client, wallet, account) {
452
+ const clientOk = isRecord(client) && hasFunctionProperty(client, "executeTransactionBlock") && hasFunctionProperty(client, "devInspectTransactionBlock") && hasFunctionProperty(client, "getCoins");
453
+ assert(clientOk, `[${caller}] invalid Sui client shape`);
454
+ const walletOk = isRecord(wallet) && hasStringProperty(wallet, "name");
455
+ assert(walletOk, `[${caller}] invalid Sui wallet shape`);
456
+ const accountOk = isRecord(account) && hasStringProperty(account, "address");
457
+ assert(accountOk, `[${caller}] invalid Sui account shape`);
458
+ }
459
+
460
+ // src/xchains/sui/SuiXService.ts
461
+ var SuiXService = class _SuiXService extends XService {
462
+ static instance;
463
+ // Hydrated by SuiHydrator. Start undefined because wallet may not be connected yet.
464
+ // suiClient is typed structurally for the methods we call directly.
465
+ // suiWallet/suiAccount are opaque — stored and passed through to SuiWalletProvider.
466
+ suiClient;
467
+ suiWallet;
468
+ suiAccount;
469
+ constructor() {
470
+ super("SUI");
406
471
  }
407
- async signTransaction(psbtBase64, finalize = false) {
408
- const { request: request3 } = await import('sats-connect');
409
- const inputCount = this.countPsbtInputs(psbtBase64);
410
- const signingIndexes = Array.from({ length: inputCount }, (_, i) => i);
411
- const response = await request3("signPsbt", {
412
- psbt: psbtBase64,
413
- broadcast: false,
414
- signInputs: {
415
- [this.address]: signingIndexes
416
- }
417
- });
418
- if (response.status === "error") {
419
- throw new Error(response.error?.message || "Xverse PSBT signing failed");
420
- }
421
- const result = response.result;
422
- if (finalize) {
423
- return Buffer.from(result.psbt, "base64").toString("hex");
472
+ static getInstance() {
473
+ if (!_SuiXService.instance) {
474
+ _SuiXService.instance = new _SuiXService();
424
475
  }
425
- return result.psbt;
476
+ return _SuiXService.instance;
426
477
  }
427
- async signEcdsaMessage(message) {
428
- const { request: request3 } = await import('sats-connect');
429
- const response = await request3("signMessage", {
430
- address: this.address,
431
- message,
432
- protocol: satsConnect.MessageSigningProtocols.ECDSA
433
- });
434
- if (response.status === "error") {
435
- throw new Error(response.error?.message || "Xverse ECDSA signing failed");
478
+ createWalletProvider() {
479
+ if (!this.suiClient || !this.suiWallet || !this.suiAccount) {
480
+ console.warn(
481
+ "[SuiXService] createWalletProvider: missing dependencies \u2014 wallet not connected yet",
482
+ { hasClient: !!this.suiClient, hasWallet: !!this.suiWallet, hasAccount: !!this.suiAccount }
483
+ );
484
+ return void 0;
436
485
  }
437
- return response.result.signature;
438
- }
439
- async signBip322Message(message) {
440
- const { request: request3 } = await import('sats-connect');
441
- const response = await request3("signMessage", {
442
- address: this.address,
443
- message,
444
- protocol: satsConnect.MessageSigningProtocols.BIP322
486
+ assertSuiProviderShape("SuiXService", this.suiClient, this.suiWallet, this.suiAccount);
487
+ return new walletSdkCore.SuiWalletProvider({
488
+ client: this.suiClient,
489
+ wallet: this.suiWallet,
490
+ account: this.suiAccount
445
491
  });
446
- if (response.status === "error") {
447
- throw new Error(response.error?.message || "Xverse BIP322 signing failed");
448
- }
449
- return response.result.signature;
450
492
  }
451
- async sendBitcoin(toAddress, satoshis) {
452
- const { request: request3 } = await import('sats-connect');
453
- const response = await request3("sendTransfer", {
454
- recipients: [
455
- {
456
- address: toAddress,
457
- amount: Number(satoshis)
493
+ // getBalance is not used because getBalances uses getAllBalances which returns all balances
494
+ async getBalances(address, xTokens) {
495
+ if (!address || !this.suiClient) return {};
496
+ const client = this.suiClient;
497
+ try {
498
+ const balancePromises = xTokens.map(async (xToken) => {
499
+ let coinType = isNativeToken(xToken) ? "0x2::sui::SUI" : xToken.address;
500
+ if (coinType === "0x03917a812fe4a6d6bc779c5ab53f8a80ba741f8af04121193fc44e0f662e2ceb::balanced_dollar::BALANCED_DOLLAR") {
501
+ coinType = "0x3917a812fe4a6d6bc779c5ab53f8a80ba741f8af04121193fc44e0f662e2ceb::balanced_dollar::BALANCED_DOLLAR";
458
502
  }
459
- ]
460
- });
461
- if (response.status === "error") {
462
- throw new Error(response.error?.message || "Xverse sendTransfer failed");
503
+ const balance = await client.getBalance({
504
+ owner: address,
505
+ coinType
506
+ });
507
+ return {
508
+ address: xToken.address,
509
+ balance: balance ? BigInt(balance.totalBalance) : void 0
510
+ };
511
+ });
512
+ const results = await Promise.all(balancePromises);
513
+ const tokenMap = {};
514
+ results.forEach((result) => {
515
+ if (result.balance !== void 0) {
516
+ tokenMap[result.address] = result.balance;
517
+ }
518
+ });
519
+ return tokenMap;
520
+ } catch (error) {
521
+ console.error("[wallet-sdk-react] SUI getBalances failed:", error);
522
+ return {};
463
523
  }
464
- return response.result.txid;
465
524
  }
466
525
  };
467
- var XVERSE_ADDRESS_TYPE_KEY = "xverse-address-type";
468
- var XverseXConnector = class _XverseXConnector extends BitcoinXConnector {
469
- constructor() {
470
- super("Xverse", "xverse");
471
- const saved = typeof window !== "undefined" ? localStorage.getItem(XVERSE_ADDRESS_TYPE_KEY) : null;
472
- this.addressPurpose = saved === "segwit" ? satsConnect.AddressPurpose.Payment : satsConnect.AddressPurpose.Ordinals;
473
- }
474
- /** Set address purpose and persist to localStorage. */
475
- setAddressPurpose(type) {
476
- this.addressPurpose = type === "taproot" ? satsConnect.AddressPurpose.Ordinals : satsConnect.AddressPurpose.Payment;
477
- if (typeof window !== "undefined") {
478
- localStorage.setItem(XVERSE_ADDRESS_TYPE_KEY, type);
479
- }
480
- }
481
- static isAvailable() {
482
- return typeof window !== "undefined" && !!window.BitcoinProvider;
526
+
527
+ // src/xchains/sui/SuiXConnector.ts
528
+ var isSuiWalletInfo = (value) => {
529
+ return isRecord(value) && hasStringProperty(value, "name") && // Some wallets may not expose `id` — in that case we fall back to `name` for stability.
530
+ // We still validate if it exists.
531
+ hasOptionalStringProperty(value, "id") && hasOptionalStringProperty(value, "icon");
532
+ };
533
+ var SuiXConnector = class extends XConnector {
534
+ wallet;
535
+ constructor(wallet) {
536
+ assert(isSuiWalletInfo(wallet), "[SuiXConnector] invalid wallet object");
537
+ const id = wallet.id ?? wallet.name;
538
+ assert(typeof id === "string" && id.length > 0, "[SuiXConnector] invalid wallet id");
539
+ super("SUI", wallet.name, id);
540
+ this.wallet = { id, name: wallet.name, icon: wallet.icon };
483
541
  }
484
- get icon() {
485
- return "https://cdn.brandfetch.io/iddzGN5Rcv/w/400/h/400/theme/dark/icon.jpeg?c=1bxid64Mup7aczewSAYMX&t=1771902357797";
542
+ getXService() {
543
+ return SuiXService.getInstance();
486
544
  }
487
545
  async connect() {
488
- if (!_XverseXConnector.isAvailable()) {
489
- throw new Error("Xverse wallet is not installed");
490
- }
491
- const { request: request3 } = await import('sats-connect');
492
- const response = await request3("getAccounts", {
493
- purposes: [this.addressPurpose],
494
- message: "Connect to Sodax"
495
- });
496
- if (response.status === "error") {
497
- throw new Error(response.error?.message || "Xverse connection failed");
498
- }
499
- const accounts = response.result;
500
- const paymentAccount = accounts.find((a) => a.purpose === this.addressPurpose) || accounts[0];
501
- if (!paymentAccount) return void 0;
502
- this.walletProvider = new XverseWalletProvider(
503
- paymentAccount.address,
504
- paymentAccount.publicKey
505
- );
506
- return {
507
- address: paymentAccount.address,
508
- publicKey: paymentAccount.publicKey,
509
- xChainType: "BITCOIN"
510
- };
546
+ return;
511
547
  }
512
548
  async disconnect() {
513
- this.walletProvider = void 0;
514
- }
515
- getWalletProvider() {
516
- return this.walletProvider;
517
549
  }
518
- recreateWalletProvider(xAccount) {
519
- if (!xAccount.address || !xAccount.publicKey) return void 0;
520
- return new XverseWalletProvider(xAccount.address, xAccount.publicKey);
550
+ get icon() {
551
+ return this.wallet.icon;
521
552
  }
522
553
  };
523
- var OKXWalletProvider = class {
524
- constructor(okx, address) {
525
- this.okx = okx;
526
- this.cachedAddress = address;
554
+ var CustomSorobanServer = class extends StellarSdk.rpc.Server {
555
+ customHeaders;
556
+ constructor(serverUrl, customHeaders) {
557
+ super(serverUrl, {
558
+ allowHttp: true
559
+ });
560
+ this.customHeaders = customHeaders;
527
561
  }
528
- async getWalletAddress() {
529
- try {
530
- const accounts = await this.okx.getAccounts();
531
- if (accounts[0]) this.cachedAddress = accounts[0];
532
- } catch {
562
+ async simulateTransaction(tx) {
563
+ const requestOptions = {
564
+ method: "POST",
565
+ headers: {
566
+ "Content-Type": "application/json",
567
+ ...this.customHeaders
568
+ },
569
+ body: JSON.stringify({
570
+ id: 1,
571
+ jsonrpc: "2.0",
572
+ method: "simulateTransaction",
573
+ params: {
574
+ transaction: tx.toXDR()
575
+ }
576
+ })
577
+ };
578
+ const response = await fetch(`${this.serverURL}`, requestOptions);
579
+ if (!response.ok) {
580
+ throw new Error(`HTTP error simulating TX! status: ${response.status}`);
533
581
  }
534
- return this.cachedAddress;
582
+ return response.json().then((json) => StellarSdk.rpc.parseRawSimulation(json.result));
535
583
  }
536
- async getPublicKey() {
537
- return this.okx.getPublicKey();
584
+ async sendTransaction(tx) {
585
+ const requestOptions = {
586
+ method: "POST",
587
+ headers: {
588
+ "Content-Type": "application/json",
589
+ ...this.customHeaders
590
+ },
591
+ body: JSON.stringify({
592
+ id: 1,
593
+ jsonrpc: "2.0",
594
+ method: "sendTransaction",
595
+ params: {
596
+ transaction: tx.toXDR()
597
+ }
598
+ })
599
+ };
600
+ const response = await fetch(`${this.serverURL}`, requestOptions);
601
+ if (!response.ok) {
602
+ throw new Error(`HTTP error submitting TX! status: ${response.status}`);
603
+ }
604
+ return response.json().then((json) => json.result);
538
605
  }
539
- async getAddressType(_address) {
540
- const address = await this.getWalletAddress();
541
- return types.detectBitcoinAddressType(address);
606
+ async getTransaction(hash) {
607
+ const requestOptions = {
608
+ method: "POST",
609
+ headers: {
610
+ "Content-Type": "application/json",
611
+ ...this.customHeaders
612
+ },
613
+ body: JSON.stringify({
614
+ id: 1,
615
+ jsonrpc: "2.0",
616
+ method: "getTransaction",
617
+ params: { hash }
618
+ })
619
+ };
620
+ const response = await fetch(`${this.serverURL}`, requestOptions);
621
+ if (!response.ok) {
622
+ throw new Error(`HTTP error getting TX! status: ${response.status}`);
623
+ }
624
+ return response.json().then((json) => json.result);
542
625
  }
543
- async signTransaction(psbtBase64, finalize = false) {
544
- const psbtHex = Buffer.from(psbtBase64, "base64").toString("hex");
545
- return this.okx.signPsbt(psbtHex, { autoFinalized: finalize });
626
+ };
627
+ var CustomSorobanServer_default = CustomSorobanServer;
628
+ var accountToScVal = (account) => new StellarSdk.Address(account).toScVal();
629
+ var simulateTx = (tx, server) => server.simulateTransaction(tx);
630
+ var getTokenBalance = async (address, tokenId, txBuilder, server) => {
631
+ const params = [accountToScVal(address)];
632
+ const contract = new StellarSdk.Contract(tokenId);
633
+ const tx = txBuilder.addOperation(contract.call("balance", ...params)).setTimeout(StellarSdk.TimeoutInfinite).build();
634
+ const result = await simulateTx(tx, server);
635
+ if (!StellarSdk.rpc.Api.isSimulationSuccess(result)) {
636
+ throw new Error(`Simulation failed: ${JSON.stringify(result)}`);
546
637
  }
547
- async signEcdsaMessage(message) {
548
- return this.okx.signMessage(message, "ecdsa");
638
+ return result.result ? StellarSdk.scValToBigInt(result.result.retval) : 0n;
639
+ };
640
+
641
+ // src/constants.ts
642
+ var SUI_DEFAULT_NETWORK = "mainnet";
643
+ var SUI_DEFAULT_AUTO_CONNECT = true;
644
+ var EVM_DEFAULT_RECONNECT_ON_MOUNT = false;
645
+ var EVM_DEFAULT_SSR = true;
646
+ var SOLANA_DEFAULT_AUTO_CONNECT = true;
647
+ var SOLANA_DEFAULT_RPC_URL = "https://api.mainnet-beta.solana.com";
648
+ var SOLANA_METAMASK_CONNECT_TIMEOUT_MS = 3e4;
649
+ var BITCOIN_DEFAULT_RPC_URL = "https://mempool.space/api";
650
+ var STELLAR_DEFAULT_HORIZON_RPC_URL = "https://horizon.stellar.org";
651
+ var STELLAR_DEFAULT_SOROBAN_RPC_URL = "https://rpc.ankr.com/stellar_soroban";
652
+ var NEAR_DEFAULT_RPC_URL = "https://1rpc.io/near";
653
+ var WALLET_METADATA = {
654
+ unisat: {
655
+ installUrl: "https://chromewebstore.google.com/detail/unisat-wallet/ppbibelpcjmhbdihakflkdcoccbgbkpo",
656
+ icon: "https://avatars.githubusercontent.com/u/125119198?s=200&v=4"
657
+ },
658
+ xverse: {
659
+ installUrl: "https://chromewebstore.google.com/detail/xverse-bitcoin-crypto-wal/idnnbdplmphpflfnlkomgpfbpcgelopg",
660
+ icon: "https://cdn.brandfetch.io/iddzGN5Rcv/w/400/h/400/theme/dark/icon.jpeg?c=1bxid64Mup7aczewSAYMX&t=1771902357797"
661
+ },
662
+ okx: {
663
+ installUrl: "https://chromewebstore.google.com/detail/okx-wallet/mcohilncbfahbmgdjkbpemcciiolgcge",
664
+ icon: "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png"
665
+ },
666
+ hana: {
667
+ installUrl: "https://chromewebstore.google.com/detail/hana-wallet/jfdlamikmbghhapbgfoogdffldioobgl",
668
+ icon: "https://raw.githubusercontent.com/balancednetwork/icons/master/wallets/hana.svg"
549
669
  }
550
- async signBip322Message(message) {
551
- return this.okx.signMessage(message, "bip322-simple");
670
+ };
671
+
672
+ // src/xchains/stellar/StellarXService.ts
673
+ var STELLAR_BASE_RESERVE_STROOPS = 5e6;
674
+ function parseXlmBalanceToStroops(balanceStr) {
675
+ const parts = balanceStr.split(".");
676
+ const whole = parts[0] ?? "0";
677
+ const frac = (parts[1] ?? "").padEnd(7, "0").slice(0, 7);
678
+ return BigInt(whole + frac);
679
+ }
680
+ var StellarXService = class _StellarXService extends XService {
681
+ static instance;
682
+ walletsKit;
683
+ server;
684
+ sorobanServer;
685
+ constructor(horizonRpcUrl, sorobanRpcUrl) {
686
+ super("STELLAR");
687
+ this.walletsKit = new stellarWalletsKit.StellarWalletsKit({
688
+ network: stellarWalletsKit.WalletNetwork.PUBLIC,
689
+ modules: stellarWalletsKit.allowAllModules()
690
+ });
691
+ this.server = new StellarSdk__namespace.Horizon.Server(horizonRpcUrl ?? STELLAR_DEFAULT_HORIZON_RPC_URL, { allowHttp: true });
692
+ this.sorobanServer = new CustomSorobanServer_default(sorobanRpcUrl ?? STELLAR_DEFAULT_SOROBAN_RPC_URL, {});
552
693
  }
553
- async sendBitcoin(toAddress, satoshis) {
554
- if (satoshis > BigInt(Number.MAX_SAFE_INTEGER)) {
555
- throw new Error(`Amount ${satoshis} satoshis exceeds safe integer range`);
694
+ static getInstance(horizonRpcUrl, sorobanRpcUrl) {
695
+ if (!_StellarXService.instance) {
696
+ _StellarXService.instance = new _StellarXService(horizonRpcUrl, sorobanRpcUrl);
697
+ } else {
698
+ if (horizonRpcUrl) {
699
+ _StellarXService.instance.server = new StellarSdk__namespace.Horizon.Server(horizonRpcUrl, { allowHttp: true });
700
+ }
701
+ if (sorobanRpcUrl) {
702
+ _StellarXService.instance.sorobanServer = new CustomSorobanServer_default(sorobanRpcUrl, {});
703
+ }
556
704
  }
557
- return this.okx.sendBitcoin(toAddress, Number(satoshis));
705
+ return _StellarXService.instance;
558
706
  }
559
- };
560
- var OKXXConnector = class extends BitcoinXConnector {
561
- constructor() {
562
- super("OKX Wallet", "okx-bitcoin");
707
+ async getBalance(address, xToken) {
708
+ if (!address) return BigInt(0);
709
+ const stellarAccount = await this.server.loadAccount(address);
710
+ if (xToken.symbol === "XLM") {
711
+ const xlmBalance = stellarAccount.balances.find((balance) => balance.asset_type === "native");
712
+ if (xlmBalance) {
713
+ const rawBalanceStroops = parseXlmBalanceToStroops(xlmBalance.balance);
714
+ const sellingLiabilitiesStroops = xlmBalance.selling_liabilities ? parseXlmBalanceToStroops(xlmBalance.selling_liabilities) : BigInt(0);
715
+ const reserveFields = stellarAccount;
716
+ const subentryCount = reserveFields.subentry_count ?? 0;
717
+ const numSponsoring = reserveFields.num_sponsoring ?? 0;
718
+ const numSponsored = reserveFields.num_sponsored ?? 0;
719
+ const reserveCount = Math.max(0, 2 + subentryCount + numSponsoring - numSponsored);
720
+ const minBalanceStroops = BigInt(reserveCount) * BigInt(STELLAR_BASE_RESERVE_STROOPS) + sellingLiabilitiesStroops;
721
+ const availableStroops = rawBalanceStroops > minBalanceStroops ? rawBalanceStroops - minBalanceStroops : BigInt(0);
722
+ return availableStroops;
723
+ }
724
+ } else {
725
+ try {
726
+ const txBuilder = new StellarSdk__namespace.TransactionBuilder(stellarAccount, {
727
+ fee: StellarSdk__namespace.BASE_FEE,
728
+ networkPassphrase: StellarSdk__namespace.Networks.PUBLIC
729
+ });
730
+ const balance = await getTokenBalance(address, xToken.address, txBuilder, this.sorobanServer);
731
+ return balance;
732
+ } catch (e) {
733
+ console.error(`Error while fetching token on Stellar: ${xToken.symbol}, Error: ${e}`);
734
+ }
735
+ }
736
+ return BigInt(0);
563
737
  }
564
- static isAvailable() {
565
- return typeof window !== "undefined" && !!window.okxwallet?.bitcoin;
738
+ };
739
+
740
+ // src/xchains/stellar/StellarWalletsKitXConnector.ts
741
+ var StellarWalletsKitXConnector = class extends XConnector {
742
+ _wallet;
743
+ constructor(wallet) {
744
+ super("STELLAR", wallet.name, wallet.id);
745
+ this._wallet = wallet;
566
746
  }
567
- get icon() {
568
- return "https://static.okx.com/cdn/assets/imgs/247/58E63FEA47A2B7D7.png";
747
+ getXService() {
748
+ return StellarXService.getInstance();
569
749
  }
570
750
  async connect() {
571
- const okx = window.okxwallet?.bitcoin;
572
- if (!okx) {
573
- throw new Error("OKX wallet is not installed");
751
+ const kit = this.getXService().walletsKit;
752
+ if (!this._wallet) {
753
+ return;
574
754
  }
575
- const { address } = await okx.connect();
576
- if (!address) return void 0;
577
- this.walletProvider = new OKXWalletProvider(okx, address);
755
+ if (!this._wallet.isAvailable) {
756
+ throw new Error(`${this._wallet.name} is not installed. Install the wallet and reload the page.`);
757
+ }
758
+ kit.setWallet(this._wallet.id);
759
+ const { address } = await kit.getAddress();
578
760
  return {
579
761
  address,
580
- xChainType: "BITCOIN"
762
+ xChainType: this.xChainType
581
763
  };
582
764
  }
583
765
  async disconnect() {
584
- this.walletProvider = void 0;
585
766
  }
586
- getWalletProvider() {
587
- return this.walletProvider;
767
+ get icon() {
768
+ return this._wallet.icon;
588
769
  }
589
- recreateWalletProvider(xAccount) {
590
- const okx = window.okxwallet?.bitcoin;
591
- if (!okx || !xAccount.address) return void 0;
592
- return new OKXWalletProvider(okx, xAccount.address);
770
+ get isInstalled() {
771
+ return this._wallet.isAvailable;
593
772
  }
594
- };
595
- var hyper = /* @__PURE__ */ viem.defineChain({
596
- id: 999,
597
- name: "HyperEVM",
598
- nativeCurrency: {
599
- decimals: 18,
600
- name: "HYPE",
601
- symbol: "HYPE"
602
- },
603
- rpcUrls: {
604
- default: { http: ["https://rpc.hyperliquid.xyz/evm"] }
605
- },
606
- blockExplorers: {
607
- default: {
608
- name: "HyperEVMScan",
609
- url: "https://hyperevmscan.io/"
610
- }
611
- },
612
- contracts: {
613
- multicall3: {
614
- address: "0xcA11bde05977b3631167028862bE2a173976CA11",
615
- blockCreated: 13051
616
- }
773
+ get installUrl() {
774
+ return this._wallet.url;
617
775
  }
618
- });
619
- var createWagmiConfig = (config, options) => {
620
- return wagmi.createConfig({
621
- chains: [
622
- chains.mainnet,
623
- chains.avalanche,
624
- chains.arbitrum,
625
- chains.base,
626
- chains.bsc,
627
- chains.sonic,
628
- chains.optimism,
629
- chains.polygon,
630
- hyper,
631
- chains.lightlinkPhoenix,
632
- chains.kaia,
633
- chains.redbellyMainnet
634
- ],
635
- ssr: options?.ssr,
636
- transports: {
637
- [chains.mainnet.id]: wagmi.http(config[types.ETHEREUM_MAINNET_CHAIN_ID]),
638
- [chains.avalanche.id]: wagmi.http(config[types.AVALANCHE_MAINNET_CHAIN_ID]),
639
- [chains.arbitrum.id]: wagmi.http(config[types.ARBITRUM_MAINNET_CHAIN_ID]),
640
- [chains.base.id]: wagmi.http(config[types.BASE_MAINNET_CHAIN_ID]),
641
- [chains.bsc.id]: wagmi.http(config[types.BSC_MAINNET_CHAIN_ID]),
642
- [chains.sonic.id]: wagmi.http(config[types.SONIC_MAINNET_CHAIN_ID]),
643
- [chains.optimism.id]: wagmi.http(config[types.OPTIMISM_MAINNET_CHAIN_ID]),
644
- [chains.polygon.id]: wagmi.http(config[types.POLYGON_MAINNET_CHAIN_ID]),
645
- [hyper.id]: wagmi.http(config[types.HYPEREVM_MAINNET_CHAIN_ID]),
646
- [chains.lightlinkPhoenix.id]: wagmi.http(config[types.LIGHTLINK_MAINNET_CHAIN_ID]),
647
- [chains.redbellyMainnet.id]: wagmi.http(config[types.REDBELLY_MAINNET_CHAIN_ID]),
648
- [chains.kaia.id]: wagmi.http(config[types.KAIA_MAINNET_CHAIN_ID])
649
- },
650
- storage: wagmi.createStorage({
651
- storage: wagmi.cookieStorage,
652
- key: "sodax"
653
- })
654
- });
655
776
  };
656
- var EvmXService = class _EvmXService extends XService {
657
- constructor() {
658
- super("EVM");
777
+ var IconSdk = "default" in IconSdkRaw__namespace.default ? IconSdkRaw__namespace.default : IconSdkRaw__namespace;
778
+ var { IconService: IconServiceConstructor, Builder: IconBuilder, Converter: IconConverter } = IconSdk;
779
+ var CHAIN_INFO = {
780
+ [1 /* MAINNET */]: {
781
+ APIEndpoint: "https://ctz.solidwallet.io/api/v3"}
782
+ };
783
+ var IconXService = class _IconXService extends XService {
784
+ static instance;
785
+ iconService;
786
+ constructor(rpcUrl) {
787
+ super("ICON");
788
+ const mainnetInfo = CHAIN_INFO[1 /* MAINNET */];
789
+ if (!mainnetInfo) throw new Error("ICON mainnet chain info not found");
790
+ this.iconService = new IconServiceConstructor(
791
+ new IconServiceConstructor.HttpProvider(rpcUrl ?? mainnetInfo.APIEndpoint)
792
+ );
659
793
  }
660
- getXConnectors() {
661
- return [];
794
+ static getInstance(rpcUrl) {
795
+ if (!_IconXService.instance) {
796
+ _IconXService.instance = new _IconXService(rpcUrl);
797
+ }
798
+ return _IconXService.instance;
662
799
  }
663
- static getInstance() {
664
- if (!_EvmXService.instance) {
665
- _EvmXService.instance = new _EvmXService();
800
+ async getAggregateData(requireSuccess, calls) {
801
+ const rawTx = new IconBuilder.CallBuilder().to("cxa4aa9185e23558cff990f494c1fd2845f6cbf741").method("tryAggregate").params({ requireSuccess: IconConverter.toHex(requireSuccess ? 1 : 0), calls }).build();
802
+ try {
803
+ const result = await this.iconService.call(rawTx).execute();
804
+ const aggs = result["returnData"];
805
+ const data = aggs.map((agg) => {
806
+ if (agg["success"] === "0x0") {
807
+ return null;
808
+ }
809
+ return agg["returnData"];
810
+ });
811
+ return data;
812
+ } catch (err) {
813
+ console.error(err);
814
+ return Array(calls.length).fill(null);
666
815
  }
667
- return _EvmXService.instance;
668
- }
669
- // get erc20 token balance in a chain (evm chain only)
670
- async _getTokenBalance(address, chainId, tokenAddress) {
671
- const publicClient = actions.getPublicClient(this.wagmiConfig, { chainId });
672
- if (!publicClient) throw new Error("Public client not found");
673
- const balance = await publicClient.readContract({
674
- abi: viem.erc20Abi,
675
- address: tokenAddress,
676
- functionName: "balanceOf",
677
- args: [address]
678
- });
679
- return balance || 0n;
680
- }
681
- //get native balance of the chain (evm chain only)
682
- async _getChainBalance(address, chainId) {
683
- const balance = await actions.getPublicClient(this.wagmiConfig, { chainId })?.getBalance({
684
- address
685
- });
686
- return balance || 0n;
687
- }
688
- async getBalance(address, xToken) {
689
- if (!address) return 0n;
690
- if (!this.wagmiConfig) return 0n;
691
- const chainId = getWagmiChainId(xToken.xChainId);
692
- if (isNativeToken(xToken)) {
693
- return this._getChainBalance(address, chainId);
694
- }
695
- throw new Error(`Unsupported token: ${xToken.symbol}`);
696
816
  }
697
817
  async getBalances(address, xTokens) {
698
818
  if (!address) return {};
699
- if (!this.wagmiConfig) return {};
700
- const nativeTokenBalancePromises = xTokens.filter((xToken) => isNativeToken(xToken)).map(async (xToken) => {
701
- const balance = await this.getBalance(address, xToken);
702
- return { symbol: xToken.symbol, address: xToken.address, balance };
703
- });
704
- const nativeTokenBalances = await Promise.all(nativeTokenBalancePromises);
705
- const tokenMap = nativeTokenBalances.reduce((map, { address: address2, balance }) => {
706
- if (balance) map[address2] = balance;
707
- return map;
708
- }, {});
819
+ const balances = {};
820
+ const nativeXToken = xTokens.find((xToken) => isNativeToken(xToken));
709
821
  const nonNativeXTokens = xTokens.filter((xToken) => !isNativeToken(xToken));
710
- const xChainId = xTokens[0].xChainId;
711
- const viemChain = this.wagmiConfig.chains.find((chain) => chain.id === getWagmiChainId(xChainId));
712
- const chainId = getWagmiChainId(xChainId);
713
- const publicClient = actions.getPublicClient(this.wagmiConfig, { chainId });
714
- if (!publicClient) throw new Error("Public client not found");
715
- if (viemChain?.contracts?.multicall3) {
716
- const result = await publicClient.multicall({
717
- contracts: nonNativeXTokens.map((token) => ({
718
- abi: viem.erc20Abi,
719
- address: token.address,
720
- functionName: "balanceOf",
721
- args: [address]
722
- }))
723
- });
724
- return nonNativeXTokens.reduce((acc, token, index) => {
725
- acc[token.address] = result?.[index]?.result?.toString() || "0";
726
- return acc;
727
- }, tokenMap);
822
+ if (nativeXToken) {
823
+ const balance = await this.iconService.getBalance(address).execute();
824
+ balances[nativeXToken.address] = BigInt(balance.toFixed());
728
825
  }
729
- const nonNativeTokenBalances = await Promise.all(
730
- nonNativeXTokens.map((token) => this._getTokenBalance(address, chainId, token.address))
826
+ const cds = nonNativeXTokens.map((token) => {
827
+ return {
828
+ target: token.address,
829
+ method: "balanceOf",
830
+ params: [address]
831
+ };
832
+ });
833
+ const data = await this.getAggregateData(
834
+ false,
835
+ cds.filter((cd) => cd.target.startsWith("cx"))
731
836
  );
732
- return nonNativeXTokens.reduce((acc, token, idx) => {
733
- acc[token.address] = nonNativeTokenBalances[idx] || "0";
734
- return acc;
735
- }, tokenMap);
837
+ return nonNativeXTokens.reduce((agg, token, idx) => {
838
+ const balance = data[idx];
839
+ if (balance) {
840
+ balances[token.address] = BigInt(balance);
841
+ }
842
+ return agg;
843
+ }, balances);
736
844
  }
737
845
  };
738
846
 
739
- // src/xchains/evm/EvmXConnector.ts
740
- var EvmXConnector = class extends XConnector {
741
- constructor(connector) {
742
- super("EVM", connector.name, connector.id);
743
- this.connector = connector;
847
+ // src/xchains/icon/iconex/index.tsx
848
+ var ICONEX_RELAY_RESPONSE = "ICONEX_RELAY_RESPONSE";
849
+ var ICONEX_RELAY_REQUEST = "ICONEX_RELAY_REQUEST";
850
+ var request = (event) => {
851
+ return new Promise((resolve, reject) => {
852
+ const handler = (evt) => {
853
+ window.removeEventListener(ICONEX_RELAY_RESPONSE, handler);
854
+ resolve(evt.detail);
855
+ };
856
+ window.addEventListener(ICONEX_RELAY_RESPONSE, handler);
857
+ window.dispatchEvent(
858
+ new CustomEvent(ICONEX_RELAY_REQUEST, {
859
+ detail: event
860
+ })
861
+ );
862
+ });
863
+ };
864
+
865
+ // src/xchains/icon/IconHanaXConnector.ts
866
+ var isHanaWallet = (value) => {
867
+ return isRecord(value) && (value.available === void 0 || hasBooleanProperty(value, "available"));
868
+ };
869
+ var IconHanaXConnector = class extends XConnector {
870
+ constructor() {
871
+ super("ICON", "Hana Wallet", "hana");
872
+ }
873
+ get isInstalled() {
874
+ if (typeof window === "undefined") return false;
875
+ const hanaWallet = window.hanaWallet;
876
+ return isHanaWallet(hanaWallet) && hanaWallet.available === true;
877
+ }
878
+ get installUrl() {
879
+ return WALLET_METADATA.hana.installUrl;
744
880
  }
745
881
  async connect() {
746
- return;
882
+ const hanaWallet = window.hanaWallet;
883
+ assert(isHanaWallet(hanaWallet) || hanaWallet === void 0, "[IconHanaXConnector] invalid window.hanaWallet type");
884
+ if (!hanaWallet || !hanaWallet.available) {
885
+ window.open(WALLET_METADATA.hana.installUrl, "_blank", "noopener,noreferrer");
886
+ return;
887
+ }
888
+ const detail = await request({
889
+ type: "REQUEST_ADDRESS" /* REQUEST_ADDRESS */
890
+ });
891
+ if (detail?.type === "RESPONSE_ADDRESS" /* RESPONSE_ADDRESS */) {
892
+ return {
893
+ address: detail?.payload,
894
+ xChainType: this.xChainType
895
+ };
896
+ }
897
+ console.warn("[IconHanaXConnector] connect: unexpected response from Hana wallet", detail);
898
+ return void 0;
747
899
  }
748
900
  async disconnect() {
749
- return;
750
- }
751
- get id() {
752
- return this.connector.id;
901
+ console.log("HanaIconXConnector disconnected");
753
902
  }
754
903
  get icon() {
755
- return this.connector.icon;
904
+ return WALLET_METADATA.hana.icon;
756
905
  }
757
906
  };
758
907
  var InjectiveXService = class _InjectiveXService extends XService {
759
- constructor() {
908
+ static instance;
909
+ walletStrategy;
910
+ indexerGrpcAccountPortfolioApi;
911
+ chainGrpcWasmApi;
912
+ msgBroadcaster;
913
+ constructor(rpcConfig) {
760
914
  super("INJECTIVE");
761
- const endpoints = networks.getNetworkEndpoints(networks.Network.Mainnet);
915
+ const defaults = networks.getNetworkEndpoints(networks.Network.Mainnet);
916
+ const endpoints = {
917
+ ...defaults,
918
+ indexer: rpcConfig?.indexer || defaults.indexer,
919
+ grpc: rpcConfig?.grpc || defaults.grpc
920
+ };
762
921
  this.walletStrategy = new walletStrategy.WalletStrategy({
763
922
  chainId: tsTypes.ChainId.Mainnet,
764
923
  strategies: {},
765
924
  evmOptions: {
766
- evmChainId: chains.mainnet.id,
767
- rpcUrl: chains.mainnet.rpcUrls.default.http[0]
925
+ evmChainId: chains$1.mainnet.id,
926
+ rpcUrl: chains$1.mainnet.rpcUrls.default.http[0]
768
927
  }
769
928
  });
770
929
  this.indexerGrpcAccountPortfolioApi = new sdkTs.IndexerGrpcAccountPortfolioApi(endpoints.indexer);
@@ -775,9 +934,15 @@ var InjectiveXService = class _InjectiveXService extends XService {
775
934
  endpoints
776
935
  });
777
936
  }
778
- static getInstance() {
937
+ /**
938
+ * @param rpcConfig - Only applied on first call. Subsequent calls return the
939
+ * existing instance unchanged — gRPC/Indexer clients are built in the
940
+ * constructor and can't be rebuilt at runtime. Pass the desired endpoints
941
+ * via `SodaxWalletProvider.config.rpcConfig` once at app init.
942
+ */
943
+ static getInstance(rpcConfig) {
779
944
  if (!_InjectiveXService.instance) {
780
- _InjectiveXService.instance = new _InjectiveXService();
945
+ _InjectiveXService.instance = new _InjectiveXService(rpcConfig);
781
946
  }
782
947
  return _InjectiveXService.instance;
783
948
  }
@@ -802,6 +967,7 @@ var WALLET_ICONS = {
802
967
  "trust-wallet": "https://trustwallet.com/assets/images/media/assets/twLogo.svg"
803
968
  };
804
969
  var InjectiveXConnector = class extends XConnector {
970
+ wallet;
805
971
  constructor(name, wallet) {
806
972
  super("INJECTIVE", name, wallet);
807
973
  this.wallet = wallet;
@@ -811,13 +977,22 @@ var InjectiveXConnector = class extends XConnector {
811
977
  }
812
978
  async connect() {
813
979
  if (walletBase.isCosmosBrowserWallet(this.wallet) && !walletCosmos.isCosmosWalletInstalled(this.wallet)) {
980
+ console.warn(`[InjectiveXConnector] connect: ${this.wallet} cosmos wallet not installed`);
814
981
  return void 0;
815
982
  }
816
983
  const walletStrategy = this.getXService().walletStrategy;
817
984
  await walletStrategy.setWallet(this.wallet);
818
985
  const addresses = await walletStrategy.getAddresses();
819
- if (!addresses?.length) return void 0;
820
- const address = walletBase.isEvmBrowserWallet(this.wallet) ? sdkTs.getInjectiveAddress(addresses[0]) : addresses[0];
986
+ if (!addresses?.length) {
987
+ console.warn(`[InjectiveXConnector] connect: ${this.wallet} returned no addresses`);
988
+ return void 0;
989
+ }
990
+ const firstAddress = addresses[0];
991
+ if (!firstAddress) {
992
+ console.warn(`[InjectiveXConnector] connect: ${this.wallet} returned empty addresses array`);
993
+ return void 0;
994
+ }
995
+ const address = walletBase.isEvmBrowserWallet(this.wallet) ? sdkTs.getInjectiveAddress(firstAddress) : firstAddress;
821
996
  return {
822
997
  address,
823
998
  xChainType: this.xChainType
@@ -833,392 +1008,1295 @@ var InjectiveXConnector = class extends XConnector {
833
1008
  get icon() {
834
1009
  return WALLET_ICONS[this.wallet];
835
1010
  }
1011
+ get isInstalled() {
1012
+ if (walletBase.isCosmosBrowserWallet(this.wallet)) {
1013
+ return walletCosmos.isCosmosWalletInstalled(this.wallet);
1014
+ }
1015
+ return true;
1016
+ }
836
1017
  };
837
- var SolanaXService = class _SolanaXService extends XService {
838
- constructor() {
839
- super("SOLANA");
1018
+
1019
+ // src/xchains/bitcoin/BitcoinXService.ts
1020
+ var BitcoinXService = class _BitcoinXService extends XService {
1021
+ static instance;
1022
+ rpcUrl;
1023
+ constructor(rpcUrl = BITCOIN_DEFAULT_RPC_URL) {
1024
+ super("BITCOIN");
1025
+ this.rpcUrl = rpcUrl;
840
1026
  }
841
- static getInstance() {
842
- if (!_SolanaXService.instance) {
843
- _SolanaXService.instance = new _SolanaXService();
1027
+ static getInstance(rpcUrl) {
1028
+ if (!_BitcoinXService.instance) {
1029
+ _BitcoinXService.instance = new _BitcoinXService(rpcUrl);
1030
+ } else if (rpcUrl && rpcUrl !== _BitcoinXService.instance.rpcUrl) {
1031
+ _BitcoinXService.instance.rpcUrl = rpcUrl;
844
1032
  }
845
- return _SolanaXService.instance;
1033
+ return _BitcoinXService.instance;
846
1034
  }
847
1035
  async getBalance(address, xToken) {
848
- if (!address) return BigInt(0);
849
- const connection = this.connection;
850
- if (!connection) {
851
- return BigInt(0);
852
- }
1036
+ if (!address) return 0n;
853
1037
  try {
854
1038
  if (isNativeToken(xToken)) {
855
- const newBalance = await connection.getBalance(new web3_js.PublicKey(address));
856
- return BigInt(newBalance);
1039
+ const response = await fetch(`${this.rpcUrl}/address/${address}/utxo`);
1040
+ if (!response.ok) return 0n;
1041
+ const utxos = await response.json();
1042
+ const totalBalance = utxos.reduce((sum, utxo) => sum + utxo.value, 0);
1043
+ return BigInt(totalBalance);
857
1044
  }
858
- const tokenAccountPubkey = splToken.getAssociatedTokenAddressSync(new web3_js.PublicKey(xToken.address), new web3_js.PublicKey(address));
859
- const tokenAccount = await splToken.getAccount(connection, tokenAccountPubkey);
860
- return BigInt(tokenAccount.amount);
861
1045
  } catch {
862
- return BigInt(0);
1046
+ return 0n;
863
1047
  }
1048
+ return 0n;
864
1049
  }
865
1050
  };
866
- var CustomSorobanServer = class extends StellarSdk.SorobanRpc.Server {
867
- constructor(serverUrl, customHeaders) {
868
- super(serverUrl, {
869
- allowHttp: true
870
- });
871
- this.customHeaders = customHeaders;
1051
+
1052
+ // src/xchains/bitcoin/BitcoinXConnector.ts
1053
+ var BitcoinXConnector = class extends XConnector {
1054
+ defaults;
1055
+ constructor(name, id, defaults) {
1056
+ super("BITCOIN", name, id);
1057
+ this.defaults = defaults;
872
1058
  }
873
- async simulateTransaction(tx) {
874
- const requestOptions = {
875
- method: "POST",
876
- headers: {
877
- "Content-Type": "application/json",
878
- ...this.customHeaders
879
- },
880
- body: JSON.stringify({
881
- id: 1,
882
- jsonrpc: "2.0",
883
- method: "simulateTransaction",
884
- params: {
885
- transaction: tx.toXDR()
886
- }
887
- })
888
- };
889
- const response = await fetch(`${this.serverURL}`, requestOptions);
890
- if (!response.ok) {
891
- throw new Error(`HTTP error simulating TX! status: ${response.status}`);
892
- }
893
- return response.json().then((json) => json.result);
1059
+ getXService() {
1060
+ return BitcoinXService.getInstance();
894
1061
  }
895
- async sendTransaction(tx) {
896
- const requestOptions = {
897
- method: "POST",
898
- headers: {
899
- "Content-Type": "application/json",
900
- ...this.customHeaders
901
- },
902
- body: JSON.stringify({
903
- id: 1,
904
- jsonrpc: "2.0",
905
- method: "sendTransaction",
906
- params: {
907
- transaction: tx.toXDR()
908
- }
909
- })
910
- };
911
- const response = await fetch(`${this.serverURL}`, requestOptions);
912
- if (!response.ok) {
913
- throw new Error(`HTTP error submitting TX! status: ${response.status}`);
914
- }
915
- return response.json().then((json) => json.result);
1062
+ };
1063
+ var UnisatWalletProvider = class {
1064
+ chainType = "BITCOIN";
1065
+ cachedAddress;
1066
+ defaults;
1067
+ constructor(address, defaults) {
1068
+ this.cachedAddress = address;
1069
+ this.defaults = defaults;
916
1070
  }
917
- async getTransaction(hash) {
918
- const requestOptions = {
919
- method: "POST",
920
- headers: {
921
- "Content-Type": "application/json",
922
- ...this.customHeaders
923
- },
924
- body: JSON.stringify({
925
- id: 1,
926
- jsonrpc: "2.0",
927
- method: "getTransaction",
928
- params: { hash }
929
- })
930
- };
931
- const response = await fetch(`${this.serverURL}`, requestOptions);
932
- if (!response.ok) {
933
- throw new Error(`HTTP error getting TX! status: ${response.status}`);
1071
+ // Lazy resolve so the provider can be constructed before the extension finishes injecting `window.unisat` (post-refresh rehydrate path).
1072
+ get unisat() {
1073
+ const u = window.unisat;
1074
+ if (!u) throw new Error("Unisat wallet not available");
1075
+ return u;
1076
+ }
1077
+ async getWalletAddress() {
1078
+ try {
1079
+ const accounts = await this.unisat.getAccounts();
1080
+ if (accounts[0]) this.cachedAddress = accounts[0];
1081
+ } catch {
934
1082
  }
935
- return response.json().then((json) => json.result);
1083
+ return this.cachedAddress;
936
1084
  }
937
- };
938
- var CustomSorobanServer_default = CustomSorobanServer;
939
- var accountToScVal = (account) => new StellarSdk.Address(account).toScVal();
940
- var simulateTx = async (tx, server) => {
941
- const response = await server.simulateTransaction(tx);
942
- if (response !== void 0) {
943
- return response;
1085
+ async getPublicKey() {
1086
+ return this.unisat.getPublicKey();
944
1087
  }
945
- throw new Error("cannot simulate transaction");
946
- };
947
- var getTokenBalance = async (address, tokenId, txBuilder, server) => {
948
- const params = [accountToScVal(address)];
949
- const contract = new StellarSdk.Contract(tokenId);
950
- const tx = txBuilder.addOperation(contract.call("balance", ...params)).setTimeout(StellarSdk.TimeoutInfinite).build();
951
- const result = await simulateTx(tx, server);
952
- return result.results ? StellarSdk.scValToBigInt(StellarSdk.xdr.ScVal.fromXDR(result.results[0].xdr, "base64")) : 0n;
953
- };
954
-
955
- // src/xchains/stellar/StellarXService.ts
956
- var STELLAR_BASE_RESERVE_STROOPS = 5e6;
957
- function parseXlmBalanceToStroops(balanceStr) {
958
- const parts = balanceStr.split(".");
959
- const whole = parts[0] ?? "0";
960
- const frac = (parts[1] ?? "").padEnd(7, "0").slice(0, 7);
961
- return BigInt(whole + frac);
962
- }
963
- var StellarXService = class _StellarXService extends XService {
964
- constructor() {
965
- super("STELLAR");
966
- this.walletsKit = new stellarWalletsKit.StellarWalletsKit({
967
- network: stellarWalletsKit.WalletNetwork.PUBLIC,
968
- modules: stellarWalletsKit.allowAllModules()
969
- });
970
- this.server = new StellarSdk__namespace.Horizon.Server("https://horizon.stellar.org", { allowHttp: true });
971
- this.sorobanServer = new CustomSorobanServer_default("https://rpc.ankr.com/stellar_soroban", {});
1088
+ async getAddressType(_address) {
1089
+ const address = await this.getWalletAddress();
1090
+ return types.detectBitcoinAddressType(address);
972
1091
  }
973
- static getInstance() {
974
- if (!_StellarXService.instance) {
975
- _StellarXService.instance = new _StellarXService();
976
- }
977
- return _StellarXService.instance;
1092
+ async signTransaction(psbtBase64, finalize) {
1093
+ const effectiveFinalize = finalize ?? this.defaults?.defaultFinalize ?? false;
1094
+ const psbtHex = Buffer.from(psbtBase64, "base64").toString("hex");
1095
+ const signedHex = await this.unisat.signPsbt(psbtHex, { autoFinalized: effectiveFinalize });
1096
+ return signedHex;
978
1097
  }
979
- async getBalance(address, xToken) {
980
- if (!address) return BigInt(0);
981
- const stellarAccount = await this.server.loadAccount(address);
982
- if (xToken.symbol === "XLM") {
983
- const xlmBalance = stellarAccount.balances.find((balance) => balance.asset_type === "native");
984
- if (xlmBalance) {
985
- const rawBalanceStroops = parseXlmBalanceToStroops(xlmBalance.balance);
986
- const sellingLiabilitiesStroops = xlmBalance.selling_liabilities ? parseXlmBalanceToStroops(xlmBalance.selling_liabilities) : BigInt(0);
987
- const reserveFields = stellarAccount;
988
- const subentryCount = reserveFields.subentry_count ?? 0;
989
- const numSponsoring = reserveFields.num_sponsoring ?? 0;
990
- const numSponsored = reserveFields.num_sponsored ?? 0;
991
- const reserveCount = Math.max(0, 2 + subentryCount + numSponsoring - numSponsored);
992
- const minBalanceStroops = BigInt(reserveCount) * BigInt(STELLAR_BASE_RESERVE_STROOPS) + sellingLiabilitiesStroops;
993
- const availableStroops = rawBalanceStroops > minBalanceStroops ? rawBalanceStroops - minBalanceStroops : BigInt(0);
994
- return availableStroops;
995
- }
996
- } else {
997
- try {
998
- const txBuilder = new StellarSdk__namespace.TransactionBuilder(stellarAccount, {
999
- fee: StellarSdk__namespace.BASE_FEE,
1000
- networkPassphrase: StellarSdk__namespace.Networks.PUBLIC
1001
- });
1002
- const balance = await getTokenBalance(address, xToken.address, txBuilder, this.sorobanServer);
1003
- return balance;
1004
- } catch (e) {
1005
- console.error(`Error while fetching token on Stellar: ${xToken.symbol}, Error: ${e}`);
1006
- }
1098
+ async signEcdsaMessage(message) {
1099
+ return this.unisat.signMessage(message, "ecdsa");
1100
+ }
1101
+ async signBip322Message(message) {
1102
+ return this.unisat.signMessage(message, "bip322-simple");
1103
+ }
1104
+ async sendBitcoin(toAddress, satoshis) {
1105
+ if (satoshis > BigInt(Number.MAX_SAFE_INTEGER)) {
1106
+ throw new Error(`Amount ${satoshis} satoshis exceeds safe integer range`);
1007
1107
  }
1008
- return BigInt(0);
1108
+ return this.unisat.sendBitcoin(toAddress, Number(satoshis));
1009
1109
  }
1010
1110
  };
1011
-
1012
- // src/xchains/stellar/StellarWalletsKitXConnector.ts
1013
- var StellarWalletsKitXConnector = class extends XConnector {
1014
- constructor(wallet) {
1015
- super("STELLAR", wallet.name, wallet.id);
1016
- this._wallet = wallet;
1111
+ var UnisatXConnector = class _UnisatXConnector extends BitcoinXConnector {
1112
+ walletProvider;
1113
+ constructor(defaults) {
1114
+ super("Unisat", "unisat", defaults);
1017
1115
  }
1018
- getXService() {
1019
- return StellarXService.getInstance();
1116
+ static isAvailable() {
1117
+ return typeof window !== "undefined" && !!window.unisat;
1118
+ }
1119
+ get isInstalled() {
1120
+ return _UnisatXConnector.isAvailable();
1121
+ }
1122
+ get installUrl() {
1123
+ return WALLET_METADATA.unisat.installUrl;
1124
+ }
1125
+ get icon() {
1126
+ return WALLET_METADATA.unisat.icon;
1020
1127
  }
1021
1128
  async connect() {
1022
- const kit = this.getXService().walletsKit;
1023
- if (!this._wallet) {
1024
- return;
1129
+ if (!window.unisat) {
1130
+ throw new Error("Unisat wallet is not installed");
1025
1131
  }
1026
- if (!this._wallet.isAvailable && this._wallet.url) {
1027
- window.open(this._wallet.url, "_blank");
1028
- return;
1132
+ const accounts = await window.unisat.requestAccounts();
1133
+ const address = accounts[0];
1134
+ if (!address) {
1135
+ console.warn("[UnisatXConnector] connect: requestAccounts returned no address");
1136
+ return void 0;
1029
1137
  }
1030
- kit.setWallet(this._wallet.id);
1031
- const { address } = await kit.getAddress();
1138
+ this.walletProvider = new UnisatWalletProvider(address, this.defaults);
1032
1139
  return {
1033
1140
  address,
1034
- xChainType: this.xChainType
1141
+ xChainType: "BITCOIN"
1035
1142
  };
1036
1143
  }
1037
1144
  async disconnect() {
1145
+ this.walletProvider = void 0;
1038
1146
  }
1039
- get icon() {
1040
- return this._wallet.icon;
1147
+ getWalletProvider() {
1148
+ return this.walletProvider;
1149
+ }
1150
+ recreateWalletProvider(xAccount) {
1151
+ if (!xAccount.address) return void 0;
1152
+ return new UnisatWalletProvider(xAccount.address, this.defaults);
1041
1153
  }
1042
1154
  };
1043
-
1044
- // src/xchains/sui/SuiXService.ts
1045
- var SuiXService = class _SuiXService extends XService {
1046
- // TODO: define suiAccount type
1047
- constructor() {
1048
- super("SUI");
1155
+ var XverseWalletProvider = class {
1156
+ chainType = "BITCOIN";
1157
+ address;
1158
+ publicKey;
1159
+ defaults;
1160
+ constructor(address, publicKey, defaults) {
1161
+ this.address = address;
1162
+ this.publicKey = publicKey;
1163
+ this.defaults = defaults;
1049
1164
  }
1050
- static getInstance() {
1051
- if (!_SuiXService.instance) {
1052
- _SuiXService.instance = new _SuiXService();
1165
+ async getWalletAddress() {
1166
+ return this.address;
1167
+ }
1168
+ async getPublicKey() {
1169
+ return this.publicKey;
1170
+ }
1171
+ async getAddressType(_address) {
1172
+ return types.detectBitcoinAddressType(this.address);
1173
+ }
1174
+ /**
1175
+ * Parse a base64-encoded PSBT to count the number of inputs.
1176
+ * Reads the unsigned transaction from the PSBT global section.
1177
+ */
1178
+ countPsbtInputs(psbtBase64) {
1179
+ const data = Buffer.from(psbtBase64, "base64");
1180
+ let offset = 5;
1181
+ const keyLen = data[offset++] ?? 0;
1182
+ if (keyLen !== 1 || data[offset++] !== 0) {
1183
+ return 1;
1053
1184
  }
1054
- return _SuiXService.instance;
1185
+ const firstByte = data[offset++] ?? 0;
1186
+ if (firstByte === 253) offset += 2;
1187
+ else if (firstByte === 254) offset += 4;
1188
+ else if (firstByte === 255) offset += 8;
1189
+ offset += 4;
1190
+ const inputByte = data[offset] ?? 0;
1191
+ if (inputByte < 253) return inputByte;
1192
+ return 1;
1055
1193
  }
1056
- // getBalance is not used because getBalances uses getAllBalances which returns all balances
1057
- async getBalances(address, xTokens) {
1058
- if (!address) return {};
1059
- try {
1060
- const balancePromises = xTokens.map(async (xToken) => {
1061
- let coinType = isNativeToken(xToken) ? "0x2::sui::SUI" : xToken.address;
1062
- if (coinType === "0x03917a812fe4a6d6bc779c5ab53f8a80ba741f8af04121193fc44e0f662e2ceb::balanced_dollar::BALANCED_DOLLAR") {
1063
- coinType = "0x3917a812fe4a6d6bc779c5ab53f8a80ba741f8af04121193fc44e0f662e2ceb::balanced_dollar::BALANCED_DOLLAR";
1064
- }
1065
- const balance = await this.suiClient.getBalance({
1066
- owner: address,
1067
- coinType
1068
- });
1069
- return {
1070
- address: xToken.address,
1071
- balance: balance ? BigInt(balance.totalBalance) : void 0
1072
- };
1073
- });
1074
- const results = await Promise.all(balancePromises);
1075
- const tokenMap = {};
1076
- results.forEach((result) => {
1077
- if (result.balance !== void 0) {
1078
- tokenMap[result.address] = result.balance;
1194
+ async signTransaction(psbtBase64, finalize) {
1195
+ const effectiveFinalize = finalize ?? this.defaults?.defaultFinalize ?? false;
1196
+ const { request: request3 } = await import('sats-connect');
1197
+ const inputCount = this.countPsbtInputs(psbtBase64);
1198
+ const signingIndexes = Array.from({ length: inputCount }, (_, i) => i);
1199
+ const response = await request3("signPsbt", {
1200
+ psbt: psbtBase64,
1201
+ broadcast: false,
1202
+ signInputs: {
1203
+ [this.address]: signingIndexes
1204
+ }
1205
+ });
1206
+ if (response.status === "error") {
1207
+ throw new Error(response.error?.message || "Xverse PSBT signing failed");
1208
+ }
1209
+ const result = response.result;
1210
+ if (effectiveFinalize) {
1211
+ return Buffer.from(result.psbt, "base64").toString("hex");
1212
+ }
1213
+ return result.psbt;
1214
+ }
1215
+ async signEcdsaMessage(message) {
1216
+ const { request: request3 } = await import('sats-connect');
1217
+ const response = await request3("signMessage", {
1218
+ address: this.address,
1219
+ message,
1220
+ protocol: satsConnect.MessageSigningProtocols.ECDSA
1221
+ });
1222
+ if (response.status === "error") {
1223
+ throw new Error(response.error?.message || "Xverse ECDSA signing failed");
1224
+ }
1225
+ return response.result.signature;
1226
+ }
1227
+ async signBip322Message(message) {
1228
+ const { request: request3 } = await import('sats-connect');
1229
+ const response = await request3("signMessage", {
1230
+ address: this.address,
1231
+ message,
1232
+ protocol: satsConnect.MessageSigningProtocols.BIP322
1233
+ });
1234
+ if (response.status === "error") {
1235
+ throw new Error(response.error?.message || "Xverse BIP322 signing failed");
1236
+ }
1237
+ return response.result.signature;
1238
+ }
1239
+ async sendBitcoin(toAddress, satoshis) {
1240
+ const { request: request3 } = await import('sats-connect');
1241
+ const response = await request3("sendTransfer", {
1242
+ recipients: [
1243
+ {
1244
+ address: toAddress,
1245
+ amount: Number(satoshis)
1079
1246
  }
1080
- });
1081
- return tokenMap;
1082
- } catch (e) {
1083
- console.log("error", e);
1084
- return {};
1247
+ ]
1248
+ });
1249
+ if (response.status === "error") {
1250
+ throw new Error(response.error?.message || "Xverse sendTransfer failed");
1085
1251
  }
1252
+ return response.result.txid;
1086
1253
  }
1087
1254
  };
1088
-
1089
- // src/xchains/sui/SuiXConnector.ts
1090
- var SuiXConnector = class extends XConnector {
1091
- constructor(wallet) {
1092
- super("SUI", wallet?.name, wallet?.name);
1093
- this.wallet = wallet;
1255
+ var XVERSE_ADDRESS_TYPE_KEY = "xverse-address-type";
1256
+ var XverseXConnector = class _XverseXConnector extends BitcoinXConnector {
1257
+ walletProvider;
1258
+ /** Address purpose used when connecting. Taproot (Ordinals) by default to match Radfi. */
1259
+ addressPurpose;
1260
+ constructor(defaults) {
1261
+ super("Xverse", "xverse", defaults);
1262
+ const saved = typeof window !== "undefined" ? localStorage.getItem(XVERSE_ADDRESS_TYPE_KEY) : null;
1263
+ this.addressPurpose = saved === "segwit" ? satsConnect.AddressPurpose.Payment : satsConnect.AddressPurpose.Ordinals;
1094
1264
  }
1095
- getXService() {
1096
- return SuiXService.getInstance();
1265
+ /** Set address purpose and persist to localStorage. */
1266
+ setAddressPurpose(type) {
1267
+ this.addressPurpose = type === "taproot" ? satsConnect.AddressPurpose.Ordinals : satsConnect.AddressPurpose.Payment;
1268
+ if (typeof window !== "undefined") {
1269
+ localStorage.setItem(XVERSE_ADDRESS_TYPE_KEY, type);
1270
+ }
1097
1271
  }
1098
- async connect() {
1099
- return;
1272
+ static isAvailable() {
1273
+ return typeof window !== "undefined" && !!window.BitcoinProvider;
1100
1274
  }
1101
- async disconnect() {
1275
+ get isInstalled() {
1276
+ return _XverseXConnector.isAvailable();
1102
1277
  }
1103
- get icon() {
1104
- return this.wallet?.icon;
1278
+ get installUrl() {
1279
+ return WALLET_METADATA.xverse.installUrl;
1105
1280
  }
1106
- };
1107
- var IconSdk = "default" in IconSdkRaw__namespace.default ? IconSdkRaw__namespace.default : IconSdkRaw__namespace;
1108
- var { IconService: IconServiceConstructor, Builder: IconBuilder, Converter: IconConverter } = IconSdk;
1109
- var CHAIN_INFO = {
1110
- [1 /* MAINNET */]: {
1111
- APIEndpoint: "https://ctz.solidwallet.io/api/v3"}
1112
- };
1113
- var IconXService = class _IconXService extends XService {
1114
- constructor() {
1115
- super("ICON");
1116
- this.iconService = new IconServiceConstructor(
1117
- new IconServiceConstructor.HttpProvider(CHAIN_INFO[1 /* MAINNET */].APIEndpoint)
1118
- );
1281
+ get icon() {
1282
+ return WALLET_METADATA.xverse.icon;
1119
1283
  }
1120
- static getInstance() {
1121
- if (!_IconXService.instance) {
1122
- _IconXService.instance = new _IconXService();
1123
- }
1124
- return _IconXService.instance;
1284
+ async connect() {
1285
+ if (!_XverseXConnector.isAvailable()) {
1286
+ throw new Error("Xverse wallet is not installed");
1287
+ }
1288
+ const { request: request3 } = await import('sats-connect');
1289
+ const response = await request3("getAccounts", {
1290
+ purposes: [this.addressPurpose],
1291
+ message: "Connect to Sodax"
1292
+ });
1293
+ if (response.status === "error") {
1294
+ throw new Error(response.error?.message || "Xverse connection failed");
1295
+ }
1296
+ const accounts = response.result;
1297
+ const paymentAccount = accounts.find((a) => a.purpose === this.addressPurpose) || accounts[0];
1298
+ if (!paymentAccount) return void 0;
1299
+ this.walletProvider = new XverseWalletProvider(
1300
+ paymentAccount.address,
1301
+ paymentAccount.publicKey,
1302
+ this.defaults
1303
+ );
1304
+ return {
1305
+ address: paymentAccount.address,
1306
+ publicKey: paymentAccount.publicKey,
1307
+ xChainType: "BITCOIN"
1308
+ };
1125
1309
  }
1126
- async getAggregateData(requireSuccess, calls) {
1127
- const rawTx = new IconBuilder.CallBuilder().to("cxa4aa9185e23558cff990f494c1fd2845f6cbf741").method("tryAggregate").params({ requireSuccess: IconConverter.toHex(requireSuccess ? 1 : 0), calls }).build();
1310
+ async disconnect() {
1311
+ this.walletProvider = void 0;
1312
+ }
1313
+ getWalletProvider() {
1314
+ return this.walletProvider;
1315
+ }
1316
+ recreateWalletProvider(xAccount) {
1317
+ if (!xAccount.address || !xAccount.publicKey) return void 0;
1318
+ return new XverseWalletProvider(xAccount.address, xAccount.publicKey, this.defaults);
1319
+ }
1320
+ };
1321
+ var OKXWalletProvider = class {
1322
+ chainType = "BITCOIN";
1323
+ cachedAddress;
1324
+ defaults;
1325
+ constructor(address, defaults) {
1326
+ this.cachedAddress = address;
1327
+ this.defaults = defaults;
1328
+ }
1329
+ // Lazy resolve so the provider can be constructed before the extension finishes injecting `window.okxwallet` (post-refresh rehydrate path).
1330
+ get okx() {
1331
+ const o = window.okxwallet?.bitcoin;
1332
+ if (!o) throw new Error("OKX wallet not available");
1333
+ return o;
1334
+ }
1335
+ async getWalletAddress() {
1128
1336
  try {
1129
- const result = await this.iconService.call(rawTx).execute();
1130
- const aggs = result["returnData"];
1131
- const data = aggs.map((agg) => {
1132
- if (agg["success"] === "0x0") {
1133
- return null;
1134
- }
1135
- return agg["returnData"];
1337
+ const accounts = await this.okx.getAccounts();
1338
+ if (accounts[0]) this.cachedAddress = accounts[0];
1339
+ } catch {
1340
+ }
1341
+ return this.cachedAddress;
1342
+ }
1343
+ async getPublicKey() {
1344
+ return this.okx.getPublicKey();
1345
+ }
1346
+ async getAddressType(_address) {
1347
+ const address = await this.getWalletAddress();
1348
+ return types.detectBitcoinAddressType(address);
1349
+ }
1350
+ async signTransaction(psbtBase64, finalize) {
1351
+ const effectiveFinalize = finalize ?? this.defaults?.defaultFinalize ?? false;
1352
+ const psbtHex = Buffer.from(psbtBase64, "base64").toString("hex");
1353
+ return this.okx.signPsbt(psbtHex, { autoFinalized: effectiveFinalize });
1354
+ }
1355
+ async signEcdsaMessage(message) {
1356
+ return this.okx.signMessage(message, "ecdsa");
1357
+ }
1358
+ async signBip322Message(message) {
1359
+ return this.okx.signMessage(message, "bip322-simple");
1360
+ }
1361
+ async sendBitcoin(toAddress, satoshis) {
1362
+ if (satoshis > BigInt(Number.MAX_SAFE_INTEGER)) {
1363
+ throw new Error(`Amount ${satoshis} satoshis exceeds safe integer range`);
1364
+ }
1365
+ return this.okx.sendBitcoin(toAddress, Number(satoshis));
1366
+ }
1367
+ };
1368
+ var OKXXConnector = class _OKXXConnector extends BitcoinXConnector {
1369
+ walletProvider;
1370
+ constructor(defaults) {
1371
+ super("OKX Wallet", "okx-bitcoin", defaults);
1372
+ }
1373
+ static isAvailable() {
1374
+ return typeof window !== "undefined" && !!window.okxwallet?.bitcoin;
1375
+ }
1376
+ get isInstalled() {
1377
+ return _OKXXConnector.isAvailable();
1378
+ }
1379
+ get installUrl() {
1380
+ return WALLET_METADATA.okx.installUrl;
1381
+ }
1382
+ get icon() {
1383
+ return WALLET_METADATA.okx.icon;
1384
+ }
1385
+ async connect() {
1386
+ const okx = window.okxwallet?.bitcoin;
1387
+ if (!okx) {
1388
+ throw new Error("OKX wallet is not installed");
1389
+ }
1390
+ const { address } = await okx.connect();
1391
+ if (!address) {
1392
+ console.warn("[OKXXConnector] connect: okx.connect() returned no address");
1393
+ return void 0;
1394
+ }
1395
+ this.walletProvider = new OKXWalletProvider(address, this.defaults);
1396
+ return {
1397
+ address,
1398
+ xChainType: "BITCOIN"
1399
+ };
1400
+ }
1401
+ async disconnect() {
1402
+ this.walletProvider = void 0;
1403
+ }
1404
+ getWalletProvider() {
1405
+ return this.walletProvider;
1406
+ }
1407
+ recreateWalletProvider(xAccount) {
1408
+ if (!xAccount.address) return void 0;
1409
+ return new OKXWalletProvider(xAccount.address, this.defaults);
1410
+ }
1411
+ };
1412
+
1413
+ // src/hooks/useXConnection.ts
1414
+ function useXConnection({ xChainType } = {}) {
1415
+ return useXWalletStore((state) => xChainType ? state.xConnections?.[xChainType] : void 0);
1416
+ }
1417
+
1418
+ // src/hooks/useXAccount.ts
1419
+ function useXAccount({ xChainId, xChainType }) {
1420
+ assert(!(xChainId && xChainType), "[useXAccount] pass either xChainId or xChainType, not both");
1421
+ assert(xChainId || xChainType, "[useXAccount] pass xChainId or xChainType");
1422
+ const target = xChainType ?? getXChainType(xChainId);
1423
+ const xConnection = useXConnection({ xChainType: target });
1424
+ return react.useMemo(
1425
+ () => xConnection?.xAccount ?? { address: void 0, xChainType: target },
1426
+ [target, xConnection]
1427
+ );
1428
+ }
1429
+
1430
+ // src/hooks/useEnabledChains.ts
1431
+ function useEnabledChains() {
1432
+ return useXWalletStore((state) => state.enabledChains);
1433
+ }
1434
+
1435
+ // src/hooks/useXConnections.ts
1436
+ function useXConnections() {
1437
+ return useXWalletStore((state) => state.xConnections);
1438
+ }
1439
+
1440
+ // src/hooks/useXAccounts.ts
1441
+ function useXAccounts() {
1442
+ const enabledChains = useEnabledChains();
1443
+ const xConnections = useXConnections();
1444
+ return react.useMemo(() => {
1445
+ const result = {};
1446
+ for (const xChainType of enabledChains) {
1447
+ const xConnection = xConnections[xChainType];
1448
+ result[xChainType] = xConnection?.xAccount ?? { address: void 0, xChainType };
1449
+ }
1450
+ return result;
1451
+ }, [enabledChains, xConnections]);
1452
+ }
1453
+ function useXConnect() {
1454
+ const setXConnection = useXWalletStore((state) => state.setXConnection);
1455
+ const actionsRegistry = useXWalletStore((state) => state.chainActions);
1456
+ return reactQuery.useMutation({
1457
+ mutationFn: async (xConnector) => {
1458
+ const chainActions = actionsRegistry[xConnector.xChainType];
1459
+ if (!chainActions) {
1460
+ throw new Error(`Chain "${xConnector.xChainType}" is not enabled or ChainActions not registered`);
1461
+ }
1462
+ const xAccount = await chainActions.connect(xConnector.id);
1463
+ if (xAccount) {
1464
+ setXConnection(xConnector.xChainType, {
1465
+ xAccount,
1466
+ xConnectorId: xConnector.id
1467
+ });
1468
+ }
1469
+ return xAccount;
1470
+ }
1471
+ });
1472
+ }
1473
+
1474
+ // src/hooks/useXConnectors.ts
1475
+ var warnedChains = /* @__PURE__ */ new Set();
1476
+ function useXConnectors({ xChainType } = {}) {
1477
+ return useXWalletStore((state) => {
1478
+ if (!xChainType) return [];
1479
+ if (!state.enabledChains.includes(xChainType) && !warnedChains.has(xChainType)) {
1480
+ warnedChains.add(xChainType);
1481
+ console.warn(
1482
+ `[useXConnectors] chain "${xChainType}" is not enabled in SodaxWalletProvider config.chains \u2014 returning empty list`
1483
+ );
1484
+ }
1485
+ return state.xConnectorsByChain[xChainType] ?? [];
1486
+ });
1487
+ }
1488
+
1489
+ // src/hooks/useXConnectorsByChain.ts
1490
+ function useXConnectorsByChain() {
1491
+ return useXWalletStore((state) => state.xConnectorsByChain);
1492
+ }
1493
+
1494
+ // src/utils/matchConnectorIdentifier.ts
1495
+ var SHORT_IDENTIFIER_THRESHOLD = 3;
1496
+ var warnedShortIdentifiers = /* @__PURE__ */ new Set();
1497
+ function matchesConnectorIdentifier(connector, identifier) {
1498
+ const needle = identifier.toLowerCase();
1499
+ if (needle.length > 0 && needle.length < SHORT_IDENTIFIER_THRESHOLD && !warnedShortIdentifiers.has(needle)) {
1500
+ warnedShortIdentifiers.add(needle);
1501
+ console.warn(
1502
+ `[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.`
1503
+ );
1504
+ }
1505
+ return connector.id.toLowerCase().includes(needle) || connector.name.toLowerCase().includes(needle);
1506
+ }
1507
+
1508
+ // src/hooks/useIsWalletInstalled.ts
1509
+ function useIsWalletInstalled(options) {
1510
+ const xConnectorsByChain = useXWalletStore((s) => s.xConnectorsByChain);
1511
+ return isAnyConnectorInstalled(options, xConnectorsByChain);
1512
+ }
1513
+ function isAnyConnectorInstalled(options, xConnectorsByChain) {
1514
+ const { connectors: identifiers, chainType } = options;
1515
+ if (identifiers === void 0 && chainType === void 0) {
1516
+ console.warn(
1517
+ "[useIsWalletInstalled] called without `connectors` or `chainType` \u2014 returning `false`. Supply at least one filter."
1518
+ );
1519
+ return false;
1520
+ }
1521
+ if (identifiers && identifiers.length === 0) return false;
1522
+ const chainsToScan = chainType ? [xConnectorsByChain[chainType]] : Object.values(xConnectorsByChain);
1523
+ for (const chainConnectors of chainsToScan) {
1524
+ if (!chainConnectors) continue;
1525
+ for (const connector of chainConnectors) {
1526
+ if (!connector.isInstalled) continue;
1527
+ if (!identifiers) return true;
1528
+ if (identifiers.some((id) => matchesConnectorIdentifier(connector, id))) return true;
1529
+ }
1530
+ }
1531
+ return false;
1532
+ }
1533
+
1534
+ // src/utils/chainOrder.ts
1535
+ function compareChainByOrder(a, b, order) {
1536
+ const ia = order.indexOf(a);
1537
+ const ib = order.indexOf(b);
1538
+ if (ia === -1 && ib === -1) return a.localeCompare(b);
1539
+ if (ia === -1) return 1;
1540
+ if (ib === -1) return -1;
1541
+ return ia - ib;
1542
+ }
1543
+
1544
+ // src/hooks/useChainGroups.ts
1545
+ function getSpokeChainKeysByType(chainType) {
1546
+ const ids = [];
1547
+ for (const chainKey of types.CHAIN_KEYS) {
1548
+ if (types.baseChainInfo[chainKey].type === chainType) ids.push(chainKey);
1549
+ }
1550
+ return ids;
1551
+ }
1552
+ function buildChainGroups(enabledChains, xConnections, registry = chainRegistry, order) {
1553
+ const chains = order ? [...enabledChains].sort((a, b) => compareChainByOrder(a, b, order)) : enabledChains;
1554
+ return chains.map((chainType) => {
1555
+ const factory = registry[chainType];
1556
+ const connection = xConnections[chainType];
1557
+ return {
1558
+ chainType,
1559
+ chainIds: getSpokeChainKeysByType(chainType),
1560
+ displayName: factory?.displayName ?? chainType,
1561
+ iconUrl: factory?.iconUrl,
1562
+ isConnected: !!connection?.xAccount.address,
1563
+ account: connection?.xAccount,
1564
+ connectorId: connection?.xConnectorId
1565
+ };
1566
+ });
1567
+ }
1568
+ function useChainGroups({ order } = {}) {
1569
+ const enabledChains = useEnabledChains();
1570
+ const xConnections = useXConnections();
1571
+ return react.useMemo(
1572
+ () => buildChainGroups(enabledChains, xConnections, chainRegistry, order),
1573
+ [enabledChains, xConnections, order]
1574
+ );
1575
+ }
1576
+ function buildConnectedChains(xConnections, xConnectorsByChain, isReady = true, order) {
1577
+ const chains = [];
1578
+ for (const chainType of types.ChainTypeArr) {
1579
+ const connection = xConnections[chainType];
1580
+ if (!connection?.xAccount.address) continue;
1581
+ const connectors = xConnectorsByChain[chainType] ?? [];
1582
+ const connector = connectors.find((c) => c.id === connection.xConnectorId);
1583
+ chains.push({
1584
+ chainType,
1585
+ account: connection.xAccount,
1586
+ connectorId: connection.xConnectorId,
1587
+ connectorName: connector?.name,
1588
+ connectorIcon: connector?.icon
1589
+ });
1590
+ }
1591
+ if (order) {
1592
+ chains.sort((a, b) => compareChainByOrder(a.chainType, b.chainType, order));
1593
+ }
1594
+ return {
1595
+ chains,
1596
+ total: chains.length,
1597
+ status: isReady ? "ready" : "loading"
1598
+ };
1599
+ }
1600
+ function subscribeHydration(onChange) {
1601
+ const unsubHydrate = useXWalletStore.persist.onHydrate(onChange);
1602
+ const unsubFinish = useXWalletStore.persist.onFinishHydration(onChange);
1603
+ return () => {
1604
+ unsubHydrate();
1605
+ unsubFinish();
1606
+ };
1607
+ }
1608
+ function useConnectedChains({ order } = {}) {
1609
+ const xConnections = useXConnections();
1610
+ const xConnectorsByChain = useXConnectorsByChain();
1611
+ const isReady = react.useSyncExternalStore(
1612
+ subscribeHydration,
1613
+ () => useXWalletStore.persist.hasHydrated(),
1614
+ () => false
1615
+ );
1616
+ return react.useMemo(
1617
+ () => buildConnectedChains(xConnections, xConnectorsByChain, isReady, order),
1618
+ [xConnections, xConnectorsByChain, isReady, order]
1619
+ );
1620
+ }
1621
+ function useXDisconnect() {
1622
+ const actionsRegistry = useXWalletStore((state) => state.chainActions);
1623
+ return react.useCallback(
1624
+ async ({ xChainType }) => {
1625
+ const chainActions = actionsRegistry[xChainType];
1626
+ if (chainActions) {
1627
+ await chainActions.disconnect();
1628
+ } else {
1629
+ console.warn(
1630
+ `[useXDisconnect] No chain actions registered for "${xChainType}". Is it enabled in config.chains?`
1631
+ );
1632
+ }
1633
+ },
1634
+ [actionsRegistry]
1635
+ );
1636
+ }
1637
+
1638
+ // src/hooks/useConnectionFlow.ts
1639
+ function useConnectionFlow() {
1640
+ const mutation = useXConnect();
1641
+ const disconnect2 = useXDisconnect();
1642
+ const [error, setError] = react.useState(null);
1643
+ const [activeConnector, setActiveConnector] = react.useState(null);
1644
+ const lastConnectorRef = react.useRef(null);
1645
+ const connect = react.useCallback(
1646
+ async (connector) => {
1647
+ lastConnectorRef.current = connector;
1648
+ setActiveConnector(connector);
1649
+ setError(null);
1650
+ try {
1651
+ return await mutation.mutateAsync(connector);
1652
+ } catch (raw) {
1653
+ setError(raw instanceof Error ? raw : new Error(String(raw)));
1654
+ return void 0;
1655
+ }
1656
+ },
1657
+ [mutation]
1658
+ );
1659
+ const retry = react.useCallback(async () => {
1660
+ const last = lastConnectorRef.current;
1661
+ if (!last) return void 0;
1662
+ return connect(last);
1663
+ }, [connect]);
1664
+ const reset = react.useCallback(() => {
1665
+ mutation.reset();
1666
+ setError(null);
1667
+ setActiveConnector(null);
1668
+ lastConnectorRef.current = null;
1669
+ }, [mutation]);
1670
+ const status = error ? "error" : mutation.isPending ? "connecting" : mutation.isSuccess ? "success" : "idle";
1671
+ return {
1672
+ status,
1673
+ error,
1674
+ activeConnector,
1675
+ activeChainType: activeConnector?.xChainType ?? null,
1676
+ connect,
1677
+ disconnect: disconnect2,
1678
+ retry,
1679
+ reset
1680
+ };
1681
+ }
1682
+ function resolveBatchTargets(connectors, connectorsByChain) {
1683
+ const targets = [];
1684
+ for (const chainType of types.ChainTypeArr) {
1685
+ const chainConnectors = connectorsByChain[chainType];
1686
+ if (!chainConnectors?.length) continue;
1687
+ for (const identifier of connectors) {
1688
+ const match = chainConnectors.find((c) => matchesConnectorIdentifier(c, identifier));
1689
+ if (match) targets.push({ chainType, connector: match });
1690
+ }
1691
+ }
1692
+ return targets;
1693
+ }
1694
+ async function runBatchConnect(targets, helpers) {
1695
+ const successful = [];
1696
+ const failed = [];
1697
+ const skipped = [];
1698
+ const finalized = /* @__PURE__ */ new Set();
1699
+ const pendingError = /* @__PURE__ */ new Map();
1700
+ const emit = (event) => {
1701
+ if (!helpers.onProgress) return;
1702
+ try {
1703
+ helpers.onProgress(event);
1704
+ } catch (err) {
1705
+ console.error("[useBatchConnect] onProgress threw:", err);
1706
+ }
1707
+ };
1708
+ for (const target of targets) {
1709
+ if (finalized.has(target.chainType)) continue;
1710
+ if (helpers.skipConnected && helpers.isConnected(target.chainType)) {
1711
+ skipped.push(target.chainType);
1712
+ finalized.add(target.chainType);
1713
+ emit({ chainType: target.chainType, outcome: "skipped" });
1714
+ continue;
1715
+ }
1716
+ try {
1717
+ await helpers.connect(target.connector);
1718
+ successful.push(target.chainType);
1719
+ finalized.add(target.chainType);
1720
+ pendingError.delete(target.chainType);
1721
+ emit({ chainType: target.chainType, outcome: "success" });
1722
+ } catch (raw) {
1723
+ const error = raw instanceof Error ? raw : new Error(String(raw));
1724
+ pendingError.set(target.chainType, error);
1725
+ emit({ chainType: target.chainType, outcome: "failure", error });
1726
+ }
1727
+ }
1728
+ for (const [chainType, error] of pendingError) {
1729
+ if (!finalized.has(chainType)) failed.push({ chainType, error });
1730
+ }
1731
+ return { successful, failed, skipped };
1732
+ }
1733
+ function useBatchConnect({
1734
+ connectors,
1735
+ skipConnected = false,
1736
+ onProgress
1737
+ }) {
1738
+ assert(Array.isArray(connectors), "useBatchConnect: connectors must be an array");
1739
+ const { mutateAsync: connect } = useXConnect();
1740
+ const xConnectorsByChain = useXConnectorsByChain();
1741
+ const xConnections = useXConnections();
1742
+ const [status, setStatus] = react.useState("idle");
1743
+ const [result, setResult] = react.useState(null);
1744
+ const inFlightRef = react.useRef(null);
1745
+ const onProgressRef = react.useRef(onProgress);
1746
+ onProgressRef.current = onProgress;
1747
+ const run = react.useCallback(async () => {
1748
+ if (inFlightRef.current) return inFlightRef.current;
1749
+ const batchPromise = (async () => {
1750
+ setStatus("running");
1751
+ const targets = resolveBatchTargets(connectors, xConnectorsByChain);
1752
+ const finalResult = await runBatchConnect(targets, {
1753
+ connect,
1754
+ isConnected: (chainType) => !!xConnections[chainType]?.xAccount.address,
1755
+ skipConnected,
1756
+ onProgress: (event) => onProgressRef.current?.(event)
1136
1757
  });
1137
- return data;
1758
+ setResult(finalResult);
1759
+ setStatus("done");
1760
+ return finalResult;
1761
+ })();
1762
+ inFlightRef.current = batchPromise;
1763
+ try {
1764
+ return await batchPromise;
1765
+ } finally {
1766
+ inFlightRef.current = null;
1767
+ }
1768
+ }, [connect, connectors, xConnectorsByChain, xConnections, skipConnected]);
1769
+ const reset = react.useCallback(() => {
1770
+ setStatus("idle");
1771
+ setResult(null);
1772
+ }, []);
1773
+ return { run, status, result, reset };
1774
+ }
1775
+ function resolveDisconnectTargets(connectors, xConnections, xConnectorsByChain) {
1776
+ const targets = [];
1777
+ for (const chainType of types.ChainTypeArr) {
1778
+ const connection = xConnections[chainType];
1779
+ if (!connection?.xAccount.address) continue;
1780
+ if (!connectors) {
1781
+ targets.push(chainType);
1782
+ continue;
1783
+ }
1784
+ const activeConnector = xConnectorsByChain[chainType]?.find((c) => c.id === connection.xConnectorId);
1785
+ if (!activeConnector) continue;
1786
+ if (connectors.some((identifier) => matchesConnectorIdentifier(activeConnector, identifier))) {
1787
+ targets.push(chainType);
1788
+ }
1789
+ }
1790
+ return targets;
1791
+ }
1792
+ async function runBatchDisconnect(chainTypes, disconnect2, onProgress) {
1793
+ const successful = [];
1794
+ const failed = [];
1795
+ const emit = (event) => {
1796
+ if (!onProgress) return;
1797
+ try {
1798
+ onProgress(event);
1138
1799
  } catch (err) {
1139
- console.error(err);
1140
- return Array(calls.length).fill(null);
1800
+ console.error("[useBatchDisconnect] onProgress threw:", err);
1801
+ }
1802
+ };
1803
+ for (const chainType of chainTypes) {
1804
+ try {
1805
+ await disconnect2({ xChainType: chainType });
1806
+ successful.push(chainType);
1807
+ emit({ chainType, outcome: "success" });
1808
+ } catch (raw) {
1809
+ const error = raw instanceof Error ? raw : new Error(String(raw));
1810
+ failed.push({ chainType, error });
1811
+ emit({ chainType, outcome: "failure", error });
1812
+ }
1813
+ }
1814
+ return { successful, failed };
1815
+ }
1816
+ function useBatchDisconnect({
1817
+ connectors,
1818
+ onProgress
1819
+ } = {}) {
1820
+ const disconnect2 = useXDisconnect();
1821
+ const xConnections = useXConnections();
1822
+ const xConnectorsByChain = useXConnectorsByChain();
1823
+ const [status, setStatus] = react.useState("idle");
1824
+ const [result, setResult] = react.useState(null);
1825
+ const inFlightRef = react.useRef(null);
1826
+ const onProgressRef = react.useRef(onProgress);
1827
+ onProgressRef.current = onProgress;
1828
+ const run = react.useCallback(async () => {
1829
+ if (inFlightRef.current) return inFlightRef.current;
1830
+ const batchPromise = (async () => {
1831
+ setStatus("running");
1832
+ const targets = resolveDisconnectTargets(connectors, xConnections, xConnectorsByChain);
1833
+ const finalResult = await runBatchDisconnect(targets, disconnect2, (event) => onProgressRef.current?.(event));
1834
+ setResult(finalResult);
1835
+ setStatus("done");
1836
+ return finalResult;
1837
+ })();
1838
+ inFlightRef.current = batchPromise;
1839
+ try {
1840
+ return await batchPromise;
1841
+ } finally {
1842
+ inFlightRef.current = null;
1843
+ }
1844
+ }, [connectors, disconnect2, xConnections, xConnectorsByChain]);
1845
+ const reset = react.useCallback(() => {
1846
+ setStatus("idle");
1847
+ setResult(null);
1848
+ }, []);
1849
+ return { run, status, result, reset };
1850
+ }
1851
+ var useWalletModalStore = zustand.create()(
1852
+ middleware.devtools(
1853
+ immer.immer((set) => ({
1854
+ walletModal: { kind: "closed" },
1855
+ open: () => {
1856
+ set((state) => {
1857
+ state.walletModal = { kind: "chainSelect" };
1858
+ });
1859
+ },
1860
+ close: () => {
1861
+ set((state) => {
1862
+ state.walletModal = { kind: "closed" };
1863
+ });
1864
+ },
1865
+ back: () => {
1866
+ set((state) => {
1867
+ const current = state.walletModal;
1868
+ switch (current.kind) {
1869
+ case "walletSelect":
1870
+ state.walletModal = { kind: "chainSelect" };
1871
+ return;
1872
+ case "connecting":
1873
+ case "error":
1874
+ state.walletModal = { kind: "walletSelect", chainType: current.chainType };
1875
+ return;
1876
+ case "success":
1877
+ state.walletModal = { kind: "closed" };
1878
+ return;
1879
+ }
1880
+ });
1881
+ },
1882
+ selectChain: (chainType) => {
1883
+ set((state) => {
1884
+ state.walletModal = { kind: "walletSelect", chainType };
1885
+ });
1886
+ },
1887
+ setConnecting: (chainType, connector) => {
1888
+ set((state) => {
1889
+ state.walletModal = { kind: "connecting", chainType, connector };
1890
+ });
1891
+ },
1892
+ setSuccess: (chainType, connector, account) => {
1893
+ set((state) => {
1894
+ state.walletModal = { kind: "success", chainType, connector, account };
1895
+ });
1896
+ },
1897
+ setError: (chainType, connector, error) => {
1898
+ set((state) => {
1899
+ state.walletModal = { kind: "error", chainType, connector, error };
1900
+ });
1901
+ }
1902
+ })),
1903
+ { name: "wallet-modal-store" }
1904
+ )
1905
+ );
1906
+
1907
+ // src/hooks/useWalletModal.ts
1908
+ var DEFAULT_HYDRATION_TIMEOUT_MS = 5e3;
1909
+ function waitForXConnection(chainType, expectedConnectorId, timeoutMs = DEFAULT_HYDRATION_TIMEOUT_MS) {
1910
+ return new Promise((resolve) => {
1911
+ let settled = false;
1912
+ const matches = (connection) => connection?.xConnectorId === expectedConnectorId && !!connection?.xAccount?.address;
1913
+ const finish = (account) => {
1914
+ if (settled) return;
1915
+ settled = true;
1916
+ clearTimeout(timer);
1917
+ unsubscribe();
1918
+ resolve(account);
1919
+ };
1920
+ const timer = setTimeout(() => finish(void 0), timeoutMs);
1921
+ const unsubscribe = useXWalletStore.subscribe((state) => {
1922
+ const connection = state.xConnections[chainType];
1923
+ if (matches(connection)) finish(connection?.xAccount);
1924
+ });
1925
+ const initial = useXWalletStore.getState().xConnections[chainType];
1926
+ if (matches(initial)) finish(initial?.xAccount);
1927
+ });
1928
+ }
1929
+ function useWalletModal({
1930
+ onConnected,
1931
+ hydrationTimeoutMs
1932
+ } = {}) {
1933
+ const state = useWalletModalStore((s) => s.walletModal);
1934
+ const open = useWalletModalStore((s) => s.open);
1935
+ const close = useWalletModalStore((s) => s.close);
1936
+ const back = useWalletModalStore((s) => s.back);
1937
+ const selectChain = useWalletModalStore((s) => s.selectChain);
1938
+ const setConnecting = useWalletModalStore((s) => s.setConnecting);
1939
+ const setSuccess = useWalletModalStore((s) => s.setSuccess);
1940
+ const setError = useWalletModalStore((s) => s.setError);
1941
+ const { mutateAsync: connect } = useXConnect();
1942
+ const inFlightRef = react.useRef(null);
1943
+ const selectWallet = react.useCallback(
1944
+ async (connector) => {
1945
+ if (inFlightRef.current?.connector === connector) {
1946
+ return inFlightRef.current.promise;
1947
+ }
1948
+ if (!connector.isInstalled) {
1949
+ const installHint = connector.installUrl ? " Install the extension and reload the page." : "";
1950
+ setError(
1951
+ connector.xChainType,
1952
+ connector,
1953
+ new Error(`${connector.name} is not installed.${installHint}`)
1954
+ );
1955
+ return void 0;
1956
+ }
1957
+ const isStillCurrent = () => {
1958
+ const current = useWalletModalStore.getState().walletModal;
1959
+ return current.kind === "connecting" && current.connector === connector;
1960
+ };
1961
+ const promise = (async () => {
1962
+ setConnecting(connector.xChainType, connector);
1963
+ try {
1964
+ const direct = await connect(connector);
1965
+ if (!isStillCurrent()) return void 0;
1966
+ const account = direct?.address ? direct : await waitForXConnection(connector.xChainType, connector.id, hydrationTimeoutMs);
1967
+ if (!isStillCurrent()) return void 0;
1968
+ if (account?.address) {
1969
+ setSuccess(connector.xChainType, connector, account);
1970
+ try {
1971
+ await onConnected?.(connector.xChainType, account);
1972
+ } catch (callbackError) {
1973
+ console.error("[useWalletModal] onConnected threw \u2014 connection is still successful:", callbackError);
1974
+ }
1975
+ return account;
1976
+ }
1977
+ setError(
1978
+ connector.xChainType,
1979
+ connector,
1980
+ new Error("Connection did not complete. Did you close the wallet popup?")
1981
+ );
1982
+ return void 0;
1983
+ } catch (raw) {
1984
+ if (!isStillCurrent()) return void 0;
1985
+ const error = raw instanceof Error ? raw : new Error(String(raw));
1986
+ setError(connector.xChainType, connector, error);
1987
+ return void 0;
1988
+ } finally {
1989
+ if (inFlightRef.current?.connector === connector) {
1990
+ inFlightRef.current = null;
1991
+ }
1992
+ }
1993
+ })();
1994
+ inFlightRef.current = { connector, promise };
1995
+ return promise;
1996
+ },
1997
+ [connect, onConnected, hydrationTimeoutMs, setConnecting, setError, setSuccess]
1998
+ );
1999
+ const retry = react.useCallback(async () => {
2000
+ if (state.kind !== "error") return void 0;
2001
+ return selectWallet(state.connector);
2002
+ }, [state, selectWallet]);
2003
+ return { state, open, close, back, selectChain, selectWallet, retry };
2004
+ }
2005
+
2006
+ // src/hooks/useXService.ts
2007
+ function useXService({ xChainType } = {}) {
2008
+ const xService = useXWalletStore((state) => xChainType ? state.xServices[xChainType] : void 0);
2009
+ return xService;
2010
+ }
2011
+
2012
+ // src/hooks/useXServices.ts
2013
+ function useXServices() {
2014
+ return useXWalletStore((state) => state.xServices);
2015
+ }
2016
+ var WalletConfigContext = react.createContext(null);
2017
+ var WalletConfigProvider = WalletConfigContext.Provider;
2018
+ function useWalletConfig() {
2019
+ const config = react.useContext(WalletConfigContext);
2020
+ if (!config) {
2021
+ throw new Error("useWalletConfig must be used within SodaxWalletProvider");
2022
+ }
2023
+ return config;
2024
+ }
2025
+ function useIsChainEnabled(chainType) {
2026
+ const config = useWalletConfig();
2027
+ return config[chainType] !== void 0;
2028
+ }
2029
+ function useEnabledChainTypes() {
2030
+ const config = useWalletConfig();
2031
+ return Object.keys(config).filter((t) => config[t] !== void 0);
2032
+ }
2033
+ function useEthereumChainId() {
2034
+ const xService = useXService({ xChainType: "INJECTIVE" });
2035
+ const injectiveXService = xService instanceof InjectiveXService ? xService : void 0;
2036
+ const [ethereumChainId, setEthereumChainId] = react.useState(null);
2037
+ react.useEffect(() => {
2038
+ if (!injectiveXService?.walletStrategy?.getWallet()) return;
2039
+ const walletStrategy = injectiveXService.walletStrategy;
2040
+ if (walletStrategy.getWallet() !== walletBase.Wallet.Metamask) return;
2041
+ const getEthereumChainId = async () => {
2042
+ try {
2043
+ const chainId = await walletStrategy.getEthereumChainId();
2044
+ setEthereumChainId(Number.parseInt(chainId));
2045
+ } catch (error) {
2046
+ console.warn("Failed to get Ethereum chain ID:", error);
2047
+ }
2048
+ };
2049
+ getEthereumChainId();
2050
+ try {
2051
+ const strategy = walletStrategy.getStrategy();
2052
+ const isEvmStrategy = isRecord(strategy) && hasFunctionProperty(strategy, "onChainIdChanged");
2053
+ assert(isEvmStrategy, "[useEthereumChainId] walletStrategy.getStrategy() is not an EvmWalletStrategy");
2054
+ strategy.onChainIdChanged(getEthereumChainId);
2055
+ } catch (error) {
2056
+ console.warn("Failed to subscribe to chain ID changes:", error);
2057
+ }
2058
+ }, [injectiveXService?.walletStrategy]);
2059
+ return ethereumChainId;
2060
+ }
2061
+ var EVM_DISABLED_RESULT = { isWrongChain: false, handleSwitchChain: () => {
2062
+ } };
2063
+ var isEip1193Provider = (value) => {
2064
+ return isRecord(value) && hasFunctionProperty(value, "request") && hasFunctionProperty(value, "on");
2065
+ };
2066
+ var getInjectedEthereumProvider = () => {
2067
+ const maybeEthereum = window.ethereum;
2068
+ assert(isEip1193Provider(maybeEthereum), "[useEvmSwitchChain] window.ethereum is not an EIP-1193 provider");
2069
+ return maybeEthereum;
2070
+ };
2071
+ var switchEthereumChain = async () => {
2072
+ const metamaskProvider = getInjectedEthereumProvider();
2073
+ return await Promise.race([
2074
+ metamaskProvider.request({
2075
+ method: "wallet_switchEthereumChain",
2076
+ params: [{ chainId: "0x1" }]
2077
+ }),
2078
+ new Promise((resolve) => {
2079
+ const handler = (chainId) => {
2080
+ if (chainId === "0x1") {
2081
+ metamaskProvider.removeListener("chainChanged", handler);
2082
+ resolve();
2083
+ }
2084
+ };
2085
+ metamaskProvider.on("chainChanged", handler);
2086
+ })
2087
+ ]);
2088
+ };
2089
+ function useEvmSwitchChain({ xChainId }) {
2090
+ const evmEnabled = useIsChainEnabled("EVM");
2091
+ if (!evmEnabled) {
2092
+ return EVM_DISABLED_RESULT;
2093
+ }
2094
+ return useEvmSwitchChainInner({ xChainId });
2095
+ }
2096
+ function useEvmSwitchChainInner({ xChainId }) {
2097
+ const xChainType = getXChainType(xChainId);
2098
+ const expectedChainId = types.baseChainInfo[xChainId].chainId;
2099
+ if (xChainType === "EVM") {
2100
+ assert(typeof expectedChainId === "number", "[useEvmSwitchChain] EVM chain must have numeric chainId");
2101
+ }
2102
+ const xService = useXService({ xChainType: "INJECTIVE" });
2103
+ const injectiveXService = xService instanceof InjectiveXService ? xService : void 0;
2104
+ const ethereumChainId = useEthereumChainId();
2105
+ const { chainId } = wagmi.useAccount();
2106
+ const isWrongChain = react.useMemo(() => {
2107
+ return xChainType === "EVM" && chainId !== expectedChainId || xChainType === "INJECTIVE" && injectiveXService !== void 0 && injectiveXService.walletStrategy.getWallet() === walletBase.Wallet.Metamask && ethereumChainId !== chains.mainnet.id;
2108
+ }, [xChainType, chainId, expectedChainId, ethereumChainId, injectiveXService]);
2109
+ const { switchChain } = wagmi.useSwitchChain();
2110
+ const handleSwitchChain = react.useCallback(() => {
2111
+ if (xChainType === "INJECTIVE") {
2112
+ switchEthereumChain();
2113
+ } else if (xChainType === "EVM" && typeof expectedChainId === "number") {
2114
+ switchChain({ chainId: expectedChainId });
2115
+ }
2116
+ }, [switchChain, expectedChainId, xChainType]);
2117
+ return react.useMemo(
2118
+ () => ({
2119
+ isWrongChain,
2120
+ handleSwitchChain
2121
+ }),
2122
+ [isWrongChain, handleSwitchChain]
2123
+ );
2124
+ }
2125
+
2126
+ // src/hooks/useWalletProvider.ts
2127
+ var warnedChains2 = /* @__PURE__ */ new Set();
2128
+ function useWalletProvider({
2129
+ xChainId,
2130
+ xChainType
2131
+ } = {}) {
2132
+ assert(!(xChainId && xChainType), "[useWalletProvider] pass either xChainId or xChainType, not both");
2133
+ const target = xChainType ?? (xChainId ? getXChainType(xChainId) : void 0);
2134
+ return useXWalletStore((state) => {
2135
+ if (!target) return void 0;
2136
+ if (!state.enabledChains.includes(target) && !warnedChains2.has(target)) {
2137
+ warnedChains2.add(target);
2138
+ console.warn(
2139
+ `[useWalletProvider] chain "${target}" is not enabled in SodaxWalletProvider config.chains \u2014 returning undefined`
2140
+ );
2141
+ }
2142
+ return state.getWalletProvider(target);
2143
+ });
2144
+ }
2145
+ function useXSignMessage() {
2146
+ const actionsRegistry = useXWalletStore((state) => state.chainActions);
2147
+ return reactQuery.useMutation({
2148
+ mutationFn: async ({ xChainType, message }) => {
2149
+ const chainActions = actionsRegistry[xChainType];
2150
+ if (!chainActions?.signMessage) {
2151
+ console.warn(`[useXSignMessage] signMessage not supported for chain "${xChainType}"`);
2152
+ return void 0;
2153
+ }
2154
+ return await chainActions.signMessage(message);
2155
+ }
2156
+ });
2157
+ }
2158
+
2159
+ // src/xchains/bitcoin/bitcoinSignGuards.ts
2160
+ function hasSignBip322(c) {
2161
+ return "signBip322Message" in c && typeof c.signBip322Message === "function";
2162
+ }
2163
+ function hasSignEcdsa(c) {
2164
+ return "signEcdsaMessage" in c && typeof c.signEcdsaMessage === "function";
2165
+ }
2166
+ var NearXService = class _NearXService extends XService {
2167
+ static instance;
2168
+ walletSelector;
2169
+ rpcUrl;
2170
+ /**
2171
+ * @param rpcUrl - Used by `getBalance` via `JsonRpcProvider({ url: rpcUrl })`.
2172
+ * Does NOT affect `walletSelector` — `@hot-labs/near-connect` only accepts
2173
+ * the network preset name (`'mainnet'`/`'testnet'`) and fetches RPC internally.
2174
+ * Custom RPC is therefore read-only for balance queries.
2175
+ */
2176
+ constructor(rpcUrl = NEAR_DEFAULT_RPC_URL) {
2177
+ super("NEAR");
2178
+ this.rpcUrl = rpcUrl;
2179
+ this.walletSelector = new nearConnect.NearConnector({
2180
+ network: "mainnet",
2181
+ logger: console,
2182
+ autoConnect: true,
2183
+ excludedWallets: ["okx-wallet"]
2184
+ });
2185
+ }
2186
+ /**
2187
+ * @param rpcUrl - Re-applied on every call (matches StacksXService semantics).
2188
+ * `rpcUrl` only drives `getBalance` via a per-call `JsonRpcProvider`, so it's
2189
+ * safe to update at runtime — no persistent chain client to rebuild.
2190
+ */
2191
+ static getInstance(rpcUrl) {
2192
+ if (!_NearXService.instance) {
2193
+ _NearXService.instance = new _NearXService(rpcUrl);
2194
+ } else if (rpcUrl) {
2195
+ _NearXService.instance.rpcUrl = rpcUrl;
1141
2196
  }
2197
+ return _NearXService.instance;
1142
2198
  }
1143
- async getBalances(address, xTokens) {
1144
- if (!address) return {};
1145
- const balances = {};
1146
- const nativeXToken = xTokens.find((xToken) => isNativeToken(xToken));
1147
- const nonNativeXTokens = xTokens.filter((xToken) => !isNativeToken(xToken));
1148
- if (nativeXToken) {
1149
- const balance = await this.iconService.getBalance(address).execute();
1150
- balances[nativeXToken.address] = BigInt(balance.toFixed());
2199
+ async getBalance(address, xToken) {
2200
+ const provider = new nearApiJs.JsonRpcProvider({ url: this.rpcUrl });
2201
+ if (xToken.symbol === "NEAR") {
2202
+ const account = await provider.viewAccount({ accountId: address ?? "" });
2203
+ return BigInt(account.amount);
1151
2204
  }
1152
- const cds = nonNativeXTokens.map((token) => {
1153
- return {
1154
- target: token.address,
1155
- method: "balanceOf",
1156
- params: [address]
1157
- };
2205
+ const res = await provider.callFunction({
2206
+ contractId: xToken.address,
2207
+ method: "ft_balance_of",
2208
+ args: { account_id: address }
1158
2209
  });
1159
- const data = await this.getAggregateData(
1160
- false,
1161
- cds.filter((cd) => cd.target.startsWith("cx"))
1162
- );
1163
- return nonNativeXTokens.reduce((agg, token, idx) => {
1164
- const balance = data[idx];
1165
- balances[token.address] = BigInt(balance);
1166
- return agg;
1167
- }, balances);
2210
+ return BigInt(res ?? 0);
1168
2211
  }
1169
2212
  };
1170
2213
 
1171
- // src/xchains/icon/iconex/index.tsx
1172
- var ICONEX_RELAY_RESPONSE = "ICONEX_RELAY_RESPONSE";
1173
- var ICONEX_RELAY_REQUEST = "ICONEX_RELAY_REQUEST";
1174
- var request = (event) => {
1175
- return new Promise((resolve, reject) => {
1176
- const handler = (evt) => {
1177
- window.removeEventListener(ICONEX_RELAY_RESPONSE, handler);
1178
- resolve(evt.detail);
1179
- };
1180
- window.addEventListener(ICONEX_RELAY_RESPONSE, handler);
1181
- window.dispatchEvent(
1182
- new CustomEvent(ICONEX_RELAY_REQUEST, {
1183
- detail: event
1184
- })
1185
- );
1186
- });
1187
- };
1188
-
1189
- // src/xchains/icon/IconHanaXConnector.ts
1190
- var IconHanaXConnector = class extends XConnector {
1191
- constructor() {
1192
- super("ICON", "Hana Wallet", "hana");
2214
+ // src/xchains/near/NearXConnector.ts
2215
+ var NearXConnector = class extends XConnector {
2216
+ _wallet;
2217
+ constructor(wallet) {
2218
+ super("NEAR", wallet.manifest.name, wallet.manifest.id);
2219
+ this._wallet = wallet;
2220
+ }
2221
+ getXService() {
2222
+ return NearXService.getInstance();
1193
2223
  }
1194
2224
  async connect() {
1195
- const { hanaWallet } = window;
1196
- if (window && !hanaWallet && !hanaWallet?.isAvailable) {
1197
- window.open("https://chromewebstore.google.com/detail/hana-wallet/jfdlamikmbghhapbgfoogdffldioobgl", "_blank");
1198
- return;
1199
- }
1200
- const detail = await request({
1201
- type: "REQUEST_ADDRESS" /* REQUEST_ADDRESS */
1202
- });
1203
- if (detail?.type === "RESPONSE_ADDRESS" /* RESPONSE_ADDRESS */) {
1204
- return {
1205
- address: detail?.payload,
1206
- xChainType: this.xChainType
1207
- };
2225
+ const walletSelector = this.getXService().walletSelector;
2226
+ const wallet = await walletSelector.connect({ walletId: this._wallet.manifest.id });
2227
+ const accounts = await wallet.getAccounts();
2228
+ if (accounts.length === 0 || accounts[0] === void 0) {
2229
+ console.warn(`[NearXConnector] connect: ${this._wallet.manifest.name} returned no accounts`);
2230
+ return void 0;
1208
2231
  }
1209
- return void 0;
2232
+ return {
2233
+ address: accounts[0].accountId,
2234
+ xChainType: this.xChainType
2235
+ };
1210
2236
  }
1211
2237
  async disconnect() {
1212
- console.log("HanaIconXConnector disconnected");
2238
+ const walletSelector = this.getXService().walletSelector;
2239
+ await walletSelector.disconnect(this._wallet);
1213
2240
  }
1214
2241
  get icon() {
1215
- return "https://raw.githubusercontent.com/balancednetwork/icons/master/wallets/hana.svg";
2242
+ return this._wallet.manifest.icon;
2243
+ }
2244
+ };
2245
+ var StacksXService = class _StacksXService extends XService {
2246
+ static instance;
2247
+ network;
2248
+ constructor(network$1) {
2249
+ super("STACKS");
2250
+ this.network = network.networkFrom(network$1 || "mainnet");
2251
+ }
2252
+ static getInstance(network$1) {
2253
+ if (!_StacksXService.instance) {
2254
+ _StacksXService.instance = new _StacksXService(network$1);
2255
+ } else if (network$1) {
2256
+ _StacksXService.instance.network = network.networkFrom(network$1);
2257
+ }
2258
+ return _StacksXService.instance;
2259
+ }
2260
+ async getBalance(address, xToken) {
2261
+ if (!address) return 0n;
2262
+ if (xToken.symbol === "STX") {
2263
+ const url = `${this.network.client.baseUrl}/extended/v1/address/${address}/balances`;
2264
+ try {
2265
+ const response = await fetch(url);
2266
+ if (!response.ok) {
2267
+ throw new Error(`Error fetching data: ${response.statusText}`);
2268
+ }
2269
+ const data = await response.json();
2270
+ return BigInt(data.stx.balance);
2271
+ } catch (error) {
2272
+ console.error("Error fetching STX balance:", error);
2273
+ return 0n;
2274
+ }
2275
+ }
2276
+ const parts = xToken.address.split(".");
2277
+ const contractAddress = parts[0] ?? "";
2278
+ const contractName = parts[1] ?? "";
2279
+ try {
2280
+ const result = await transactions.fetchCallReadOnlyFunction({
2281
+ contractAddress,
2282
+ contractName,
2283
+ functionName: "get-balance",
2284
+ functionArgs: [transactions.Cl.principal(address)],
2285
+ network: this.network,
2286
+ senderAddress: address
2287
+ });
2288
+ return result.value.value;
2289
+ } catch (error) {
2290
+ console.error("Error fetching token balance:", error);
2291
+ return 0n;
2292
+ }
1216
2293
  }
1217
2294
  };
1218
2295
  function getProviderFromId(id) {
1219
2296
  return id.split(".").reduce((acc, part) => acc?.[part], window);
1220
2297
  }
1221
2298
  var StacksXConnector = class extends XConnector {
2299
+ config;
1222
2300
  constructor(config) {
1223
2301
  super("STACKS", config.name, config.id);
1224
2302
  this.config = config;
@@ -1226,14 +2304,15 @@ var StacksXConnector = class extends XConnector {
1226
2304
  async connect() {
1227
2305
  const provider = this.getProvider();
1228
2306
  if (!provider) {
1229
- if (this.config.installUrl) {
1230
- window.open(this.config.installUrl, "_blank");
1231
- }
1232
- return void 0;
2307
+ throw new Error(`${this.config.name} is not installed. Install the extension and reload the page.`);
1233
2308
  }
1234
2309
  const response = await connect.request({ provider }, "stx_getAddresses");
1235
2310
  const stxAddress = response.addresses.find((a) => a.purpose === "stacks");
1236
2311
  if (!stxAddress) {
2312
+ console.warn(
2313
+ `[StacksXConnector] ${this.config.name}: no address with purpose="stacks" returned from stx_getAddresses`,
2314
+ response.addresses
2315
+ );
1237
2316
  return void 0;
1238
2317
  }
1239
2318
  return {
@@ -1247,6 +2326,13 @@ var StacksXConnector = class extends XConnector {
1247
2326
  get icon() {
1248
2327
  return this.config.icon;
1249
2328
  }
2329
+ get isInstalled() {
2330
+ if (typeof window === "undefined") return false;
2331
+ return getProviderFromId(this.config.id) !== void 0;
2332
+ }
2333
+ get installUrl() {
2334
+ return this.config.installUrl;
2335
+ }
1250
2336
  getProvider() {
1251
2337
  return getProviderFromId(this.config.id);
1252
2338
  }
@@ -1283,258 +2369,553 @@ var STACKS_PROVIDERS = [
1283
2369
  installUrl: "https://chromewebstore.google.com/detail/fordefi/hcmehenccjdmfbojapcbcofkgdpbnlle"
1284
2370
  }
1285
2371
  ];
1286
- function useStacksXConnectors() {
1287
- return React2.useMemo(() => STACKS_PROVIDERS.map((config) => new StacksXConnector(config)), []);
1288
- }
1289
2372
 
1290
- // src/useXWagmiStore.ts
1291
- var initXServices = () => {
2373
+ // src/chainRegistry.ts
2374
+ function defineChain2(factory) {
2375
+ return factory;
2376
+ }
2377
+ function narrowConnectors(items, chainType) {
2378
+ return items.filter((item) => {
2379
+ if (!(item instanceof XConnector)) {
2380
+ console.warn(
2381
+ `[chainRegistry] ${chainType} connector "${item.id}" must extend XConnector \u2014 skipping. Implement the abstract XConnector class instead of raw IXConnector for full SDK support.`
2382
+ );
2383
+ return false;
2384
+ }
2385
+ return true;
2386
+ });
2387
+ }
2388
+ function readConnectorsOverride(chainType, walletConfig) {
2389
+ return walletConfig?.[chainType]?.connectors;
2390
+ }
2391
+ function hasChainOfType(chainType, walletConfig) {
2392
+ return walletConfig[chainType] !== void 0;
2393
+ }
2394
+ var createDefaultActions = (chainType, service, getStore) => ({
2395
+ connect: async (xConnectorId) => {
2396
+ const connector = service.getXConnectorById(xConnectorId);
2397
+ return connector?.connect();
2398
+ },
2399
+ disconnect: async () => {
2400
+ const store = getStore();
2401
+ const connectorId = store.xConnections[chainType]?.xConnectorId;
2402
+ const connector = connectorId ? service.getXConnectorById(connectorId) : void 0;
2403
+ try {
2404
+ await connector?.disconnect();
2405
+ } finally {
2406
+ store.unsetXConnection(chainType);
2407
+ }
2408
+ },
2409
+ getConnectors: () => getStore().xConnectorsByChain[chainType] ?? [],
2410
+ getConnection: () => getStore().xConnections[chainType]
2411
+ });
2412
+ var chainRegistry = {
2413
+ EVM: defineChain2({
2414
+ createService: () => EvmXService.getInstance(),
2415
+ displayName: "EVM",
2416
+ defaultConnectors: () => [],
2417
+ providerManaged: true
2418
+ }),
2419
+ SUI: defineChain2({
2420
+ createService: () => SuiXService.getInstance(),
2421
+ displayName: "Sui",
2422
+ defaultConnectors: () => [],
2423
+ providerManaged: true
2424
+ }),
2425
+ SOLANA: defineChain2({
2426
+ createService: () => SolanaXService.getInstance(),
2427
+ displayName: "Solana",
2428
+ defaultConnectors: () => [],
2429
+ providerManaged: true
2430
+ }),
2431
+ BITCOIN: defineChain2({
2432
+ createService: (walletConfig) => BitcoinXService.getInstance(getRpcUrl(walletConfig?.BITCOIN?.chains?.[types.ChainKeys.BITCOIN_MAINNET])),
2433
+ displayName: "Bitcoin",
2434
+ defaultConnectors: (walletConfig) => {
2435
+ const defaults = getEntryDefaults(
2436
+ walletConfig?.BITCOIN?.chains?.[types.ChainKeys.BITCOIN_MAINNET]
2437
+ );
2438
+ return [new UnisatXConnector(defaults), new XverseXConnector(defaults), new OKXXConnector(defaults)];
2439
+ },
2440
+ providerManaged: false,
2441
+ createActions: (service, getStore) => ({
2442
+ ...createDefaultActions("BITCOIN", service, getStore),
2443
+ signMessage: async (message) => {
2444
+ const store = getStore();
2445
+ const connection = store.xConnections.BITCOIN;
2446
+ const connector = connection?.xConnectorId ? service.getXConnectorById(connection.xConnectorId) : void 0;
2447
+ if (!(connector instanceof BitcoinXConnector)) {
2448
+ throw new Error("Bitcoin wallet not connected");
2449
+ }
2450
+ const address = connection?.xAccount.address;
2451
+ if (!address) throw new Error("Bitcoin address not found");
2452
+ const addressType = types.detectBitcoinAddressType(address);
2453
+ switch (addressType) {
2454
+ case "P2WPKH":
2455
+ case "P2TR": {
2456
+ if (!hasSignBip322(connector)) {
2457
+ throw new Error(`${connector.id} does not support BIP-322 signing`);
2458
+ }
2459
+ return connector.signBip322Message(message);
2460
+ }
2461
+ case "P2SH":
2462
+ case "P2PKH": {
2463
+ if (!hasSignEcdsa(connector)) {
2464
+ throw new Error(`${connector.id} does not support ECDSA signing`);
2465
+ }
2466
+ return connector.signEcdsaMessage(message);
2467
+ }
2468
+ default: {
2469
+ const _exhaustiveCheck = addressType;
2470
+ throw new Error(`Unhandled Bitcoin address type: ${_exhaustiveCheck}`);
2471
+ }
2472
+ }
2473
+ }
2474
+ }),
2475
+ createWalletProvider: (service, getStore) => {
2476
+ const store = getStore();
2477
+ const connection = store.xConnections.BITCOIN;
2478
+ if (!connection?.xConnectorId) return void 0;
2479
+ const connector = service.getXConnectorById(connection.xConnectorId);
2480
+ if (!(connector instanceof BitcoinXConnector)) return void 0;
2481
+ return connector.recreateWalletProvider(connection.xAccount);
2482
+ }
2483
+ }),
2484
+ INJECTIVE: defineChain2({
2485
+ createService: (walletConfig) => InjectiveXService.getInstance(walletConfig?.INJECTIVE?.chains?.[types.ChainKeys.INJECTIVE_MAINNET]),
2486
+ displayName: "Injective",
2487
+ defaultConnectors: () => [
2488
+ new InjectiveXConnector("MetaMask", walletBase.Wallet.Metamask),
2489
+ new InjectiveXConnector("Keplr", walletBase.Wallet.Keplr),
2490
+ new InjectiveXConnector("Leap", walletBase.Wallet.Leap)
2491
+ ],
2492
+ providerManaged: false,
2493
+ createActions: (service, getStore) => ({
2494
+ ...createDefaultActions("INJECTIVE", service, getStore),
2495
+ signMessage: async (message) => {
2496
+ const store = getStore();
2497
+ const address = store.xConnections.INJECTIVE?.xAccount.address;
2498
+ if (!address) throw new Error("Injective address not found");
2499
+ const ethereumAddress = sdkTs.getEthereumAddress(address);
2500
+ const walletStrategy = service.walletStrategy;
2501
+ const res = await walletStrategy.signArbitrary(
2502
+ walletStrategy.getWallet() === walletBase.Wallet.Metamask ? ethereumAddress : address,
2503
+ message
2504
+ );
2505
+ if (!res) throw new Error("Injective signature not found");
2506
+ return res;
2507
+ }
2508
+ }),
2509
+ createWalletProvider: (service, getStore) => {
2510
+ if (!service) return void 0;
2511
+ const defaults = getEntryDefaults(
2512
+ getStore().walletConfig?.INJECTIVE?.chains?.[types.ChainKeys.INJECTIVE_MAINNET]
2513
+ );
2514
+ return new walletSdkCore.InjectiveWalletProvider({ msgBroadcaster: service.msgBroadcaster, defaults });
2515
+ }
2516
+ }),
2517
+ STELLAR: defineChain2({
2518
+ createService: (walletConfig) => {
2519
+ const stellarRpc = walletConfig?.STELLAR?.chains?.[types.ChainKeys.STELLAR_MAINNET];
2520
+ return StellarXService.getInstance(stellarRpc?.horizonRpcUrl, stellarRpc?.sorobanRpcUrl);
2521
+ },
2522
+ displayName: "Stellar",
2523
+ defaultConnectors: () => [],
2524
+ providerManaged: false,
2525
+ discoverConnectors: async (service, getStore) => {
2526
+ const STELLAR_DISCOVER_DELAYS_MS = [0, 100, 500];
2527
+ let lastIds = "";
2528
+ for (const delay of STELLAR_DISCOVER_DELAYS_MS) {
2529
+ if (delay) await new Promise((r) => setTimeout(r, delay));
2530
+ const wallets = await service.walletsKit.getSupportedWallets();
2531
+ const connectors = wallets.filter((w) => w.isAvailable).map((w) => new StellarWalletsKitXConnector(w));
2532
+ const ids = connectors.map((c) => c.id).sort().join(",");
2533
+ if (ids === lastIds) break;
2534
+ lastIds = ids;
2535
+ service.setXConnectors(connectors);
2536
+ getStore().setXConnectors("STELLAR", connectors);
2537
+ }
2538
+ },
2539
+ createActions: (service, getStore) => ({
2540
+ ...createDefaultActions("STELLAR", service, getStore),
2541
+ signMessage: async (message) => {
2542
+ const res = await service.walletsKit.signMessage(message);
2543
+ return res.signedMessage;
2544
+ }
2545
+ }),
2546
+ createWalletProvider: (service, getStore) => {
2547
+ if (!service?.walletsKit) return void 0;
2548
+ const defaults = getEntryDefaults(
2549
+ getStore().walletConfig?.STELLAR?.chains?.[types.ChainKeys.STELLAR_MAINNET]
2550
+ );
2551
+ return new walletSdkCore.StellarWalletProvider({
2552
+ type: "BROWSER_EXTENSION",
2553
+ walletsKit: service.walletsKit,
2554
+ network: "PUBLIC",
2555
+ defaults
2556
+ });
2557
+ }
2558
+ }),
2559
+ // ICON: signMessage not implemented — Hana wallet does not expose a signing API.
2560
+ // connect/disconnect use createDefaultActions (no createActions override needed).
2561
+ ICON: defineChain2({
2562
+ createService: (walletConfig) => IconXService.getInstance(getRpcUrl(walletConfig?.ICON?.chains?.[types.ChainKeys.ICON_MAINNET])),
2563
+ displayName: "ICON",
2564
+ defaultConnectors: () => [new IconHanaXConnector()],
2565
+ providerManaged: false,
2566
+ createWalletProvider: (_service, getStore) => {
2567
+ const store = getStore();
2568
+ const address = store.xConnections.ICON?.xAccount.address;
2569
+ if (!address) return void 0;
2570
+ const chainInfo = CHAIN_INFO[1 /* MAINNET */];
2571
+ if (!chainInfo) throw new Error("ICON mainnet chain info not found");
2572
+ const defaults = getEntryDefaults(
2573
+ store.walletConfig?.ICON?.chains?.[types.ChainKeys.ICON_MAINNET]
2574
+ );
2575
+ return new walletSdkCore.IconWalletProvider({
2576
+ walletAddress: address,
2577
+ rpcUrl: chainInfo.APIEndpoint,
2578
+ defaults
2579
+ });
2580
+ }
2581
+ }),
2582
+ NEAR: defineChain2({
2583
+ createService: (walletConfig) => NearXService.getInstance(getRpcUrl(walletConfig?.NEAR?.chains?.[types.ChainKeys.NEAR_MAINNET])),
2584
+ displayName: "NEAR",
2585
+ defaultConnectors: () => [],
2586
+ providerManaged: false,
2587
+ discoverConnectors: async (service, getStore) => {
2588
+ await service.walletSelector.whenManifestLoaded;
2589
+ const connectors = service.walletSelector.availableWallets.map((w) => new NearXConnector(w));
2590
+ service.setXConnectors(connectors);
2591
+ getStore().setXConnectors("NEAR", connectors);
2592
+ },
2593
+ createActions: (service, getStore) => ({
2594
+ ...createDefaultActions("NEAR", service, getStore),
2595
+ disconnect: async () => {
2596
+ try {
2597
+ service.walletSelector.disconnect();
2598
+ } finally {
2599
+ getStore().unsetXConnection("NEAR");
2600
+ }
2601
+ }
2602
+ }),
2603
+ createWalletProvider: (service, getStore) => {
2604
+ if (!service?.walletSelector) return void 0;
2605
+ const defaults = getEntryDefaults(
2606
+ getStore().walletConfig?.NEAR?.chains?.[types.ChainKeys.NEAR_MAINNET]
2607
+ );
2608
+ return new walletSdkCore.NearWalletProvider({ wallet: service.walletSelector, defaults });
2609
+ }
2610
+ }),
2611
+ STACKS: defineChain2({
2612
+ createService: (walletConfig) => StacksXService.getInstance(walletConfig?.STACKS?.chains?.[types.ChainKeys.STACKS_MAINNET]),
2613
+ displayName: "Stacks",
2614
+ defaultConnectors: () => STACKS_PROVIDERS.map((c) => new StacksXConnector(c)),
2615
+ providerManaged: false,
2616
+ createWalletProvider: (service, getStore) => {
2617
+ const store = getStore();
2618
+ const connection = store.xConnections.STACKS;
2619
+ const address = connection?.xAccount.address;
2620
+ if (!address) return void 0;
2621
+ const connector = connection?.xConnectorId ? service.getXConnectorById(connection.xConnectorId) : void 0;
2622
+ const provider = connector instanceof StacksXConnector ? connector.getProvider() : void 0;
2623
+ const defaults = getEntryDefaults(
2624
+ store.walletConfig?.STACKS?.chains?.[types.ChainKeys.STACKS_MAINNET]
2625
+ );
2626
+ return new walletSdkCore.StacksWalletProvider({ address, provider, defaults });
2627
+ }
2628
+ })
2629
+ };
2630
+ var createChainServices = (walletConfig, getStore) => {
1292
2631
  const xServices = {};
1293
- ["EVM", "BITCOIN", "INJECTIVE", "STELLAR", "SUI", "SOLANA", "ICON", "NEAR", "STACKS"].forEach((key) => {
1294
- const xChainType = key;
1295
- switch (xChainType) {
1296
- // EVM, SUI, Solana wallet connectors are supported by their own sdks. wagmi, @mysten/dapp-kit, @solana/wallet-adapter-react.
1297
- case "EVM":
1298
- xServices[xChainType] = EvmXService.getInstance();
1299
- xServices[xChainType].setXConnectors([]);
1300
- break;
1301
- case "SUI":
1302
- xServices[xChainType] = SuiXService.getInstance();
1303
- xServices[xChainType].setXConnectors([]);
1304
- break;
1305
- case "SOLANA":
1306
- xServices[xChainType] = SolanaXService.getInstance();
1307
- xServices[xChainType].setXConnectors([]);
1308
- break;
1309
- case "BITCOIN":
1310
- xServices[xChainType] = BitcoinXService.getInstance();
1311
- xServices[xChainType].setXConnectors([new UnisatXConnector(), new XverseXConnector(), new OKXXConnector()]);
1312
- break;
1313
- // Injective, Stellar, Icon wallet connectors are supported by sodax wallet-sdk-react sdk.
1314
- case "INJECTIVE":
1315
- xServices[xChainType] = InjectiveXService.getInstance();
1316
- xServices[xChainType].setXConnectors([
1317
- // EVM wallets (auto-detected via EIP-6963)
1318
- new InjectiveXConnector("MetaMask", walletBase.Wallet.Metamask),
1319
- // Cosmos wallets (detected via window globals)
1320
- new InjectiveXConnector("Keplr", walletBase.Wallet.Keplr),
1321
- new InjectiveXConnector("Leap", walletBase.Wallet.Leap)
1322
- ]);
1323
- break;
1324
- case "STELLAR":
1325
- xServices[xChainType] = StellarXService.getInstance();
1326
- xServices[xChainType].setXConnectors([]);
1327
- break;
1328
- case "ICON":
1329
- xServices[xChainType] = IconXService.getInstance();
1330
- xServices[xChainType].setXConnectors([new IconHanaXConnector()]);
1331
- break;
1332
- case "NEAR":
1333
- xServices[xChainType] = NearXService.getInstance();
1334
- xServices[xChainType].setXConnectors([]);
1335
- break;
1336
- case "STACKS":
1337
- xServices[xChainType] = StacksXService.getInstance();
1338
- xServices[xChainType].setXConnectors(STACKS_PROVIDERS.map((config) => new StacksXConnector(config)));
1339
- break;
2632
+ const xConnectorsByChain = {};
2633
+ const enabledChains = [];
2634
+ const chainActions = {};
2635
+ for (const chainType of types.ChainTypeArr) {
2636
+ if (!hasChainOfType(chainType, walletConfig)) continue;
2637
+ const factory = chainRegistry[chainType];
2638
+ if (!factory) continue;
2639
+ const service = factory.createService(walletConfig);
2640
+ xServices[chainType] = service;
2641
+ enabledChains.push(chainType);
2642
+ if (!factory.providerManaged) {
2643
+ const override = readConnectorsOverride(chainType, walletConfig);
2644
+ const connectors = override ? narrowConnectors(override, chainType) : factory.defaultConnectors(walletConfig);
2645
+ service.setXConnectors(connectors);
2646
+ xConnectorsByChain[chainType] = connectors;
2647
+ chainActions[chainType] = factory.createActions ? factory.createActions(service, getStore) : createDefaultActions(chainType, service, getStore);
2648
+ if (factory.discoverConnectors) {
2649
+ factory.discoverConnectors(service, getStore).catch((err) => {
2650
+ console.warn(`[wallet-sdk-react] discoverConnectors failed for ${chainType}:`, err);
2651
+ });
2652
+ }
1340
2653
  }
1341
- });
1342
- return xServices;
2654
+ }
2655
+ return { xServices, xConnectorsByChain, enabledChains, chainActions };
1343
2656
  };
1344
- var useXWagmiStore = zustand.create()(
2657
+
2658
+ // src/useXWalletStore.ts
2659
+ var useXWalletStore = zustand.create()(
1345
2660
  middleware.devtools(
1346
2661
  middleware.persist(
1347
2662
  immer.immer((set, get) => ({
1348
- xServices: initXServices(),
2663
+ xServices: {},
1349
2664
  xConnections: {},
2665
+ xConnectorsByChain: {},
2666
+ enabledChains: [],
2667
+ chainActions: {},
2668
+ walletProviders: {},
2669
+ walletConfig: void 0,
2670
+ userDisconnected: {},
1350
2671
  setXConnection: (xChainType, xConnection) => {
1351
2672
  set((state) => {
1352
2673
  state.xConnections[xChainType] = xConnection;
1353
2674
  });
2675
+ const factory = chainRegistry[xChainType]?.createWalletProvider;
2676
+ if (factory) {
2677
+ const service = get().xServices[xChainType];
2678
+ if (service) {
2679
+ const provider = factory(service, () => get());
2680
+ get().setWalletProvider(xChainType, provider);
2681
+ }
2682
+ }
1354
2683
  },
1355
2684
  unsetXConnection: (xChainType) => {
1356
2685
  set((state) => {
1357
2686
  delete state.xConnections[xChainType];
2687
+ delete state.walletProviders[xChainType];
2688
+ });
2689
+ },
2690
+ setXConnectors: (xChainType, connectors) => {
2691
+ set((state) => {
2692
+ state.xConnectorsByChain[xChainType] = connectors;
2693
+ });
2694
+ },
2695
+ registerChainActions: (xChainType, actions) => {
2696
+ set((state) => {
2697
+ state.chainActions[xChainType] = actions;
2698
+ });
2699
+ },
2700
+ setWalletProvider: (xChainType, provider) => {
2701
+ set((state) => {
2702
+ if (provider) {
2703
+ state.walletProviders[xChainType] = provider;
2704
+ } else {
2705
+ delete state.walletProviders[xChainType];
2706
+ }
2707
+ });
2708
+ },
2709
+ getWalletProvider: (xChainType) => {
2710
+ if (!xChainType) return void 0;
2711
+ return get().walletProviders[xChainType];
2712
+ },
2713
+ initChainServices: (walletConfig) => {
2714
+ const result = createChainServices(walletConfig, () => get());
2715
+ set((state) => {
2716
+ state.xServices = result.xServices;
2717
+ state.enabledChains = result.enabledChains;
2718
+ Object.assign(state.xConnectorsByChain, result.xConnectorsByChain);
2719
+ Object.assign(state.chainActions, result.chainActions);
2720
+ });
2721
+ set({ walletConfig });
2722
+ },
2723
+ cleanupDisabledConnections: () => {
2724
+ set((state) => {
2725
+ for (const chainType of types.ChainTypeArr) {
2726
+ if (state.xConnections[chainType] && !state.enabledChains.includes(chainType)) {
2727
+ delete state.xConnections[chainType];
2728
+ delete state.walletProviders[chainType];
2729
+ }
2730
+ }
2731
+ });
2732
+ },
2733
+ markUserDisconnected: (xChainType) => {
2734
+ set((state) => {
2735
+ state.userDisconnected[xChainType] = true;
2736
+ });
2737
+ },
2738
+ clearUserDisconnected: (xChainType) => {
2739
+ set((state) => {
2740
+ delete state.userDisconnected[xChainType];
1358
2741
  });
1359
2742
  }
1360
2743
  })),
1361
2744
  {
2745
+ // key kept as 'xwagmi-store' for backward compat — existing users won't lose persisted connections on upgrade
1362
2746
  name: "xwagmi-store",
1363
2747
  storage: middleware.createJSONStorage(() => localStorage),
1364
- partialize: (state) => ({ xConnections: state.xConnections })
2748
+ partialize: (state) => ({
2749
+ xConnections: state.xConnections,
2750
+ userDisconnected: state.userDisconnected
2751
+ })
1365
2752
  }
1366
2753
  ),
1367
2754
  { name: "xwagmi-store" }
1368
2755
  )
1369
2756
  );
1370
2757
 
1371
- // src/hooks/useXConnection.ts
1372
- function useXConnection(xChainType) {
1373
- const xConnection = useXWagmiStore((state) => xChainType ? state.xConnections?.[xChainType] : void 0);
1374
- const evmConnections = wagmi.useConnections();
1375
- const { address: evmAddress } = wagmi.useAccount();
1376
- const suiAccount = dappKit.useCurrentAccount();
1377
- const suiCurrentWallet = dappKit.useCurrentWallet();
1378
- const solanaWallet = walletAdapterReact.useWallet();
1379
- const xConnection2 = React2.useMemo(() => {
1380
- if (!xChainType) {
1381
- return void 0;
1382
- }
1383
- switch (xChainType) {
1384
- case "EVM":
1385
- return {
1386
- xAccount: { address: evmAddress, xChainType },
1387
- xConnectorId: evmConnections?.[0]?.connector.id
1388
- };
1389
- case "SUI":
1390
- if (suiCurrentWallet.currentWallet && suiCurrentWallet.connectionStatus === "connected") {
1391
- return {
1392
- xAccount: { address: suiAccount?.address, xChainType },
1393
- xConnectorId: suiCurrentWallet.currentWallet.name
1394
- };
1395
- }
1396
- return void 0;
1397
- case "SOLANA":
1398
- if (solanaWallet.connected) {
1399
- return {
1400
- xAccount: { address: solanaWallet.publicKey?.toString(), xChainType },
1401
- xConnectorId: `${solanaWallet.wallet?.adapter.name}`
1402
- };
1403
- }
1404
- return void 0;
1405
- default:
1406
- return xConnection;
1407
- }
1408
- }, [xChainType, xConnection, evmAddress, suiAccount, evmConnections, suiCurrentWallet, solanaWallet]);
1409
- return xConnection2;
1410
- }
1411
-
1412
- // src/hooks/useXAccount.ts
1413
- function isChainType(chainIdentifier) {
1414
- return types.ChainTypeArr.includes(chainIdentifier);
1415
- }
1416
- function useXAccount(chainIdentifier) {
1417
- const resolvedChainType = chainIdentifier ? isChainType(chainIdentifier) ? chainIdentifier : getXChainType(chainIdentifier) : void 0;
1418
- const xConnection = useXConnection(resolvedChainType);
1419
- const xAccount = React2.useMemo(() => {
1420
- if (!resolvedChainType) {
1421
- return {
1422
- address: void 0,
1423
- xChainType: void 0
1424
- };
1425
- }
1426
- return xConnection?.xAccount || { address: void 0, xChainType: resolvedChainType };
1427
- }, [resolvedChainType, xConnection]);
1428
- return xAccount;
2758
+ // src/actions/getXService.ts
2759
+ function getXService(xChainType) {
2760
+ const service = useXWalletStore.getState().xServices[xChainType];
2761
+ if (!service) {
2762
+ throw new Error(`XService for chain type "${xChainType}" is not initialized. Is the chain enabled in config?`);
2763
+ }
2764
+ return service;
1429
2765
  }
1430
- function useXAccounts() {
1431
- const xChainTypes = useXWagmiStore((state) => Object.keys(state.xServices));
1432
- const xConnections = useXWagmiStore((state) => state.xConnections);
1433
- const { address: evmAddress } = wagmi.useAccount();
1434
- const suiAccount = dappKit.useCurrentAccount();
1435
- const solanaWallet = walletAdapterReact.useWallet();
1436
- const xAccounts = React2.useMemo(() => {
1437
- const result = {};
1438
- for (const xChainType of xChainTypes) {
1439
- const xConnection = xConnections[xChainType];
1440
- if (xConnection?.xAccount) {
1441
- result[xChainType] = xConnection.xAccount;
1442
- } else {
1443
- result[xChainType] = {
1444
- address: void 0,
1445
- xChainType
1446
- };
1447
- }
1448
- }
1449
- if (evmAddress) {
1450
- result["EVM"] = {
1451
- address: evmAddress,
1452
- xChainType: "EVM"
1453
- };
1454
- }
1455
- if (suiAccount) {
1456
- result["SUI"] = {
1457
- address: suiAccount.address,
1458
- xChainType: "SUI"
1459
- };
1460
- }
1461
- if (solanaWallet.publicKey) {
1462
- result["SOLANA"] = {
1463
- address: solanaWallet.publicKey.toString(),
1464
- xChainType: "SOLANA"
1465
- };
2766
+ var EvmHydrator = () => {
2767
+ const wagmiConfig = wagmi.useConfig();
2768
+ const connectors = wagmi.useConnectors();
2769
+ const { address, status, connector } = wagmi.useAccount();
2770
+ const evmPublicClient = wagmi.usePublicClient();
2771
+ const { data: evmWalletClient } = wagmi.useWalletClient();
2772
+ const setXConnection = useXWalletStore((state) => state.setXConnection);
2773
+ const unsetXConnection = useXWalletStore((state) => state.unsetXConnection);
2774
+ const setWalletProvider = useXWalletStore((state) => state.setWalletProvider);
2775
+ const userDisconnectedEvm = useXWalletStore((state) => state.userDisconnected.EVM);
2776
+ const { reconnect } = wagmi.useReconnect();
2777
+ const walletConfig = useWalletConfig();
2778
+ react.useEffect(() => {
2779
+ if (wagmiConfig) {
2780
+ EvmXService.getInstance().wagmiConfig = wagmiConfig;
1466
2781
  }
1467
- return result;
1468
- }, [xChainTypes, xConnections, evmAddress, suiAccount, solanaWallet]);
1469
- return xAccounts;
1470
- }
1471
- function useXConnect() {
1472
- const setXConnection = useXWagmiStore((state) => state.setXConnection);
1473
- const { connectAsync: evmConnectAsync } = wagmi.useConnect();
1474
- const { mutateAsync: suiConnectAsync } = dappKit.useConnectWallet();
1475
- const { select, connect } = walletAdapterReact.useWallet();
1476
- return reactQuery.useMutation({
1477
- mutationFn: async (xConnector) => {
1478
- const xChainType = xConnector.xChainType;
1479
- let xAccount;
1480
- switch (xChainType) {
1481
- case "EVM":
1482
- await evmConnectAsync({ connector: xConnector.connector });
1483
- break;
1484
- case "SUI":
1485
- await suiConnectAsync({ wallet: xConnector.wallet });
1486
- break;
1487
- case "SOLANA": {
1488
- const walletName = xConnector.wallet.adapter.name;
1489
- select(walletName);
1490
- const adapter = xConnector.wallet.adapter;
1491
- if (!adapter) throw new Error("No adapter found for Solana wallet");
1492
- if (walletName === "MetaMask") {
1493
- await new Promise((resolve, reject) => {
1494
- const timeout = setTimeout(() => {
1495
- cleanup();
1496
- reject(new Error("Wallet connection timeout"));
1497
- }, 3e4);
1498
- const handleConnect = () => {
1499
- cleanup();
1500
- resolve();
1501
- };
1502
- const handleError = (error) => {
1503
- cleanup();
1504
- reject(error);
1505
- };
1506
- const cleanup = () => {
1507
- clearTimeout(timeout);
1508
- adapter.off("connect", handleConnect);
1509
- adapter.off("error", handleError);
1510
- };
1511
- adapter.on("connect", handleConnect);
1512
- adapter.on("error", handleError);
1513
- connect().catch((err) => {
1514
- cleanup();
1515
- reject(err);
1516
- });
1517
- });
2782
+ }, [wagmiConfig]);
2783
+ const evmConnectors = react.useMemo(() => connectors.map((c) => new EvmXConnector(c)), [connectors]);
2784
+ react.useEffect(() => {
2785
+ EvmXService.getInstance().setXConnectors(evmConnectors);
2786
+ useXWalletStore.getState().setXConnectors("EVM", evmConnectors);
2787
+ }, [evmConnectors]);
2788
+ const [hydrated, setHydrated] = react.useState(() => useXWalletStore.persist.hasHydrated());
2789
+ react.useEffect(() => {
2790
+ if (hydrated) return;
2791
+ const unsub = useXWalletStore.persist.onFinishHydration(() => setHydrated(true));
2792
+ return unsub;
2793
+ }, [hydrated]);
2794
+ react.useEffect(() => {
2795
+ if (!hydrated) return;
2796
+ if (status !== "disconnected") return;
2797
+ const state = useXWalletStore.getState();
2798
+ if (!state.xConnections.EVM) return;
2799
+ if (state.userDisconnected.EVM) return;
2800
+ reconnect();
2801
+ }, [hydrated, connectors, status, reconnect]);
2802
+ const wasConnectedRef = react.useRef(false);
2803
+ react.useEffect(() => {
2804
+ if (status === "connecting" || status === "reconnecting") return;
2805
+ if (status === "connected" && address && connector) {
2806
+ if (userDisconnectedEvm) return;
2807
+ wasConnectedRef.current = true;
2808
+ setXConnection("EVM", {
2809
+ xAccount: { address, xChainType: "EVM" },
2810
+ xConnectorId: connector.id
2811
+ });
2812
+ } else if (status === "disconnected" && wasConnectedRef.current) {
2813
+ wasConnectedRef.current = false;
2814
+ unsetXConnection("EVM");
2815
+ }
2816
+ }, [address, status, connector, userDisconnectedEvm, setXConnection, unsetXConnection]);
2817
+ const walletProvider = react.useMemo(() => {
2818
+ if (!evmPublicClient || !evmWalletClient) return void 0;
2819
+ if (userDisconnectedEvm) return void 0;
2820
+ const defaults = resolveEvmDefaults(evmWalletClient.chain.id, walletConfig.EVM?.chains);
2821
+ return new walletSdkCore.EvmWalletProvider({
2822
+ walletClient: evmWalletClient,
2823
+ publicClient: evmPublicClient,
2824
+ defaults
2825
+ });
2826
+ }, [evmPublicClient, evmWalletClient, walletConfig.EVM?.chains, userDisconnectedEvm]);
2827
+ react.useEffect(() => {
2828
+ setWalletProvider("EVM", walletProvider);
2829
+ }, [walletProvider, setWalletProvider]);
2830
+ return null;
2831
+ };
2832
+ var EvmActions = () => {
2833
+ const wagmiConfig = wagmi.useConfig();
2834
+ const { connectAsync } = wagmi.useConnect();
2835
+ const { disconnectAsync } = wagmi.useDisconnect();
2836
+ const { signMessageAsync } = wagmi.useSignMessage();
2837
+ const registerChainActions = useXWalletStore((state) => state.registerChainActions);
2838
+ const connectRef = react.useRef(connectAsync);
2839
+ const disconnectRef = react.useRef(disconnectAsync);
2840
+ const signMessageRef = react.useRef(signMessageAsync);
2841
+ const wagmiConfigRef = react.useRef(wagmiConfig);
2842
+ react.useEffect(() => {
2843
+ connectRef.current = connectAsync;
2844
+ disconnectRef.current = disconnectAsync;
2845
+ signMessageRef.current = signMessageAsync;
2846
+ wagmiConfigRef.current = wagmiConfig;
2847
+ }, [connectAsync, disconnectAsync, signMessageAsync, wagmiConfig]);
2848
+ react.useEffect(() => {
2849
+ registerChainActions("EVM", {
2850
+ connect: async (xConnectorId) => {
2851
+ const connector = wagmiConfigRef.current.connectors.find((c) => c.id === xConnectorId);
2852
+ if (!connector) {
2853
+ console.warn(
2854
+ `[EvmActions] connect: connector "${xConnectorId}" not found in wagmi config`,
2855
+ wagmiConfigRef.current.connectors.map((c) => c.id)
2856
+ );
2857
+ return void 0;
2858
+ }
2859
+ useXWalletStore.getState().clearUserDisconnected("EVM");
2860
+ try {
2861
+ await connectRef.current({ connector });
2862
+ } catch (error) {
2863
+ if (error instanceof Error && error.name === "ConnectorAlreadyConnectedError") {
2864
+ return void 0;
1518
2865
  }
1519
- break;
2866
+ throw error;
2867
+ }
2868
+ return void 0;
2869
+ },
2870
+ disconnect: async () => {
2871
+ const store = useXWalletStore.getState();
2872
+ store.unsetXConnection("EVM");
2873
+ store.markUserDisconnected("EVM");
2874
+ try {
2875
+ await disconnectRef.current();
2876
+ } catch (error) {
2877
+ console.warn("[EvmActions] wagmi disconnect failed (zustand already cleared):", error);
1520
2878
  }
1521
- default:
1522
- xAccount = await xConnector.connect();
1523
- break;
2879
+ },
2880
+ getConnectors: () => useXWalletStore.getState().xConnectorsByChain.EVM ?? [],
2881
+ getConnection: () => useXWalletStore.getState().xConnections.EVM,
2882
+ signMessage: async (message) => {
2883
+ const signature = await signMessageRef.current({ message });
2884
+ return signature;
1524
2885
  }
1525
- if (xAccount) {
1526
- setXConnection(xConnector.xChainType, {
1527
- xAccount,
1528
- xConnectorId: xConnector.id
1529
- });
2886
+ });
2887
+ }, [registerChainActions]);
2888
+ return null;
2889
+ };
2890
+ var EvmProvider = ({ children, config }) => {
2891
+ const reconnectOnMount = config.reconnectOnMount ?? EVM_DEFAULT_RECONNECT_ON_MOUNT;
2892
+ const ssr = config.ssr ?? EVM_DEFAULT_SSR;
2893
+ const queryClientRef = react.useRef(null);
2894
+ if (!queryClientRef.current) {
2895
+ queryClientRef.current = new reactQuery.QueryClient();
2896
+ }
2897
+ const walletConnectConfig = config.walletConnect;
2898
+ const wagmiConfig = react.useMemo(() => {
2899
+ const connectors$1 = [];
2900
+ if (walletConnectConfig) {
2901
+ if (walletConnectConfig.projectId) {
2902
+ connectors$1.push(connectors.walletConnect({ showQrModal: true, ...walletConnectConfig }));
2903
+ } else {
2904
+ console.warn("[wallet-sdk-react] walletConnect.projectId is required \u2014 WalletConnect connector skipped.");
1530
2905
  }
1531
- return xAccount;
1532
2906
  }
1533
- });
1534
- }
2907
+ return createWagmiConfig(config.chains, { ssr, connectors: connectors$1 });
2908
+ }, [config.chains, reconnectOnMount, ssr, walletConnectConfig]);
2909
+ return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClientRef.current, children: /* @__PURE__ */ jsxRuntime.jsxs(wagmi.WagmiProvider, { reconnectOnMount, config: wagmiConfig, initialState: config.initialState, children: [
2910
+ /* @__PURE__ */ jsxRuntime.jsx(EvmHydrator, {}),
2911
+ /* @__PURE__ */ jsxRuntime.jsx(EvmActions, {}),
2912
+ children
2913
+ ] }) });
2914
+ };
1535
2915
 
1536
2916
  // src/xchains/solana/SolanaXConnector.ts
1537
2917
  var SolanaXConnector = class extends XConnector {
2918
+ wallet;
1538
2919
  constructor(wallet) {
1539
2920
  super("SOLANA", wallet?.adapter.name, wallet?.adapter.name);
1540
2921
  this.wallet = wallet;
@@ -1550,598 +2931,407 @@ var SolanaXConnector = class extends XConnector {
1550
2931
  get icon() {
1551
2932
  return this.wallet?.adapter.icon;
1552
2933
  }
1553
- };
1554
- var useStellarXConnectors = () => {
1555
- const xService = useXService("STELLAR");
1556
- return reactQuery.useQuery({
1557
- queryKey: ["stellar-wallets", xService],
1558
- queryFn: async () => {
1559
- if (!xService) {
1560
- return [];
1561
- }
1562
- const wallets = await xService.walletsKit.getSupportedWallets();
1563
- return wallets.filter((wallet) => wallet.isAvailable).map((wallet) => new StellarWalletsKitXConnector(wallet));
1564
- }
1565
- });
1566
- };
1567
-
1568
- // src/hooks/useXService.ts
1569
- function useXService(xChainType) {
1570
- const xService = useXWagmiStore((state) => xChainType ? state.xServices[xChainType] : void 0);
1571
- return xService;
1572
- }
1573
-
1574
- // src/xchains/near/NearXConnector.ts
1575
- var NearXConnector = class extends XConnector {
1576
- constructor(wallet) {
1577
- super("NEAR", wallet.manifest.name, wallet.manifest.id);
1578
- this._wallet = wallet;
1579
- }
1580
- getXService() {
1581
- return NearXService.getInstance();
1582
- }
1583
- async connect() {
1584
- const walletSelector = this.getXService().walletSelector;
1585
- const wallet = await walletSelector.connect({ walletId: this._wallet.manifest.id });
1586
- const accounts = await wallet.getAccounts();
1587
- if (accounts.length === 0 || accounts[0] === void 0) {
1588
- return void 0;
1589
- }
1590
- return {
1591
- address: accounts[0].accountId,
1592
- xChainType: this.xChainType
1593
- };
1594
- }
1595
- async disconnect() {
1596
- const walletSelector = this.getXService().walletSelector;
1597
- await walletSelector.disconnect(this._wallet);
2934
+ get isInstalled() {
2935
+ const state = this.wallet?.readyState;
2936
+ return state === "Installed" || state === "Loadable";
1598
2937
  }
1599
- get icon() {
1600
- return this._wallet.manifest.icon;
2938
+ get installUrl() {
2939
+ return this.wallet?.adapter.url;
1601
2940
  }
1602
2941
  };
1603
2942
 
1604
- // src/xchains/near/useNearXConnectors.ts
1605
- var useNearXConnectors = () => {
1606
- const xService = useXService("NEAR");
1607
- return reactQuery.useQuery({
1608
- queryKey: ["near-wallets"],
1609
- queryFn: async () => {
1610
- if (!xService) {
1611
- return [];
1612
- }
1613
- await xService.walletSelector.whenManifestLoaded;
1614
- const wallets = xService.walletSelector.availableWallets;
1615
- return wallets.map((wallet) => new NearXConnector(wallet));
1616
- }
1617
- });
1618
- };
1619
-
1620
- // src/hooks/useXConnectors.ts
1621
- function useXConnectors(xChainType) {
1622
- const xService = useXService(xChainType);
1623
- const evmConnectors = wagmi.useConnectors();
1624
- const suiWallets = dappKit.useWallets();
1625
- const { data: stellarXConnectors } = useStellarXConnectors();
1626
- const { data: nearXConnectors } = useNearXConnectors();
1627
- const stacksXConnectors = useStacksXConnectors();
1628
- const { wallets: solanaWallets } = walletAdapterReact.useWallet();
1629
- const xConnectors = React2.useMemo(() => {
1630
- if (!xChainType || !xService) {
1631
- return [];
1632
- }
1633
- switch (xChainType) {
1634
- case "EVM":
1635
- return evmConnectors.map((connector) => new EvmXConnector(connector));
1636
- case "SUI":
1637
- return suiWallets.map((wallet) => new SuiXConnector(wallet));
1638
- case "STELLAR":
1639
- return stellarXConnectors || [];
1640
- case "SOLANA":
1641
- return solanaWallets.filter((wallet) => wallet.readyState === "Installed").map((wallet) => new SolanaXConnector(wallet));
1642
- case "NEAR":
1643
- return nearXConnectors || [];
1644
- case "STACKS":
1645
- return stacksXConnectors;
1646
- default:
1647
- return xService.getXConnectors();
1648
- }
1649
- }, [
1650
- xService,
1651
- xChainType,
1652
- evmConnectors,
1653
- suiWallets,
1654
- stellarXConnectors,
1655
- solanaWallets,
1656
- nearXConnectors,
1657
- stacksXConnectors
1658
- ]);
1659
- return xConnectors;
1660
- }
1661
- function useXDisconnect() {
1662
- const xConnections = useXWagmiStore((state) => state.xConnections);
1663
- const unsetXConnection = useXWagmiStore((state) => state.unsetXConnection);
1664
- const { disconnectAsync } = wagmi.useDisconnect();
1665
- const { mutateAsync: suiDisconnectAsync } = dappKit.useDisconnectWallet();
2943
+ // src/providers/solana/SolanaHydrator.tsx
2944
+ var SolanaHydrator = () => {
2945
+ const { connection } = walletAdapterReact.useConnection();
1666
2946
  const solanaWallet = walletAdapterReact.useWallet();
1667
- return React2.useCallback(
1668
- async (xChainType) => {
1669
- switch (xChainType) {
1670
- case "EVM":
1671
- await disconnectAsync();
1672
- break;
1673
- case "SUI":
1674
- await suiDisconnectAsync();
1675
- break;
1676
- case "SOLANA":
1677
- await solanaWallet.disconnect();
1678
- break;
1679
- case "NEAR": {
1680
- const nearXService = getXService("NEAR");
1681
- nearXService.walletSelector.disconnect();
1682
- break;
1683
- }
1684
- default: {
1685
- const xService = getXService(xChainType);
1686
- const xConnectorId = xConnections[xChainType]?.xConnectorId;
1687
- const xConnector = xConnectorId ? xService.getXConnectorById(xConnectorId) : void 0;
1688
- await xConnector?.disconnect();
1689
- break;
1690
- }
1691
- }
1692
- unsetXConnection(xChainType);
1693
- },
1694
- [xConnections, unsetXConnection, disconnectAsync, suiDisconnectAsync, solanaWallet]
2947
+ const setXConnection = useXWalletStore((state) => state.setXConnection);
2948
+ const unsetXConnection = useXWalletStore((state) => state.unsetXConnection);
2949
+ const setWalletProvider = useXWalletStore((state) => state.setWalletProvider);
2950
+ const walletConfig = useWalletConfig();
2951
+ const solanaDefaults = getEntryDefaults(
2952
+ walletConfig.SOLANA?.chains?.[types.ChainKeys.SOLANA_MAINNET]
1695
2953
  );
1696
- }
1697
- function useXBalances({
1698
- xChainId,
1699
- xTokens,
1700
- address
1701
- }) {
1702
- const xService = useXService(getXChainType(xChainId));
1703
- return reactQuery.useQuery({
1704
- queryKey: ["xBalances", xChainId, xTokens.map((x) => x.symbol), address],
1705
- queryFn: async () => {
1706
- if (!xService) {
1707
- return {};
1708
- }
1709
- const balances = await xService.getBalances(address, xTokens);
1710
- return balances;
1711
- },
1712
- enabled: !!xService && !!address && (xTokens?.length ?? 0) > 0,
1713
- refetchInterval: 5e3
2954
+ react.useEffect(() => {
2955
+ if (connection) {
2956
+ SolanaXService.getInstance().connection = connection;
2957
+ }
2958
+ }, [connection]);
2959
+ const solanaWalletRef = react.useRef(solanaWallet);
2960
+ react.useEffect(() => {
2961
+ solanaWalletRef.current = solanaWallet;
1714
2962
  });
1715
- }
1716
- function useEthereumChainId() {
1717
- const injectiveXService = useXService("INJECTIVE");
1718
- const [ethereumChainId, setEthereumChainId] = React2__default.default.useState(null);
1719
- React2.useEffect(() => {
1720
- if (!injectiveXService?.walletStrategy?.getWallet()) return;
1721
- const walletStrategy = injectiveXService.walletStrategy;
1722
- if (walletStrategy.getWallet() !== walletBase.Wallet.Metamask) return;
1723
- const getEthereumChainId = async () => {
1724
- try {
1725
- const chainId = await walletStrategy.getEthereumChainId();
1726
- setEthereumChainId(Number.parseInt(chainId));
1727
- } catch (e) {
1728
- console.warn("Failed to get Ethereum chain ID:", e);
1729
- }
1730
- };
1731
- getEthereumChainId();
1732
- try {
1733
- walletStrategy.getStrategy().onChainIdChanged(getEthereumChainId);
1734
- } catch (e) {
1735
- console.warn("Failed to subscribe to chain ID changes:", e);
1736
- }
1737
- }, [injectiveXService?.walletStrategy]);
1738
- return ethereumChainId;
1739
- }
1740
- var switchEthereumChain = async () => {
1741
- const metamaskProvider = window.ethereum;
1742
- return await Promise.race([
1743
- metamaskProvider.request({
1744
- method: "wallet_switchEthereumChain",
1745
- params: [{ chainId: "0x1" }]
1746
- }),
1747
- new Promise(
1748
- (resolve) => metamaskProvider.on("change", ({ chain }) => {
1749
- if (chain?.id === 1) {
1750
- resolve();
1751
- }
1752
- })
1753
- )
1754
- ]);
1755
- };
1756
- var useEvmSwitchChain = (expectedXChainId) => {
1757
- const xChainType = getXChainType(expectedXChainId);
1758
- const expectedChainId = types.baseChainInfo[expectedXChainId].chainId;
1759
- const injectiveXService = useXService("INJECTIVE");
1760
- const ethereumChainId = useEthereumChainId();
1761
- const { chainId } = wagmi.useAccount();
1762
- const isWrongChain = React2.useMemo(() => {
1763
- return xChainType === "EVM" && chainId !== expectedChainId || xChainType === "INJECTIVE" && injectiveXService && injectiveXService.walletStrategy.getWallet() === walletBase.Wallet.Metamask && ethereumChainId !== chains$1.mainnet.id;
1764
- }, [xChainType, chainId, expectedChainId, ethereumChainId, injectiveXService]);
1765
- const { switchChain } = wagmi.useSwitchChain();
1766
- const handleSwitchChain = React2.useCallback(() => {
1767
- if (xChainType === "INJECTIVE") {
1768
- switchEthereumChain();
1769
- } else {
1770
- switchChain({ chainId: expectedChainId });
1771
- }
1772
- }, [switchChain, expectedChainId, xChainType]);
1773
- return React2.useMemo(
1774
- () => ({
1775
- isWrongChain,
1776
- handleSwitchChain
1777
- }),
1778
- [isWrongChain, handleSwitchChain]
2963
+ const solanaConnectors = react.useMemo(
2964
+ () => solanaWallet.wallets.filter((wallet) => wallet.readyState === "Installed").map((wallet) => new SolanaXConnector(wallet)),
2965
+ [solanaWallet.wallets]
1779
2966
  );
2967
+ react.useEffect(() => {
2968
+ SolanaXService.getInstance().setXConnectors(solanaConnectors);
2969
+ useXWalletStore.getState().setXConnectors("SOLANA", solanaConnectors);
2970
+ }, [solanaConnectors]);
2971
+ const wasConnectedRef = react.useRef(!!useXWalletStore.getState().xConnections.SOLANA);
2972
+ react.useEffect(() => {
2973
+ if (solanaWallet.connected && solanaWallet.publicKey) {
2974
+ wasConnectedRef.current = true;
2975
+ setXConnection("SOLANA", {
2976
+ xAccount: { address: solanaWallet.publicKey.toString(), xChainType: "SOLANA" },
2977
+ xConnectorId: `${solanaWallet.wallet?.adapter.name}`
2978
+ });
2979
+ } else if (wasConnectedRef.current) {
2980
+ wasConnectedRef.current = false;
2981
+ unsetXConnection("SOLANA");
2982
+ }
2983
+ }, [solanaWallet.connected, solanaWallet.publicKey, solanaWallet.wallet, setXConnection, unsetXConnection]);
2984
+ const walletProvider = react.useMemo(() => {
2985
+ if (solanaWallet.connected && solanaWallet.publicKey && solanaWallet.wallet && connection) {
2986
+ return new walletSdkCore.SolanaWalletProvider({
2987
+ wallet: solanaWallet,
2988
+ endpoint: connection.rpcEndpoint,
2989
+ defaults: solanaDefaults
2990
+ });
2991
+ }
2992
+ return void 0;
2993
+ }, [solanaWallet.connected, solanaWallet.publicKey, solanaWallet.wallet, connection, solanaDefaults]);
2994
+ react.useEffect(() => {
2995
+ SolanaXService.getInstance().wallet = solanaWalletRef.current;
2996
+ setWalletProvider("SOLANA", walletProvider);
2997
+ }, [walletProvider, setWalletProvider]);
2998
+ return null;
1780
2999
  };
1781
- function useWalletProvider(spokeChainId) {
1782
- const xChainType = getXChainType(spokeChainId);
1783
- const evmPublicClient = wagmi.usePublicClient();
1784
- const { data: evmWalletClient } = wagmi.useWalletClient();
1785
- const xService = useXService(getXChainType(spokeChainId));
1786
- const xAccount = useXAccount(spokeChainId);
1787
- const stacksConnection = useXConnection("STACKS");
1788
- const stacksConnectors = useXConnectors("STACKS");
1789
- const xConnection = useXConnection(xChainType);
1790
- return React2.useMemo(() => {
1791
- switch (xChainType) {
1792
- case "EVM": {
1793
- if (!evmWalletClient) {
1794
- return void 0;
1795
- }
1796
- if (!evmPublicClient) {
1797
- return void 0;
1798
- }
1799
- return new walletSdkCore.EvmWalletProvider({
1800
- walletClient: evmWalletClient,
1801
- publicClient: evmPublicClient
1802
- });
1803
- }
1804
- case "SUI": {
1805
- const suiXService = xService;
1806
- const { client, wallet, account } = {
1807
- client: suiXService.suiClient,
1808
- wallet: suiXService.suiWallet,
1809
- account: suiXService.suiAccount
1810
- };
1811
- return new walletSdkCore.SuiWalletProvider({ client, wallet, account });
1812
- }
1813
- case "ICON": {
1814
- const { walletAddress, rpcUrl } = {
1815
- walletAddress: xAccount.address,
1816
- rpcUrl: CHAIN_INFO[1 /* MAINNET */].APIEndpoint
1817
- };
1818
- return new walletSdkCore.IconWalletProvider({
1819
- walletAddress,
1820
- rpcUrl
1821
- });
1822
- }
1823
- case "INJECTIVE": {
1824
- const injectiveXService = xService;
1825
- if (!injectiveXService) {
1826
- return void 0;
1827
- }
1828
- return new walletSdkCore.InjectiveWalletProvider({
1829
- msgBroadcaster: injectiveXService.msgBroadcaster
1830
- });
1831
- }
1832
- case "STELLAR": {
1833
- const stellarXService = xService;
1834
- if (!stellarXService.walletsKit) {
1835
- return void 0;
1836
- }
1837
- return new walletSdkCore.StellarWalletProvider({
1838
- type: "BROWSER_EXTENSION",
1839
- walletsKit: stellarXService.walletsKit,
1840
- network: "PUBLIC"
1841
- });
1842
- }
1843
- case "SOLANA": {
1844
- const solanaXService = xService;
1845
- if (!solanaXService.wallet) {
3000
+ var SolanaActions = () => {
3001
+ const solanaWallet = walletAdapterReact.useWallet();
3002
+ const registerChainActions = useXWalletStore((state) => state.registerChainActions);
3003
+ const walletRef = react.useRef(solanaWallet);
3004
+ react.useEffect(() => {
3005
+ walletRef.current = solanaWallet;
3006
+ }, [solanaWallet]);
3007
+ react.useEffect(() => {
3008
+ registerChainActions("SOLANA", {
3009
+ connect: async (xConnectorId) => {
3010
+ const wallet = walletRef.current.wallets.find((w) => w.adapter.name === xConnectorId);
3011
+ if (!wallet) {
3012
+ console.warn(
3013
+ `[SolanaActions] connect: wallet "${xConnectorId}" not found in adapter list`,
3014
+ walletRef.current.wallets.map((w) => w.adapter.name)
3015
+ );
1846
3016
  return void 0;
1847
3017
  }
1848
- if (!solanaXService.connection) {
3018
+ walletRef.current.select(wallet.adapter.name);
3019
+ if (wallet.adapter.connected) {
1849
3020
  return void 0;
1850
3021
  }
1851
- return new walletSdkCore.SolanaWalletProvider({
1852
- wallet: solanaXService.wallet,
1853
- endpoint: solanaXService.connection.rpcEndpoint
3022
+ await new Promise((resolve, reject) => {
3023
+ const timeout = setTimeout(() => {
3024
+ cleanup();
3025
+ reject(new Error("Wallet connection timeout"));
3026
+ }, SOLANA_METAMASK_CONNECT_TIMEOUT_MS);
3027
+ const onConnect = () => {
3028
+ cleanup();
3029
+ resolve();
3030
+ };
3031
+ const onError = (err) => {
3032
+ cleanup();
3033
+ reject(err);
3034
+ };
3035
+ const cleanup = () => {
3036
+ clearTimeout(timeout);
3037
+ wallet.adapter.off("connect", onConnect);
3038
+ wallet.adapter.off("error", onError);
3039
+ };
3040
+ wallet.adapter.on("connect", onConnect);
3041
+ wallet.adapter.on("error", onError);
3042
+ setTimeout(() => {
3043
+ if (!wallet.adapter.connected && !wallet.adapter.connecting) {
3044
+ walletRef.current.connect().catch((err) => {
3045
+ cleanup();
3046
+ reject(err);
3047
+ });
3048
+ }
3049
+ }, 0);
1854
3050
  });
1855
- }
1856
- case "BITCOIN": {
1857
- if (!xConnection?.xConnectorId) return void 0;
1858
- const connector = BitcoinXService.getInstance().getXConnectorById(xConnection.xConnectorId);
1859
- if (!connector) return void 0;
1860
- return connector.recreateWalletProvider(xConnection.xAccount);
1861
- }
1862
- case "NEAR": {
1863
- const nearXService = xService;
1864
- if (!nearXService.walletSelector) {
1865
- return void 0;
1866
- }
1867
- return new walletSdkCore.NearWalletProvider({ wallet: nearXService.walletSelector });
1868
- }
1869
- case "STACKS": {
1870
- const address = xAccount.address;
1871
- if (!address) {
1872
- return void 0;
3051
+ return void 0;
3052
+ },
3053
+ disconnect: async () => {
3054
+ await walletRef.current.disconnect();
3055
+ },
3056
+ getConnectors: () => useXWalletStore.getState().xConnectorsByChain.SOLANA ?? [],
3057
+ getConnection: () => useXWalletStore.getState().xConnections.SOLANA,
3058
+ signMessage: async (message) => {
3059
+ if (!walletRef.current.signMessage) {
3060
+ throw new Error("Solana wallet not connected");
1873
3061
  }
1874
- const activeStacksConnector = stacksConnectors.find((c) => c.id === stacksConnection?.xConnectorId);
1875
- return new walletSdkCore.StacksWalletProvider({ address, provider: activeStacksConnector?.getProvider() });
3062
+ const signature = await walletRef.current.signMessage(new TextEncoder().encode(message));
3063
+ return Buffer.from(signature).toString("base64");
1876
3064
  }
1877
- default:
1878
- return void 0;
3065
+ });
3066
+ }, [registerChainActions]);
3067
+ return null;
3068
+ };
3069
+ var emptyWallets = [];
3070
+ var SolanaProvider = ({ children, config }) => {
3071
+ const autoConnect = config.autoConnect ?? SOLANA_DEFAULT_AUTO_CONNECT;
3072
+ const endpoint = config.chains?.[types.ChainKeys.SOLANA_MAINNET]?.rpcUrl ?? SOLANA_DEFAULT_RPC_URL;
3073
+ return /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReact.ConnectionProvider, { endpoint, children: /* @__PURE__ */ jsxRuntime.jsxs(walletAdapterReact.WalletProvider, { wallets: emptyWallets, autoConnect, children: [
3074
+ /* @__PURE__ */ jsxRuntime.jsx(SolanaHydrator, {}),
3075
+ /* @__PURE__ */ jsxRuntime.jsx(SolanaActions, {}),
3076
+ children
3077
+ ] }) });
3078
+ };
3079
+ var SuiHydrator = () => {
3080
+ const suiClient = dappKit.useSuiClient();
3081
+ const { currentWallet } = dappKit.useCurrentWallet();
3082
+ const suiAccount = dappKit.useCurrentAccount();
3083
+ const suiWallets = dappKit.useWallets();
3084
+ const setXConnection = useXWalletStore((state) => state.setXConnection);
3085
+ const unsetXConnection = useXWalletStore((state) => state.unsetXConnection);
3086
+ const setWalletProvider = useXWalletStore((state) => state.setWalletProvider);
3087
+ const walletConfig = useWalletConfig();
3088
+ const suiDefaults = getEntryDefaults(walletConfig.SUI?.chains?.[types.ChainKeys.SUI_MAINNET]);
3089
+ react.useEffect(() => {
3090
+ const service = SuiXService.getInstance();
3091
+ if (suiClient) service.suiClient = suiClient;
3092
+ if (currentWallet) service.suiWallet = currentWallet;
3093
+ if (suiAccount) service.suiAccount = suiAccount;
3094
+ }, [suiClient, currentWallet, suiAccount]);
3095
+ const suiConnectors = react.useMemo(() => suiWallets.map((wallet) => new SuiXConnector(wallet)), [suiWallets]);
3096
+ react.useEffect(() => {
3097
+ SuiXService.getInstance().setXConnectors(suiConnectors);
3098
+ useXWalletStore.getState().setXConnectors("SUI", suiConnectors);
3099
+ }, [suiConnectors]);
3100
+ const wasConnectedRef = react.useRef(!!useXWalletStore.getState().xConnections.SUI);
3101
+ react.useEffect(() => {
3102
+ if (currentWallet && suiAccount?.address) {
3103
+ wasConnectedRef.current = true;
3104
+ setXConnection("SUI", {
3105
+ xAccount: { address: suiAccount.address, xChainType: "SUI" },
3106
+ // Match SuiXConnector.id derivation: prefer Wallet Standard `id`, fall back to `name`.
3107
+ xConnectorId: currentWallet.id ?? currentWallet.name
3108
+ });
3109
+ } else if (wasConnectedRef.current) {
3110
+ wasConnectedRef.current = false;
3111
+ unsetXConnection("SUI");
3112
+ }
3113
+ }, [currentWallet, suiAccount, setXConnection, unsetXConnection]);
3114
+ const walletProvider = react.useMemo(() => {
3115
+ if (suiClient && currentWallet && suiAccount) {
3116
+ assertSuiProviderShape("SuiHydrator", suiClient, currentWallet, suiAccount);
3117
+ return new walletSdkCore.SuiWalletProvider({
3118
+ client: suiClient,
3119
+ wallet: currentWallet,
3120
+ account: suiAccount,
3121
+ defaults: suiDefaults
3122
+ });
1879
3123
  }
1880
- }, [
1881
- xChainType,
1882
- evmPublicClient,
1883
- evmWalletClient,
1884
- xService,
1885
- xAccount,
1886
- stacksConnection,
1887
- stacksConnectors,
1888
- xConnection
1889
- ]);
1890
- }
1891
- function useXSignMessage() {
1892
- const { signMessage } = walletAdapterReact.useWallet();
1893
- const { signMessageAsync: evmSignMessage } = wagmi.useSignMessage();
3124
+ return void 0;
3125
+ }, [suiClient, currentWallet, suiAccount, suiDefaults]);
3126
+ react.useEffect(() => {
3127
+ setWalletProvider("SUI", walletProvider);
3128
+ }, [walletProvider, setWalletProvider]);
3129
+ return null;
3130
+ };
3131
+ var SuiActions = () => {
3132
+ const suiWallets = dappKit.useWallets();
3133
+ const { mutateAsync: suiConnectAsync } = dappKit.useConnectWallet();
3134
+ const { mutateAsync: suiDisconnectAsync } = dappKit.useDisconnectWallet();
1894
3135
  const { mutateAsync: signPersonalMessage } = dappKit.useSignPersonalMessage();
1895
- const { address: injectiveAddress } = useXAccount("INJECTIVE");
1896
- return reactQuery.useMutation({
1897
- mutationFn: async ({ xChainType, message }) => {
1898
- let signature;
1899
- switch (xChainType) {
1900
- case "EVM": {
1901
- signature = await evmSignMessage({ message });
1902
- break;
1903
- }
1904
- case "SUI": {
1905
- const res = await signPersonalMessage({ message: new Uint8Array(new TextEncoder().encode(message)) });
1906
- signature = res.signature;
1907
- break;
1908
- }
1909
- case "SOLANA": {
1910
- if (!signMessage) {
1911
- throw new Error("Solana wallet not connected");
1912
- }
1913
- signature = await signMessage(new TextEncoder().encode(message));
1914
- break;
1915
- }
1916
- case "STELLAR": {
1917
- const res = await StellarXService.getInstance().walletsKit.signMessage(message);
1918
- signature = res.signedMessage;
1919
- break;
1920
- }
1921
- case "INJECTIVE": {
1922
- if (!injectiveAddress) {
1923
- throw new Error("Injective address not found");
1924
- }
1925
- const ethereumAddress = sdkTs.getEthereumAddress(injectiveAddress);
1926
- const walletStrategy = InjectiveXService.getInstance().walletStrategy;
1927
- const res = await walletStrategy.signArbitrary(
1928
- walletStrategy.getWallet() === walletBase.Wallet.Metamask ? ethereumAddress : injectiveAddress,
1929
- message
3136
+ const registerChainActions = useXWalletStore((state) => state.registerChainActions);
3137
+ const connectRef = react.useRef(suiConnectAsync);
3138
+ const disconnectRef = react.useRef(suiDisconnectAsync);
3139
+ const signMessageRef = react.useRef(signPersonalMessage);
3140
+ const walletsRef = react.useRef(suiWallets);
3141
+ react.useEffect(() => {
3142
+ connectRef.current = suiConnectAsync;
3143
+ }, [suiConnectAsync]);
3144
+ react.useEffect(() => {
3145
+ disconnectRef.current = suiDisconnectAsync;
3146
+ }, [suiDisconnectAsync]);
3147
+ react.useEffect(() => {
3148
+ signMessageRef.current = signPersonalMessage;
3149
+ }, [signPersonalMessage]);
3150
+ react.useEffect(() => {
3151
+ walletsRef.current = suiWallets;
3152
+ }, [suiWallets]);
3153
+ react.useEffect(() => {
3154
+ registerChainActions("SUI", {
3155
+ connect: async (xConnectorId) => {
3156
+ const wallet = walletsRef.current.find((w) => (w.id ?? w.name) === xConnectorId);
3157
+ if (!wallet) {
3158
+ console.warn(
3159
+ `[SuiActions] connect: wallet "${xConnectorId}" not found in adapter list`,
3160
+ walletsRef.current.map((w) => w.name)
1930
3161
  );
1931
- if (!res) {
1932
- throw new Error("Injective signature not found");
1933
- }
1934
- signature = res;
1935
- break;
3162
+ return void 0;
1936
3163
  }
1937
- default:
1938
- console.warn("Unsupported chain type");
1939
- break;
3164
+ await connectRef.current({ wallet });
3165
+ return void 0;
3166
+ },
3167
+ disconnect: async () => {
3168
+ await disconnectRef.current();
3169
+ },
3170
+ getConnectors: () => useXWalletStore.getState().xConnectorsByChain.SUI ?? [],
3171
+ getConnection: () => useXWalletStore.getState().xConnections.SUI,
3172
+ signMessage: async (message) => {
3173
+ const res = await signMessageRef.current({ message: new Uint8Array(new TextEncoder().encode(message)) });
3174
+ return res.signature;
1940
3175
  }
1941
- return signature;
1942
- }
1943
- });
1944
- }
1945
-
1946
- // src/xchains/bitcoin/useBitcoinXConnectors.ts
1947
- function useBitcoinXConnectors() {
1948
- const xService = useXService("BITCOIN");
1949
- return React2.useMemo(() => {
1950
- return xService?.getXConnectors() || [];
1951
- }, [xService]);
1952
- }
1953
- var Hydrate = ({ rpcConfig }) => {
1954
- const suiClient = dappKit.useSuiClient();
1955
- React2.useEffect(() => {
1956
- if (suiClient) {
1957
- SuiXService.getInstance().suiClient = suiClient;
1958
- }
1959
- }, [suiClient]);
1960
- const { currentWallet: suiWallet } = dappKit.useCurrentWallet();
1961
- React2.useEffect(() => {
1962
- if (suiWallet) {
1963
- SuiXService.getInstance().suiWallet = suiWallet;
1964
- }
1965
- }, [suiWallet]);
1966
- const suiAccount = dappKit.useCurrentAccount();
1967
- React2.useEffect(() => {
1968
- if (suiAccount) {
1969
- SuiXService.getInstance().suiAccount = suiAccount;
1970
- }
1971
- }, [suiAccount]);
1972
- const { connection: solanaConnection } = walletAdapterReact.useConnection();
1973
- const solanaWallet = walletAdapterReact.useWallet();
1974
- React2.useEffect(() => {
1975
- if (solanaConnection) {
1976
- SolanaXService.getInstance().connection = solanaConnection;
1977
- }
1978
- }, [solanaConnection]);
1979
- React2.useEffect(() => {
1980
- if (solanaWallet) {
1981
- SolanaXService.getInstance().wallet = solanaWallet;
1982
- }
1983
- }, [solanaWallet]);
1984
- const wagmiConfig = wagmi.useConfig();
1985
- React2.useEffect(() => {
1986
- if (wagmiConfig) {
1987
- EvmXService.getInstance().wagmiConfig = wagmiConfig;
1988
- }
1989
- }, [wagmiConfig]);
1990
- React2.useEffect(() => {
1991
- StacksXService.getInstance().network = network.createNetwork({
1992
- network: "mainnet",
1993
- client: { baseUrl: rpcConfig.stacks ?? "https://api.mainnet.hiro.so" }
1994
3176
  });
1995
- }, [rpcConfig.stacks]);
3177
+ }, [registerChainActions]);
1996
3178
  return null;
1997
3179
  };
3180
+ var SuiProvider = ({ children, config }) => {
3181
+ const autoConnect = config.autoConnect ?? SUI_DEFAULT_AUTO_CONNECT;
3182
+ const network = config.network ?? SUI_DEFAULT_NETWORK;
3183
+ const rpcUrl = config.chains?.[types.ChainKeys.SUI_MAINNET]?.rpcUrl ?? client.getFullnodeUrl(network);
3184
+ return /* @__PURE__ */ jsxRuntime.jsx(dappKit.SuiClientProvider, { networks: { [network]: { url: rpcUrl } }, defaultNetwork: network, children: /* @__PURE__ */ jsxRuntime.jsxs(dappKit.WalletProvider, { autoConnect, children: [
3185
+ /* @__PURE__ */ jsxRuntime.jsx(SuiHydrator, {}),
3186
+ /* @__PURE__ */ jsxRuntime.jsx(SuiActions, {}),
3187
+ children
3188
+ ] }) });
3189
+ };
1998
3190
 
1999
3191
  // src/xchains/icon/actions.ts
2000
3192
  var reconnectIcon = async () => {
2001
- const iconConnection = useXWagmiStore.getState().xConnections.ICON;
3193
+ const iconConnection = useXWalletStore.getState().xConnections.ICON;
2002
3194
  if (!iconConnection) return;
2003
3195
  const recentXConnectorId = iconConnection.xConnectorId;
2004
3196
  const detail = await request({
2005
3197
  type: "REQUEST_ADDRESS" /* REQUEST_ADDRESS */
2006
3198
  });
2007
3199
  if (detail?.type === "RESPONSE_ADDRESS" /* RESPONSE_ADDRESS */) {
2008
- useXWagmiStore.setState({
2009
- xConnections: {
2010
- ...useXWagmiStore.getState().xConnections,
2011
- ICON: {
2012
- xAccount: {
2013
- address: detail?.payload,
2014
- xChainType: "ICON"
2015
- },
2016
- xConnectorId: recentXConnectorId
2017
- }
2018
- }
3200
+ useXWalletStore.getState().setXConnection("ICON", {
3201
+ xAccount: {
3202
+ address: detail?.payload,
3203
+ xChainType: "ICON"
3204
+ },
3205
+ xConnectorId: recentXConnectorId
2019
3206
  });
2020
3207
  }
2021
3208
  };
3209
+ function isWallet(value) {
3210
+ return Object.values(walletBase.Wallet).some((v) => v === value);
3211
+ }
2022
3212
  var reconnectInjective = async () => {
2023
- const injectiveConnection = useXWagmiStore.getState().xConnections.INJECTIVE;
3213
+ const injectiveConnection = useXWalletStore.getState().xConnections.INJECTIVE;
2024
3214
  if (!injectiveConnection) return;
2025
3215
  const recentXConnectorId = injectiveConnection.xConnectorId;
3216
+ if (!isWallet(recentXConnectorId)) {
3217
+ console.warn(`[Injective] Stale wallet ID skipped: ${recentXConnectorId}`);
3218
+ return;
3219
+ }
2026
3220
  const walletStrategy = InjectiveXService.getInstance().walletStrategy;
2027
3221
  await walletStrategy.setWallet(recentXConnectorId);
2028
3222
  const addresses = await walletStrategy.getAddresses();
2029
- const address = walletBase.isEvmBrowserWallet(recentXConnectorId) ? sdkTs.getInjectiveAddress(addresses?.[0]) : addresses?.[0];
2030
- useXWagmiStore.setState({
2031
- xConnections: {
2032
- ...useXWagmiStore.getState().xConnections,
2033
- INJECTIVE: {
2034
- xAccount: {
2035
- address,
2036
- xChainType: "INJECTIVE"
2037
- },
2038
- xConnectorId: recentXConnectorId
2039
- }
2040
- }
3223
+ const firstAddress = addresses?.[0];
3224
+ if (!firstAddress) return;
3225
+ const address = walletBase.isEvmBrowserWallet(recentXConnectorId) ? sdkTs.getInjectiveAddress(firstAddress) : firstAddress;
3226
+ useXWalletStore.getState().setXConnection("INJECTIVE", {
3227
+ xAccount: {
3228
+ address,
3229
+ xChainType: "INJECTIVE"
3230
+ },
3231
+ xConnectorId: recentXConnectorId
2041
3232
  });
2042
3233
  };
2043
3234
 
2044
3235
  // src/xchains/stellar/actions.ts
2045
3236
  var reconnectStellar = async () => {
2046
- const stellarConnection = useXWagmiStore.getState().xConnections.STELLAR;
3237
+ const stellarConnection = useXWalletStore.getState().xConnections.STELLAR;
2047
3238
  if (!stellarConnection) return;
2048
3239
  const recentXConnectorId = stellarConnection.xConnectorId;
2049
3240
  const stellarWalletKit = StellarXService.getInstance().walletsKit;
2050
3241
  stellarWalletKit.setWallet(recentXConnectorId);
2051
3242
  const { address } = await stellarWalletKit.getAddress();
2052
- useXWagmiStore.setState({
2053
- xConnections: {
2054
- ...useXWagmiStore.getState().xConnections,
2055
- STELLAR: {
2056
- xAccount: {
2057
- address,
2058
- xChainType: "STELLAR"
2059
- },
2060
- xConnectorId: recentXConnectorId
2061
- }
2062
- }
3243
+ useXWalletStore.getState().setXConnection("STELLAR", {
3244
+ xAccount: {
3245
+ address,
3246
+ xChainType: "STELLAR"
3247
+ },
3248
+ xConnectorId: recentXConnectorId
2063
3249
  });
2064
3250
  };
2065
- var queryClient = new reactQuery.QueryClient();
2066
- var defaultOptions = {
2067
- wagmi: {
2068
- reconnectOnMount: false,
2069
- ssr: true
2070
- },
2071
- solana: {
2072
- autoConnect: true
2073
- },
2074
- sui: {
2075
- autoConnect: true
3251
+
3252
+ // src/hooks/useInitChainServices.ts
3253
+ function useInitChainServices(walletConfig) {
3254
+ const initChainServices = useXWalletStore((state) => state.initChainServices);
3255
+ const cleanupDisabledConnections = useXWalletStore((state) => state.cleanupDisabledConnections);
3256
+ react.useEffect(() => {
3257
+ initChainServices(walletConfig);
3258
+ const afterHydration = () => {
3259
+ cleanupDisabledConnections();
3260
+ const store = useXWalletStore.getState();
3261
+ for (const chainType of Object.keys(store.xConnections)) {
3262
+ if (!chainRegistry[chainType]?.createWalletProvider) continue;
3263
+ const conn = store.xConnections[chainType];
3264
+ if (conn) store.setXConnection(chainType, conn);
3265
+ }
3266
+ if (walletConfig.ICON) {
3267
+ reconnectIcon().catch((error) => console.warn("[wallet-sdk-react] ICON reconnect failed:", error));
3268
+ }
3269
+ if (walletConfig.INJECTIVE) {
3270
+ reconnectInjective().catch((error) => console.warn("[wallet-sdk-react] Injective reconnect failed:", error));
3271
+ }
3272
+ if (walletConfig.STELLAR) {
3273
+ reconnectStellar().catch((error) => console.warn("[wallet-sdk-react] Stellar reconnect failed:", error));
3274
+ }
3275
+ };
3276
+ if (useXWalletStore.persist.hasHydrated()) {
3277
+ afterHydration();
3278
+ } else {
3279
+ useXWalletStore.persist.onFinishHydration(afterHydration);
3280
+ }
3281
+ }, []);
3282
+ }
3283
+ var SodaxWalletProvider = ({ children, config }) => {
3284
+ const configRef = react.useRef(config);
3285
+ const frozen = configRef.current;
3286
+ useInitChainServices(frozen);
3287
+ let content = /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
3288
+ if (frozen.SOLANA) {
3289
+ content = /* @__PURE__ */ jsxRuntime.jsx(SolanaProvider, { config: frozen.SOLANA, children: content });
2076
3290
  }
3291
+ if (frozen.SUI) {
3292
+ content = /* @__PURE__ */ jsxRuntime.jsx(SuiProvider, { config: frozen.SUI, children: content });
3293
+ }
3294
+ if (frozen.EVM) {
3295
+ content = /* @__PURE__ */ jsxRuntime.jsx(EvmProvider, { config: frozen.EVM, children: content });
3296
+ }
3297
+ return /* @__PURE__ */ jsxRuntime.jsx(WalletConfigProvider, { value: frozen, children: content });
2077
3298
  };
2078
- var SodaxWalletProvider = ({ children, rpcConfig, options, initialState }) => {
2079
- const wagmi$1 = React2.useMemo(() => ({ ...defaultOptions.wagmi, ...options?.wagmi }), [options?.wagmi]);
2080
- const wagmiConfig = React2.useMemo(() => {
2081
- return createWagmiConfig(rpcConfig, wagmi$1);
2082
- }, [rpcConfig, wagmi$1]);
2083
- const wallets = React2.useMemo(() => [new walletAdapterWallets.UnsafeBurnerWalletAdapter()], []);
2084
- const solana = React2.useMemo(() => ({ ...defaultOptions.solana, ...options?.solana }), [options?.solana]);
2085
- const sui = React2.useMemo(() => ({ ...defaultOptions.sui, ...options?.sui }), [options?.sui]);
2086
- return /* @__PURE__ */ React2__default.default.createElement(reactQuery.QueryClientProvider, { client: queryClient }, /* @__PURE__ */ React2__default.default.createElement(wagmi.WagmiProvider, { reconnectOnMount: wagmi$1.reconnectOnMount, config: wagmiConfig, initialState }, /* @__PURE__ */ React2__default.default.createElement(dappKit.SuiClientProvider, { networks: { mainnet: { url: client.getFullnodeUrl("mainnet") } }, defaultNetwork: "mainnet" }, /* @__PURE__ */ React2__default.default.createElement(dappKit.WalletProvider, { autoConnect: sui.autoConnect }, /* @__PURE__ */ React2__default.default.createElement(walletAdapterReact.ConnectionProvider, { endpoint: rpcConfig["solana"] ?? "https://api.mainnet-beta.solana.com" }, /* @__PURE__ */ React2__default.default.createElement(walletAdapterReact.WalletProvider, { wallets, autoConnect: solana.autoConnect }, /* @__PURE__ */ React2__default.default.createElement(Hydrate, { rpcConfig }), children))))));
2087
- };
2088
- reconnectIcon();
2089
- reconnectInjective();
2090
- reconnectStellar();
2091
-
2092
- // src/types/index.ts
2093
- var WalletId = /* @__PURE__ */ ((WalletId2) => {
2094
- WalletId2["METAMASK"] = "metamask";
2095
- WalletId2["HANA"] = "hana";
2096
- WalletId2["PHANTOM"] = "phantom";
2097
- WalletId2["SUI"] = "sui";
2098
- WalletId2["KEPLR"] = "keplr";
2099
- return WalletId2;
2100
- })(WalletId || {});
2101
3299
 
2102
- exports.BitcoinXConnector = BitcoinXConnector;
2103
- exports.BitcoinXService = BitcoinXService;
2104
- exports.EvmXConnector = EvmXConnector;
2105
- exports.EvmXService = EvmXService;
2106
- exports.IconHanaXConnector = IconHanaXConnector;
2107
- exports.IconXService = IconXService;
2108
- exports.InjectiveXConnector = InjectiveXConnector;
2109
- exports.InjectiveXService = InjectiveXService;
2110
- exports.OKXXConnector = OKXXConnector;
2111
- exports.STACKS_PROVIDERS = STACKS_PROVIDERS;
2112
3300
  exports.SodaxWalletProvider = SodaxWalletProvider;
2113
- exports.SolanaXConnector = SolanaXConnector;
2114
- exports.SolanaXService = SolanaXService;
2115
- exports.StacksXConnector = StacksXConnector;
2116
- exports.StacksXService = StacksXService;
2117
- exports.StellarWalletsKitXConnector = StellarWalletsKitXConnector;
2118
- exports.StellarXService = StellarXService;
2119
- exports.SuiXConnector = SuiXConnector;
2120
- exports.SuiXService = SuiXService;
2121
- exports.UnisatXConnector = UnisatXConnector;
2122
- exports.WalletId = WalletId;
3301
+ exports.WalletConfigProvider = WalletConfigProvider;
2123
3302
  exports.XConnector = XConnector;
2124
3303
  exports.XService = XService;
2125
- exports.XverseXConnector = XverseXConnector;
2126
- exports.createWagmi = createWagmiConfig;
2127
- exports.createWagmiConfig = createWagmiConfig;
3304
+ exports.getEntryDefaults = getEntryDefaults;
3305
+ exports.getRpcUrl = getRpcUrl;
2128
3306
  exports.getWagmiChainId = getWagmiChainId;
2129
3307
  exports.getXChainType = getXChainType;
2130
3308
  exports.getXService = getXService;
2131
3309
  exports.isNativeToken = isNativeToken;
2132
- exports.useBitcoinXConnectors = useBitcoinXConnectors;
3310
+ exports.resolveEvmDefaults = resolveEvmDefaults;
3311
+ exports.sortConnectors = sortConnectors;
3312
+ exports.useBatchConnect = useBatchConnect;
3313
+ exports.useBatchDisconnect = useBatchDisconnect;
3314
+ exports.useChainGroups = useChainGroups;
3315
+ exports.useConnectedChains = useConnectedChains;
3316
+ exports.useConnectionFlow = useConnectionFlow;
3317
+ exports.useEnabledChainTypes = useEnabledChainTypes;
3318
+ exports.useEnabledChains = useEnabledChains;
2133
3319
  exports.useEvmSwitchChain = useEvmSwitchChain;
2134
- exports.useStacksXConnectors = useStacksXConnectors;
3320
+ exports.useIsChainEnabled = useIsChainEnabled;
3321
+ exports.useIsWalletInstalled = useIsWalletInstalled;
3322
+ exports.useWalletConfig = useWalletConfig;
3323
+ exports.useWalletModal = useWalletModal;
2135
3324
  exports.useWalletProvider = useWalletProvider;
2136
3325
  exports.useXAccount = useXAccount;
2137
3326
  exports.useXAccounts = useXAccounts;
2138
- exports.useXBalances = useXBalances;
2139
3327
  exports.useXConnect = useXConnect;
2140
3328
  exports.useXConnection = useXConnection;
3329
+ exports.useXConnections = useXConnections;
2141
3330
  exports.useXConnectors = useXConnectors;
3331
+ exports.useXConnectorsByChain = useXConnectorsByChain;
2142
3332
  exports.useXDisconnect = useXDisconnect;
2143
3333
  exports.useXService = useXService;
3334
+ exports.useXServices = useXServices;
2144
3335
  exports.useXSignMessage = useXSignMessage;
2145
- exports.useXWagmiStore = useXWagmiStore;
2146
3336
  //# sourceMappingURL=index.cjs.map
2147
3337
  //# sourceMappingURL=index.cjs.map