@miden-sdk/react 0.13.1 → 0.13.3

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 ADDED
@@ -0,0 +1,426 @@
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
+ ### Custom Account Components
336
+
337
+ Signer providers can attach custom `AccountComponent` instances to accounts
338
+ via the `customComponents` field on `SignerAccountConfig`. This is useful for
339
+ including application-specific logic compiled from `.masp` packages (e.g. a
340
+ DEX component or custom smart contract) alongside the default auth and basic
341
+ wallet components.
342
+
343
+ ```tsx
344
+ import { SignerContext, type SignerAccountConfig } from "@miden-sdk/react";
345
+ import { AccountComponent } from "@miden-sdk/miden-sdk";
346
+
347
+ // Load a compiled .masp component (e.g. from your build pipeline)
348
+ const myDexComponent: AccountComponent = await loadCompiledComponent();
349
+
350
+ const accountConfig: SignerAccountConfig = {
351
+ publicKeyCommitment: userPublicKeyCommitment,
352
+ accountType: "RegularAccountUpdatableCode",
353
+ storageMode: myStorageMode,
354
+ customComponents: [myDexComponent],
355
+ };
356
+ ```
357
+
358
+ Components are appended to the `AccountBuilder` after the default basic wallet
359
+ component and before `build()` is called, so the account always includes wallet
360
+ functionality plus any extras you provide. The field is optional — omitting it
361
+ or passing an empty array preserves the default behavior.
362
+
363
+ ## Account ID Formats
364
+
365
+ Both formats work interchangeably in all hooks:
366
+
367
+ ```tsx
368
+ // Hex format
369
+ useAccount("0x1234567890abcdef");
370
+
371
+ // Bech32 format
372
+ useAccount("miden1qy35...");
373
+
374
+ // Convert to bech32 for display
375
+ account.bech32id(); // "miden1qy35..."
376
+ ```
377
+
378
+ ## Hook Reference
379
+
380
+ | Hook | Returns | Purpose |
381
+ |------|---------|---------|
382
+ | `useAccounts()` | `{ wallets, faucets, all }` | List all accounts |
383
+ | `useAccount(id)` | `Account` | Account details + balances |
384
+ | `useNotes(filter?)` | `{ input, consumable }` | Available notes |
385
+ | `useSyncState()` | `{ syncHeight, sync() }` | Sync status |
386
+ | `useAssetMetadata(id)` | `{ symbol, decimals }` | Token info |
387
+ | `useCreateWallet()` | `Account` | Create wallet |
388
+ | `useCreateFaucet()` | `Account` | Create faucet |
389
+ | `useImportAccount()` | `Account` | Import account |
390
+ | `useSend()` | `TransactionResult` | Send tokens |
391
+ | `useMultiSend()` | `TransactionResult` | Multi-recipient send |
392
+ | `useMint()` | `TransactionResult` | Mint tokens |
393
+ | `useConsume()` | `TransactionResult` | Claim notes |
394
+ | `useSwap()` | `TransactionResult` | Atomic swap |
395
+ | `useTransaction()` | `TransactionResult` | Custom transaction |
396
+
397
+ ## Type Imports
398
+
399
+ ```tsx
400
+ import type {
401
+ // Config
402
+ MidenConfig,
403
+
404
+ // Hook results
405
+ QueryResult,
406
+ MutationResult,
407
+ AccountsResult,
408
+
409
+ // SDK types (re-exported)
410
+ Account,
411
+ AccountId,
412
+ Note,
413
+ TransactionRecord,
414
+ FungibleAsset,
415
+ } from "@miden-sdk/react";
416
+ ```
417
+
418
+ ## Troubleshooting
419
+
420
+ | Issue | Solution |
421
+ |-------|----------|
422
+ | "Client not ready" | Wrap component in `MidenProvider`, check `useMiden().isReady` |
423
+ | Transaction stuck | Check `stage` value, network connectivity, prover availability |
424
+ | Notes not appearing | Call `sync()` manually, check `autoSyncInterval` config |
425
+ | Bech32 address wrong | Verify `rpcUrl` matches intended network |
426
+ | WASM init fails | Check browser compatibility, ensure WASM served with correct MIME type |