@sodax/wallet-sdk-react 2.0.0-rc.10 → 2.0.0-rc.12

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.
@@ -1,16 +1,16 @@
1
1
  import { StellarWalletsKitXConnector, StellarXService } from './chunk-X7BHR7WS.mjs';
2
2
  import { SuiXService } from './chunk-JQ4H4GJ5.mjs';
3
3
  import { EvmXService } from './chunk-Z5GXDHGL.mjs';
4
- import { InjectiveXConnector, InjectiveXService } from './chunk-MWWVB7TD.mjs';
5
- import { NearXConnector, NearXService } from './chunk-C6M34IVL.mjs';
6
- import { SolanaXService } from './chunk-FSOGMSJH.mjs';
7
4
  import { IconHanaXConnector, CHAIN_INFO, IconXService } from './chunk-WPZOLGVB.mjs';
8
5
  import { assert, isRecord, hasFunctionProperty } from './chunk-TACW7Z4D.mjs';
6
+ import { InjectiveXConnector, InjectiveXService } from './chunk-MWWVB7TD.mjs';
7
+ import { NearXConnector, NearXService } from './chunk-C6M34IVL.mjs';
9
8
  import { BITCOIN_DEFAULT_RPC_URL, WALLET_METADATA } from './chunk-NAKCAL2M.mjs';
9
+ import { SolanaXService } from './chunk-VPNYFVP6.mjs';
10
10
  import { isNativeToken, getEntryDefaults, getRpcUrl } from './chunk-7V7O3Q7Y.mjs';
11
11
  import { StacksXConnector, STACKS_PROVIDERS, StacksXService } from './chunk-OPYSVPRW.mjs';
12
12
  import { XConnector, XService } from './chunk-IFXZQW4C.mjs';
13
- import { ChainTypeArr, baseChainInfo, ChainKeys, detectBitcoinAddressType, CHAIN_KEYS } from '@sodax/types';
13
+ import { ChainTypeArr, baseChainInfo, ChainKeys, usesBip322MessageSigning, detectBitcoinAddressType, CHAIN_KEYS } from '@sodax/types';
14
14
  import { AddressPurpose, MessageSigningProtocols } from 'sats-connect';
15
15
  import { createContext, useMemo, useSyncExternalStore, useCallback, useState, useRef, useContext, useEffect } from 'react';
16
16
  import { create } from 'zustand';
