@sodax/wallet-sdk-core 2.0.0-rc.2 → 2.0.0-rc.4
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.
- package/README.md +1 -2
- package/dist/index.cjs +1 -4
- package/dist/index.mjs +1 -4
- package/package.json +18 -11
- package/ai-exported/AGENTS.md +0 -139
- package/ai-exported/integration/README.md +0 -108
- package/ai-exported/integration/ai-rules.md +0 -141
- package/ai-exported/integration/architecture.md +0 -212
- package/ai-exported/integration/features/README.md +0 -22
- package/ai-exported/integration/features/bitcoin.md +0 -103
- package/ai-exported/integration/features/evm.md +0 -102
- package/ai-exported/integration/features/icon.md +0 -88
- package/ai-exported/integration/features/injective.md +0 -92
- package/ai-exported/integration/features/near.md +0 -92
- package/ai-exported/integration/features/solana.md +0 -104
- package/ai-exported/integration/features/stacks.md +0 -91
- package/ai-exported/integration/features/stellar.md +0 -95
- package/ai-exported/integration/features/sui.md +0 -96
- package/ai-exported/integration/quickstart.md +0 -259
- package/ai-exported/integration/recipes/README.md +0 -15
- package/ai-exported/integration/recipes/bridge-to-sdk.md +0 -145
- package/ai-exported/integration/recipes/defaults-and-overrides.md +0 -159
- package/ai-exported/integration/recipes/library-exports.md +0 -129
- package/ai-exported/integration/recipes/setup-browser-extension.md +0 -137
- package/ai-exported/integration/recipes/setup-private-key.md +0 -115
- package/ai-exported/integration/recipes/sign-and-broadcast.md +0 -201
- package/ai-exported/integration/recipes/testing.md +0 -163
- package/ai-exported/integration/reference/README.md +0 -13
- package/ai-exported/integration/reference/chain-support.md +0 -65
- package/ai-exported/integration/reference/glossary.md +0 -28
- package/ai-exported/integration/reference/interfaces.md +0 -131
- package/ai-exported/integration/reference/provider-classes.md +0 -54
- package/ai-exported/integration/reference/public-api.md +0 -128
- package/ai-exported/migration/README.md +0 -84
- package/ai-exported/migration/ai-rules.md +0 -139
- package/ai-exported/migration/breaking-changes/README.md +0 -14
- package/ai-exported/migration/breaking-changes/base-wallet-provider.md +0 -52
- package/ai-exported/migration/breaking-changes/defaults-config.md +0 -57
- package/ai-exported/migration/breaking-changes/folder-layout.md +0 -99
- package/ai-exported/migration/breaking-changes/library-exports.md +0 -58
- package/ai-exported/migration/checklist.md +0 -62
- package/ai-exported/migration/recipes/README.md +0 -12
- package/ai-exported/migration/recipes/adopt-defaults.md +0 -84
- package/ai-exported/migration/recipes/adopt-library-exports.md +0 -99
- package/ai-exported/migration/reference/README.md +0 -12
- package/ai-exported/migration/reference/added-fields.md +0 -71
- package/ai-exported/migration/reference/deleted-exports.md +0 -35
- package/ai-exported/migration/reference/renamed-symbols.md +0 -31
- package/ai-exported/migration/reference/return-shapes.md +0 -23
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
# Quickstart — Copy/paste examples
|
|
2
|
-
|
|
3
|
-
Minimal end-to-end snippets per chain family. Pick the chain you need, copy the snippet, and run it. Each snippet covers **both** modes (private-key + browser-extension).
|
|
4
|
-
|
|
5
|
-
For chain-specific gotchas (Sui's mnemonics, Injective's `secret` wrapper, …) see [`features/<chain>.md`](./features/). For the mental model see [`architecture.md`](./architecture.md).
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Install
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
pnpm add @sodax/wallet-sdk-core @sodax/types
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
If you plan to call `@sodax/sdk` after constructing the provider, also add it:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
pnpm add @sodax/sdk
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## EVM (12 chains)
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
import { EvmWalletProvider } from '@sodax/wallet-sdk-core';
|
|
27
|
-
import { ChainKeys } from '@sodax/types';
|
|
28
|
-
|
|
29
|
-
// Private-key (Node / scripts / CI)
|
|
30
|
-
const evmPk = new EvmWalletProvider({
|
|
31
|
-
privateKey: '0x…',
|
|
32
|
-
chainId: ChainKeys.SONIC_MAINNET,
|
|
33
|
-
rpcUrl: 'https://rpc.soniclabs.com',
|
|
34
|
-
defaults: {
|
|
35
|
-
sendTransaction: { gas: 3_000_000n },
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
console.log(await evmPk.getWalletAddress());
|
|
39
|
-
|
|
40
|
-
// Browser-extension (consumer supplies viem clients)
|
|
41
|
-
const evmBrowser = new EvmWalletProvider({
|
|
42
|
-
walletClient: myViemWalletClient, // from wagmi / viem
|
|
43
|
-
publicClient: myViemPublicClient,
|
|
44
|
-
});
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
See [`features/evm.md`](./features/evm.md).
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Solana
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
import { SolanaWalletProvider } from '@sodax/wallet-sdk-core';
|
|
55
|
-
|
|
56
|
-
// Private-key — secret key bytes (Uint8Array length 64)
|
|
57
|
-
const solanaPk = new SolanaWalletProvider({
|
|
58
|
-
privateKey: new Uint8Array(64),
|
|
59
|
-
endpoint: 'https://api.mainnet-beta.solana.com',
|
|
60
|
-
defaults: {
|
|
61
|
-
connectionCommitment: 'confirmed',
|
|
62
|
-
sendOptions: { skipPreflight: false },
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Browser-extension — wallet adapter context
|
|
67
|
-
const solanaBrowser = new SolanaWalletProvider({
|
|
68
|
-
wallet: {
|
|
69
|
-
publicKey: myPublicKey, // PublicKey | null
|
|
70
|
-
signTransaction: mySignTransaction, // SignerWalletAdapterProps['signTransaction'] | undefined
|
|
71
|
-
},
|
|
72
|
-
endpoint: 'https://api.mainnet-beta.solana.com',
|
|
73
|
-
});
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
See [`features/solana.md`](./features/solana.md).
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Sui
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
import { SuiWalletProvider } from '@sodax/wallet-sdk-core';
|
|
84
|
-
|
|
85
|
-
// Private-key — DERIVED FROM MNEMONIC, not a raw key
|
|
86
|
-
const suiPk = new SuiWalletProvider({
|
|
87
|
-
rpcUrl: 'https://fullnode.mainnet.sui.io:443',
|
|
88
|
-
mnemonics: 'word1 word2 … word12',
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Browser-extension — wallet-standard wallet
|
|
92
|
-
const suiBrowser = new SuiWalletProvider({
|
|
93
|
-
client: mySuiClient, // SuiClient
|
|
94
|
-
wallet: myWalletWithSuiFeatures, // WalletWithFeatures<Partial<SuiWalletFeatures>>
|
|
95
|
-
account: myActiveWalletAccount, // WalletAccount
|
|
96
|
-
});
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
See [`features/sui.md`](./features/sui.md).
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## Bitcoin
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
import { BitcoinWalletProvider } from '@sodax/wallet-sdk-core';
|
|
107
|
-
|
|
108
|
-
// Private-key — uses explicit uppercase `type`
|
|
109
|
-
const btcPk = new BitcoinWalletProvider({
|
|
110
|
-
type: 'PRIVATE_KEY',
|
|
111
|
-
privateKey: '0x…',
|
|
112
|
-
network: 'TESTNET',
|
|
113
|
-
addressType: 'P2WPKH', // optional
|
|
114
|
-
defaults: { defaultFinalize: true },
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// Browser-extension — uses explicit uppercase `type`
|
|
118
|
-
const btcBrowser = new BitcoinWalletProvider({
|
|
119
|
-
type: 'BROWSER_EXTENSION',
|
|
120
|
-
walletsKit: myBitcoinWalletsKit, // Xverse / Unisat / OKX adapter
|
|
121
|
-
network: 'TESTNET',
|
|
122
|
-
});
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
See [`features/bitcoin.md`](./features/bitcoin.md).
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## Stellar
|
|
130
|
-
|
|
131
|
-
```ts
|
|
132
|
-
import { StellarWalletProvider } from '@sodax/wallet-sdk-core';
|
|
133
|
-
|
|
134
|
-
// Private-key — explicit uppercase `type`
|
|
135
|
-
const stellarPk = new StellarWalletProvider({
|
|
136
|
-
type: 'PRIVATE_KEY',
|
|
137
|
-
privateKey: '0x…',
|
|
138
|
-
network: 'PUBLIC', // 'PUBLIC' | 'TESTNET'
|
|
139
|
-
rpcUrl: 'https://horizon.stellar.org',
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
// Browser-extension — explicit uppercase `type`
|
|
143
|
-
const stellarBrowser = new StellarWalletProvider({
|
|
144
|
-
type: 'BROWSER_EXTENSION',
|
|
145
|
-
walletsKit: myStellarWalletsKit, // Freighter / xBull / Lobstr kit
|
|
146
|
-
network: 'PUBLIC',
|
|
147
|
-
});
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
See [`features/stellar.md`](./features/stellar.md).
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## ICON
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
import { IconWalletProvider } from '@sodax/wallet-sdk-core';
|
|
158
|
-
|
|
159
|
-
// Private-key (Node / scripts / CI)
|
|
160
|
-
const iconPk = new IconWalletProvider({
|
|
161
|
-
privateKey: '0x…',
|
|
162
|
-
rpcUrl: 'https://ctz.solidwallet.io/api/v3',
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
// Browser-extension — Hana wallet
|
|
166
|
-
const iconBrowser = new IconWalletProvider({
|
|
167
|
-
walletAddress: 'hx…', // optional; resolved at first signing call if omitted
|
|
168
|
-
rpcUrl: 'https://ctz.solidwallet.io/api/v3',
|
|
169
|
-
});
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
See [`features/icon.md`](./features/icon.md).
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## Injective
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
import { InjectiveWalletProvider } from '@sodax/wallet-sdk-core';
|
|
180
|
-
import type { ChainId, Network } from '@sodax/wallet-sdk-core';
|
|
181
|
-
|
|
182
|
-
// Secret-credential variant: private key
|
|
183
|
-
const injectivePk = new InjectiveWalletProvider({
|
|
184
|
-
secret: { privateKey: '…' },
|
|
185
|
-
chainId: 'injective-1' as ChainId,
|
|
186
|
-
network: 'Mainnet' as Network,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// Secret-credential variant: mnemonic
|
|
190
|
-
const injectiveMnemonic = new InjectiveWalletProvider({
|
|
191
|
-
secret: { mnemonics: 'word1 word2 …' },
|
|
192
|
-
chainId: 'injective-1' as ChainId,
|
|
193
|
-
network: 'Mainnet' as Network,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Browser-extension — caller supplies a configured MsgBroadcaster
|
|
197
|
-
const injectiveBrowser = new InjectiveWalletProvider({
|
|
198
|
-
msgBroadcaster: myMsgBroadcaster,
|
|
199
|
-
});
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
> Note: the private-key variant uses a nested `secret` wrapper instead of a top-level `privateKey`. See [`features/injective.md`](./features/injective.md).
|
|
203
|
-
|
|
204
|
-
---
|
|
205
|
-
|
|
206
|
-
## NEAR
|
|
207
|
-
|
|
208
|
-
```ts
|
|
209
|
-
import { NearWalletProvider } from '@sodax/wallet-sdk-core';
|
|
210
|
-
|
|
211
|
-
// Private-key — accountId + raw key
|
|
212
|
-
const nearPk = new NearWalletProvider({
|
|
213
|
-
rpcUrl: 'https://rpc.mainnet.near.org',
|
|
214
|
-
accountId: 'alice.near',
|
|
215
|
-
privateKey: 'ed25519:…',
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// Browser-extension — NearConnector
|
|
219
|
-
const nearBrowser = new NearWalletProvider({
|
|
220
|
-
wallet: myNearConnector, // from @hot-labs/near-connect
|
|
221
|
-
});
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
See [`features/near.md`](./features/near.md).
|
|
225
|
-
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
## Stacks
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
import { StacksWalletProvider } from '@sodax/wallet-sdk-core';
|
|
232
|
-
|
|
233
|
-
// Private-key (Node / scripts / CI)
|
|
234
|
-
const stacksPk = new StacksWalletProvider({
|
|
235
|
-
privateKey: '…',
|
|
236
|
-
endpoint: 'https://api.mainnet.hiro.so',
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// Browser-extension — Leather / Xverse / Asigna
|
|
240
|
-
const stacksBrowser = new StacksWalletProvider({
|
|
241
|
-
address: 'SP…',
|
|
242
|
-
endpoint: 'https://api.mainnet.hiro.so',
|
|
243
|
-
provider: myStacksProvider, // StacksProvider from @stacks/connect
|
|
244
|
-
});
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
See [`features/stacks.md`](./features/stacks.md).
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## Next steps
|
|
252
|
-
|
|
253
|
-
After construction:
|
|
254
|
-
|
|
255
|
-
- **Get the wallet address** — every provider exposes `getWalletAddress(): Promise<string>` (narrowed to a chain-specific brand by subclasses).
|
|
256
|
-
- **Sign and broadcast** — see [`recipes/sign-and-broadcast.md`](./recipes/sign-and-broadcast.md) for the per-chain flow.
|
|
257
|
-
- **Hand off to `@sodax/sdk`** — see [`recipes/bridge-to-sdk.md`](./recipes/bridge-to-sdk.md).
|
|
258
|
-
- **Tune defaults** — see [`recipes/defaults-and-overrides.md`](./recipes/defaults-and-overrides.md).
|
|
259
|
-
- **Avoid direct chain-SDK deps** — see [`recipes/library-exports.md`](./recipes/library-exports.md).
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# Recipes
|
|
2
|
-
|
|
3
|
-
Self-contained, task-oriented guides. Each recipe has paired before/after code, prerequisites, and verification steps.
|
|
4
|
-
|
|
5
|
-
| Recipe | When to use | Depends on |
|
|
6
|
-
|---|---|---|
|
|
7
|
-
| [`setup-private-key.md`](./setup-private-key.md) | Construct a provider from a raw key (Node scripts, CI, tests). | none |
|
|
8
|
-
| [`setup-browser-extension.md`](./setup-browser-extension.md) | Construct a provider from a wallet-extension adapter (consumer dApps). | none |
|
|
9
|
-
| [`bridge-to-sdk.md`](./bridge-to-sdk.md) | Pass the provider to `@sodax/sdk` calls. | a setup recipe |
|
|
10
|
-
| [`defaults-and-overrides.md`](./defaults-and-overrides.md) | Configure the `defaults` slice and understand shallow-merge semantics. | a setup recipe |
|
|
11
|
-
| [`library-exports.md`](./library-exports.md) | Avoid direct deps on `viem`, `@mysten/sui`, etc. by re-importing types from `@sodax/wallet-sdk-core`. | none |
|
|
12
|
-
| [`sign-and-broadcast.md`](./sign-and-broadcast.md) | Typical raw-tx flow per chain. | a setup recipe |
|
|
13
|
-
| [`testing.md`](./testing.md) | Mock providers in unit tests. | none |
|
|
14
|
-
|
|
15
|
-
Pick the recipe that matches the user's task. Recipes are intentionally short and self-contained — do **not** chain more than 2 in one apply.
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# Recipe: Bridge to `@sodax/sdk`
|
|
2
|
-
|
|
3
|
-
Pass the constructed provider to `@sodax/sdk` so the SDK can sign and submit hub/spoke transactions on the user's behalf.
|
|
4
|
-
|
|
5
|
-
**Depends on:** a constructed provider (see [`setup-private-key.md`](./setup-private-key.md) or [`setup-browser-extension.md`](./setup-browser-extension.md)).
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## The contract: `IXxxWalletProvider`
|
|
10
|
-
|
|
11
|
-
`@sodax/sdk` consumes the chain-specific **interfaces** from `@sodax/types`, not the concrete classes. This is the indirection that keeps the SDK decoupled from `wallet-sdk-core`:
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import type {
|
|
15
|
-
IEvmWalletProvider,
|
|
16
|
-
ISolanaWalletProvider,
|
|
17
|
-
ISuiWalletProvider,
|
|
18
|
-
IBitcoinWalletProvider,
|
|
19
|
-
IStellarWalletProvider,
|
|
20
|
-
IIconWalletProvider,
|
|
21
|
-
IInjectiveWalletProvider,
|
|
22
|
-
INearWalletProvider,
|
|
23
|
-
IStacksWalletProvider,
|
|
24
|
-
} from '@sodax/types';
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Each `*WalletProvider` class from `wallet-sdk-core` `implements` the matching interface. So:
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
import { EvmWalletProvider } from '@sodax/wallet-sdk-core';
|
|
31
|
-
import type { IEvmWalletProvider } from '@sodax/types';
|
|
32
|
-
|
|
33
|
-
const evm: IEvmWalletProvider = new EvmWalletProvider({ /* … */ });
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
In your SDK call signatures, take the **interface**, not the class:
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
// ✅ DO
|
|
40
|
-
async function deposit(wallet: IEvmWalletProvider) { /* … */ }
|
|
41
|
-
|
|
42
|
-
// ❌ DON'T — couples the function to the implementation
|
|
43
|
-
async function deposit(wallet: EvmWalletProvider) { /* … */ }
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Pattern: pass the provider to a `Sodax` feature service
|
|
49
|
-
|
|
50
|
-
Construct the wallet provider once, instantiate the `Sodax` facade, and pass the provider as `walletProvider` to the feature method you want (swap, bridge, money market, staking, …). The `Sodax` facade owns the per-chain spoke services internally — you do **not** construct `*SpokeService` yourself.
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
import { Sodax } from '@sodax/sdk';
|
|
54
|
-
import { EvmWalletProvider } from '@sodax/wallet-sdk-core';
|
|
55
|
-
import { ChainKeys } from '@sodax/types';
|
|
56
|
-
|
|
57
|
-
const walletProvider = new EvmWalletProvider({
|
|
58
|
-
privateKey: process.env.EVM_PK as `0x${string}`,
|
|
59
|
-
chainId: ChainKeys.SONIC_MAINNET,
|
|
60
|
-
rpcUrl: process.env.EVM_RPC,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const sodax = new Sodax(/* optional SodaxConfig — see @sodax/sdk docs */);
|
|
64
|
-
|
|
65
|
-
// Example: supply to the money market on BSC. The wallet provider goes in
|
|
66
|
-
// at the feature-method call, not at facade construction.
|
|
67
|
-
const result = await sodax.moneyMarket.supply({
|
|
68
|
-
params: {
|
|
69
|
-
srcChainKey: ChainKeys.BSC_MAINNET,
|
|
70
|
-
srcAddress: await walletProvider.getWalletAddress(),
|
|
71
|
-
token: '0x…',
|
|
72
|
-
amount: 1_000n,
|
|
73
|
-
action: 'supply',
|
|
74
|
-
},
|
|
75
|
-
walletProvider, // ← the IEvmWalletProvider
|
|
76
|
-
});
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
The same shape applies to `sodax.swaps.*`, `sodax.bridge.*`, `sodax.staking.*`, `sodax.migration.*`, etc. — each feature service method that needs signing takes a `walletProvider` argument typed to the chain-specific interface.
|
|
80
|
-
|
|
81
|
-
> If you need the underlying spoke service for advanced read-only operations, get it via `sodax.spoke.getSpokeService(chainKey)` — but never `new EvmSpokeService(...)` yourself.
|
|
82
|
-
|
|
83
|
-
For SDK-level recipes (initialise the `Sodax` facade, configure hub provider, raw-tx flows, error handling) see `@sodax/sdk`'s `ai-exported/`.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## Pattern: React layer (typical)
|
|
88
|
-
|
|
89
|
-
In a React dApp you almost never construct providers manually. `@sodax/wallet-sdk-react` returns the typed interface for you, and `@sodax/dapp-kit` wraps SDK calls into hooks:
|
|
90
|
-
|
|
91
|
-
```tsx
|
|
92
|
-
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
93
|
-
import { useSwap } from '@sodax/dapp-kit';
|
|
94
|
-
import { ChainKeys } from '@sodax/types';
|
|
95
|
-
|
|
96
|
-
function SwapButton() {
|
|
97
|
-
const evm = useWalletProvider({ xChainId: ChainKeys.SONIC_MAINNET });
|
|
98
|
-
// evm: IEvmWalletProvider | undefined
|
|
99
|
-
|
|
100
|
-
const swap = useSwap();
|
|
101
|
-
|
|
102
|
-
return (
|
|
103
|
-
<button
|
|
104
|
-
disabled={!evm}
|
|
105
|
-
onClick={() => evm && swap.mutateAsync({ /* params */, walletProvider: evm })}
|
|
106
|
-
>
|
|
107
|
-
Swap
|
|
108
|
-
</button>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
The hook narrows on `xChainId`, returns the chain-specific interface, and is `undefined` until the user is connected on that family. Refer to `@sodax/wallet-sdk-react`'s own docs for the full pattern.
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## Patterns to avoid
|
|
118
|
-
|
|
119
|
-
| Anti-pattern | Why bad | Replacement |
|
|
120
|
-
|---|---|---|
|
|
121
|
-
| Re-constructing the provider in every call site | Wastes work, can drop default config | Construct once, pass the instance around |
|
|
122
|
-
| Typing functions on the concrete class (`EvmWalletProvider`) | Couples to `wallet-sdk-core` | Use the `IXxxWalletProvider` interface |
|
|
123
|
-
| Casting between provider classes (`as ISolanaWalletProvider`) | Hides a chain-type mismatch | Pick the right provider for the chain at the call site |
|
|
124
|
-
| Storing the provider in a long-lived Zustand / Redux store | Provider holds live SDK clients / network connections | Store the **config** (e.g. PK + chainId), construct on demand |
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## Verification
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
# 1. Type check passes
|
|
132
|
-
pnpm checkTs
|
|
133
|
-
|
|
134
|
-
# 2. SDK calls type-check against the interface, not the class
|
|
135
|
-
grep -rn "IEvmWalletProvider\|ISolanaWalletProvider\|IBitcoinWalletProvider" <user-src>
|
|
136
|
-
# expect at least one match in your function signatures
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Next steps
|
|
142
|
-
|
|
143
|
-
- [`defaults-and-overrides.md`](./defaults-and-overrides.md) — fine-tune the `defaults` slice for tx options.
|
|
144
|
-
- [`library-exports.md`](./library-exports.md) — type-only re-exports to avoid upstream chain-SDK deps.
|
|
145
|
-
- [`testing.md`](./testing.md) — mocking providers in tests.
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# Recipe: Defaults and per-call overrides
|
|
2
|
-
|
|
3
|
-
Configure the `defaults` slice and understand the shallow-merge semantics shared by every provider.
|
|
4
|
-
|
|
5
|
-
**Depends on:** [`setup-private-key.md`](./setup-private-key.md) or [`setup-browser-extension.md`](./setup-browser-extension.md).
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Mental model
|
|
10
|
-
|
|
11
|
-
Every provider class extends `BaseWalletProvider<TDefaults>`. `defaults` is captured at construction time; per-call `options` are shallow-merged over the relevant slice at call time:
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
final = shallowMerge(defaults[key], options) // mergePolicy('key', options)
|
|
15
|
-
OR
|
|
16
|
-
= shallowMerge(defaults, options) // mergeDefaults(options)
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Two helpers, two shapes:
|
|
20
|
-
|
|
21
|
-
| Helper | When the chain uses it | Example |
|
|
22
|
-
|---|---|---|
|
|
23
|
-
| `mergePolicy('foo', opts)` | `defaults` is **grouped per method** | EVM: `defaults.sendTransaction`, `defaults.waitForTransactionReceipt` |
|
|
24
|
-
| `mergeDefaults(opts)` | `defaults` is **flat** | Bitcoin: `defaultFinalize`; Stellar: `pollInterval`, `pollTimeout` |
|
|
25
|
-
|
|
26
|
-
For the helper each chain uses, see [`../features/<chain>.md`](../features/).
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Shallow, not deep
|
|
31
|
-
|
|
32
|
-
Top-level keys merge; **nested objects are replaced wholesale**.
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
const provider = new EvmWalletProvider({
|
|
36
|
-
// …
|
|
37
|
-
defaults: {
|
|
38
|
-
sendTransaction: { gas: 3_000_000n, nonce: 0 },
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
await provider.sendTransaction(txData, { gas: 5_000_000n });
|
|
43
|
-
// ^^^^^^^^^^^^^^^^
|
|
44
|
-
// Final policy: { gas: 5_000_000n } ← nonce is DROPPED
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
If you need `nonce` to persist, include it in the per-call options:
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
await provider.sendTransaction(txData, { gas: 5_000_000n, nonce: 0 });
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Or split the default so each tunable lives at the top level — see `src/utils/merge.ts` for the implementation. The behavior is intentional: deep merge would silently smuggle stale fields across call sites.
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## `undefined` is "no opinion"
|
|
58
|
-
|
|
59
|
-
The merge skips:
|
|
60
|
-
|
|
61
|
-
- `undefined` **layers** entirely (no options object → use defaults verbatim).
|
|
62
|
-
- `undefined` **values** inside a layer (`{ gas: undefined }` does **not** override the previous layer).
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
const policy: Partial<EvmSendTransactionPolicy> = { gas: undefined };
|
|
66
|
-
await provider.sendTransaction(txData, policy);
|
|
67
|
-
// gas falls back to defaults.sendTransaction.gas
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
This is useful when threading options through optional parameters — `undefined` reads as "use the default".
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Where to put what
|
|
75
|
-
|
|
76
|
-
| Tunable | Goes where | Why |
|
|
77
|
-
|---|---|---|
|
|
78
|
-
| Env-level constants (RPC URL, default gas, default commitment) | `defaults` at construction | One place, captured at startup |
|
|
79
|
-
| Per-call tweaks (this tx needs more gas) | per-call `options` argument | Localized, doesn't leak into other calls |
|
|
80
|
-
| Anything that changes after construction (active network in PK mode) | re-construct the provider | `defaults` is frozen at startup |
|
|
81
|
-
|
|
82
|
-
You **cannot** mutate `defaults` after construction — `BaseWalletProvider` captures the reference into a `protected readonly` field. Later mutations have no effect.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Worked example: EVM with two default slices
|
|
87
|
-
|
|
88
|
-
```ts
|
|
89
|
-
import { EvmWalletProvider } from '@sodax/wallet-sdk-core';
|
|
90
|
-
import { ChainKeys } from '@sodax/types';
|
|
91
|
-
|
|
92
|
-
const provider = new EvmWalletProvider({
|
|
93
|
-
privateKey: process.env.PK as `0x${string}`,
|
|
94
|
-
chainId: ChainKeys.SONIC_MAINNET,
|
|
95
|
-
defaults: {
|
|
96
|
-
// Slice grouped by method — merged via mergePolicy('sendTransaction', …)
|
|
97
|
-
sendTransaction: { gas: 3_000_000n },
|
|
98
|
-
|
|
99
|
-
// Another method-grouped slice
|
|
100
|
-
waitForTransactionReceipt: { confirmations: 1, timeout: 60_000 },
|
|
101
|
-
|
|
102
|
-
// Constructor-time slices (private-key mode only — ignored in browser-extension mode)
|
|
103
|
-
transport: { batch: { batchSize: 10 } },
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Default gas: 3M. This call bumps to 5M.
|
|
108
|
-
const hash = await provider.sendTransaction(tx, { gas: 5_000_000n });
|
|
109
|
-
|
|
110
|
-
// Default 1 confirmation, 60s timeout. This call overrides both.
|
|
111
|
-
const receipt = await provider.waitForTransactionReceipt(hash, {
|
|
112
|
-
confirmations: 2,
|
|
113
|
-
timeout: 30_000,
|
|
114
|
-
});
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Browser-extension warning
|
|
120
|
-
|
|
121
|
-
In **browser-extension** mode the constructor-time slices (`transport`, `publicClient`, `walletClient` on EVM; analogous on other chains) are **ignored** — the consumer already supplied built clients, so there is nothing for the provider to configure. A one-time `console.warn` is logged.
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
[EvmWalletProvider] defaults.{transport,publicClient,walletClient} ignored in browser-extension mode.
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
This is informational, not a bug. The method-grouped slices (`sendTransaction`, `waitForTransactionReceipt`, …) still apply in both modes.
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Verification
|
|
132
|
-
|
|
133
|
-
```ts
|
|
134
|
-
// Assert that defaults applied — run on a testnet
|
|
135
|
-
const hash = await provider.sendTransaction(tx); // no per-call options
|
|
136
|
-
// Then read the receipt and confirm gas matches your default
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
pnpm checkTs
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Common pitfalls
|
|
146
|
-
|
|
147
|
-
| Pitfall | Symptom | Fix |
|
|
148
|
-
|---|---|---|
|
|
149
|
-
| Expecting deep merge | A nested field was "dropped" | The whole object was replaced. Include both fields in the per-call options. |
|
|
150
|
-
| Mutating `defaults` after construction | Tunable doesn't take effect | Reconstruct the provider, or pass the new value per call. |
|
|
151
|
-
| Setting transport defaults in browser-extension mode | Warning logged, no effect | Move them out — they only apply in PK mode. |
|
|
152
|
-
| Putting RPC URL in `defaults` | RPC URL is a top-level config field on every chain, not a `defaults` slice | Use `rpcUrl: '…'` at the config root (PK mode), or pass `publicClient` / `client` directly (browser-extension mode). |
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## See also
|
|
157
|
-
|
|
158
|
-
- [`../architecture.md`](../architecture.md) § `BaseWalletProvider` and the `defaults` model.
|
|
159
|
-
- [`../features/`](../features/) — per-chain `*Defaults` shape and which helper each chain uses.
|