@miden-sdk/react 0.13.1 → 0.13.2
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/CLAUDE.md +398 -0
- package/dist/index.js +71 -45
- package/dist/index.mjs +71 -45
- package/package.json +3 -2
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# Miden React SDK - Usage Guide
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @miden-sdk/react @miden-sdk/miden-sdk
|
|
7
|
+
# or
|
|
8
|
+
yarn add @miden-sdk/react @miden-sdk/miden-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { MidenProvider } from "@miden-sdk/react";
|
|
15
|
+
|
|
16
|
+
function App() {
|
|
17
|
+
return (
|
|
18
|
+
<MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
19
|
+
<YourApp />
|
|
20
|
+
</MidenProvider>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<MidenProvider
|
|
29
|
+
config={{
|
|
30
|
+
rpcUrl: "testnet", // "devnet" | "testnet" | "localhost" | custom URL
|
|
31
|
+
prover: "testnet", // "local" | "devnet" | "testnet" | custom URL
|
|
32
|
+
autoSyncInterval: 15000, // ms, set to 0 to disable
|
|
33
|
+
noteTransportUrl: "...", // optional: for private note delivery
|
|
34
|
+
}}
|
|
35
|
+
loadingComponent={<Loading />} // shown during WASM init
|
|
36
|
+
errorComponent={<Error />} // shown on init failure
|
|
37
|
+
>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| Network | Use When |
|
|
41
|
+
|---------|----------|
|
|
42
|
+
| `devnet` | Development, testing with fake tokens |
|
|
43
|
+
| `testnet` | Pre-production testing |
|
|
44
|
+
| `localhost` | Local node at `http://localhost:57291` |
|
|
45
|
+
|
|
46
|
+
## Reading Data (Query Hooks)
|
|
47
|
+
|
|
48
|
+
All query hooks return `{ data, isLoading, error, refetch }`.
|
|
49
|
+
|
|
50
|
+
### List Accounts
|
|
51
|
+
```tsx
|
|
52
|
+
const { data: accounts, isLoading } = useAccounts();
|
|
53
|
+
|
|
54
|
+
// accounts.wallets - regular accounts
|
|
55
|
+
// accounts.faucets - token faucets
|
|
56
|
+
// accounts.all - everything
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Get Account Details
|
|
60
|
+
```tsx
|
|
61
|
+
const { data: account } = useAccount(accountId);
|
|
62
|
+
|
|
63
|
+
// account.id, account.nonce, account.bech32id()
|
|
64
|
+
// account.balance(faucetId) - get token balance
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Get Notes
|
|
68
|
+
```tsx
|
|
69
|
+
const { data: notes } = useNotes();
|
|
70
|
+
|
|
71
|
+
// notes.input - incoming notes
|
|
72
|
+
// notes.consumable - ready to claim
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Check Sync Status
|
|
76
|
+
```tsx
|
|
77
|
+
const { syncHeight, isSyncing, sync } = useSyncState();
|
|
78
|
+
|
|
79
|
+
// Manual sync
|
|
80
|
+
await sync();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Get Token Metadata
|
|
84
|
+
```tsx
|
|
85
|
+
const { data: metadata } = useAssetMetadata(faucetId);
|
|
86
|
+
// metadata.symbol, metadata.decimals
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Writing Data (Mutation Hooks)
|
|
90
|
+
|
|
91
|
+
All mutation hooks return `{ mutate, data, isLoading, stage, error, reset }`.
|
|
92
|
+
|
|
93
|
+
**Transaction stages:** `idle` → `executing` → `proving` → `submitting` → `complete`
|
|
94
|
+
|
|
95
|
+
### Create Wallet
|
|
96
|
+
```tsx
|
|
97
|
+
const { mutate: createWallet, isLoading } = useCreateWallet();
|
|
98
|
+
|
|
99
|
+
const account = await createWallet({
|
|
100
|
+
storageMode: "private", // "private" | "public" | "network"
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Send Tokens
|
|
105
|
+
```tsx
|
|
106
|
+
const { mutate: send, stage } = useSend();
|
|
107
|
+
|
|
108
|
+
await send({
|
|
109
|
+
from: senderAccountId,
|
|
110
|
+
to: recipientAccountId,
|
|
111
|
+
faucetId: tokenFaucetId,
|
|
112
|
+
amount: 1000n,
|
|
113
|
+
noteType: "private", // "private" | "public"
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Send to Multiple Recipients
|
|
118
|
+
```tsx
|
|
119
|
+
const { mutate: multiSend } = useMultiSend();
|
|
120
|
+
|
|
121
|
+
await multiSend({
|
|
122
|
+
from: senderAccountId,
|
|
123
|
+
outputs: [
|
|
124
|
+
{ to: recipient1, faucetId, amount: 500n },
|
|
125
|
+
{ to: recipient2, faucetId, amount: 300n },
|
|
126
|
+
],
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Claim Notes
|
|
131
|
+
```tsx
|
|
132
|
+
const { mutate: consume } = useConsume();
|
|
133
|
+
|
|
134
|
+
await consume({
|
|
135
|
+
accountId: myAccountId,
|
|
136
|
+
noteIds: [noteId1, noteId2], // optional: consume specific notes
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Mint Tokens (Faucet Owner)
|
|
141
|
+
```tsx
|
|
142
|
+
const { mutate: mint } = useMint();
|
|
143
|
+
|
|
144
|
+
await mint({
|
|
145
|
+
faucetId: myFaucetId,
|
|
146
|
+
to: recipientAccountId,
|
|
147
|
+
amount: 10000n,
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Create Faucet
|
|
152
|
+
```tsx
|
|
153
|
+
const { mutate: createFaucet } = useCreateFaucet();
|
|
154
|
+
|
|
155
|
+
const faucet = await createFaucet({
|
|
156
|
+
symbol: "TOKEN",
|
|
157
|
+
decimals: 8,
|
|
158
|
+
maxSupply: 1000000n,
|
|
159
|
+
storageMode: "public",
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Common Patterns
|
|
164
|
+
|
|
165
|
+
### Show Transaction Progress
|
|
166
|
+
```tsx
|
|
167
|
+
function SendButton() {
|
|
168
|
+
const { mutate: send, stage, isLoading, error } = useSend();
|
|
169
|
+
|
|
170
|
+
const handleSend = async () => {
|
|
171
|
+
try {
|
|
172
|
+
await send({ from, to, faucetId, amount });
|
|
173
|
+
} catch (err) {
|
|
174
|
+
console.error("Transaction failed:", err);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<div>
|
|
180
|
+
<button onClick={handleSend} disabled={isLoading}>
|
|
181
|
+
{isLoading ? `${stage}...` : "Send"}
|
|
182
|
+
</button>
|
|
183
|
+
{error && <p>Error: {error.message}</p>}
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Format Token Amounts
|
|
190
|
+
```tsx
|
|
191
|
+
import { formatAssetAmount, parseAssetAmount } from "@miden-sdk/react";
|
|
192
|
+
|
|
193
|
+
// Display: 1000000n with 8 decimals → "0.01"
|
|
194
|
+
const display = formatAssetAmount(balance, 8);
|
|
195
|
+
|
|
196
|
+
// User input: "0.01" with 8 decimals → 1000000n
|
|
197
|
+
const amount = parseAssetAmount("0.01", 8);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Display Note Summary
|
|
201
|
+
```tsx
|
|
202
|
+
import { getNoteSummary, formatNoteSummary } from "@miden-sdk/react";
|
|
203
|
+
|
|
204
|
+
const summary = getNoteSummary(note);
|
|
205
|
+
const text = formatNoteSummary(summary); // "1.5 TOKEN"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Wait for Transaction Confirmation
|
|
209
|
+
```tsx
|
|
210
|
+
const { mutate: waitForCommit } = useWaitForCommit();
|
|
211
|
+
|
|
212
|
+
// After sending
|
|
213
|
+
const result = await send({ ... });
|
|
214
|
+
await waitForCommit({ transactionId: result.transactionId });
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Access Client Directly
|
|
218
|
+
```tsx
|
|
219
|
+
const client = useMidenClient();
|
|
220
|
+
|
|
221
|
+
// For advanced operations not covered by hooks
|
|
222
|
+
const blockHeader = await client.getBlockHeaderByNumber(100);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Prevent Race Conditions
|
|
226
|
+
```tsx
|
|
227
|
+
const { runExclusive } = useMiden();
|
|
228
|
+
|
|
229
|
+
// Ensures sequential execution
|
|
230
|
+
await runExclusive(async (client) => {
|
|
231
|
+
// Multiple operations that must not interleave
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## External Signer Integration
|
|
236
|
+
|
|
237
|
+
For wallets using external key management, use the pre-built signer providers:
|
|
238
|
+
|
|
239
|
+
### Para (EVM Wallets)
|
|
240
|
+
```tsx
|
|
241
|
+
import { ParaSignerProvider } from "@miden-sdk/para";
|
|
242
|
+
|
|
243
|
+
<ParaSignerProvider apiKey="your-api-key" environment="PRODUCTION">
|
|
244
|
+
<MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
245
|
+
<App />
|
|
246
|
+
</MidenProvider>
|
|
247
|
+
</ParaSignerProvider>
|
|
248
|
+
|
|
249
|
+
// Access Para-specific data
|
|
250
|
+
const { para, wallet, isConnected } = useParaSigner();
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Turnkey
|
|
254
|
+
```tsx
|
|
255
|
+
import { TurnkeySignerProvider } from "@miden-sdk/miden-turnkey-react";
|
|
256
|
+
|
|
257
|
+
// Config is optional — defaults to https://api.turnkey.com
|
|
258
|
+
// and reads VITE_TURNKEY_ORG_ID from environment
|
|
259
|
+
<TurnkeySignerProvider>
|
|
260
|
+
<MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
261
|
+
<App />
|
|
262
|
+
</MidenProvider>
|
|
263
|
+
</TurnkeySignerProvider>
|
|
264
|
+
|
|
265
|
+
// Or with explicit config:
|
|
266
|
+
<TurnkeySignerProvider config={{
|
|
267
|
+
apiBaseUrl: "https://api.turnkey.com",
|
|
268
|
+
defaultOrganizationId: "your-org-id",
|
|
269
|
+
}}>
|
|
270
|
+
...
|
|
271
|
+
</TurnkeySignerProvider>
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Connect via passkey authentication:
|
|
275
|
+
```tsx
|
|
276
|
+
import { useSigner } from "@miden-sdk/react";
|
|
277
|
+
import { useTurnkeySigner } from "@miden-sdk/miden-turnkey-react";
|
|
278
|
+
|
|
279
|
+
// useSigner() handles connect/disconnect
|
|
280
|
+
const { isConnected, connect, disconnect } = useSigner();
|
|
281
|
+
await connect(); // triggers passkey flow, auto-selects account
|
|
282
|
+
|
|
283
|
+
// useTurnkeySigner() exposes Turnkey-specific extras
|
|
284
|
+
const { client, account, setAccount } = useTurnkeySigner();
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### MidenFi Wallet Adapter
|
|
288
|
+
```tsx
|
|
289
|
+
import { MidenFiSignerProvider } from "@miden-sdk/wallet-adapter-react";
|
|
290
|
+
|
|
291
|
+
<MidenFiSignerProvider network="Testnet">
|
|
292
|
+
<MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
293
|
+
<App />
|
|
294
|
+
</MidenProvider>
|
|
295
|
+
</MidenFiSignerProvider>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Using the Unified Signer Interface
|
|
299
|
+
```tsx
|
|
300
|
+
import { useSigner } from "@miden-sdk/react";
|
|
301
|
+
|
|
302
|
+
// Works with any signer provider above
|
|
303
|
+
const { isConnected, connect, disconnect, name } = useSigner();
|
|
304
|
+
|
|
305
|
+
if (!isConnected) {
|
|
306
|
+
return <button onClick={connect}>Connect {name}</button>;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Building a Custom Signer Provider
|
|
311
|
+
```tsx
|
|
312
|
+
import { SignerContext } from "@miden-sdk/react";
|
|
313
|
+
|
|
314
|
+
<SignerContext.Provider value={{
|
|
315
|
+
name: "MyWallet",
|
|
316
|
+
storeName: `mywallet_${userAddress}`, // unique per user for DB isolation
|
|
317
|
+
isConnected: true,
|
|
318
|
+
accountConfig: {
|
|
319
|
+
publicKey: userPublicKeyCommitment, // Uint8Array
|
|
320
|
+
storageMode: "private",
|
|
321
|
+
},
|
|
322
|
+
signCb: async (pubKey, signingInputs) => {
|
|
323
|
+
// Route to your signing service
|
|
324
|
+
return signature; // Uint8Array
|
|
325
|
+
},
|
|
326
|
+
connect: async () => { /* trigger wallet connection */ },
|
|
327
|
+
disconnect: async () => { /* clear session */ },
|
|
328
|
+
}}>
|
|
329
|
+
<MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
330
|
+
<App />
|
|
331
|
+
</MidenProvider>
|
|
332
|
+
</SignerContext.Provider>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Account ID Formats
|
|
336
|
+
|
|
337
|
+
Both formats work interchangeably in all hooks:
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
// Hex format
|
|
341
|
+
useAccount("0x1234567890abcdef");
|
|
342
|
+
|
|
343
|
+
// Bech32 format
|
|
344
|
+
useAccount("miden1qy35...");
|
|
345
|
+
|
|
346
|
+
// Convert to bech32 for display
|
|
347
|
+
account.bech32id(); // "miden1qy35..."
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## Hook Reference
|
|
351
|
+
|
|
352
|
+
| Hook | Returns | Purpose |
|
|
353
|
+
|------|---------|---------|
|
|
354
|
+
| `useAccounts()` | `{ wallets, faucets, all }` | List all accounts |
|
|
355
|
+
| `useAccount(id)` | `Account` | Account details + balances |
|
|
356
|
+
| `useNotes(filter?)` | `{ input, consumable }` | Available notes |
|
|
357
|
+
| `useSyncState()` | `{ syncHeight, sync() }` | Sync status |
|
|
358
|
+
| `useAssetMetadata(id)` | `{ symbol, decimals }` | Token info |
|
|
359
|
+
| `useCreateWallet()` | `Account` | Create wallet |
|
|
360
|
+
| `useCreateFaucet()` | `Account` | Create faucet |
|
|
361
|
+
| `useImportAccount()` | `Account` | Import account |
|
|
362
|
+
| `useSend()` | `TransactionResult` | Send tokens |
|
|
363
|
+
| `useMultiSend()` | `TransactionResult` | Multi-recipient send |
|
|
364
|
+
| `useMint()` | `TransactionResult` | Mint tokens |
|
|
365
|
+
| `useConsume()` | `TransactionResult` | Claim notes |
|
|
366
|
+
| `useSwap()` | `TransactionResult` | Atomic swap |
|
|
367
|
+
| `useTransaction()` | `TransactionResult` | Custom transaction |
|
|
368
|
+
|
|
369
|
+
## Type Imports
|
|
370
|
+
|
|
371
|
+
```tsx
|
|
372
|
+
import type {
|
|
373
|
+
// Config
|
|
374
|
+
MidenConfig,
|
|
375
|
+
|
|
376
|
+
// Hook results
|
|
377
|
+
QueryResult,
|
|
378
|
+
MutationResult,
|
|
379
|
+
AccountsResult,
|
|
380
|
+
|
|
381
|
+
// SDK types (re-exported)
|
|
382
|
+
Account,
|
|
383
|
+
AccountId,
|
|
384
|
+
Note,
|
|
385
|
+
TransactionRecord,
|
|
386
|
+
FungibleAsset,
|
|
387
|
+
} from "@miden-sdk/react";
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Troubleshooting
|
|
391
|
+
|
|
392
|
+
| Issue | Solution |
|
|
393
|
+
|-------|----------|
|
|
394
|
+
| "Client not ready" | Wrap component in `MidenProvider`, check `useMiden().isReady` |
|
|
395
|
+
| Transaction stuck | Check `stage` value, network connectivity, prover availability |
|
|
396
|
+
| Notes not appearing | Call `sync()` manually, check `autoSyncInterval` config |
|
|
397
|
+
| Bech32 address wrong | Verify `rpcUrl` matches intended network |
|
|
398
|
+
| WASM init fails | Check browser compatibility, ensure WASM served with correct MIME type |
|
package/dist/index.js
CHANGED
|
@@ -499,7 +499,7 @@ function MidenProvider({
|
|
|
499
499
|
(0, import_react2.useEffect)(() => {
|
|
500
500
|
if (!signerContext && isInitializedRef.current) return;
|
|
501
501
|
if (signerContext && !signerContext.isConnected) {
|
|
502
|
-
if (client) {
|
|
502
|
+
if (useMidenStore.getState().client) {
|
|
503
503
|
useMidenStore.getState().reset();
|
|
504
504
|
setClient(null);
|
|
505
505
|
setSignerAccountId(null);
|
|
@@ -509,53 +509,80 @@ function MidenProvider({
|
|
|
509
509
|
if (!signerContext) {
|
|
510
510
|
isInitializedRef.current = true;
|
|
511
511
|
}
|
|
512
|
+
let cancelled = false;
|
|
512
513
|
const initClient = async () => {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
if (signerContext && signerContext.isConnected) {
|
|
518
|
-
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
519
|
-
webClient = await import_miden_sdk5.WebClient.createClientWithExternalKeystore(
|
|
520
|
-
resolvedConfig.rpcUrl,
|
|
521
|
-
resolvedConfig.noteTransportUrl,
|
|
522
|
-
resolvedConfig.seed,
|
|
523
|
-
storeName,
|
|
524
|
-
void 0,
|
|
525
|
-
// getKeyCb - not needed for public accounts
|
|
526
|
-
void 0,
|
|
527
|
-
// insertKeyCb - not needed for public accounts
|
|
528
|
-
signerContext.signCb
|
|
529
|
-
);
|
|
530
|
-
const accountId = await initializeSignerAccount(
|
|
531
|
-
webClient,
|
|
532
|
-
signerContext.accountConfig
|
|
533
|
-
);
|
|
534
|
-
setSignerAccountId(accountId);
|
|
535
|
-
} else {
|
|
536
|
-
const seed = resolvedConfig.seed;
|
|
537
|
-
webClient = await import_miden_sdk5.WebClient.createClient(
|
|
538
|
-
resolvedConfig.rpcUrl,
|
|
539
|
-
resolvedConfig.noteTransportUrl,
|
|
540
|
-
seed
|
|
541
|
-
);
|
|
542
|
-
}
|
|
543
|
-
setClient(webClient);
|
|
514
|
+
await runExclusive(async () => {
|
|
515
|
+
if (cancelled) return;
|
|
516
|
+
setInitializing(true);
|
|
517
|
+
setConfig(resolvedConfig);
|
|
544
518
|
try {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
519
|
+
let webClient;
|
|
520
|
+
let didSignerInit = false;
|
|
521
|
+
if (signerContext && signerContext.isConnected) {
|
|
522
|
+
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
523
|
+
webClient = await import_miden_sdk5.WebClient.createClientWithExternalKeystore(
|
|
524
|
+
resolvedConfig.rpcUrl,
|
|
525
|
+
resolvedConfig.noteTransportUrl,
|
|
526
|
+
resolvedConfig.seed,
|
|
527
|
+
storeName,
|
|
528
|
+
void 0,
|
|
529
|
+
// getKeyCb - not needed for public accounts
|
|
530
|
+
void 0,
|
|
531
|
+
// insertKeyCb - not needed for public accounts
|
|
532
|
+
signerContext.signCb
|
|
533
|
+
);
|
|
534
|
+
if (cancelled) return;
|
|
535
|
+
const accountId = await initializeSignerAccount(
|
|
536
|
+
webClient,
|
|
537
|
+
signerContext.accountConfig
|
|
538
|
+
);
|
|
539
|
+
if (cancelled) return;
|
|
540
|
+
setSignerAccountId(accountId);
|
|
541
|
+
didSignerInit = true;
|
|
542
|
+
} else {
|
|
543
|
+
const seed = resolvedConfig.seed;
|
|
544
|
+
webClient = await import_miden_sdk5.WebClient.createClient(
|
|
545
|
+
resolvedConfig.rpcUrl,
|
|
546
|
+
resolvedConfig.noteTransportUrl,
|
|
547
|
+
seed
|
|
548
|
+
);
|
|
549
|
+
if (cancelled) return;
|
|
550
|
+
}
|
|
551
|
+
if (!didSignerInit) {
|
|
552
|
+
try {
|
|
553
|
+
const summary = await webClient.syncState();
|
|
554
|
+
if (cancelled) return;
|
|
555
|
+
setSyncState({
|
|
556
|
+
syncHeight: summary.blockNum(),
|
|
557
|
+
lastSyncTime: Date.now()
|
|
558
|
+
});
|
|
559
|
+
} catch {
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (!cancelled) {
|
|
563
|
+
try {
|
|
564
|
+
const accounts = await webClient.getAccounts();
|
|
565
|
+
if (cancelled) return;
|
|
566
|
+
useMidenStore.getState().setAccounts(accounts);
|
|
567
|
+
} catch {
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (!cancelled) {
|
|
571
|
+
setClient(webClient);
|
|
572
|
+
}
|
|
573
|
+
} catch (error) {
|
|
574
|
+
if (!cancelled) {
|
|
575
|
+
setInitError(
|
|
576
|
+
error instanceof Error ? error : new Error(String(error))
|
|
577
|
+
);
|
|
578
|
+
}
|
|
553
579
|
}
|
|
554
|
-
}
|
|
555
|
-
setInitError(error instanceof Error ? error : new Error(String(error)));
|
|
556
|
-
}
|
|
580
|
+
});
|
|
557
581
|
};
|
|
558
582
|
initClient();
|
|
583
|
+
return () => {
|
|
584
|
+
cancelled = true;
|
|
585
|
+
};
|
|
559
586
|
}, [
|
|
560
587
|
runExclusive,
|
|
561
588
|
resolvedConfig,
|
|
@@ -564,8 +591,7 @@ function MidenProvider({
|
|
|
564
591
|
setInitError,
|
|
565
592
|
setInitializing,
|
|
566
593
|
setSyncState,
|
|
567
|
-
signerContext
|
|
568
|
-
client
|
|
594
|
+
signerContext
|
|
569
595
|
]);
|
|
570
596
|
(0, import_react2.useEffect)(() => {
|
|
571
597
|
if (!isReady || !client) return;
|
package/dist/index.mjs
CHANGED
|
@@ -448,7 +448,7 @@ function MidenProvider({
|
|
|
448
448
|
useEffect(() => {
|
|
449
449
|
if (!signerContext && isInitializedRef.current) return;
|
|
450
450
|
if (signerContext && !signerContext.isConnected) {
|
|
451
|
-
if (client) {
|
|
451
|
+
if (useMidenStore.getState().client) {
|
|
452
452
|
useMidenStore.getState().reset();
|
|
453
453
|
setClient(null);
|
|
454
454
|
setSignerAccountId(null);
|
|
@@ -458,53 +458,80 @@ function MidenProvider({
|
|
|
458
458
|
if (!signerContext) {
|
|
459
459
|
isInitializedRef.current = true;
|
|
460
460
|
}
|
|
461
|
+
let cancelled = false;
|
|
461
462
|
const initClient = async () => {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (signerContext && signerContext.isConnected) {
|
|
467
|
-
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
468
|
-
webClient = await WebClient.createClientWithExternalKeystore(
|
|
469
|
-
resolvedConfig.rpcUrl,
|
|
470
|
-
resolvedConfig.noteTransportUrl,
|
|
471
|
-
resolvedConfig.seed,
|
|
472
|
-
storeName,
|
|
473
|
-
void 0,
|
|
474
|
-
// getKeyCb - not needed for public accounts
|
|
475
|
-
void 0,
|
|
476
|
-
// insertKeyCb - not needed for public accounts
|
|
477
|
-
signerContext.signCb
|
|
478
|
-
);
|
|
479
|
-
const accountId = await initializeSignerAccount(
|
|
480
|
-
webClient,
|
|
481
|
-
signerContext.accountConfig
|
|
482
|
-
);
|
|
483
|
-
setSignerAccountId(accountId);
|
|
484
|
-
} else {
|
|
485
|
-
const seed = resolvedConfig.seed;
|
|
486
|
-
webClient = await WebClient.createClient(
|
|
487
|
-
resolvedConfig.rpcUrl,
|
|
488
|
-
resolvedConfig.noteTransportUrl,
|
|
489
|
-
seed
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
setClient(webClient);
|
|
463
|
+
await runExclusive(async () => {
|
|
464
|
+
if (cancelled) return;
|
|
465
|
+
setInitializing(true);
|
|
466
|
+
setConfig(resolvedConfig);
|
|
493
467
|
try {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
468
|
+
let webClient;
|
|
469
|
+
let didSignerInit = false;
|
|
470
|
+
if (signerContext && signerContext.isConnected) {
|
|
471
|
+
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
472
|
+
webClient = await WebClient.createClientWithExternalKeystore(
|
|
473
|
+
resolvedConfig.rpcUrl,
|
|
474
|
+
resolvedConfig.noteTransportUrl,
|
|
475
|
+
resolvedConfig.seed,
|
|
476
|
+
storeName,
|
|
477
|
+
void 0,
|
|
478
|
+
// getKeyCb - not needed for public accounts
|
|
479
|
+
void 0,
|
|
480
|
+
// insertKeyCb - not needed for public accounts
|
|
481
|
+
signerContext.signCb
|
|
482
|
+
);
|
|
483
|
+
if (cancelled) return;
|
|
484
|
+
const accountId = await initializeSignerAccount(
|
|
485
|
+
webClient,
|
|
486
|
+
signerContext.accountConfig
|
|
487
|
+
);
|
|
488
|
+
if (cancelled) return;
|
|
489
|
+
setSignerAccountId(accountId);
|
|
490
|
+
didSignerInit = true;
|
|
491
|
+
} else {
|
|
492
|
+
const seed = resolvedConfig.seed;
|
|
493
|
+
webClient = await WebClient.createClient(
|
|
494
|
+
resolvedConfig.rpcUrl,
|
|
495
|
+
resolvedConfig.noteTransportUrl,
|
|
496
|
+
seed
|
|
497
|
+
);
|
|
498
|
+
if (cancelled) return;
|
|
499
|
+
}
|
|
500
|
+
if (!didSignerInit) {
|
|
501
|
+
try {
|
|
502
|
+
const summary = await webClient.syncState();
|
|
503
|
+
if (cancelled) return;
|
|
504
|
+
setSyncState({
|
|
505
|
+
syncHeight: summary.blockNum(),
|
|
506
|
+
lastSyncTime: Date.now()
|
|
507
|
+
});
|
|
508
|
+
} catch {
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (!cancelled) {
|
|
512
|
+
try {
|
|
513
|
+
const accounts = await webClient.getAccounts();
|
|
514
|
+
if (cancelled) return;
|
|
515
|
+
useMidenStore.getState().setAccounts(accounts);
|
|
516
|
+
} catch {
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (!cancelled) {
|
|
520
|
+
setClient(webClient);
|
|
521
|
+
}
|
|
522
|
+
} catch (error) {
|
|
523
|
+
if (!cancelled) {
|
|
524
|
+
setInitError(
|
|
525
|
+
error instanceof Error ? error : new Error(String(error))
|
|
526
|
+
);
|
|
527
|
+
}
|
|
502
528
|
}
|
|
503
|
-
}
|
|
504
|
-
setInitError(error instanceof Error ? error : new Error(String(error)));
|
|
505
|
-
}
|
|
529
|
+
});
|
|
506
530
|
};
|
|
507
531
|
initClient();
|
|
532
|
+
return () => {
|
|
533
|
+
cancelled = true;
|
|
534
|
+
};
|
|
508
535
|
}, [
|
|
509
536
|
runExclusive,
|
|
510
537
|
resolvedConfig,
|
|
@@ -513,8 +540,7 @@ function MidenProvider({
|
|
|
513
540
|
setInitError,
|
|
514
541
|
setInitializing,
|
|
515
542
|
setSyncState,
|
|
516
|
-
signerContext
|
|
517
|
-
client
|
|
543
|
+
signerContext
|
|
518
544
|
]);
|
|
519
545
|
useEffect(() => {
|
|
520
546
|
if (!isReady || !client) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miden-sdk/react",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "React hooks library for Miden Web Client",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
-
"README.md"
|
|
17
|
+
"README.md",
|
|
18
|
+
"CLAUDE.md"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|