@@ -262,7 +262,7 @@ var XverseWalletProvider = class {
262
262
  var XVERSE_ADDRESS_TYPE_KEY = "xverse-address-type";
263
263
  var XverseXConnector = class _XverseXConnector extends BitcoinXConnector {
264
264
  walletProvider;
265
- /** Address purpose used when connecting. Taproot (Ordinals) by default to match Radfi. */
265
+ /** Address purpose used when connecting. Taproot (Ordinals) by default to match Bound Exchange. */
266
266
  addressPurpose;
267
267
  constructor(defaults) {
268
268
  super("Xverse", "xverse", defaults);
@@ -510,27 +510,16 @@ var chainRegistry = {
510
510
  }
511
511
  const address = connection?.xAccount.address;
512
512
  if (!address) throw new Error("Bitcoin address not found");
513
- const addressType = detectBitcoinAddressType(address);
514
- switch (addressType) {
515
- case "P2WPKH":
516
- case "P2TR": {
517
- if (!hasSignBip322(connector)) {
518
- throw new Error(`${connector.id} does not support BIP-322 signing`);
519
- }
520
- return connector.signBip322Message(message);
521
- }
522
- case "P2SH":
523
- case "P2PKH": {
524
- if (!hasSignEcdsa(connector)) {
525
- throw new Error(`${connector.id} does not support ECDSA signing`);
526
- }
527
- return connector.signEcdsaMessage(message);
528
- }
529
- default: {
530
- const _exhaustiveCheck = addressType;
531
- throw new Error(`Unhandled Bitcoin address type: ${_exhaustiveCheck}`);
513
+ if (usesBip322MessageSigning(detectBitcoinAddressType(address))) {
514
+ if (!hasSignBip322(connector)) {
515
+ throw new Error(`${connector.id} does not support BIP-322 signing`);
532
516
  }
517
+ return connector.signBip322Message(message);
518
+ }
519
+ if (!hasSignEcdsa(connector)) {
520
+ throw new Error(`${connector.id} does not support ECDSA signing`);
533
521
  }
522
+ return connector.signEcdsaMessage(message);
534
523
  }
535
524
  }),
536
525
  createWalletProvider: (service, getStore) => {
@@ -1,7 +1,7 @@
1
1
  import { isNativeToken } from './chunk-7V7O3Q7Y.mjs';
2
2
  import { XService } from './chunk-IFXZQW4C.mjs';
3
3
  import { PublicKey } from '@solana/web3.js';
4
- import { getAssociatedTokenAddressSync, getAccount } from '@solana/spl-token';
4
+ import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, unpackAccount } from '@solana/spl-token';
5
5
 
6
6
  var SolanaXService = class _SolanaXService extends XService {
7
7
  static instance;
@@ -27,9 +27,23 @@ var SolanaXService = class _SolanaXService extends XService {
27
27
  const newBalance = await connection.getBalance(new PublicKey(address));
28
28
  return BigInt(newBalance);
29
29
  }
30
- const tokenAccountPubkey = getAssociatedTokenAddressSync(new PublicKey(xToken.address), new PublicKey(address));
31
- const tokenAccount = await getAccount(connection, tokenAccountPubkey);
32
- return BigInt(tokenAccount.amount);
30
+ const owner = new PublicKey(address);
31
+ const mint = new PublicKey(xToken.address);
32
+ const candidates = [TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID].map((programId) => ({
33
+ programId,
34
+ ata: getAssociatedTokenAddressSync(mint, owner, true, programId)
35
+ }));
36
+ const accounts = await connection.getMultipleAccountsInfo(candidates.map((c) => c.ata));
37
+ let balance = BigInt(0);
38
+ for (const [i, candidate] of candidates.entries()) {
39
+ const info = accounts[i];
40
+ if (!info) continue;
41
+ try {
42
+ balance += unpackAccount(candidate.ata, info, candidate.programId).amount;
43
+ } catch {
44
+ }
45
+ }
46
+ return balance;
33
47
  } catch {
34
48
  return BigInt(0);
35
49
  }
@@ -1,4 +1,4 @@
1
- import { SolanaXService } from './chunk-FSOGMSJH.mjs';
1
+ import { SolanaXService } from './chunk-VPNYFVP6.mjs';
2
2
  import { XConnector } from './chunk-IFXZQW4C.mjs';
3
3
 
4
4
  // src/xchains/solana/SolanaXConnector.ts
package/dist/index.mjs CHANGED
@@ -1,15 +1,15 @@
1
- import { WalletConfigProvider, useXWalletStore, whenPersistReady, chainRegistry, useWalletConfig, usePersistHydrated } from './chunk-DQTYAMKF.mjs';
2
- export { WalletConfigProvider, getXChainType, getXService, useBatchConnect, useBatchDisconnect, useChainGroups, useConnectedChains, useConnectionFlow, useEnabledChainTypes, useEnabledChains, useEvmSwitchChain, useIsChainEnabled, useIsWalletInstalled, useWalletConfig, useWalletModal, useWalletProvider, useXAccount, useXAccounts, useXConnect, useXConnection, useXConnections, useXConnectors, useXConnectorsByChain, useXDisconnect, useXService, useXServices, useXSignMessage } from './chunk-DQTYAMKF.mjs';
1
+ import { WalletConfigProvider, useXWalletStore, whenPersistReady, chainRegistry, useWalletConfig, usePersistHydrated } from './chunk-5XBNBT3J.mjs';
2
+ export { WalletConfigProvider, getXChainType, getXService, useBatchConnect, useBatchDisconnect, useChainGroups, useConnectedChains, useConnectionFlow, useEnabledChainTypes, useEnabledChains, useEvmSwitchChain, useIsChainEnabled, useIsWalletInstalled, useWalletConfig, useWalletModal, useWalletProvider, useXAccount, useXAccounts, useXConnect, useXConnection, useXConnections, useXConnectors, useXConnectorsByChain, useXDisconnect, useXService, useXServices, useXSignMessage } from './chunk-5XBNBT3J.mjs';
3
3
  import { StellarXService } from './chunk-X7BHR7WS.mjs';
4
4
  import { SuiXService, SuiXConnector } from './chunk-JQ4H4GJ5.mjs';
5
5
  import { createWagmiConfig, EvmXService, EvmXConnector } from './chunk-Z5GXDHGL.mjs';
6
- import { InjectiveXService } from './chunk-MWWVB7TD.mjs';
7
- import './chunk-C6M34IVL.mjs';
8
- import { SolanaXConnector } from './chunk-LKSSME2J.mjs';
9
- import { SolanaXService } from './chunk-FSOGMSJH.mjs';
10
6
  import { request } from './chunk-WPZOLGVB.mjs';
11
7
  import { assertSuiProviderShape } from './chunk-TACW7Z4D.mjs';
8
+ import { InjectiveXService } from './chunk-MWWVB7TD.mjs';
9
+ import './chunk-C6M34IVL.mjs';
12
10
  import { SOLANA_DEFAULT_AUTO_CONNECT, SOLANA_DEFAULT_RPC_URL, SUI_DEFAULT_AUTO_CONNECT, SUI_DEFAULT_NETWORK, EVM_DEFAULT_RECONNECT_ON_MOUNT, EVM_DEFAULT_SSR, SOLANA_METAMASK_CONNECT_TIMEOUT_MS } from './chunk-NAKCAL2M.mjs';
11
+ import { SolanaXConnector } from './chunk-XJA2MJMG.mjs';
12
+ import { SolanaXService } from './chunk-VPNYFVP6.mjs';
13
13
  import { getEntryDefaults, resolveEvmDefaults } from './chunk-7V7O3Q7Y.mjs';
14
14
  export { getEntryDefaults, getRpcUrl, getWagmiChainId, isNativeToken, resolveEvmDefaults, sortConnectors } from './chunk-7V7O3Q7Y.mjs';
15
15
  import './chunk-OPYSVPRW.mjs';
@@ -69,7 +69,7 @@ declare class UnisatXConnector extends BitcoinXConnector {
69
69
 
70
70
  declare class XverseXConnector extends BitcoinXConnector {
71
71
  private walletProvider;
72
- /** Address purpose used when connecting. Taproot (Ordinals) by default to match Radfi. */
72
+ /** Address purpose used when connecting. Taproot (Ordinals) by default to match Bound Exchange. */
73
73
  addressPurpose: AddressPurpose;
74
74
  constructor(defaults?: BitcoinWalletDefaults);
75
75
  /** Set address purpose and persist to localStorage. */
@@ -1,13 +1,13 @@
1
- export { BitcoinXConnector, BitcoinXService, OKXXConnector, UnisatXConnector, XverseXConnector, useBitcoinXConnectors } from '../../chunk-DQTYAMKF.mjs';
1
+ export { BitcoinXConnector, BitcoinXService, OKXXConnector, UnisatXConnector, XverseXConnector, useBitcoinXConnectors } from '../../chunk-5XBNBT3J.mjs';
2
2
  import '../../chunk-X7BHR7WS.mjs';
3
3
  import '../../chunk-JQ4H4GJ5.mjs';
4
4
  import '../../chunk-Z5GXDHGL.mjs';
5
- import '../../chunk-MWWVB7TD.mjs';
6
- import '../../chunk-C6M34IVL.mjs';
7
- import '../../chunk-FSOGMSJH.mjs';
8
5
  import '../../chunk-WPZOLGVB.mjs';
9
6
  import '../../chunk-TACW7Z4D.mjs';
7
+ import '../../chunk-MWWVB7TD.mjs';
8
+ import '../../chunk-C6M34IVL.mjs';
10
9
  import '../../chunk-NAKCAL2M.mjs';
10
+ import '../../chunk-VPNYFVP6.mjs';
11
11
  import '../../chunk-7V7O3Q7Y.mjs';
12
12
  import '../../chunk-OPYSVPRW.mjs';
13
13
  import '../../chunk-QMXBY3UI.mjs';
@@ -1,5 +1,5 @@
1
- export { SolanaXConnector } from '../../chunk-LKSSME2J.mjs';
2
- export { SolanaXService } from '../../chunk-FSOGMSJH.mjs';
1
+ export { SolanaXConnector } from '../../chunk-XJA2MJMG.mjs';
2
+ export { SolanaXService } from '../../chunk-VPNYFVP6.mjs';
3
3
  import '../../chunk-7V7O3Q7Y.mjs';
4
4
  import '../../chunk-QMXBY3UI.mjs';
5
5
  import '../../chunk-IFXZQW4C.mjs';
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "access": "public"
6
6
  },
7
7
  "license": "MIT",
8
- "version": "2.0.0-rc.10",
8
+ "version": "2.0.0-rc.12",
9
9
  "description": "Wallet SDK of Sodax",
10
10
  "keywords": [
11
11
  "sodax",
@@ -29,8 +29,7 @@
29
29
  "files": [
30
30
  "dist",
31
31
  "!dist/**/*.map",
32
- "README.md",
33
- "docs"
32
+ "README.md"
34
33
  ],
35
34
  "sideEffects": false,
36
35
  "exports": {
@@ -76,9 +75,9 @@
76
75
  "viem": "2.29.2",
77
76
  "wagmi": "2.16.9",
78
77
  "zustand": "4.5.2",
79
- "@sodax/types": "2.0.0-rc.10",
80
- "@sodax/libs": "2.0.0-rc.10",
81
- "@sodax/wallet-sdk-core": "2.0.0-rc.10"
78
+ "@sodax/libs": "2.0.0-rc.12",
79
+ "@sodax/wallet-sdk-core": "2.0.0-rc.12",
80
+ "@sodax/types": "2.0.0-rc.12"
82
81
  },
83
82
  "devDependencies": {
84
83
  "@arethetypeswrong/cli": "0.17.4",
@@ -1,440 +0,0 @@
1
- # Adding a New Chain
2
-
3
- This document is the contributor workflow for onboarding a new chain family (e.g. Aptos, Cosmos, …) into `@sodax/wallet-sdk-react`. Most steps are mechanical because the central abstractions (`ChainMeta`, `chainRegistry`, sub-path exports) auto-derive downstream types — adding a chain is mostly **filling in entries**, not rewriting hooks.
4
-
5
- Prerequisite: read [`ARCHITECTURE.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/ARCHITECTURE.md) first, especially the [Provider-managed vs non-provider](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/ARCHITECTURE.md#provider-managed-vs-non-provider-chains) split — that decision drives the rest of this guide.
6
-
7
- ## Table of contents
8
-
9
- 1. [Decision tree — provider-managed or not?](#decision-tree--provider-managed-or-not)
10
- 2. [Step 1 — types in `@sodax/types`](#step-1--types-in-sodaxtypes)
11
- 3. [Step 2 — wallet provider in `@sodax/wallet-sdk-core`](#step-2--wallet-provider-in-sodaxwallet-sdk-core)
12
- 4. [Step 3 — `XService` + `XConnector` in `xchains/<chain>/`](#step-3--xservice--xconnector-in-xchainschain)
13
- 5. [Step 4 — `xchains/<chain>/index.ts` barrel for sub-path export](#step-4--xchainschainindexts-barrel-for-sub-path-export)
14
- 6. [Step 5 — `ChainMeta` entry in `types/config.ts`](#step-5--chainmeta-entry-in-typesconfigts)
15
- 7. [Step 6 — register in `chainRegistry`](#step-6--register-in-chainregistry)
16
- 8. [Step 7 — provider-managed only — Provider/Hydrator/Actions trio](#step-7--provider-managed-only--providerhydratoractions-trio)
17
- 9. [Step 8 — barrel surface (`src/index.ts`)](#step-8--barrel-surface-srcindexts)
18
- 10. [Step 9 — tests](#step-9--tests)
19
- 11. [Verification checklist](#verification-checklist)
20
-
21
- ---
22
-
23
- ## Decision tree — provider-managed or not?
24
-
25
- Set `providerManaged: true` if **any** of these is true:
26
-
27
- - The chain ships a React adapter library (wagmi, `@solana/wallet-adapter-react`, `@mysten/dapp-kit`, etc.) that you want to use.
28
- - The wallet-side SDK requires a long-lived React context to register handlers and survive component re-renders.
29
- - Wallet discovery is reactive (EIP-6963 announcements, dynamic adapter registration) and you want components to re-render automatically.
30
-
31
- Set `providerManaged: false` if:
32
-
33
- - You can probe `window.<wallet>` synchronously per-call.
34
- - Connection lifecycle is short-lived (call `connect()`, get an account back, no React context needed).
35
- - The native SDK is plain TS classes/functions with no React glue (e.g. `sats-connect`, `icon-sdk-js`).
36
-
37
- **Mixing** — you can have a non-provider chain whose `discoverConnectors` is async (Stellar). That's still `providerManaged: false` because the connectors are static after discovery; the React adapter pattern isn't used.
38
-
39
- ---
40
-
41
- ## Step 1 — types in `@sodax/types`
42
-
43
- Add the chain's identity and types to `packages/types/src/`:
44
-
45
- 1. **Chain key** in [`packages/types/src/chains/chain-keys.ts`](https://github.com/icon-project/sodax-sdks/blob/main/packages/types/src/chains/chain-keys.ts):
46
- ```typescript
47
- export const ChainKeys = {
48
- ...
49
- APTOS_MAINNET: 'aptos',
50
- };
51
- ```
52
- 2. **Chain type** in `ChainTypeArr`:
53
- ```typescript
54
- export const ChainTypeArr = [..., 'APTOS'] as const;
55
- ```
56
- 3. **Chain key type alias**:
57
- ```typescript
58
- export type AptosChainKey = typeof ChainKeys.APTOS_MAINNET;
59
- ```
60
- 4. **Chain info entry** in [`packages/types/src/chains/chains.ts`](https://github.com/icon-project/sodax-sdks/blob/main/packages/types/src/chains/chains.ts) (`baseChainInfo`):
61
- ```typescript
62
- [ChainKeys.APTOS_MAINNET]: { type: 'APTOS', chainId: '0x1' /* or numeric */, displayName: 'Aptos' }
63
- ```
64
- 5. **Wallet provider interface** in `packages/types/src/aptos.ts`:
65
- ```typescript
66
- export interface IAptosWalletProvider extends WalletAddressProvider {
67
- readonly chainType: 'APTOS';
68
- // chain-specific methods: signAndSubmitTransaction, signMessage, ...
69
- }
70
- ```
71
- 6. **Add to root barrel** if you want it re-exported from `@sodax/types`, or leave as a sub-package export per [`packages/types/CLAUDE.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/types/CLAUDE.md).
72
-
73
- The `ChainKey` and `ChainType` unions auto-derive — once these entries land, downstream code in `@sodax/sdk` and `@sodax/wallet-sdk-react` sees the new chain at the type level.
74
-
75
- ---
76
-
77
- ## Step 2 — wallet provider in `@sodax/wallet-sdk-core`
78
-
79
- Add `packages/wallet-sdk-core/src/wallet-providers/aptos/`:
80
-
81
- ```
82
- aptos/
83
- ├── AptosWalletProvider.ts
84
- ├── AptosWalletProvider.test.ts
85
- ├── types.ts # PrivateKey<chain>WalletConfig + BrowserExtension<chain>WalletConfig + AptosWalletDefaults
86
- └── index.ts # Barrel re-export
87
- ```
88
-
89
- `AptosWalletProvider` extends `BaseWalletProvider<AptosWalletDefaults>` and implements `IAptosWalletProvider`. Discriminated config — pick a discriminant pattern:
90
-
91
- - **Field presence** (no `type` field): `privateKey` field present vs. absent. Most chains use this.
92
- - **Explicit `type`**: `'PRIVATE_KEY'` | `'BROWSER_EXTENSION'`. Use when both modes share fields that would clash without a discriminant (Bitcoin, Stellar).
93
-
94
- See [`packages/wallet-sdk-core/CLAUDE.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-core/CLAUDE.md#config-variants-discriminants) for the canonical patterns.
95
-
96
- Re-export from `packages/wallet-sdk-core/src/wallet-providers/index.ts`:
97
-
98
- ```typescript
99
- export * from './aptos/index.js';
100
- ```
101
-
102
- ---
103
-
104
- ## Step 3 — `XService` + `XConnector` in `xchains/<chain>/`
105
-
106
- Create `packages/wallet-sdk-react/src/xchains/aptos/`:
107
-
108
- ```
109
- aptos/
110
- ├── AptosXService.ts
111
- ├── AptosXConnector.ts
112
- ├── AptosXConnector.test.ts
113
- └── index.ts
114
- ```
115
-
116
- ### `AptosXService`
117
-
118
- Singleton that owns the connector list and exposes balance reads. Extend the abstract `XService`:
119
-
120
- ```typescript
121
- import type { XToken } from '@sodax/types';
122
- import { XService } from '@/core/index.js';
123
-
124
- export class AptosXService extends XService {
125
- private static instance: AptosXService | undefined;
126
-
127
- static getInstance(rpcConfig?: { rpcUrl?: string }): AptosXService {
128
- if (!AptosXService.instance) AptosXService.instance = new AptosXService(rpcConfig);
129
- return AptosXService.instance;
130
- }
131
-
132
- // chain-specific state (RPC client, etc.)
133
-
134
- async getBalance(address: string, xToken: XToken): Promise<bigint> {
135
- // …
136
- }
137
- }
138
- ```
139
-
140
- ### `AptosXConnector`
141
-
142
- Extend `XConnector`. The base class provides `id`, `icon`, `isInstalled = true` defaults; override `isInstalled` / `installUrl` for browser-extension-backed connectors:
143
-
144
- ```typescript
145
- import { XConnector } from '@/core/index.js';
146
- import type { XAccount } from '@/types/index.js';
147
-
148
- export class AptosWalletXConnector extends XConnector {
149
- constructor() {
150
- super('APTOS', 'Aptos Wallet', 'aptos.wallet');
151
- }
152
-
153
- override get isInstalled(): boolean {
154
- return typeof window !== 'undefined' && 'aptos' in window;
155
- }
156
-
157
- override get installUrl(): string {
158
- return 'https://chrome.google.com/webstore/detail/...';
159
- }
160
-
161
- async connect(): Promise<XAccount | undefined> {
162
- const account = await window.aptos.connect();
163
- return account ? { address: account.address, xChainType: 'APTOS', publicKey: account.publicKey } : undefined;
164
- }
165
-
166
- async disconnect(): Promise<void> {
167
- await window.aptos.disconnect();
168
- }
169
- }
170
- ```
171
-
172
- For chains with multiple wallets (Bitcoin: Unisat / Xverse / OKX; Injective: MetaMask / Keplr / Leap), create one `XConnector` subclass per wallet and have an abstract intermediate base if shared logic exists (Bitcoin uses `BitcoinXConnector` abstract).
173
-
174
- ---
175
-
176
- ## Step 4 — `xchains/<chain>/index.ts` barrel for sub-path export
177
-
178
- Create the barrel that powers `@sodax/wallet-sdk-react/xchains/aptos`:
179
-
180
- ```typescript
181
- // src/xchains/aptos/index.ts
182
- export { AptosXService } from './AptosXService.js';
183
- export { AptosWalletXConnector } from './AptosXConnector.js';
184
- ```
185
-
186
- `tsup.config.ts` already picks up `src/xchains/*/index.ts` via glob — **no config edit needed**. The sub-path export will resolve as `@sodax/wallet-sdk-react/xchains/aptos`.
187
-
188
- See [`SUB_PATH_EXPORTS.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/SUB_PATH_EXPORTS.md) for the export plumbing.
189
-
190
- ---
191
-
192
- ## Step 5 — `ChainMeta` entry in `types/config.ts`
193
-
194
- [`ChainMeta`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/src/types/config.ts) is the **single source of truth** for per-chain-type metadata. `SodaxWalletConfig`, `ChainTypeConfig<T>`, `ChainEntry<K>`, `WalletDefaultsByKey<K>` all derive from it automatically.
195
-
196
- Add **one entry**:
197
-
198
- ```typescript
199
- export type AptosChainEntry = SimpleChainEntry<AptosWalletDefaults>;
200
-
201
- export type ChainMeta = {
202
- EVM: { ... };
203
- // ...
204
- APTOS: {
205
- keys: AptosChainKey; // from @sodax/types
206
- entry: AptosChainEntry; // { rpcUrl?, defaults? } (or richer if chain has multi-field RPC)
207
- defaults: AptosWalletDefaults;
208
- adapter: {}; // {} for non-provider chains; AptosAdapterFields if provider-managed
209
- };
210
- };
211
- ```
212
-
213
- If the chain has multi-field RPC (Stellar's horizon + soroban, Bitcoin's RPC + Radfi), define a custom entry shape that extends `*RpcConfig` from `@sodax/types`:
214
-
215
- ```typescript
216
- export type AptosChainEntry = AptosRpcConfig & { defaults?: AptosWalletDefaults };
217
- ```
218
-
219
- If provider-managed, define `AptosAdapterFields` (one value per React provider — wagmi-config-level settings, not per-chain):
220
-
221
- ```typescript
222
- export type AptosAdapterFields = {
223
- network?: 'mainnet' | 'testnet' | 'devnet';
224
- autoConnect?: boolean;
225
- };
226
- ```
227
-
228
- Add the per-chain-type alias for external typing convenience:
229
-
230
- ```typescript
231
- export type AptosTypeConfig = ChainTypeConfig<'APTOS'>;
232
- ```
233
-
234
- ---
235
-
236
- ## Step 6 — register in `chainRegistry`
237
-
238
- Add an entry to [`chainRegistry`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/src/chainRegistry.ts):
239
-
240
- ### Non-provider chain
241
-
242
- ```typescript
243
- APTOS: defineChain({
244
- createService: walletConfig =>
245
- AptosXService.getInstance({ rpcUrl: getRpcUrl(walletConfig?.APTOS?.chains?.[ChainKeys.APTOS_MAINNET]) }),
246
- displayName: 'Aptos',
247
- defaultConnectors: () => [new AptosWalletXConnector()],
248
- providerManaged: false,
249
- // Optional — provide createActions if signMessage needs custom dispatch (Bitcoin's BIP-322/ECDSA)
250
- createActions: (service, getStore) => ({
251
- ...createDefaultActions('APTOS', service, getStore),
252
- signMessage: async (message: string) => {
253
- // chain-specific signing logic
254
- },
255
- }),
256
- // Optional — provide createWalletProvider if the chain needs a wallet provider in `walletProviders` map
257
- createWalletProvider: (service, getStore) => {
258
- const connection = getStore().xConnections.APTOS;
259
- if (!connection?.xConnectorId) return undefined;
260
- const defaults = getEntryDefaults<typeof ChainKeys.APTOS_MAINNET>(
261
- getStore().walletConfig?.APTOS?.chains?.[ChainKeys.APTOS_MAINNET],
262
- );
263
- return new AptosWalletProvider({ /* ... */, defaults });
264
- },
265
- // Optional — provide discoverConnectors if connectors require async detection
266
- discoverConnectors: async (service, getStore) => {
267
- const wallets = await detectInstalledAptosWallets();
268
- const connectors = wallets.map(w => new AptosWalletXConnector(w));
269
- service.setXConnectors(connectors);
270
- getStore().setXConnectors('APTOS', connectors);
271
- },
272
- }),
273
- ```
274
-
275
- ### Provider-managed chain
276
-
277
- ```typescript
278
- APTOS: defineChain({
279
- createService: () => AptosXService.getInstance(),
280
- displayName: 'Aptos',
281
- defaultConnectors: () => [], // ignored — connectors come from the React adapter
282
- providerManaged: true,
283
- // No createActions / createWalletProvider — the Hydrator handles both.
284
- }),
285
- ```
286
-
287
- ---
288
-
289
- ## Step 7 — provider-managed only — Provider/Hydrator/Actions trio
290
-
291
- Skip this step for `providerManaged: false`.
292
-
293
- Create `packages/wallet-sdk-react/src/providers/aptos/`:
294
-
295
- ```
296
- aptos/
297
- ├── AptosProvider.tsx # Wraps native React adapter
298
- ├── AptosHydrator.tsx # Sole writer of connection state + walletProviders
299
- ├── AptosActions.tsx # Registers ChainActions (connect/disconnect/signMessage)
300
- ├── AptosHydrator.test.tsx
301
- └── index.ts
302
- ```
303
-
304
- ### `<AptosProvider>`
305
-
306
- Wraps the chain's native React provider:
307
-
308
- ```tsx
309
- import { type ReactNode } from 'react';
310
- import { AptosProvider as NativeProvider } from 'aptos-adapter-react';
311
- import { AptosHydrator } from './AptosHydrator.js';
312
- import { AptosActions } from './AptosActions.js';
313
- import type { AptosTypeConfig } from '@/types/config.js';
314
-
315
- type AptosProviderProps = {
316
- children: ReactNode;
317
- config: AptosTypeConfig;
318
- };
319
-
320
- export const AptosProvider = ({ children, config }: AptosProviderProps) => (
321
- <NativeProvider network={config.network ?? 'mainnet'} autoConnect={config.autoConnect ?? true}>
322
- <AptosHydrator />
323
- <AptosActions />
324
- {children}
325
- </NativeProvider>
326
- );
327
- ```
328
-
329
- ### `<AptosHydrator>`
330
-
331
- Sole writer. Subscribes to native SDK hooks; writes through `setXConnection` / `setWalletProvider`. **Never** writes inside an event handler — only inside `useEffect` reactions to native state.
332
-
333
- ```typescript
334
- import { useAccount } from 'aptos-adapter-react';
335
-
336
- export const AptosHydrator = () => {
337
- const { address, status, connector } = useAccount();
338
- const setXConnection = useXWalletStore(s => s.setXConnection);
339
- const unsetXConnection = useXWalletStore(s => s.unsetXConnection);
340
-
341
- useEffect(() => {
342
- if (status === 'connected' && address) {
343
- setXConnection('APTOS', { xAccount: { address, xChainType: 'APTOS' }, xConnectorId: connector.id });
344
- } else if (status === 'disconnected') {
345
- unsetXConnection('APTOS');
346
- }
347
- }, [address, status, connector]);
348
-
349
- // ... build wallet provider similarly via useMemo + setWalletProvider
350
-
351
- return null;
352
- };
353
- ```
354
-
355
- ### `<AptosActions>`
356
-
357
- Registers `ChainActions` using **refs** to native SDK functions, so the registered closures always call the latest function without re-registering:
358
-
359
- ```typescript
360
- const connectRef = useRef(connectAsync);
361
- useEffect(() => { connectRef.current = connectAsync; }, [connectAsync]);
362
-
363
- useEffect(() => {
364
- registerChainActions('APTOS', {
365
- connect: async (id) => connectRef.current({ connector: id }),
366
- disconnect: async () => disconnectRef.current(),
367
- // ...
368
- });
369
- }, []); // empty deps — register once
370
-
371
- return null;
372
- ```
373
-
374
- ### Mount in `SodaxWalletProvider.tsx`
375
-
376
- ```tsx
377
- {frozen.APTOS && (
378
- <AptosProvider config={frozen.APTOS}>
379
- {content}
380
- </AptosProvider>
381
- )}
382
- ```
383
-
384
- ---
385
-
386
- ## Step 8 — barrel surface (`src/index.ts`)
387
-
388
- **Do NOT** add `export * from './xchains/aptos'` to the root `src/index.ts`. Concrete classes stay behind sub-path imports.
389
-
390
- If consumers need a **type** from the barrel for type-only ergonomics, add an explicit `export type` line:
391
-
392
- ```typescript
393
- // src/index.ts
394
- export type { AptosWalletAddressType } from './xchains/aptos/index.js';
395
- ```
396
-
397
- This keeps runtime classes off the barrel but lets consumers `import type { AptosWalletAddressType } from '@sodax/wallet-sdk-react'` without going through the deep import for a type-only reference.
398
-
399
- See [`SUB_PATH_EXPORTS.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/SUB_PATH_EXPORTS.md) for why concrete classes are deep-imported.
400
-
401
- ---
402
-
403
- ## Step 9 — tests
404
-
405
- Required test surface per `vitest.config.ts`:
406
-
407
- - `AptosXConnector.test.ts` — connector constructor, `connect/disconnect`, `isInstalled`/`installUrl` window probes
408
- - `AptosXService.test.ts` (or co-located) — singleton behavior, balance reads
409
- - `AptosWalletProvider.test.ts` (in wallet-sdk-core) — config variants, defaults merge, core method dispatch
410
- - `AptosHydrator.test.tsx` (provider-managed only) — fake adapter state → assert store writes
411
-
412
- Pattern reference: [`EvmHydrator.test.tsx`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/src/providers/evm/EvmHydrator.test.tsx).
413
-
414
- ---
415
-
416
- ## Verification checklist
417
-
418
- Before opening a PR, walk through each item:
419
-
420
- - [ ] `pnpm checkTs` passes — `SodaxWalletConfig.APTOS` is recognized; `useWalletProvider({ xChainType: 'APTOS' })` returns the right type.
421
- - [ ] `pnpm test` passes for new files.
422
- - [ ] `pnpm build:packages` produces `dist/xchains/aptos/index.{mjs,d.ts}`.
423
- - [ ] `import { AptosXService } from '@sodax/wallet-sdk-react/xchains/aptos'` resolves in a consumer app.
424
- - [ ] `import { AptosXService } from '@sodax/wallet-sdk-react'` is **not** available (intentional — concrete classes stay behind deep imports).
425
- - [ ] Adding `APTOS: {}` to `SodaxWalletConfig` mounts the chain; omitting the slot skips it.
426
- - [ ] `useEnabledChains()` includes `'APTOS'` only when the slot is present.
427
- - [ ] Connect → disconnect cycle updates `xConnections.APTOS` correctly; `localStorage` persists.
428
- - [ ] On reload, `cleanupDisabledConnections` removes `xConnections.APTOS` if the slot is later removed.
429
- - [ ] Documentation: add an entry to the connector reference in [`CONNECTORS.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONNECTORS.md) and the chain-type tables in [`CONFIGURE_PROVIDER.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONFIGURE_PROVIDER.md).
430
-
431
- ---
432
-
433
- ## Related docs
434
-
435
- - [Architecture](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/ARCHITECTURE.md) — store + registry + Hydrator pattern
436
- - [Sub-path Exports](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/SUB_PATH_EXPORTS.md) — barrel vs deep-import boundary
437
- - [Configure SodaxWalletProvider](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONFIGURE_PROVIDER.md) — config schema (auto-extends from `ChainMeta`)
438
- - [Connectors](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-react/docs/CONNECTORS.md) — IXConnector contract + sub-path map
439
- - [`packages/wallet-sdk-core/CLAUDE.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/wallet-sdk-core/CLAUDE.md) — wallet provider class patterns
440
- - [`packages/types/CLAUDE.md`](https://github.com/icon-project/sodax-sdks/blob/main/packages/types/CLAUDE.md) — interface conventions