@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 +426 -0
- package/README.md +402 -6
- package/dist/index.d.mts +264 -12
- package/dist/index.d.ts +264 -12
- package/dist/index.js +1211 -408
- package/dist/index.mjs +1210 -407
- package/package.json +3 -2
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 |
|