@miden-sdk/react 0.14.5 → 0.14.9
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 +66 -47
- package/LICENSE +21 -0
- package/README.md +67 -12
- package/dist/index.d.ts +16 -0
- package/dist/index.mjs +36 -17
- package/dist/lazy.d.ts +16 -0
- package/dist/lazy.mjs +36 -17
- package/dist/{lazy.d.mts → mt/lazy.d.ts} +16 -0
- package/dist/{index.js → mt/lazy.mjs} +458 -465
- package/dist/{index.d.mts → mt.d.ts} +16 -0
- package/dist/{lazy.js → mt.mjs} +458 -465
- package/lazy/package.json +5 -0
- package/mt/lazy/package.json +5 -0
- package/mt/package.json +5 -0
- package/package.json +36 -33
package/CLAUDE.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install @miden-sdk/react @miden-sdk/miden-sdk
|
|
7
7
|
# or
|
|
8
|
-
|
|
8
|
+
pnpm add @miden-sdk/react @miden-sdk/miden-sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Getting Started
|
|
@@ -45,36 +45,37 @@ function App() {
|
|
|
45
45
|
|
|
46
46
|
## Reading Data (Query Hooks)
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Query hooks return `{ ...data, isLoading, error, refetch }` — the data fields are spread directly onto the result object, with hook-specific names (no generic `data` field).
|
|
49
49
|
|
|
50
50
|
### List Accounts
|
|
51
51
|
```tsx
|
|
52
|
-
const {
|
|
52
|
+
const { accounts, wallets, faucets, isLoading } = useAccounts();
|
|
53
53
|
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
// accounts
|
|
54
|
+
// wallets - regular accounts
|
|
55
|
+
// faucets - token faucets
|
|
56
|
+
// accounts - both, combined
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
### Get Account Details
|
|
60
60
|
```tsx
|
|
61
|
-
const {
|
|
61
|
+
const { account, isLoading } = useAccount(accountId);
|
|
62
62
|
|
|
63
|
-
// account.id, account.nonce, account.bech32id()
|
|
64
|
-
// account.
|
|
63
|
+
// account.id(), account.nonce(), account.bech32id()
|
|
64
|
+
// account.vault().getBalance(assetId) - get token balance
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
### Get Notes
|
|
68
68
|
```tsx
|
|
69
|
-
const {
|
|
69
|
+
const { notes, consumableNotes, noteSummaries, consumableNoteSummaries } = useNotes();
|
|
70
70
|
|
|
71
|
-
// notes
|
|
72
|
-
//
|
|
71
|
+
// notes - all input notes for this account
|
|
72
|
+
// consumableNotes - subset that's ready to claim
|
|
73
|
+
// noteSummaries / consumableNoteSummaries - same lists, projected to UI-friendly summaries
|
|
73
74
|
```
|
|
74
75
|
|
|
75
76
|
### Check Sync Status
|
|
76
77
|
```tsx
|
|
77
|
-
const { syncHeight, isSyncing, sync } = useSyncState();
|
|
78
|
+
const { syncHeight, isSyncing, lastSyncTime, sync, error } = useSyncState();
|
|
78
79
|
|
|
79
80
|
// Manual sync
|
|
80
81
|
await sync();
|
|
@@ -82,19 +83,19 @@ await sync();
|
|
|
82
83
|
|
|
83
84
|
### Get Token Metadata
|
|
84
85
|
```tsx
|
|
85
|
-
const {
|
|
86
|
+
const { metadata, isLoading } = useAssetMetadata(assetId);
|
|
86
87
|
// metadata.symbol, metadata.decimals
|
|
87
88
|
```
|
|
88
89
|
|
|
89
90
|
## Writing Data (Mutation Hooks)
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
Mutation hooks return `{ <action>, result, isLoading, stage, error, reset }` — the action callback is named after the hook (`send`, `consume`, `mint`, ...) and the resolved value is on `result`.
|
|
92
93
|
|
|
93
94
|
**Transaction stages:** `idle` → `executing` → `proving` → `submitting` → `complete`
|
|
94
95
|
|
|
95
96
|
### Create Wallet
|
|
96
97
|
```tsx
|
|
97
|
-
const {
|
|
98
|
+
const { createWallet, isLoading } = useCreateWallet();
|
|
98
99
|
|
|
99
100
|
const account = await createWallet({
|
|
100
101
|
storageMode: "private", // "private" | "public" | "network"
|
|
@@ -103,12 +104,12 @@ const account = await createWallet({
|
|
|
103
104
|
|
|
104
105
|
### Send Tokens
|
|
105
106
|
```tsx
|
|
106
|
-
const {
|
|
107
|
+
const { send, stage } = useSend();
|
|
107
108
|
|
|
108
109
|
await send({
|
|
109
110
|
from: senderAccountId,
|
|
110
111
|
to: recipientAccountId,
|
|
111
|
-
|
|
112
|
+
assetId: tokenFaucetId,
|
|
112
113
|
amount: 1000n,
|
|
113
114
|
noteType: "private", // "private" | "public"
|
|
114
115
|
});
|
|
@@ -116,20 +117,20 @@ await send({
|
|
|
116
117
|
|
|
117
118
|
### Send to Multiple Recipients
|
|
118
119
|
```tsx
|
|
119
|
-
const {
|
|
120
|
+
const { multiSend } = useMultiSend();
|
|
120
121
|
|
|
121
122
|
await multiSend({
|
|
122
123
|
from: senderAccountId,
|
|
123
|
-
|
|
124
|
-
{ to: recipient1,
|
|
125
|
-
{ to: recipient2,
|
|
124
|
+
recipients: [
|
|
125
|
+
{ to: recipient1, assetId, amount: 500n },
|
|
126
|
+
{ to: recipient2, assetId, amount: 300n },
|
|
126
127
|
],
|
|
127
128
|
});
|
|
128
129
|
```
|
|
129
130
|
|
|
130
131
|
### Claim Notes
|
|
131
132
|
```tsx
|
|
132
|
-
const {
|
|
133
|
+
const { consume } = useConsume();
|
|
133
134
|
|
|
134
135
|
await consume({
|
|
135
136
|
accountId: myAccountId,
|
|
@@ -139,7 +140,7 @@ await consume({
|
|
|
139
140
|
|
|
140
141
|
### Mint Tokens (Faucet Owner)
|
|
141
142
|
```tsx
|
|
142
|
-
const {
|
|
143
|
+
const { mint } = useMint();
|
|
143
144
|
|
|
144
145
|
await mint({
|
|
145
146
|
faucetId: myFaucetId,
|
|
@@ -150,7 +151,7 @@ await mint({
|
|
|
150
151
|
|
|
151
152
|
### Create Faucet
|
|
152
153
|
```tsx
|
|
153
|
-
const {
|
|
154
|
+
const { createFaucet } = useCreateFaucet();
|
|
154
155
|
|
|
155
156
|
const faucet = await createFaucet({
|
|
156
157
|
symbol: "TOKEN",
|
|
@@ -165,11 +166,11 @@ const faucet = await createFaucet({
|
|
|
165
166
|
### Show Transaction Progress
|
|
166
167
|
```tsx
|
|
167
168
|
function SendButton() {
|
|
168
|
-
const {
|
|
169
|
+
const { send, stage, isLoading, error } = useSend();
|
|
169
170
|
|
|
170
171
|
const handleSend = async () => {
|
|
171
172
|
try {
|
|
172
|
-
await send({ from, to,
|
|
173
|
+
await send({ from, to, assetId, amount });
|
|
173
174
|
} catch (err) {
|
|
174
175
|
console.error("Transaction failed:", err);
|
|
175
176
|
}
|
|
@@ -207,11 +208,11 @@ const text = formatNoteSummary(summary); // "1.5 TOKEN"
|
|
|
207
208
|
|
|
208
209
|
### Wait for Transaction Confirmation
|
|
209
210
|
```tsx
|
|
210
|
-
const {
|
|
211
|
+
const { waitForCommit } = useWaitForCommit();
|
|
211
212
|
|
|
212
213
|
// After sending
|
|
213
214
|
const result = await send({ ... });
|
|
214
|
-
await waitForCommit({
|
|
215
|
+
await waitForCommit({ txId: result.txId });
|
|
215
216
|
```
|
|
216
217
|
|
|
217
218
|
### Access Client Directly
|
|
@@ -316,7 +317,8 @@ import { SignerContext } from "@miden-sdk/react";
|
|
|
316
317
|
storeName: `mywallet_${userAddress}`, // unique per user for DB isolation
|
|
317
318
|
isConnected: true,
|
|
318
319
|
accountConfig: {
|
|
319
|
-
|
|
320
|
+
publicKeyCommitment: userPublicKeyCommitment, // Uint8Array
|
|
321
|
+
accountType: "RegularAccountUpdatableCode",
|
|
320
322
|
storageMode: "private",
|
|
321
323
|
},
|
|
322
324
|
signCb: async (pubKey, signingInputs) => {
|
|
@@ -377,23 +379,40 @@ account.bech32id(); // "miden1qy35..."
|
|
|
377
379
|
|
|
378
380
|
## Hook Reference
|
|
379
381
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
|
384
|
-
|
|
385
|
-
| `
|
|
386
|
-
| `
|
|
387
|
-
| `
|
|
388
|
-
| `
|
|
389
|
-
| `
|
|
390
|
-
| `
|
|
391
|
-
| `
|
|
392
|
-
| `
|
|
393
|
-
| `
|
|
394
|
-
| `
|
|
395
|
-
|
|
396
|
-
|
|
382
|
+
Query hooks return `{ ...data, isLoading, error, refetch }`. Mutation hooks return `{ <action>, result, isLoading, stage, error, reset }`.
|
|
383
|
+
|
|
384
|
+
### Query (read)
|
|
385
|
+
| Hook | Data fields | Purpose |
|
|
386
|
+
|------|-------------|---------|
|
|
387
|
+
| `useAccounts()` | `accounts`, `wallets`, `faucets` | List local accounts |
|
|
388
|
+
| `useAccount(id)` | `account` | Account details + balances |
|
|
389
|
+
| `useNotes(filter?)` | `notes`, `consumableNotes`, `noteSummaries`, `consumableNoteSummaries` | Input notes + UI summaries |
|
|
390
|
+
| `useNoteStream(filter?)` | streaming variant of `useNotes` | Auto-updates as notes arrive |
|
|
391
|
+
| `useSyncState()` | `syncHeight`, `isSyncing`, `lastSyncTime`, `sync()` | Sync status + manual trigger |
|
|
392
|
+
| `useSyncControl()` | `pause()`, `resume()`, `isPaused` | Pause/resume the auto-sync timer |
|
|
393
|
+
| `useAssetMetadata(id)` | `metadata: { symbol, decimals }` | Token info |
|
|
394
|
+
| `useTransactionHistory(...)` | `transactions` | Local transaction log |
|
|
395
|
+
| `useSessionAccount()` | `account` | The signer's connected account |
|
|
396
|
+
| `useWaitForNotes(...)` | resolves when matching notes appear | Pull-style note waiting |
|
|
397
|
+
|
|
398
|
+
### Mutation (write)
|
|
399
|
+
| Hook | Action | Returns on success |
|
|
400
|
+
|------|--------|--------------------|
|
|
401
|
+
| `useCreateWallet()` | `createWallet({ storageMode })` | `Account` |
|
|
402
|
+
| `useCreateFaucet()` | `createFaucet({ symbol, decimals, ... })` | `Account` |
|
|
403
|
+
| `useImportAccount()` | `importAccount(...)` | `Account` |
|
|
404
|
+
| `useImportNote()` | `importNote(...)` | imported `InputNoteRecord` |
|
|
405
|
+
| `useExportNote()` | `exportNote(...)` | serialized note bytes |
|
|
406
|
+
| `useImportStore()` / `useExportStore()` | store import/export | bytes / `void` |
|
|
407
|
+
| `useSend()` | `send({ from, to, assetId, amount, noteType })` | `SendResult` (with `txId`, `note`) |
|
|
408
|
+
| `useMultiSend()` | `multiSend({ from, recipients })` | `TransactionResult` |
|
|
409
|
+
| `useMint()` | `mint({ faucetId, to, amount })` | `TransactionResult` |
|
|
410
|
+
| `useConsume()` | `consume({ accountId, notes })` | `TransactionResult` |
|
|
411
|
+
| `useSwap()` | `swap({ ... })` | `TransactionResult` |
|
|
412
|
+
| `useTransaction()` | `transact({ ... })` | `TransactionResult` (custom tx) |
|
|
413
|
+
| `useExecuteProgram()` | `execute(...)` | program output |
|
|
414
|
+
| `useCompile()` | `compile({ source })` | `{ component, txScript, noteScript }` |
|
|
415
|
+
| `useWaitForCommit()` | `waitForCommit({ txId })` | resolves when committed on-chain |
|
|
397
416
|
|
|
398
417
|
## Type Imports
|
|
399
418
|
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Miden
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ React hooks library for the Miden Web Client. Provides a simple, ergonomic inter
|
|
|
21
21
|
```bash
|
|
22
22
|
npm install @miden-sdk/react @miden-sdk/miden-sdk
|
|
23
23
|
# or
|
|
24
|
-
|
|
24
|
+
pnpm add @miden-sdk/react @miden-sdk/miden-sdk
|
|
25
25
|
# or
|
|
26
26
|
pnpm add @miden-sdk/react @miden-sdk/miden-sdk
|
|
27
27
|
```
|
|
@@ -32,14 +32,14 @@ From `packages/react-sdk`:
|
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
# Unit tests
|
|
35
|
-
|
|
35
|
+
pnpm test:unit
|
|
36
36
|
|
|
37
37
|
# Integration tests (Playwright) in test/
|
|
38
38
|
# Build the web-client dist first:
|
|
39
|
-
cd ../../crates/web-client &&
|
|
39
|
+
cd ../../crates/web-client && pnpm build
|
|
40
40
|
cd ../../packages/react-sdk
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
pnpm exec playwright install --with-deps
|
|
42
|
+
pnpm test:integration
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
## Quick Start
|
|
@@ -119,14 +119,25 @@ function App() {
|
|
|
119
119
|
}
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
##
|
|
122
|
+
## Subpaths: Eager / Lazy × ST / MT
|
|
123
|
+
|
|
124
|
+
The React SDK ships **four** bundle variants built from a single source tree. The two axes are independent:
|
|
125
|
+
|
|
126
|
+
- **WASM init timing** — _eager_ awaits at SDK load (TLA); _lazy_ leaves init to `MidenClient.ready()` or first awaiting method.
|
|
127
|
+
- **WASM threading model** — _ST_ (single-threaded) loads anywhere; _MT_ (multi-threaded via `wasm-bindgen-rayon`) parallelizes proving but **requires the page to be cross-origin-isolated**.
|
|
128
|
+
|
|
129
|
+
| Subpath | SDK variant | When to use |
|
|
130
|
+
| ---------------------------------- | --------------------------------- | ---------------------------------------------------------- |
|
|
131
|
+
| `@miden-sdk/react` | eager + ST | Plain browser apps, Vite, CRA, esbuild — no host control needed. |
|
|
132
|
+
| `@miden-sdk/react/lazy` | lazy + ST | Next.js / SSR, Capacitor (iOS/Android WKWebView). |
|
|
133
|
+
| `@miden-sdk/react/mt` | eager + MT | dApps with COOP/COEP set; want fast proving and tolerate TLA. |
|
|
134
|
+
| `@miden-sdk/react/mt/lazy` | lazy + MT | dApps with COOP/COEP set, on Next.js or anywhere TLA can't run. |
|
|
123
135
|
|
|
124
|
-
|
|
136
|
+
All four exports have identical APIs. The choice affects which `@miden-sdk/miden-sdk` variant your bundler resolves and therefore the underlying WASM behavior.
|
|
125
137
|
|
|
126
|
-
|
|
127
|
-
- `@miden-sdk/react/lazy` — internally consumes the lazy SDK. Use this in Next.js (app router or pages), SSR, or inside a Capacitor iOS/Android WKWebView host (the wallet shell uses this).
|
|
138
|
+
### Next.js / SSR
|
|
128
139
|
|
|
129
|
-
|
|
140
|
+
The lazy variants (`/lazy`, `/mt/lazy`) do not run a top-level `await` at module evaluation. Server-side rendering never hangs on WASM init. Use these in any Next.js app or Capacitor host:
|
|
130
141
|
|
|
131
142
|
```tsx
|
|
132
143
|
// Next.js: app/providers.tsx
|
|
@@ -141,6 +152,50 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
141
152
|
|
|
142
153
|
`MidenProvider` gates child rendering on `isReady`, so you don't have to await anything manually in components — hooks already fire only after WASM is initialized.
|
|
143
154
|
|
|
155
|
+
### Multi-threaded proving (`/mt`, `/mt/lazy`)
|
|
156
|
+
|
|
157
|
+
The MT variants enable `wasm-bindgen-rayon` for ~3–5× faster local proving on commodity laptops. Same API surface as the ST variants. Two extra requirements compared to ST:
|
|
158
|
+
|
|
159
|
+
**1. The page must be cross-origin-isolated.** Set the host response headers:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
Cross-Origin-Opener-Policy: same-origin
|
|
163
|
+
Cross-Origin-Embedder-Policy: require-corp
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Without those, the browser refuses to construct `WebAssembly.Memory({ shared: true })` and the MT WASM fails to instantiate at SDK load. See the underlying [`@miden-sdk/miden-sdk` README](https://github.com/0xMiden/web-sdk/blob/main/crates/web-client/README.md#setting-cross-origin-isolation-headers) for snippets per host (Vite, Next.js, Express, browser-extension manifests). COEP also blocks cross-origin resources unless they carry CORP / proper CORS — opt in deliberately.
|
|
167
|
+
|
|
168
|
+
**2. Bring up the rayon thread pool once at startup.** Re-exported as `initThreadPool(n)`. The React SDK does NOT call this for you — consumers must `await` it before the first transaction:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
"use client";
|
|
172
|
+
import { useEffect } from "react";
|
|
173
|
+
import { MidenProvider, useMiden } from "@miden-sdk/react/mt/lazy";
|
|
174
|
+
import { initThreadPool } from "@miden-sdk/miden-sdk/mt/lazy";
|
|
175
|
+
|
|
176
|
+
function ThreadPoolBoot() {
|
|
177
|
+
const { isReady } = useMiden();
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (!isReady) return;
|
|
180
|
+
void initThreadPool(navigator.hardwareConcurrency);
|
|
181
|
+
}, [isReady]);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
186
|
+
return (
|
|
187
|
+
<MidenProvider config={{ rpcUrl: "testnet" }}>
|
|
188
|
+
<ThreadPoolBoot />
|
|
189
|
+
{children}
|
|
190
|
+
</MidenProvider>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`initThreadPool` is idempotent — calling it multiple times resolves with the existing pool. Without this call, the rayon global thread pool spawns zero workers on `wasm32` and every `par_iter(...)` falls through to a sequential loop. You'd be shipping multi-threaded WASM that runs single-threaded.
|
|
196
|
+
|
|
197
|
+
If you can't satisfy the COI requirement (third-party host, CDN that won't set headers), stay on the default `@miden-sdk/react` / `/lazy` subpaths — they ship the ST WASM and load anywhere.
|
|
198
|
+
|
|
144
199
|
### Constructing wasm-bindgen types directly in Next.js
|
|
145
200
|
|
|
146
201
|
Hooks accept strings for account IDs, asset IDs, and note IDs (auto-detecting hex vs. bech32) and parse them internally inside async callbacks, so **most apps never touch wasm-bindgen types directly**. If you do need to (e.g. to inspect an ID's prefix/suffix, validate a pasted string, or use a low-level API like `new Felt(…)`), import from `@miden-sdk/miden-sdk/lazy` and gate the call on `isReady`:
|
|
@@ -1616,8 +1671,8 @@ One runnable Vite example lives in `examples/`:
|
|
|
1616
1671
|
|
|
1617
1672
|
```bash
|
|
1618
1673
|
cd examples/wallet
|
|
1619
|
-
|
|
1620
|
-
|
|
1674
|
+
pnpm install
|
|
1675
|
+
pnpm dev
|
|
1621
1676
|
```
|
|
1622
1677
|
|
|
1623
1678
|
## Requirements
|
package/dist/index.d.ts
CHANGED
|
@@ -150,6 +150,22 @@ interface MidenConfig {
|
|
|
150
150
|
proverUrls?: ProverUrls;
|
|
151
151
|
/** Default timeout for remote prover requests in milliseconds. */
|
|
152
152
|
proverTimeoutMs?: number | bigint;
|
|
153
|
+
/**
|
|
154
|
+
* Enable the Web Worker shim that runs WASM calls off the main thread.
|
|
155
|
+
* Defaults to `true` — leave it that way in browsers/extensions so the UI
|
|
156
|
+
* stays responsive while WASM is busy.
|
|
157
|
+
*
|
|
158
|
+
* Set to `false` when:
|
|
159
|
+
* - You pass a `CallbackProver` (e.g. a native iOS/Android prover via
|
|
160
|
+
* a Capacitor plugin). The worker boundary serializes the prover with
|
|
161
|
+
* `TransactionProver.serialize()`, which has no encoding for the
|
|
162
|
+
* callback variant and silently downgrades to `"local"` — your
|
|
163
|
+
* callback would never fire.
|
|
164
|
+
* - You're embedding the client in a single-WebView native shell
|
|
165
|
+
* (Capacitor host, Tauri, Electron preload), where the UI thread
|
|
166
|
+
* isn't competing with the WASM thread anyway.
|
|
167
|
+
*/
|
|
168
|
+
useWorker?: boolean;
|
|
153
169
|
}
|
|
154
170
|
interface MidenState {
|
|
155
171
|
client: WasmWebClient | null;
|
package/dist/index.mjs
CHANGED
|
@@ -425,6 +425,7 @@ function createRemoteProver(config, fallbackTimeout) {
|
|
|
425
425
|
}
|
|
426
426
|
return TransactionProver.newRemoteProver(
|
|
427
427
|
url,
|
|
428
|
+
/* v8 ignore next 1 — timeoutMs is always provided in tests; ?? fallbackTimeout path unreachable */
|
|
428
429
|
normalizeTimeout(timeoutMs ?? fallbackTimeout)
|
|
429
430
|
);
|
|
430
431
|
}
|
|
@@ -570,10 +571,12 @@ function MidenProvider({
|
|
|
570
571
|
isReady,
|
|
571
572
|
resolvedConfig.prover,
|
|
572
573
|
resolvedConfig.proverTimeoutMs,
|
|
574
|
+
/* v8 ignore next 2 — optional chain on proverUrls; tests don't pass proverUrls config */
|
|
573
575
|
resolvedConfig.proverUrls?.devnet,
|
|
574
576
|
resolvedConfig.proverUrls?.testnet
|
|
575
577
|
]);
|
|
576
578
|
const runExclusive = useCallback(
|
|
579
|
+
/* v8 ignore next 3 — runExclusive callback body; only called by advanced consumers, not directly in tests */
|
|
577
580
|
async (fn) => clientLockRef.current.runExclusive(fn),
|
|
578
581
|
[]
|
|
579
582
|
);
|
|
@@ -608,6 +611,8 @@ function MidenProvider({
|
|
|
608
611
|
signCbRef.current = signerContext?.signCb ?? null;
|
|
609
612
|
}, [signerContext?.signCb]);
|
|
610
613
|
const wrappedSignCb = useCallback(
|
|
614
|
+
/* v8 ignore next 11 — wrappedSignCb body is only called during external signer operations;
|
|
615
|
+
* tests don't exercise the full signing flow through MidenProvider directly. */
|
|
611
616
|
async (pubKey, signingInputs) => {
|
|
612
617
|
const cb = signCbRef.current;
|
|
613
618
|
if (!cb) {
|
|
@@ -658,7 +663,9 @@ function MidenProvider({
|
|
|
658
663
|
storeName,
|
|
659
664
|
signerContext.getKeyCb,
|
|
660
665
|
signerContext.insertKeyCb,
|
|
661
|
-
wrappedSignCb
|
|
666
|
+
wrappedSignCb,
|
|
667
|
+
void 0,
|
|
668
|
+
resolvedConfig.useWorker
|
|
662
669
|
);
|
|
663
670
|
if (cancelled) return;
|
|
664
671
|
const accountId = await initializeSignerAccount(
|
|
@@ -674,7 +681,10 @@ function MidenProvider({
|
|
|
674
681
|
webClient = await WebClient.createClient(
|
|
675
682
|
resolvedConfig.rpcUrl,
|
|
676
683
|
resolvedConfig.noteTransportUrl,
|
|
677
|
-
seed
|
|
684
|
+
seed,
|
|
685
|
+
void 0,
|
|
686
|
+
void 0,
|
|
687
|
+
resolvedConfig.useWorker
|
|
678
688
|
);
|
|
679
689
|
if (cancelled) return;
|
|
680
690
|
}
|
|
@@ -855,7 +865,10 @@ function MultiSignerProvider({ children }) {
|
|
|
855
865
|
() => ({ register, unregister }),
|
|
856
866
|
[register, unregister]
|
|
857
867
|
);
|
|
858
|
-
const activeSigner = activeSignerName ?
|
|
868
|
+
const activeSigner = activeSignerName ? (
|
|
869
|
+
/* v8 ignore next 1 — ?? null fallback; find() returns undefined only when the signer was unregistered between renders */
|
|
870
|
+
signersSnapshot.find((s) => s.name === activeSignerName) ?? null
|
|
871
|
+
) : null;
|
|
859
872
|
const stableSignCb = useCallback2(
|
|
860
873
|
async (pubKey, signingInputs) => {
|
|
861
874
|
const name = activeSignerName;
|
|
@@ -1307,6 +1320,7 @@ function getNoteType(type) {
|
|
|
1307
1320
|
return NoteType.Private;
|
|
1308
1321
|
case "public":
|
|
1309
1322
|
return NoteType.Public;
|
|
1323
|
+
/* v8 ignore next 2 — TypeScript type ensures only "private"|"public"; default is unreachable */
|
|
1310
1324
|
default:
|
|
1311
1325
|
return NoteType.Private;
|
|
1312
1326
|
}
|
|
@@ -1782,6 +1796,7 @@ function buildFilter(filter, ids, idsHex) {
|
|
|
1782
1796
|
}
|
|
1783
1797
|
return {
|
|
1784
1798
|
filter: TransactionFilter2.all(),
|
|
1799
|
+
/* v8 ignore next 1 — idsHex is always non-null when ids is non-empty; ?? [] is a safety net */
|
|
1785
1800
|
localFilterHexes: idsHex ?? []
|
|
1786
1801
|
};
|
|
1787
1802
|
}
|
|
@@ -2271,7 +2286,7 @@ function useSend() {
|
|
|
2271
2286
|
txRequest,
|
|
2272
2287
|
prover
|
|
2273
2288
|
) : await client.submitNewTransaction(execFromId, txRequest);
|
|
2274
|
-
return { txId: txId.
|
|
2289
|
+
return { txId: txId.toHex(), note: p2idNote };
|
|
2275
2290
|
});
|
|
2276
2291
|
setStage("complete");
|
|
2277
2292
|
setResult(returnResult);
|
|
@@ -2323,7 +2338,6 @@ function useSend() {
|
|
|
2323
2338
|
() => client.submitProvenTransaction(provenTransaction, txResult)
|
|
2324
2339
|
);
|
|
2325
2340
|
const txIdHex = txResult.id().toHex();
|
|
2326
|
-
const txIdString = txResult.id().toString();
|
|
2327
2341
|
let fullNote = null;
|
|
2328
2342
|
if (noteType === NoteType2.Private) {
|
|
2329
2343
|
fullNote = extractFullNote(txResult);
|
|
@@ -2347,7 +2361,7 @@ function useSend() {
|
|
|
2347
2361
|
);
|
|
2348
2362
|
}
|
|
2349
2363
|
const sendResult = {
|
|
2350
|
-
txId:
|
|
2364
|
+
txId: txIdHex,
|
|
2351
2365
|
note: null
|
|
2352
2366
|
};
|
|
2353
2367
|
setStage("complete");
|
|
@@ -2459,7 +2473,11 @@ function useMultiSend() {
|
|
|
2459
2473
|
};
|
|
2460
2474
|
}
|
|
2461
2475
|
);
|
|
2462
|
-
const
|
|
2476
|
+
const ownOutputs = new NoteArray2();
|
|
2477
|
+
for (const o of outputs) {
|
|
2478
|
+
ownOutputs.push(o.note);
|
|
2479
|
+
}
|
|
2480
|
+
const txRequest = new TransactionRequestBuilder2().withOwnOutputNotes(ownOutputs).build();
|
|
2463
2481
|
const txSenderId = parseAccountId(options.from);
|
|
2464
2482
|
const txResult = await client.executeTransaction(txSenderId, txRequest);
|
|
2465
2483
|
setStage("proving");
|
|
@@ -2476,7 +2494,6 @@ function useMultiSend() {
|
|
|
2476
2494
|
txResult
|
|
2477
2495
|
);
|
|
2478
2496
|
const txIdHex = txResult.id().toHex();
|
|
2479
|
-
const txIdString = txResult.id().toString();
|
|
2480
2497
|
await client.applyTransaction(txResult, submissionHeight);
|
|
2481
2498
|
const hasPrivate = outputs.some((o) => o.noteType === NoteType3.Private);
|
|
2482
2499
|
if (hasPrivate) {
|
|
@@ -2494,7 +2511,7 @@ function useMultiSend() {
|
|
|
2494
2511
|
}
|
|
2495
2512
|
}
|
|
2496
2513
|
}
|
|
2497
|
-
const txSummary = { transactionId:
|
|
2514
|
+
const txSummary = { transactionId: txIdHex };
|
|
2498
2515
|
setStage("complete");
|
|
2499
2516
|
setResult(txSummary);
|
|
2500
2517
|
await sync();
|
|
@@ -2643,7 +2660,7 @@ function useMint() {
|
|
|
2643
2660
|
txRequest,
|
|
2644
2661
|
prover
|
|
2645
2662
|
) : await client.submitNewTransaction(faucetIdObj, txRequest);
|
|
2646
|
-
return { transactionId: txId.
|
|
2663
|
+
return { transactionId: txId.toHex() };
|
|
2647
2664
|
});
|
|
2648
2665
|
setStage("complete");
|
|
2649
2666
|
setResult(txResult);
|
|
@@ -2719,16 +2736,17 @@ function useConsume() {
|
|
|
2719
2736
|
}
|
|
2720
2737
|
}
|
|
2721
2738
|
if (lookupIds.length > 0) {
|
|
2739
|
+
const lookupIdStrings = lookupIds.map((id) => id.toString());
|
|
2722
2740
|
const filter = new NoteFilter3(NoteFilterTypes2.List, lookupIds);
|
|
2723
2741
|
const noteRecords = await client.getInputNotes(filter);
|
|
2724
|
-
if (noteRecords.length !==
|
|
2742
|
+
if (noteRecords.length !== lookupIdStrings.length) {
|
|
2725
2743
|
throw new Error("Some notes could not be found for provided IDs");
|
|
2726
2744
|
}
|
|
2727
2745
|
const recordById = new Map(
|
|
2728
2746
|
noteRecords.map((r) => [r.id().toString(), r])
|
|
2729
2747
|
);
|
|
2730
2748
|
for (let j = 0; j < lookupIndices.length; j++) {
|
|
2731
|
-
const record = recordById.get(
|
|
2749
|
+
const record = recordById.get(lookupIdStrings[j]);
|
|
2732
2750
|
if (!record) {
|
|
2733
2751
|
throw new Error(
|
|
2734
2752
|
"Some notes could not be found for provided IDs"
|
|
@@ -2750,7 +2768,7 @@ function useConsume() {
|
|
|
2750
2768
|
txRequest,
|
|
2751
2769
|
prover
|
|
2752
2770
|
) : await client.submitNewTransaction(accountIdObj, txRequest);
|
|
2753
|
-
return { transactionId: txId.
|
|
2771
|
+
return { transactionId: txId.toHex() };
|
|
2754
2772
|
});
|
|
2755
2773
|
setStage("complete");
|
|
2756
2774
|
setResult(txResult);
|
|
@@ -2824,7 +2842,7 @@ function useSwap() {
|
|
|
2824
2842
|
txRequest,
|
|
2825
2843
|
prover
|
|
2826
2844
|
) : await client.submitNewTransaction(accountIdObj, txRequest);
|
|
2827
|
-
return { transactionId: txId.
|
|
2845
|
+
return { transactionId: txId.toHex() };
|
|
2828
2846
|
});
|
|
2829
2847
|
setStage("complete");
|
|
2830
2848
|
setResult(txResult);
|
|
@@ -2959,7 +2977,7 @@ function useTransaction() {
|
|
|
2959
2977
|
);
|
|
2960
2978
|
}
|
|
2961
2979
|
}
|
|
2962
|
-
const txSummary = { transactionId: txId.
|
|
2980
|
+
const txSummary = { transactionId: txId.toHex() };
|
|
2963
2981
|
setStage("complete");
|
|
2964
2982
|
setResult(txSummary);
|
|
2965
2983
|
await sync();
|
|
@@ -3191,13 +3209,14 @@ function useSessionAccount(options) {
|
|
|
3191
3209
|
setSessionAccountId(walletId);
|
|
3192
3210
|
localStorage.setItem(`${storagePrefix}:accountId`, walletId);
|
|
3193
3211
|
}
|
|
3212
|
+
const resolvedWalletId = walletId;
|
|
3194
3213
|
setStep("funding");
|
|
3195
|
-
await fundRef.current(
|
|
3214
|
+
await fundRef.current(resolvedWalletId);
|
|
3196
3215
|
if (cancelledRef.current) return;
|
|
3197
3216
|
setStep("consuming");
|
|
3198
3217
|
await waitAndConsume(
|
|
3199
3218
|
client,
|
|
3200
|
-
|
|
3219
|
+
resolvedWalletId,
|
|
3201
3220
|
pollIntervalMs,
|
|
3202
3221
|
maxWaitMs,
|
|
3203
3222
|
cancelledRef
|
package/dist/lazy.d.ts
CHANGED
|
@@ -150,6 +150,22 @@ interface MidenConfig {
|
|
|
150
150
|
proverUrls?: ProverUrls;
|
|
151
151
|
/** Default timeout for remote prover requests in milliseconds. */
|
|
152
152
|
proverTimeoutMs?: number | bigint;
|
|
153
|
+
/**
|
|
154
|
+
* Enable the Web Worker shim that runs WASM calls off the main thread.
|
|
155
|
+
* Defaults to `true` — leave it that way in browsers/extensions so the UI
|
|
156
|
+
* stays responsive while WASM is busy.
|
|
157
|
+
*
|
|
158
|
+
* Set to `false` when:
|
|
159
|
+
* - You pass a `CallbackProver` (e.g. a native iOS/Android prover via
|
|
160
|
+
* a Capacitor plugin). The worker boundary serializes the prover with
|
|
161
|
+
* `TransactionProver.serialize()`, which has no encoding for the
|
|
162
|
+
* callback variant and silently downgrades to `"local"` — your
|
|
163
|
+
* callback would never fire.
|
|
164
|
+
* - You're embedding the client in a single-WebView native shell
|
|
165
|
+
* (Capacitor host, Tauri, Electron preload), where the UI thread
|
|
166
|
+
* isn't competing with the WASM thread anyway.
|
|
167
|
+
*/
|
|
168
|
+
useWorker?: boolean;
|
|
153
169
|
}
|
|
154
170
|
interface MidenState {
|
|
155
171
|
client: WasmWebClient | null;
|