@miden-sdk/react 0.13.3 → 0.14.0
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 +2 -2
- package/README.md +111 -3
- package/dist/index.d.mts +339 -124
- package/dist/index.d.ts +339 -124
- package/dist/index.js +1124 -623
- package/dist/index.mjs +1043 -549
- package/package.json +9 -2
package/dist/index.mjs
CHANGED
|
@@ -17,24 +17,33 @@ var initialSyncState = {
|
|
|
17
17
|
lastSyncTime: null,
|
|
18
18
|
error: null
|
|
19
19
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
20
|
+
function freshCachedState() {
|
|
21
|
+
return {
|
|
22
|
+
sync: { ...initialSyncState },
|
|
23
|
+
syncPaused: false,
|
|
24
|
+
accounts: [],
|
|
25
|
+
accountDetails: /* @__PURE__ */ new Map(),
|
|
26
|
+
notes: [],
|
|
27
|
+
consumableNotes: [],
|
|
28
|
+
assetMetadata: /* @__PURE__ */ new Map(),
|
|
29
|
+
noteFirstSeen: /* @__PURE__ */ new Map(),
|
|
30
|
+
isLoadingAccounts: false,
|
|
31
|
+
isLoadingNotes: false
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function freshState() {
|
|
35
|
+
return {
|
|
36
|
+
client: null,
|
|
37
|
+
isReady: false,
|
|
38
|
+
isInitializing: false,
|
|
39
|
+
initError: null,
|
|
40
|
+
config: {},
|
|
41
|
+
signerConnected: null,
|
|
42
|
+
...freshCachedState()
|
|
43
|
+
};
|
|
44
|
+
}
|
|
36
45
|
var useMidenStore = create()((set) => ({
|
|
37
|
-
...
|
|
46
|
+
...freshState(),
|
|
38
47
|
setClient: (client) => set({
|
|
39
48
|
client,
|
|
40
49
|
isReady: client !== null,
|
|
@@ -48,9 +57,11 @@ var useMidenStore = create()((set) => ({
|
|
|
48
57
|
isReady: false
|
|
49
58
|
}),
|
|
50
59
|
setConfig: (config) => set({ config }),
|
|
60
|
+
setSignerConnected: (signerConnected) => set({ signerConnected }),
|
|
51
61
|
setSyncState: (sync) => set((state) => ({
|
|
52
62
|
sync: { ...state.sync, ...sync }
|
|
53
63
|
})),
|
|
64
|
+
setSyncPaused: (syncPaused) => set({ syncPaused }),
|
|
54
65
|
setAccounts: (accounts) => set({ accounts }),
|
|
55
66
|
setAccountDetails: (accountId, account) => set((state) => {
|
|
56
67
|
const newMap = new Map(state.accountDetails);
|
|
@@ -132,7 +143,8 @@ var useMidenStore = create()((set) => ({
|
|
|
132
143
|
}),
|
|
133
144
|
setLoadingAccounts: (isLoadingAccounts) => set({ isLoadingAccounts }),
|
|
134
145
|
setLoadingNotes: (isLoadingNotes) => set({ isLoadingNotes }),
|
|
135
|
-
|
|
146
|
+
resetInMemoryState: () => set(freshCachedState()),
|
|
147
|
+
reset: () => set(freshState())
|
|
136
148
|
}));
|
|
137
149
|
var useSyncStateStore = () => useMidenStore((state) => state.sync);
|
|
138
150
|
var useAccountsStore = () => useMidenStore((state) => state.accounts);
|
|
@@ -157,11 +169,13 @@ var parseAccountIdFromString = (value) => {
|
|
|
157
169
|
return AccountId.fromHex(normalizeHexInput(value));
|
|
158
170
|
};
|
|
159
171
|
var parseAccountId = (value) => {
|
|
160
|
-
if (typeof value
|
|
161
|
-
return value;
|
|
172
|
+
if (typeof value === "string") {
|
|
173
|
+
return parseAccountIdFromString(normalizeAccountIdInput(value));
|
|
162
174
|
}
|
|
163
|
-
|
|
164
|
-
|
|
175
|
+
if (typeof value.id === "function") {
|
|
176
|
+
return value.id();
|
|
177
|
+
}
|
|
178
|
+
return value;
|
|
165
179
|
};
|
|
166
180
|
function isFaucetId(accountId) {
|
|
167
181
|
try {
|
|
@@ -177,6 +191,10 @@ function isFaucetId(accountId) {
|
|
|
177
191
|
}
|
|
178
192
|
}
|
|
179
193
|
var parseAddress = (value, accountId) => {
|
|
194
|
+
if (typeof value !== "string") {
|
|
195
|
+
const resolvedId = accountId ?? parseAccountId(value);
|
|
196
|
+
return Address.fromAccountId(resolvedId, "BasicWallet");
|
|
197
|
+
}
|
|
180
198
|
const normalized = normalizeAccountIdInput(value);
|
|
181
199
|
if (isBech32Input(normalized)) {
|
|
182
200
|
try {
|
|
@@ -288,16 +306,17 @@ import {
|
|
|
288
306
|
useMemo,
|
|
289
307
|
useState
|
|
290
308
|
} from "react";
|
|
291
|
-
import { WebClient } from "@miden-sdk/miden-sdk";
|
|
309
|
+
import { WasmWebClient as WebClient } from "@miden-sdk/miden-sdk";
|
|
292
310
|
|
|
293
311
|
// src/types/index.ts
|
|
312
|
+
import { AuthScheme } from "@miden-sdk/miden-sdk";
|
|
294
313
|
var DEFAULTS = {
|
|
295
314
|
RPC_URL: void 0,
|
|
296
315
|
// Will use SDK's testnet default
|
|
297
316
|
AUTO_SYNC_INTERVAL: 15e3,
|
|
298
317
|
STORAGE_MODE: "private",
|
|
299
318
|
WALLET_MUTABLE: true,
|
|
300
|
-
AUTH_SCHEME:
|
|
319
|
+
AUTH_SCHEME: AuthScheme.AuthRpoFalcon512,
|
|
301
320
|
NOTE_TYPE: "private",
|
|
302
321
|
FAUCET_DECIMALS: 8
|
|
303
322
|
};
|
|
@@ -351,9 +370,35 @@ function resolveTransactionProver(config) {
|
|
|
351
370
|
if (!prover) {
|
|
352
371
|
return null;
|
|
353
372
|
}
|
|
354
|
-
if (
|
|
355
|
-
|
|
356
|
-
|
|
373
|
+
if (isFallbackConfig(prover)) {
|
|
374
|
+
return resolveProverTarget(prover.primary, config);
|
|
375
|
+
}
|
|
376
|
+
return resolveProverTarget(prover, config);
|
|
377
|
+
}
|
|
378
|
+
async function proveWithFallback(proveFn, config) {
|
|
379
|
+
const primaryProver = resolveTransactionProver(config);
|
|
380
|
+
try {
|
|
381
|
+
return await proveFn(primaryProver ?? void 0);
|
|
382
|
+
} catch (primaryError) {
|
|
383
|
+
const { prover } = config;
|
|
384
|
+
if (!prover || !isFallbackConfig(prover) || !prover.fallback) {
|
|
385
|
+
throw primaryError;
|
|
386
|
+
}
|
|
387
|
+
if (prover.disableFallback?.()) {
|
|
388
|
+
throw primaryError;
|
|
389
|
+
}
|
|
390
|
+
const fallbackProver = resolveProverTarget(prover.fallback, config);
|
|
391
|
+
prover.onFallback?.();
|
|
392
|
+
return await proveFn(fallbackProver ?? void 0);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function isFallbackConfig(prover) {
|
|
396
|
+
return typeof prover === "object" && "primary" in prover;
|
|
397
|
+
}
|
|
398
|
+
function resolveProverTarget(target, config) {
|
|
399
|
+
if (typeof target === "string") {
|
|
400
|
+
const normalized = target.trim().toLowerCase();
|
|
401
|
+
if (normalized === "local" || normalized === "localhost") {
|
|
357
402
|
return TransactionProver.newLocalProver();
|
|
358
403
|
}
|
|
359
404
|
if (normalized === "devnet" || normalized === "testnet") {
|
|
@@ -367,11 +412,11 @@ function resolveTransactionProver(config) {
|
|
|
367
412
|
);
|
|
368
413
|
}
|
|
369
414
|
return TransactionProver.newRemoteProver(
|
|
370
|
-
|
|
415
|
+
target,
|
|
371
416
|
normalizeTimeout(config.proverTimeoutMs)
|
|
372
417
|
);
|
|
373
418
|
}
|
|
374
|
-
return createRemoteProver(
|
|
419
|
+
return createRemoteProver(target, config.proverTimeoutMs);
|
|
375
420
|
}
|
|
376
421
|
function createRemoteProver(config, fallbackTimeout) {
|
|
377
422
|
const { url, timeoutMs } = config;
|
|
@@ -401,35 +446,41 @@ function useSigner() {
|
|
|
401
446
|
}
|
|
402
447
|
|
|
403
448
|
// src/utils/signerAccount.ts
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return AccountType.FungibleFaucet;
|
|
413
|
-
case "NonFungibleFaucet":
|
|
414
|
-
return AccountType.NonFungibleFaucet;
|
|
415
|
-
default:
|
|
416
|
-
return AccountType.RegularAccountImmutableCode;
|
|
417
|
-
}
|
|
449
|
+
var WASM_ACCOUNT_TYPE = {
|
|
450
|
+
FungibleFaucet: 0,
|
|
451
|
+
NonFungibleFaucet: 1,
|
|
452
|
+
RegularAccountImmutableCode: 2,
|
|
453
|
+
RegularAccountUpdatableCode: 3
|
|
454
|
+
};
|
|
455
|
+
function getAccountType(accountType) {
|
|
456
|
+
return WASM_ACCOUNT_TYPE[accountType] ?? WASM_ACCOUNT_TYPE.RegularAccountImmutableCode;
|
|
418
457
|
}
|
|
419
458
|
function isPrivateStorageMode(storageMode) {
|
|
420
459
|
return storageMode.toString() === "private";
|
|
421
460
|
}
|
|
422
461
|
async function initializeSignerAccount(client, config) {
|
|
423
|
-
const { AccountBuilder, AccountComponent, Word: Word2 } = await import("@miden-sdk/miden-sdk");
|
|
462
|
+
const { AccountBuilder, AccountComponent, AuthScheme: AuthScheme2, Word: Word2 } = await import("@miden-sdk/miden-sdk");
|
|
424
463
|
await client.syncState();
|
|
464
|
+
if (config.importAccountId) {
|
|
465
|
+
const accountId2 = parseAccountId(config.importAccountId);
|
|
466
|
+
try {
|
|
467
|
+
await client.importAccountById(accountId2);
|
|
468
|
+
} catch (e) {
|
|
469
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
470
|
+
if (!msg.includes("already being tracked")) {
|
|
471
|
+
throw e;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
await client.syncState();
|
|
475
|
+
return config.importAccountId;
|
|
476
|
+
}
|
|
425
477
|
const commitmentWord = Word2.deserialize(config.publicKeyCommitment);
|
|
426
478
|
const seed = config.accountSeed ?? crypto.getRandomValues(new Uint8Array(32));
|
|
427
|
-
const accountType =
|
|
479
|
+
const accountType = getAccountType(config.accountType);
|
|
428
480
|
let builder = new AccountBuilder(seed).withAuthComponent(
|
|
429
481
|
AccountComponent.createAuthComponentFromCommitment(
|
|
430
482
|
commitmentWord,
|
|
431
|
-
|
|
432
|
-
// ECDSA auth scheme (K256/Keccak)
|
|
483
|
+
AuthScheme2.AuthEcdsaK256Keccak
|
|
433
484
|
)
|
|
434
485
|
).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent();
|
|
435
486
|
if (config.customComponents?.length) {
|
|
@@ -480,15 +531,19 @@ function MidenProvider({
|
|
|
480
531
|
isReady,
|
|
481
532
|
isInitializing,
|
|
482
533
|
initError,
|
|
534
|
+
signerConnected,
|
|
483
535
|
setClient,
|
|
484
536
|
setInitializing,
|
|
485
537
|
setInitError,
|
|
486
538
|
setConfig,
|
|
487
|
-
setSyncState
|
|
539
|
+
setSyncState,
|
|
540
|
+
setSignerConnected
|
|
488
541
|
} = useMidenStore();
|
|
489
542
|
const syncIntervalRef = useRef(null);
|
|
490
543
|
const isInitializedRef = useRef(false);
|
|
491
544
|
const clientLockRef = useRef(new AsyncLock());
|
|
545
|
+
const currentStoreNameRef = useRef(null);
|
|
546
|
+
const signCbRef = useRef(null);
|
|
492
547
|
const signerContext = useSigner();
|
|
493
548
|
const [signerAccountId, setSignerAccountId] = useState(null);
|
|
494
549
|
const resolvedConfig = useMemo(
|
|
@@ -516,35 +571,62 @@ function MidenProvider({
|
|
|
516
571
|
const store = useMidenStore.getState();
|
|
517
572
|
if (store.sync.isSyncing) return;
|
|
518
573
|
setSyncState({ isSyncing: true, error: null });
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
574
|
+
try {
|
|
575
|
+
const summary = await client.syncState();
|
|
576
|
+
const syncHeight = summary.blockNum();
|
|
577
|
+
setSyncState({
|
|
578
|
+
syncHeight,
|
|
579
|
+
isSyncing: false,
|
|
580
|
+
lastSyncTime: Date.now(),
|
|
581
|
+
error: null
|
|
582
|
+
});
|
|
583
|
+
const accounts = await client.getAccounts();
|
|
584
|
+
useMidenStore.getState().setAccounts(accounts);
|
|
585
|
+
} catch (error) {
|
|
586
|
+
setSyncState({
|
|
587
|
+
isSyncing: false,
|
|
588
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
}, [client, isReady, setSyncState]);
|
|
592
|
+
const signerIsConnected = signerContext?.isConnected ?? null;
|
|
593
|
+
const signerStoreName = signerContext?.storeName ?? null;
|
|
594
|
+
const signerAccountType = signerContext?.accountConfig?.accountType ?? null;
|
|
595
|
+
const signerStorageMode = signerContext?.accountConfig?.storageMode?.toString() ?? null;
|
|
596
|
+
useEffect(() => {
|
|
597
|
+
signCbRef.current = signerContext?.signCb ?? null;
|
|
598
|
+
}, [signerContext?.signCb]);
|
|
599
|
+
const wrappedSignCb = useCallback(
|
|
600
|
+
async (pubKey, signingInputs) => {
|
|
601
|
+
const cb = signCbRef.current;
|
|
602
|
+
if (!cb) {
|
|
603
|
+
throw new Error("Signer is disconnected. Cannot sign.");
|
|
536
604
|
}
|
|
537
|
-
|
|
538
|
-
|
|
605
|
+
return cb(pubKey, signingInputs);
|
|
606
|
+
},
|
|
607
|
+
[]
|
|
608
|
+
);
|
|
539
609
|
useEffect(() => {
|
|
540
|
-
if (
|
|
541
|
-
if (
|
|
542
|
-
|
|
543
|
-
|
|
610
|
+
if (signerIsConnected === null && isInitializedRef.current) return;
|
|
611
|
+
if (signerIsConnected === false) {
|
|
612
|
+
const store = useMidenStore.getState();
|
|
613
|
+
if (store.signerConnected !== false) {
|
|
614
|
+
setSignerConnected(false);
|
|
615
|
+
}
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (signerIsConnected === true && signerStoreName !== null) {
|
|
619
|
+
const store = useMidenStore.getState();
|
|
620
|
+
if (currentStoreNameRef.current === signerStoreName && store.client !== null) {
|
|
621
|
+
store.client.setSignCb(wrappedSignCb);
|
|
622
|
+
setSignerConnected(true);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
if (currentStoreNameRef.current !== null && currentStoreNameRef.current !== signerStoreName) {
|
|
626
|
+
store.resetInMemoryState();
|
|
544
627
|
setClient(null);
|
|
545
628
|
setSignerAccountId(null);
|
|
546
629
|
}
|
|
547
|
-
return;
|
|
548
630
|
}
|
|
549
631
|
let cancelled = false;
|
|
550
632
|
const initClient = async () => {
|
|
@@ -555,18 +637,17 @@ function MidenProvider({
|
|
|
555
637
|
try {
|
|
556
638
|
let webClient;
|
|
557
639
|
let didSignerInit = false;
|
|
558
|
-
if (signerContext &&
|
|
640
|
+
if (signerContext && signerIsConnected === true) {
|
|
559
641
|
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
642
|
+
signCbRef.current = signerContext.signCb;
|
|
560
643
|
webClient = await WebClient.createClientWithExternalKeystore(
|
|
561
644
|
resolvedConfig.rpcUrl,
|
|
562
645
|
resolvedConfig.noteTransportUrl,
|
|
563
646
|
resolvedConfig.seed,
|
|
564
647
|
storeName,
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
// insertKeyCb - not needed for public accounts
|
|
569
|
-
signerContext.signCb
|
|
648
|
+
signerContext.getKeyCb,
|
|
649
|
+
signerContext.insertKeyCb,
|
|
650
|
+
wrappedSignCb
|
|
570
651
|
);
|
|
571
652
|
if (cancelled) return;
|
|
572
653
|
const accountId = await initializeSignerAccount(
|
|
@@ -576,6 +657,7 @@ function MidenProvider({
|
|
|
576
657
|
if (cancelled) return;
|
|
577
658
|
setSignerAccountId(accountId);
|
|
578
659
|
didSignerInit = true;
|
|
660
|
+
currentStoreNameRef.current = signerContext.storeName;
|
|
579
661
|
} else {
|
|
580
662
|
const seed = resolvedConfig.seed;
|
|
581
663
|
webClient = await WebClient.createClient(
|
|
@@ -609,6 +691,9 @@ function MidenProvider({
|
|
|
609
691
|
isInitializedRef.current = true;
|
|
610
692
|
}
|
|
611
693
|
setClient(webClient);
|
|
694
|
+
if (signerIsConnected === true) {
|
|
695
|
+
setSignerConnected(true);
|
|
696
|
+
}
|
|
612
697
|
}
|
|
613
698
|
} catch (error) {
|
|
614
699
|
if (!cancelled) {
|
|
@@ -632,14 +717,26 @@ function MidenProvider({
|
|
|
632
717
|
setInitError,
|
|
633
718
|
setInitializing,
|
|
634
719
|
setSyncState,
|
|
635
|
-
|
|
720
|
+
setSignerConnected,
|
|
721
|
+
signerIsConnected,
|
|
722
|
+
signerStoreName,
|
|
723
|
+
signerAccountType,
|
|
724
|
+
signerStorageMode,
|
|
725
|
+
wrappedSignCb
|
|
726
|
+
// Note: signerContext is intentionally NOT a dep — we use stable primitives
|
|
727
|
+
// (signerIsConnected, signerStoreName, signerAccountType, signerStorageMode)
|
|
728
|
+
// to avoid re-running when the signer provider creates a new object ref.
|
|
729
|
+
// signCb changes are handled by the dedicated useEffect + signCbRef above,
|
|
730
|
+
// not by this effect.
|
|
636
731
|
]);
|
|
637
732
|
useEffect(() => {
|
|
638
733
|
if (!isReady || !client) return;
|
|
639
734
|
const interval = config.autoSyncInterval ?? DEFAULTS.AUTO_SYNC_INTERVAL;
|
|
640
735
|
if (interval <= 0) return;
|
|
641
736
|
syncIntervalRef.current = setInterval(() => {
|
|
642
|
-
|
|
737
|
+
if (!useMidenStore.getState().syncPaused) {
|
|
738
|
+
sync();
|
|
739
|
+
}
|
|
643
740
|
}, interval);
|
|
644
741
|
return () => {
|
|
645
742
|
if (syncIntervalRef.current) {
|
|
@@ -648,6 +745,20 @@ function MidenProvider({
|
|
|
648
745
|
}
|
|
649
746
|
};
|
|
650
747
|
}, [isReady, client, config.autoSyncInterval, sync]);
|
|
748
|
+
useEffect(() => {
|
|
749
|
+
if (!isReady || !client) return;
|
|
750
|
+
const unsubscribe = client.onStateChanged?.(async () => {
|
|
751
|
+
try {
|
|
752
|
+
const accounts = await client.getAccounts();
|
|
753
|
+
useMidenStore.getState().setAccounts(accounts);
|
|
754
|
+
setSyncState({ lastSyncTime: Date.now() });
|
|
755
|
+
} catch {
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
return () => {
|
|
759
|
+
unsubscribe?.();
|
|
760
|
+
};
|
|
761
|
+
}, [isReady, client, setSyncState]);
|
|
651
762
|
if (isInitializing && loadingComponent) {
|
|
652
763
|
return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent });
|
|
653
764
|
}
|
|
@@ -665,7 +776,8 @@ function MidenProvider({
|
|
|
665
776
|
sync,
|
|
666
777
|
runExclusive,
|
|
667
778
|
prover: defaultProver,
|
|
668
|
-
signerAccountId
|
|
779
|
+
signerAccountId,
|
|
780
|
+
signerConnected
|
|
669
781
|
};
|
|
670
782
|
return /* @__PURE__ */ jsx(MidenContext.Provider, { value: contextValue, children });
|
|
671
783
|
}
|
|
@@ -686,35 +798,191 @@ function useMidenClient() {
|
|
|
686
798
|
return client;
|
|
687
799
|
}
|
|
688
800
|
|
|
689
|
-
// src/
|
|
690
|
-
import {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
801
|
+
// src/context/MultiSignerProvider.tsx
|
|
802
|
+
import {
|
|
803
|
+
createContext as createContext3,
|
|
804
|
+
useContext as useContext3,
|
|
805
|
+
useEffect as useEffect2,
|
|
806
|
+
useRef as useRef2,
|
|
807
|
+
useState as useState2,
|
|
808
|
+
useCallback as useCallback2,
|
|
809
|
+
useMemo as useMemo2
|
|
810
|
+
} from "react";
|
|
811
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
812
|
+
var MultiSignerRegistryContext = createContext3(null);
|
|
813
|
+
var MultiSignerContext = createContext3(null);
|
|
814
|
+
function MultiSignerProvider({ children }) {
|
|
815
|
+
const signersRef = useRef2(/* @__PURE__ */ new Map());
|
|
816
|
+
const [signersSnapshot, setSignersSnapshot] = useState2(
|
|
817
|
+
[]
|
|
818
|
+
);
|
|
819
|
+
const [activeSignerName, setActiveSignerName] = useState2(null);
|
|
820
|
+
const activeSignerNameRef = useRef2(null);
|
|
821
|
+
const generationRef = useRef2(0);
|
|
822
|
+
const updateSnapshot = useCallback2(() => {
|
|
823
|
+
setSignersSnapshot(Array.from(signersRef.current.values()));
|
|
824
|
+
}, []);
|
|
825
|
+
const register = useCallback2(
|
|
826
|
+
(value) => {
|
|
827
|
+
const prev = signersRef.current.get(value.name);
|
|
828
|
+
signersRef.current.set(value.name, value);
|
|
829
|
+
if (!prev || prev.name !== value.name || prev.isConnected !== value.isConnected || prev.storeName !== value.storeName || prev.accountConfig !== value.accountConfig) {
|
|
830
|
+
updateSnapshot();
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
[updateSnapshot]
|
|
834
|
+
);
|
|
835
|
+
const unregister = useCallback2(
|
|
836
|
+
(name) => {
|
|
837
|
+
signersRef.current.delete(name);
|
|
838
|
+
setActiveSignerName((current) => current === name ? null : current);
|
|
839
|
+
updateSnapshot();
|
|
840
|
+
},
|
|
841
|
+
[updateSnapshot]
|
|
842
|
+
);
|
|
843
|
+
const registry = useMemo2(
|
|
844
|
+
() => ({ register, unregister }),
|
|
845
|
+
[register, unregister]
|
|
846
|
+
);
|
|
847
|
+
const activeSigner = activeSignerName ? signersSnapshot.find((s) => s.name === activeSignerName) ?? null : null;
|
|
848
|
+
const stableSignCb = useCallback2(
|
|
849
|
+
async (pubKey, signingInputs) => {
|
|
850
|
+
const name = activeSignerName;
|
|
851
|
+
if (!name) throw new Error("No active signer (signer was disconnected)");
|
|
852
|
+
const signer = signersRef.current.get(name);
|
|
853
|
+
if (!signer) throw new Error(`Signer "${name}" not found in registry`);
|
|
854
|
+
return signer.signCb(pubKey, signingInputs);
|
|
855
|
+
},
|
|
856
|
+
[activeSignerName]
|
|
857
|
+
);
|
|
858
|
+
const stableConnect = useCallback2(async () => {
|
|
859
|
+
const name = activeSignerName;
|
|
860
|
+
if (!name) throw new Error("No active signer (signer was disconnected)");
|
|
861
|
+
const signer = signersRef.current.get(name);
|
|
862
|
+
if (!signer) throw new Error(`Signer "${name}" not found in registry`);
|
|
863
|
+
return signer.connect();
|
|
864
|
+
}, [activeSignerName]);
|
|
865
|
+
const stableDisconnect = useCallback2(async () => {
|
|
866
|
+
const name = activeSignerName;
|
|
867
|
+
if (!name) throw new Error("No active signer (signer was disconnected)");
|
|
868
|
+
const signer = signersRef.current.get(name);
|
|
869
|
+
if (!signer) throw new Error(`Signer "${name}" not found in registry`);
|
|
870
|
+
return signer.disconnect();
|
|
871
|
+
}, [activeSignerName]);
|
|
872
|
+
const forwardedValue = useMemo2(() => {
|
|
873
|
+
if (!activeSigner) return null;
|
|
874
|
+
return {
|
|
875
|
+
name: activeSigner.name,
|
|
876
|
+
isConnected: activeSigner.isConnected,
|
|
877
|
+
storeName: activeSigner.storeName,
|
|
878
|
+
accountConfig: activeSigner.accountConfig,
|
|
879
|
+
signCb: stableSignCb,
|
|
880
|
+
connect: stableConnect,
|
|
881
|
+
disconnect: stableDisconnect
|
|
882
|
+
};
|
|
883
|
+
}, [
|
|
884
|
+
activeSigner?.name,
|
|
885
|
+
activeSigner?.isConnected,
|
|
886
|
+
activeSigner?.storeName,
|
|
887
|
+
activeSigner?.accountConfig,
|
|
888
|
+
stableSignCb,
|
|
889
|
+
stableConnect,
|
|
890
|
+
stableDisconnect
|
|
891
|
+
]);
|
|
892
|
+
const setActiveName = useCallback2((name) => {
|
|
893
|
+
activeSignerNameRef.current = name;
|
|
894
|
+
setActiveSignerName(name);
|
|
895
|
+
}, []);
|
|
896
|
+
const connectSigner = useCallback2(
|
|
897
|
+
async (name) => {
|
|
898
|
+
const currentName = activeSignerNameRef.current;
|
|
899
|
+
const currentSigner = currentName ? signersRef.current.get(currentName) : null;
|
|
900
|
+
if (currentName === name && currentSigner?.isConnected) return;
|
|
901
|
+
const newSigner = signersRef.current.get(name);
|
|
902
|
+
if (!newSigner) throw new Error(`Signer "${name}" not found`);
|
|
903
|
+
const generation = ++generationRef.current;
|
|
904
|
+
setActiveName(name);
|
|
905
|
+
if (currentSigner?.isConnected) {
|
|
906
|
+
currentSigner.disconnect().catch((err) => {
|
|
907
|
+
console.warn("Failed to disconnect previous signer:", err);
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
try {
|
|
911
|
+
await newSigner.connect();
|
|
912
|
+
if (generation !== generationRef.current) return;
|
|
913
|
+
} catch (err) {
|
|
914
|
+
if (generation !== generationRef.current) return;
|
|
915
|
+
setActiveName(null);
|
|
916
|
+
throw err;
|
|
917
|
+
}
|
|
918
|
+
},
|
|
919
|
+
[setActiveName]
|
|
920
|
+
);
|
|
921
|
+
const disconnectSigner = useCallback2(async () => {
|
|
922
|
+
++generationRef.current;
|
|
923
|
+
const currentName = activeSignerNameRef.current;
|
|
924
|
+
const signer = currentName ? signersRef.current.get(currentName) : null;
|
|
925
|
+
setActiveName(null);
|
|
926
|
+
if (signer?.isConnected) {
|
|
927
|
+
signer.disconnect().catch((err) => {
|
|
928
|
+
console.warn("Failed to disconnect signer:", err);
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
}, [setActiveName]);
|
|
932
|
+
const multiSignerValue = useMemo2(
|
|
933
|
+
() => ({
|
|
934
|
+
signers: signersSnapshot,
|
|
935
|
+
activeSigner,
|
|
936
|
+
connectSigner,
|
|
937
|
+
disconnectSigner
|
|
938
|
+
}),
|
|
939
|
+
[signersSnapshot, activeSigner, connectSigner, disconnectSigner]
|
|
940
|
+
);
|
|
941
|
+
return /* @__PURE__ */ jsx2(SignerContext.Provider, { value: forwardedValue, children: /* @__PURE__ */ jsx2(MultiSignerRegistryContext.Provider, { value: registry, children: /* @__PURE__ */ jsx2(MultiSignerContext.Provider, { value: multiSignerValue, children }) }) });
|
|
942
|
+
}
|
|
943
|
+
function SignerSlot() {
|
|
944
|
+
const signerValue = useSigner();
|
|
945
|
+
const registry = useContext3(MultiSignerRegistryContext);
|
|
946
|
+
const nameRef = useRef2();
|
|
947
|
+
useEffect2(() => {
|
|
948
|
+
if (!signerValue || !registry) return;
|
|
949
|
+
nameRef.current = signerValue.name;
|
|
950
|
+
registry.register(signerValue);
|
|
951
|
+
}, [signerValue, registry]);
|
|
952
|
+
useEffect2(() => {
|
|
953
|
+
return () => {
|
|
954
|
+
if (nameRef.current && registry) {
|
|
955
|
+
registry.unregister(nameRef.current);
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
}, [registry]);
|
|
959
|
+
return null;
|
|
960
|
+
}
|
|
961
|
+
function useMultiSigner() {
|
|
962
|
+
return useContext3(MultiSignerContext);
|
|
963
|
+
}
|
|
694
964
|
|
|
695
965
|
// src/hooks/useAccounts.ts
|
|
966
|
+
import { useCallback as useCallback3, useEffect as useEffect3 } from "react";
|
|
696
967
|
function useAccounts() {
|
|
697
|
-
const { client, isReady
|
|
698
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
968
|
+
const { client, isReady } = useMiden();
|
|
699
969
|
const accounts = useAccountsStore();
|
|
700
970
|
const isLoadingAccounts = useMidenStore((state) => state.isLoadingAccounts);
|
|
701
971
|
const setLoadingAccounts = useMidenStore((state) => state.setLoadingAccounts);
|
|
702
972
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
703
|
-
const refetch =
|
|
973
|
+
const refetch = useCallback3(async () => {
|
|
704
974
|
if (!client || !isReady) return;
|
|
705
975
|
setLoadingAccounts(true);
|
|
706
976
|
try {
|
|
707
|
-
const fetchedAccounts = await
|
|
708
|
-
() => client.getAccounts()
|
|
709
|
-
);
|
|
977
|
+
const fetchedAccounts = await client.getAccounts();
|
|
710
978
|
setAccounts(fetchedAccounts);
|
|
711
979
|
} catch (error) {
|
|
712
980
|
console.error("Failed to fetch accounts:", error);
|
|
713
981
|
} finally {
|
|
714
982
|
setLoadingAccounts(false);
|
|
715
983
|
}
|
|
716
|
-
}, [client, isReady,
|
|
717
|
-
|
|
984
|
+
}, [client, isReady, setAccounts, setLoadingAccounts]);
|
|
985
|
+
useEffect3(() => {
|
|
718
986
|
if (isReady && accounts.length === 0) {
|
|
719
987
|
refetch();
|
|
720
988
|
}
|
|
@@ -740,10 +1008,10 @@ function useAccounts() {
|
|
|
740
1008
|
}
|
|
741
1009
|
|
|
742
1010
|
// src/hooks/useAccount.ts
|
|
743
|
-
import { useCallback as
|
|
1011
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useState as useState3, useMemo as useMemo4 } from "react";
|
|
744
1012
|
|
|
745
1013
|
// src/hooks/useAssetMetadata.ts
|
|
746
|
-
import { useEffect as
|
|
1014
|
+
import { useEffect as useEffect4, useMemo as useMemo3 } from "react";
|
|
747
1015
|
import {
|
|
748
1016
|
BasicFungibleFaucetComponent,
|
|
749
1017
|
Endpoint,
|
|
@@ -783,12 +1051,12 @@ function useAssetMetadata(assetIds = []) {
|
|
|
783
1051
|
const assetMetadata = useAssetMetadataStore();
|
|
784
1052
|
const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
|
|
785
1053
|
const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
|
|
786
|
-
const rpcClient =
|
|
787
|
-
const uniqueAssetIds =
|
|
1054
|
+
const rpcClient = useMemo3(() => getRpcClient(rpcUrl), [rpcUrl]);
|
|
1055
|
+
const uniqueAssetIds = useMemo3(
|
|
788
1056
|
() => Array.from(new Set(assetIds.filter(Boolean))),
|
|
789
1057
|
[assetIds]
|
|
790
1058
|
);
|
|
791
|
-
|
|
1059
|
+
useEffect4(() => {
|
|
792
1060
|
if (!rpcClient || uniqueAssetIds.length === 0) return;
|
|
793
1061
|
uniqueAssetIds.forEach((assetId) => {
|
|
794
1062
|
const existing = assetMetadata.get(assetId);
|
|
@@ -807,31 +1075,25 @@ function useAssetMetadata(assetIds = []) {
|
|
|
807
1075
|
|
|
808
1076
|
// src/hooks/useAccount.ts
|
|
809
1077
|
function useAccount(accountId) {
|
|
810
|
-
const { client, isReady
|
|
811
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1078
|
+
const { client, isReady } = useMiden();
|
|
812
1079
|
const accountDetails = useMidenStore((state) => state.accountDetails);
|
|
813
1080
|
const setAccountDetails = useMidenStore((state) => state.setAccountDetails);
|
|
814
1081
|
const { lastSyncTime } = useSyncStateStore();
|
|
815
|
-
const [isLoading, setIsLoading] =
|
|
816
|
-
const [error, setError] =
|
|
817
|
-
const accountIdStr =
|
|
1082
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
1083
|
+
const [error, setError] = useState3(null);
|
|
1084
|
+
const accountIdStr = useMemo4(() => {
|
|
818
1085
|
if (!accountId) return void 0;
|
|
819
1086
|
if (typeof accountId === "string") return accountId;
|
|
820
|
-
|
|
821
|
-
return accountId.toString();
|
|
822
|
-
}
|
|
823
|
-
return String(accountId);
|
|
1087
|
+
return parseAccountId(accountId).toString();
|
|
824
1088
|
}, [accountId]);
|
|
825
1089
|
const account = accountIdStr ? accountDetails.get(accountIdStr) ?? null : null;
|
|
826
|
-
const refetch =
|
|
1090
|
+
const refetch = useCallback4(async () => {
|
|
827
1091
|
if (!client || !isReady || !accountIdStr) return;
|
|
828
1092
|
setIsLoading(true);
|
|
829
1093
|
setError(null);
|
|
830
1094
|
try {
|
|
831
1095
|
const accountIdObj = parseAccountId(accountIdStr);
|
|
832
|
-
const fetchedAccount = await
|
|
833
|
-
() => client.getAccount(accountIdObj)
|
|
834
|
-
);
|
|
1096
|
+
const fetchedAccount = await client.getAccount(accountIdObj);
|
|
835
1097
|
if (fetchedAccount) {
|
|
836
1098
|
ensureAccountBech32(fetchedAccount);
|
|
837
1099
|
setAccountDetails(accountIdStr, fetchedAccount);
|
|
@@ -841,17 +1103,17 @@ function useAccount(accountId) {
|
|
|
841
1103
|
} finally {
|
|
842
1104
|
setIsLoading(false);
|
|
843
1105
|
}
|
|
844
|
-
}, [client, isReady,
|
|
845
|
-
|
|
1106
|
+
}, [client, isReady, accountIdStr, setAccountDetails]);
|
|
1107
|
+
useEffect5(() => {
|
|
846
1108
|
if (isReady && accountIdStr && !account) {
|
|
847
1109
|
refetch();
|
|
848
1110
|
}
|
|
849
1111
|
}, [isReady, accountIdStr, account, refetch]);
|
|
850
|
-
|
|
1112
|
+
useEffect5(() => {
|
|
851
1113
|
if (!isReady || !accountIdStr || !lastSyncTime) return;
|
|
852
1114
|
refetch();
|
|
853
1115
|
}, [isReady, accountIdStr, lastSyncTime, refetch]);
|
|
854
|
-
const rawAssets =
|
|
1116
|
+
const rawAssets = useMemo4(() => {
|
|
855
1117
|
if (!account) return [];
|
|
856
1118
|
try {
|
|
857
1119
|
const vault = account.vault();
|
|
@@ -868,12 +1130,12 @@ function useAccount(accountId) {
|
|
|
868
1130
|
return [];
|
|
869
1131
|
}
|
|
870
1132
|
}, [account]);
|
|
871
|
-
const assetIds =
|
|
1133
|
+
const assetIds = useMemo4(
|
|
872
1134
|
() => rawAssets.map((asset) => asset.assetId),
|
|
873
1135
|
[rawAssets]
|
|
874
1136
|
);
|
|
875
1137
|
const { assetMetadata } = useAssetMetadata(assetIds);
|
|
876
|
-
const assets =
|
|
1138
|
+
const assets = useMemo4(
|
|
877
1139
|
() => rawAssets.map((asset) => {
|
|
878
1140
|
const metadata = assetMetadata.get(asset.assetId);
|
|
879
1141
|
return {
|
|
@@ -884,7 +1146,7 @@ function useAccount(accountId) {
|
|
|
884
1146
|
}),
|
|
885
1147
|
[rawAssets, assetMetadata]
|
|
886
1148
|
);
|
|
887
|
-
const getBalance =
|
|
1149
|
+
const getBalance = useCallback4(
|
|
888
1150
|
(assetId) => {
|
|
889
1151
|
const asset = assets.find((a) => a.assetId === assetId);
|
|
890
1152
|
return asset?.amount ?? 0n;
|
|
@@ -902,17 +1164,18 @@ function useAccount(accountId) {
|
|
|
902
1164
|
}
|
|
903
1165
|
|
|
904
1166
|
// src/hooks/useNotes.ts
|
|
905
|
-
import { useCallback as
|
|
1167
|
+
import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useState as useState4 } from "react";
|
|
906
1168
|
import { NoteFilter } from "@miden-sdk/miden-sdk";
|
|
907
1169
|
|
|
908
1170
|
// src/utils/amounts.ts
|
|
909
1171
|
var formatAssetAmount = (amount, decimals) => {
|
|
1172
|
+
const amt = BigInt(amount);
|
|
910
1173
|
if (!decimals || decimals <= 0) {
|
|
911
|
-
return
|
|
1174
|
+
return amt.toString();
|
|
912
1175
|
}
|
|
913
1176
|
const factor = 10n ** BigInt(decimals);
|
|
914
|
-
const whole =
|
|
915
|
-
const fraction =
|
|
1177
|
+
const whole = amt / factor;
|
|
1178
|
+
const fraction = amt % factor;
|
|
916
1179
|
if (fraction === 0n) {
|
|
917
1180
|
return whole.toString();
|
|
918
1181
|
}
|
|
@@ -1069,8 +1332,7 @@ function normalizeHex(value) {
|
|
|
1069
1332
|
|
|
1070
1333
|
// src/hooks/useNotes.ts
|
|
1071
1334
|
function useNotes(options) {
|
|
1072
|
-
const { client, isReady
|
|
1073
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1335
|
+
const { client, isReady } = useMiden();
|
|
1074
1336
|
const notes = useNotesStore();
|
|
1075
1337
|
const consumableNotes = useConsumableNotesStore();
|
|
1076
1338
|
const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
|
|
@@ -1080,30 +1342,22 @@ function useNotes(options) {
|
|
|
1080
1342
|
(state) => state.setConsumableNotesIfChanged
|
|
1081
1343
|
);
|
|
1082
1344
|
const { lastSyncTime } = useSyncStateStore();
|
|
1083
|
-
const [error, setError] =
|
|
1084
|
-
const refetch =
|
|
1345
|
+
const [error, setError] = useState4(null);
|
|
1346
|
+
const refetch = useCallback5(async () => {
|
|
1085
1347
|
if (!client || !isReady) return;
|
|
1086
1348
|
setLoadingNotes(true);
|
|
1087
1349
|
setError(null);
|
|
1088
1350
|
try {
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
consumableResult = await client.getConsumableNotes();
|
|
1100
|
-
}
|
|
1101
|
-
return {
|
|
1102
|
-
fetchedNotes: notesResult,
|
|
1103
|
-
fetchedConsumable: consumableResult
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
);
|
|
1351
|
+
const filterType = getNoteFilterType(options?.status);
|
|
1352
|
+
const filter = new NoteFilter(filterType);
|
|
1353
|
+
const fetchedNotes = await client.getInputNotes(filter);
|
|
1354
|
+
let fetchedConsumable;
|
|
1355
|
+
if (options?.accountId) {
|
|
1356
|
+
const accountIdObj = parseAccountId(options.accountId);
|
|
1357
|
+
fetchedConsumable = await client.getConsumableNotes(accountIdObj);
|
|
1358
|
+
} else {
|
|
1359
|
+
fetchedConsumable = await client.getConsumableNotes();
|
|
1360
|
+
}
|
|
1107
1361
|
setNotesIfChanged(fetchedNotes);
|
|
1108
1362
|
setConsumableNotesIfChanged(fetchedConsumable);
|
|
1109
1363
|
} catch (err) {
|
|
@@ -1114,23 +1368,22 @@ function useNotes(options) {
|
|
|
1114
1368
|
}, [
|
|
1115
1369
|
client,
|
|
1116
1370
|
isReady,
|
|
1117
|
-
runExclusive,
|
|
1118
1371
|
options?.status,
|
|
1119
1372
|
options?.accountId,
|
|
1120
1373
|
setLoadingNotes,
|
|
1121
1374
|
setNotesIfChanged,
|
|
1122
1375
|
setConsumableNotesIfChanged
|
|
1123
1376
|
]);
|
|
1124
|
-
|
|
1377
|
+
useEffect6(() => {
|
|
1125
1378
|
if (isReady && notes.length === 0) {
|
|
1126
1379
|
refetch();
|
|
1127
1380
|
}
|
|
1128
1381
|
}, [isReady, notes.length, refetch]);
|
|
1129
|
-
|
|
1382
|
+
useEffect6(() => {
|
|
1130
1383
|
if (!isReady || !lastSyncTime) return;
|
|
1131
1384
|
refetch();
|
|
1132
1385
|
}, [isReady, lastSyncTime, refetch]);
|
|
1133
|
-
const noteAssetIds =
|
|
1386
|
+
const noteAssetIds = useMemo5(() => {
|
|
1134
1387
|
const ids = /* @__PURE__ */ new Set();
|
|
1135
1388
|
const collect = (note) => {
|
|
1136
1389
|
const summary = getNoteSummary(note);
|
|
@@ -1142,11 +1395,11 @@ function useNotes(options) {
|
|
|
1142
1395
|
return Array.from(ids);
|
|
1143
1396
|
}, [notes, consumableNotes]);
|
|
1144
1397
|
const { assetMetadata } = useAssetMetadata(noteAssetIds);
|
|
1145
|
-
const getMetadata =
|
|
1398
|
+
const getMetadata = useCallback5(
|
|
1146
1399
|
(assetId) => assetMetadata.get(assetId),
|
|
1147
1400
|
[assetMetadata]
|
|
1148
1401
|
);
|
|
1149
|
-
const normalizedSender =
|
|
1402
|
+
const normalizedSender = useMemo5(() => {
|
|
1150
1403
|
if (!options?.sender) return null;
|
|
1151
1404
|
try {
|
|
1152
1405
|
return normalizeAccountId(options.sender);
|
|
@@ -1154,11 +1407,11 @@ function useNotes(options) {
|
|
|
1154
1407
|
return options.sender;
|
|
1155
1408
|
}
|
|
1156
1409
|
}, [options?.sender]);
|
|
1157
|
-
const excludeIdsKey =
|
|
1410
|
+
const excludeIdsKey = useMemo5(() => {
|
|
1158
1411
|
if (!options?.excludeIds || options.excludeIds.length === 0) return "";
|
|
1159
1412
|
return [...options.excludeIds].sort().join("\0");
|
|
1160
1413
|
}, [options?.excludeIds]);
|
|
1161
|
-
const filterBySender =
|
|
1414
|
+
const filterBySender = useCallback5(
|
|
1162
1415
|
(summaries, target) => {
|
|
1163
1416
|
const cache = /* @__PURE__ */ new Map();
|
|
1164
1417
|
return summaries.filter((s) => {
|
|
@@ -1177,7 +1430,7 @@ function useNotes(options) {
|
|
|
1177
1430
|
},
|
|
1178
1431
|
[]
|
|
1179
1432
|
);
|
|
1180
|
-
const noteSummaries =
|
|
1433
|
+
const noteSummaries = useMemo5(() => {
|
|
1181
1434
|
let summaries = notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1182
1435
|
if (normalizedSender) {
|
|
1183
1436
|
summaries = filterBySender(summaries, normalizedSender);
|
|
@@ -1188,7 +1441,7 @@ function useNotes(options) {
|
|
|
1188
1441
|
}
|
|
1189
1442
|
return summaries;
|
|
1190
1443
|
}, [notes, getMetadata, normalizedSender, excludeIdsKey, filterBySender]);
|
|
1191
|
-
const consumableNoteSummaries =
|
|
1444
|
+
const consumableNoteSummaries = useMemo5(() => {
|
|
1192
1445
|
let summaries = consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1193
1446
|
if (normalizedSender) {
|
|
1194
1447
|
summaries = filterBySender(summaries, normalizedSender);
|
|
@@ -1217,7 +1470,7 @@ function useNotes(options) {
|
|
|
1217
1470
|
}
|
|
1218
1471
|
|
|
1219
1472
|
// src/hooks/useNoteStream.ts
|
|
1220
|
-
import { useCallback as
|
|
1473
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3, useState as useState5 } from "react";
|
|
1221
1474
|
import { NoteFilter as NoteFilter2 } from "@miden-sdk/miden-sdk";
|
|
1222
1475
|
|
|
1223
1476
|
// src/utils/noteAttachment.ts
|
|
@@ -1293,54 +1546,51 @@ function createNoteAttachment(values) {
|
|
|
1293
1546
|
|
|
1294
1547
|
// src/hooks/useNoteStream.ts
|
|
1295
1548
|
function useNoteStream(options = {}) {
|
|
1296
|
-
const { client, isReady
|
|
1297
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1549
|
+
const { client, isReady } = useMiden();
|
|
1298
1550
|
const allNotes = useNotesStore();
|
|
1299
1551
|
const noteFirstSeen = useNoteFirstSeenStore();
|
|
1300
1552
|
const { lastSyncTime } = useSyncStateStore();
|
|
1301
1553
|
const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
|
|
1302
|
-
const [isLoading, setIsLoading] =
|
|
1303
|
-
const [error, setError] =
|
|
1304
|
-
const handledIdsRef =
|
|
1305
|
-
const [handledVersion, setHandledVersion] =
|
|
1554
|
+
const [isLoading, setIsLoading] = useState5(false);
|
|
1555
|
+
const [error, setError] = useState5(null);
|
|
1556
|
+
const handledIdsRef = useRef3(/* @__PURE__ */ new Set());
|
|
1557
|
+
const [handledVersion, setHandledVersion] = useState5(0);
|
|
1306
1558
|
const status = options.status ?? "committed";
|
|
1307
1559
|
const sender = options.sender ?? null;
|
|
1308
1560
|
const since = options.since;
|
|
1309
|
-
const amountFilterRef =
|
|
1561
|
+
const amountFilterRef = useRef3(options.amountFilter);
|
|
1310
1562
|
amountFilterRef.current = options.amountFilter;
|
|
1311
|
-
const excludeIdsKey =
|
|
1563
|
+
const excludeIdsKey = useMemo6(() => {
|
|
1312
1564
|
if (!options.excludeIds) return "";
|
|
1313
1565
|
if (options.excludeIds instanceof Set)
|
|
1314
1566
|
return Array.from(options.excludeIds).sort().join("\0");
|
|
1315
1567
|
return [...options.excludeIds].sort().join("\0");
|
|
1316
1568
|
}, [options.excludeIds]);
|
|
1317
|
-
const excludeIdSet =
|
|
1569
|
+
const excludeIdSet = useMemo6(() => {
|
|
1318
1570
|
if (!excludeIdsKey) return null;
|
|
1319
1571
|
return new Set(excludeIdsKey.split("\0"));
|
|
1320
1572
|
}, [excludeIdsKey]);
|
|
1321
|
-
const refetch =
|
|
1573
|
+
const refetch = useCallback6(async () => {
|
|
1322
1574
|
if (!client || !isReady) return;
|
|
1323
1575
|
setIsLoading(true);
|
|
1324
1576
|
setError(null);
|
|
1325
1577
|
try {
|
|
1326
1578
|
const filterType = getNoteFilterType(status);
|
|
1327
1579
|
const filter = new NoteFilter2(filterType);
|
|
1328
|
-
const fetched = await
|
|
1329
|
-
() => client.getInputNotes(filter)
|
|
1330
|
-
);
|
|
1580
|
+
const fetched = await client.getInputNotes(filter);
|
|
1331
1581
|
setNotesIfChanged(fetched);
|
|
1332
1582
|
} catch (err) {
|
|
1333
1583
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1334
1584
|
} finally {
|
|
1335
1585
|
setIsLoading(false);
|
|
1336
1586
|
}
|
|
1337
|
-
}, [client, isReady,
|
|
1338
|
-
|
|
1587
|
+
}, [client, isReady, status, setNotesIfChanged]);
|
|
1588
|
+
useEffect7(() => {
|
|
1339
1589
|
if (isReady) {
|
|
1340
1590
|
refetch();
|
|
1341
1591
|
}
|
|
1342
1592
|
}, [isReady, lastSyncTime, refetch]);
|
|
1343
|
-
const streamedNotes =
|
|
1593
|
+
const streamedNotes = useMemo6(() => {
|
|
1344
1594
|
void handledVersion;
|
|
1345
1595
|
const result = [];
|
|
1346
1596
|
let normalizedSender = null;
|
|
@@ -1365,15 +1615,15 @@ function useNoteStream(options = {}) {
|
|
|
1365
1615
|
result.sort((a, b) => a.firstSeenAt - b.firstSeenAt);
|
|
1366
1616
|
return result;
|
|
1367
1617
|
}, [allNotes, noteFirstSeen, excludeIdSet, sender, since, handledVersion]);
|
|
1368
|
-
const latest =
|
|
1618
|
+
const latest = useMemo6(
|
|
1369
1619
|
() => streamedNotes.length > 0 ? streamedNotes[streamedNotes.length - 1] : null,
|
|
1370
1620
|
[streamedNotes]
|
|
1371
1621
|
);
|
|
1372
|
-
const markHandled =
|
|
1622
|
+
const markHandled = useCallback6((noteId) => {
|
|
1373
1623
|
handledIdsRef.current = new Set(handledIdsRef.current).add(noteId);
|
|
1374
1624
|
setHandledVersion((v) => v + 1);
|
|
1375
1625
|
}, []);
|
|
1376
|
-
const markAllHandled =
|
|
1626
|
+
const markAllHandled = useCallback6(() => {
|
|
1377
1627
|
const newSet = new Set(handledIdsRef.current);
|
|
1378
1628
|
for (const note of streamedNotes) {
|
|
1379
1629
|
newSet.add(note.id);
|
|
@@ -1381,7 +1631,7 @@ function useNoteStream(options = {}) {
|
|
|
1381
1631
|
handledIdsRef.current = newSet;
|
|
1382
1632
|
setHandledVersion((v) => v + 1);
|
|
1383
1633
|
}, [streamedNotes]);
|
|
1384
|
-
const snapshot =
|
|
1634
|
+
const snapshot = useCallback6(() => {
|
|
1385
1635
|
const ids = /* @__PURE__ */ new Set();
|
|
1386
1636
|
for (const note of streamedNotes) {
|
|
1387
1637
|
ids.add(note.id);
|
|
@@ -1437,21 +1687,20 @@ function buildStreamedNote(record, noteFirstSeen) {
|
|
|
1437
1687
|
}
|
|
1438
1688
|
|
|
1439
1689
|
// src/hooks/useTransactionHistory.ts
|
|
1440
|
-
import { useCallback as
|
|
1690
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo7, useState as useState6 } from "react";
|
|
1441
1691
|
import { TransactionFilter as TransactionFilter2 } from "@miden-sdk/miden-sdk";
|
|
1442
1692
|
function useTransactionHistory(options = {}) {
|
|
1443
|
-
const { client, isReady
|
|
1444
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1693
|
+
const { client, isReady } = useMiden();
|
|
1445
1694
|
const { lastSyncTime } = useSyncStateStore();
|
|
1446
|
-
const [records, setRecords] =
|
|
1447
|
-
const [isLoading, setIsLoading] =
|
|
1448
|
-
const [error, setError] =
|
|
1449
|
-
const rawIds =
|
|
1695
|
+
const [records, setRecords] = useState6([]);
|
|
1696
|
+
const [isLoading, setIsLoading] = useState6(false);
|
|
1697
|
+
const [error, setError] = useState6(null);
|
|
1698
|
+
const rawIds = useMemo7(() => {
|
|
1450
1699
|
if (options.id) return [options.id];
|
|
1451
1700
|
if (options.ids && options.ids.length > 0) return options.ids;
|
|
1452
1701
|
return null;
|
|
1453
1702
|
}, [options.id, options.ids]);
|
|
1454
|
-
const idsHex =
|
|
1703
|
+
const idsHex = useMemo7(() => {
|
|
1455
1704
|
if (!rawIds) return null;
|
|
1456
1705
|
return rawIds.map(
|
|
1457
1706
|
(id) => normalizeHex2(typeof id === "string" ? id : id.toHex())
|
|
@@ -1459,7 +1708,7 @@ function useTransactionHistory(options = {}) {
|
|
|
1459
1708
|
}, [rawIds]);
|
|
1460
1709
|
const filter = options.filter;
|
|
1461
1710
|
const refreshOnSync = options.refreshOnSync !== false;
|
|
1462
|
-
const refetch =
|
|
1711
|
+
const refetch = useCallback7(async () => {
|
|
1463
1712
|
if (!client || !isReady) return;
|
|
1464
1713
|
setIsLoading(true);
|
|
1465
1714
|
setError(null);
|
|
@@ -1469,9 +1718,7 @@ function useTransactionHistory(options = {}) {
|
|
|
1469
1718
|
rawIds,
|
|
1470
1719
|
idsHex
|
|
1471
1720
|
);
|
|
1472
|
-
const fetched = await
|
|
1473
|
-
() => client.getTransactions(resolvedFilter)
|
|
1474
|
-
);
|
|
1721
|
+
const fetched = await client.getTransactions(resolvedFilter);
|
|
1475
1722
|
const filtered = localFilterHexes ? fetched.filter(
|
|
1476
1723
|
(record2) => localFilterHexes.includes(normalizeHex2(record2.id().toHex()))
|
|
1477
1724
|
) : fetched;
|
|
@@ -1481,20 +1728,20 @@ function useTransactionHistory(options = {}) {
|
|
|
1481
1728
|
} finally {
|
|
1482
1729
|
setIsLoading(false);
|
|
1483
1730
|
}
|
|
1484
|
-
}, [client, isReady,
|
|
1485
|
-
|
|
1731
|
+
}, [client, isReady, filter, rawIds, idsHex]);
|
|
1732
|
+
useEffect8(() => {
|
|
1486
1733
|
if (!isReady) return;
|
|
1487
1734
|
refetch();
|
|
1488
1735
|
}, [isReady, refetch]);
|
|
1489
|
-
|
|
1736
|
+
useEffect8(() => {
|
|
1490
1737
|
if (!isReady || !refreshOnSync || !lastSyncTime) return;
|
|
1491
1738
|
refetch();
|
|
1492
1739
|
}, [isReady, lastSyncTime, refreshOnSync, refetch]);
|
|
1493
|
-
const record =
|
|
1740
|
+
const record = useMemo7(() => {
|
|
1494
1741
|
if (!idsHex || idsHex.length !== 1) return null;
|
|
1495
1742
|
return records.find((item) => normalizeHex2(item.id().toHex()) === idsHex[0]) ?? null;
|
|
1496
1743
|
}, [records, idsHex]);
|
|
1497
|
-
const status =
|
|
1744
|
+
const status = useMemo7(() => {
|
|
1498
1745
|
if (!record) return null;
|
|
1499
1746
|
const current = record.transactionStatus();
|
|
1500
1747
|
if (current.isCommitted()) return "committed";
|
|
@@ -1534,11 +1781,11 @@ function normalizeHex2(value) {
|
|
|
1534
1781
|
}
|
|
1535
1782
|
|
|
1536
1783
|
// src/hooks/useSyncState.ts
|
|
1537
|
-
import { useCallback as
|
|
1784
|
+
import { useCallback as useCallback8 } from "react";
|
|
1538
1785
|
function useSyncState() {
|
|
1539
1786
|
const { sync: triggerSync } = useMiden();
|
|
1540
1787
|
const syncState = useSyncStateStore();
|
|
1541
|
-
const sync =
|
|
1788
|
+
const sync = useCallback8(async () => {
|
|
1542
1789
|
await triggerSync();
|
|
1543
1790
|
}, [triggerSync]);
|
|
1544
1791
|
return {
|
|
@@ -1548,21 +1795,25 @@ function useSyncState() {
|
|
|
1548
1795
|
}
|
|
1549
1796
|
|
|
1550
1797
|
// src/hooks/useCreateWallet.ts
|
|
1551
|
-
import { useCallback as
|
|
1798
|
+
import { useCallback as useCallback9, useState as useState7 } from "react";
|
|
1552
1799
|
import { AccountStorageMode } from "@miden-sdk/miden-sdk";
|
|
1800
|
+
|
|
1801
|
+
// src/utils/runExclusive.ts
|
|
1802
|
+
var runExclusiveDirect = async (fn) => fn();
|
|
1803
|
+
|
|
1804
|
+
// src/hooks/useCreateWallet.ts
|
|
1553
1805
|
function useCreateWallet() {
|
|
1554
|
-
const { client, isReady,
|
|
1806
|
+
const { client, isReady, runExclusive } = useMiden();
|
|
1555
1807
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1556
1808
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1557
|
-
const [wallet, setWallet] =
|
|
1558
|
-
const [isCreating, setIsCreating] =
|
|
1559
|
-
const [error, setError] =
|
|
1560
|
-
const createWallet =
|
|
1809
|
+
const [wallet, setWallet] = useState7(null);
|
|
1810
|
+
const [isCreating, setIsCreating] = useState7(false);
|
|
1811
|
+
const [error, setError] = useState7(null);
|
|
1812
|
+
const createWallet = useCallback9(
|
|
1561
1813
|
async (options = {}) => {
|
|
1562
1814
|
if (!client || !isReady) {
|
|
1563
1815
|
throw new Error("Miden client is not ready");
|
|
1564
1816
|
}
|
|
1565
|
-
await sync();
|
|
1566
1817
|
setIsCreating(true);
|
|
1567
1818
|
setError(null);
|
|
1568
1819
|
try {
|
|
@@ -1595,7 +1846,7 @@ function useCreateWallet() {
|
|
|
1595
1846
|
},
|
|
1596
1847
|
[client, isReady, runExclusive, setAccounts]
|
|
1597
1848
|
);
|
|
1598
|
-
const reset =
|
|
1849
|
+
const reset = useCallback9(() => {
|
|
1599
1850
|
setWallet(null);
|
|
1600
1851
|
setIsCreating(false);
|
|
1601
1852
|
setError(null);
|
|
@@ -1622,16 +1873,16 @@ function getStorageMode(mode) {
|
|
|
1622
1873
|
}
|
|
1623
1874
|
|
|
1624
1875
|
// src/hooks/useCreateFaucet.ts
|
|
1625
|
-
import { useCallback as
|
|
1876
|
+
import { useCallback as useCallback10, useState as useState8 } from "react";
|
|
1626
1877
|
import { AccountStorageMode as AccountStorageMode2 } from "@miden-sdk/miden-sdk";
|
|
1627
1878
|
function useCreateFaucet() {
|
|
1628
1879
|
const { client, isReady, runExclusive } = useMiden();
|
|
1629
1880
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1630
1881
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1631
|
-
const [faucet, setFaucet] =
|
|
1632
|
-
const [isCreating, setIsCreating] =
|
|
1633
|
-
const [error, setError] =
|
|
1634
|
-
const createFaucet =
|
|
1882
|
+
const [faucet, setFaucet] = useState8(null);
|
|
1883
|
+
const [isCreating, setIsCreating] = useState8(false);
|
|
1884
|
+
const [error, setError] = useState8(null);
|
|
1885
|
+
const createFaucet = useCallback10(
|
|
1635
1886
|
async (options) => {
|
|
1636
1887
|
if (!client || !isReady) {
|
|
1637
1888
|
throw new Error("Miden client is not ready");
|
|
@@ -1651,7 +1902,7 @@ function useCreateFaucet() {
|
|
|
1651
1902
|
// nonFungible - currently only fungible faucets supported
|
|
1652
1903
|
options.tokenSymbol,
|
|
1653
1904
|
decimals,
|
|
1654
|
-
options.maxSupply,
|
|
1905
|
+
BigInt(options.maxSupply),
|
|
1655
1906
|
authScheme
|
|
1656
1907
|
);
|
|
1657
1908
|
const accounts = await client.getAccounts();
|
|
@@ -1670,7 +1921,7 @@ function useCreateFaucet() {
|
|
|
1670
1921
|
},
|
|
1671
1922
|
[client, isReady, runExclusive, setAccounts]
|
|
1672
1923
|
);
|
|
1673
|
-
const reset =
|
|
1924
|
+
const reset = useCallback10(() => {
|
|
1674
1925
|
setFaucet(null);
|
|
1675
1926
|
setIsCreating(false);
|
|
1676
1927
|
setError(null);
|
|
@@ -1697,25 +1948,79 @@ function getStorageMode2(mode) {
|
|
|
1697
1948
|
}
|
|
1698
1949
|
|
|
1699
1950
|
// src/hooks/useImportAccount.ts
|
|
1700
|
-
import { useCallback as
|
|
1951
|
+
import { useCallback as useCallback11, useState as useState9 } from "react";
|
|
1701
1952
|
import { AccountFile } from "@miden-sdk/miden-sdk";
|
|
1953
|
+
|
|
1954
|
+
// src/utils/errors.ts
|
|
1955
|
+
var MidenError = class extends Error {
|
|
1956
|
+
constructor(message, options) {
|
|
1957
|
+
super(message);
|
|
1958
|
+
this.name = "MidenError";
|
|
1959
|
+
this.code = options?.code ?? "UNKNOWN";
|
|
1960
|
+
if (options?.cause !== void 0) {
|
|
1961
|
+
this.cause = options.cause;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
};
|
|
1965
|
+
var ERROR_PATTERNS = [
|
|
1966
|
+
{
|
|
1967
|
+
test: (msg) => msg.includes("_assertClass") || msg.includes("expected instance of"),
|
|
1968
|
+
code: "WASM_CLASS_MISMATCH",
|
|
1969
|
+
message: "WASM class identity mismatch. This usually means multiple copies of @miden-sdk/miden-sdk are bundled. Ensure your bundler deduplicates the package. For Vite: add resolve.dedupe and optimizeDeps.exclude for @miden-sdk/miden-sdk."
|
|
1970
|
+
},
|
|
1971
|
+
{
|
|
1972
|
+
test: (msg) => msg.includes("null pointer") || msg.includes("already been freed") || msg.includes("dereferencing a null"),
|
|
1973
|
+
code: "WASM_POINTER_CONSUMED",
|
|
1974
|
+
message: "WASM object was already consumed. Some WASM-bound objects can only be passed once \u2014 if you need to reuse a value, create a fresh instance before each call."
|
|
1975
|
+
},
|
|
1976
|
+
{
|
|
1977
|
+
test: (msg) => msg.includes("not initialized") || msg.includes("Cannot read properties of null"),
|
|
1978
|
+
code: "WASM_NOT_INITIALIZED",
|
|
1979
|
+
message: "Miden client is not initialized. Ensure you are inside a <MidenProvider> and the client is ready before calling SDK methods."
|
|
1980
|
+
},
|
|
1981
|
+
{
|
|
1982
|
+
test: (msg) => msg.includes("state commitment mismatch") || msg.includes("stale state"),
|
|
1983
|
+
code: "WASM_SYNC_REQUIRED",
|
|
1984
|
+
message: "Account state is stale. Call sync() before executing transactions, or ensure no concurrent transactions are running against the same account."
|
|
1985
|
+
}
|
|
1986
|
+
];
|
|
1987
|
+
function assertSignerConnected(signerConnected) {
|
|
1988
|
+
if (signerConnected === false) {
|
|
1989
|
+
throw new Error(
|
|
1990
|
+
"Signer is disconnected. Reconnect your wallet to perform transactions."
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
function wrapWasmError(e) {
|
|
1995
|
+
if (e instanceof MidenError) return e;
|
|
1996
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1997
|
+
for (const pattern of ERROR_PATTERNS) {
|
|
1998
|
+
if (pattern.test(msg)) {
|
|
1999
|
+
return new MidenError(pattern.message, { cause: e, code: pattern.code });
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
if (e instanceof Error) return e;
|
|
2003
|
+
return new Error(msg);
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
// src/hooks/useImportAccount.ts
|
|
1702
2007
|
function useImportAccount() {
|
|
1703
|
-
const { client, isReady,
|
|
1704
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2008
|
+
const { client, isReady, signerConnected } = useMiden();
|
|
1705
2009
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1706
|
-
const [account, setAccount] =
|
|
1707
|
-
const [isImporting, setIsImporting] =
|
|
1708
|
-
const [error, setError] =
|
|
1709
|
-
const importAccount =
|
|
2010
|
+
const [account, setAccount] = useState9(null);
|
|
2011
|
+
const [isImporting, setIsImporting] = useState9(false);
|
|
2012
|
+
const [error, setError] = useState9(null);
|
|
2013
|
+
const importAccount = useCallback11(
|
|
1710
2014
|
async (options) => {
|
|
1711
2015
|
if (!client || !isReady) {
|
|
1712
2016
|
throw new Error("Miden client is not ready");
|
|
1713
2017
|
}
|
|
2018
|
+
assertSignerConnected(signerConnected);
|
|
1714
2019
|
setIsImporting(true);
|
|
1715
2020
|
setError(null);
|
|
1716
2021
|
try {
|
|
1717
2022
|
let accountsAfter = null;
|
|
1718
|
-
const imported = await
|
|
2023
|
+
const imported = await (async () => {
|
|
1719
2024
|
switch (options.type) {
|
|
1720
2025
|
case "file": {
|
|
1721
2026
|
const accountsBefore = await client.getAccounts();
|
|
@@ -1767,7 +2072,7 @@ function useImportAccount() {
|
|
|
1767
2072
|
throw new Error("Account not found after import");
|
|
1768
2073
|
}
|
|
1769
2074
|
case "id": {
|
|
1770
|
-
const accountId =
|
|
2075
|
+
const accountId = parseAccountId(options.accountId);
|
|
1771
2076
|
await client.importAccountById(accountId);
|
|
1772
2077
|
const fetchedAccount = await client.getAccount(accountId);
|
|
1773
2078
|
if (!fetchedAccount) {
|
|
@@ -1785,7 +2090,7 @@ function useImportAccount() {
|
|
|
1785
2090
|
);
|
|
1786
2091
|
}
|
|
1787
2092
|
}
|
|
1788
|
-
});
|
|
2093
|
+
})();
|
|
1789
2094
|
ensureAccountBech32(imported);
|
|
1790
2095
|
const accounts = accountsAfter ?? await client.getAccounts();
|
|
1791
2096
|
setAccounts(accounts);
|
|
@@ -1799,9 +2104,9 @@ function useImportAccount() {
|
|
|
1799
2104
|
setIsImporting(false);
|
|
1800
2105
|
}
|
|
1801
2106
|
},
|
|
1802
|
-
[client, isReady,
|
|
2107
|
+
[client, isReady, setAccounts, signerConnected]
|
|
1803
2108
|
);
|
|
1804
|
-
const reset =
|
|
2109
|
+
const reset = useCallback11(() => {
|
|
1805
2110
|
setAccount(null);
|
|
1806
2111
|
setIsImporting(false);
|
|
1807
2112
|
setError(null);
|
|
@@ -1814,9 +2119,6 @@ function useImportAccount() {
|
|
|
1814
2119
|
reset
|
|
1815
2120
|
};
|
|
1816
2121
|
}
|
|
1817
|
-
function resolveAccountId(accountId) {
|
|
1818
|
-
return parseAccountId(accountId);
|
|
1819
|
-
}
|
|
1820
2122
|
async function resolveAccountFile(file) {
|
|
1821
2123
|
if (file instanceof Uint8Array) {
|
|
1822
2124
|
return AccountFile.deserialize(file);
|
|
@@ -1851,72 +2153,25 @@ function bytesEqual(left, right) {
|
|
|
1851
2153
|
}
|
|
1852
2154
|
|
|
1853
2155
|
// src/hooks/useSend.ts
|
|
1854
|
-
import { useCallback as
|
|
2156
|
+
import { useCallback as useCallback12, useRef as useRef4, useState as useState10 } from "react";
|
|
1855
2157
|
import {
|
|
1856
2158
|
FungibleAsset,
|
|
1857
2159
|
Note,
|
|
1858
2160
|
NoteAssets,
|
|
2161
|
+
NoteAttachment as NoteAttachment2,
|
|
1859
2162
|
NoteType as NoteType2,
|
|
1860
|
-
|
|
1861
|
-
OutputNoteArray,
|
|
2163
|
+
NoteArray,
|
|
1862
2164
|
TransactionRequestBuilder
|
|
1863
2165
|
} from "@miden-sdk/miden-sdk";
|
|
1864
|
-
|
|
1865
|
-
// src/utils/errors.ts
|
|
1866
|
-
var MidenError = class extends Error {
|
|
1867
|
-
constructor(message, options) {
|
|
1868
|
-
super(message);
|
|
1869
|
-
this.name = "MidenError";
|
|
1870
|
-
this.code = options?.code ?? "UNKNOWN";
|
|
1871
|
-
if (options?.cause !== void 0) {
|
|
1872
|
-
this.cause = options.cause;
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
};
|
|
1876
|
-
var ERROR_PATTERNS = [
|
|
1877
|
-
{
|
|
1878
|
-
test: (msg) => msg.includes("_assertClass") || msg.includes("expected instance of"),
|
|
1879
|
-
code: "WASM_CLASS_MISMATCH",
|
|
1880
|
-
message: "WASM class identity mismatch. This usually means multiple copies of @miden-sdk/miden-sdk are bundled. Ensure your bundler deduplicates the package. For Vite: add resolve.dedupe and optimizeDeps.exclude for @miden-sdk/miden-sdk."
|
|
1881
|
-
},
|
|
1882
|
-
{
|
|
1883
|
-
test: (msg) => msg.includes("null pointer") || msg.includes("already been freed") || msg.includes("dereferencing a null"),
|
|
1884
|
-
code: "WASM_POINTER_CONSUMED",
|
|
1885
|
-
message: "WASM object was already consumed. Some WASM-bound objects can only be passed once \u2014 if you need to reuse a value, create a fresh instance before each call."
|
|
1886
|
-
},
|
|
1887
|
-
{
|
|
1888
|
-
test: (msg) => msg.includes("not initialized") || msg.includes("Cannot read properties of null"),
|
|
1889
|
-
code: "WASM_NOT_INITIALIZED",
|
|
1890
|
-
message: "Miden client is not initialized. Ensure you are inside a <MidenProvider> and the client is ready before calling SDK methods."
|
|
1891
|
-
},
|
|
1892
|
-
{
|
|
1893
|
-
test: (msg) => msg.includes("state commitment mismatch") || msg.includes("stale state"),
|
|
1894
|
-
code: "WASM_SYNC_REQUIRED",
|
|
1895
|
-
message: "Account state is stale. Call sync() before executing transactions, or ensure no concurrent transactions are running against the same account."
|
|
1896
|
-
}
|
|
1897
|
-
];
|
|
1898
|
-
function wrapWasmError(e) {
|
|
1899
|
-
if (e instanceof MidenError) return e;
|
|
1900
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
1901
|
-
for (const pattern of ERROR_PATTERNS) {
|
|
1902
|
-
if (pattern.test(msg)) {
|
|
1903
|
-
return new MidenError(pattern.message, { cause: e, code: pattern.code });
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
if (e instanceof Error) return e;
|
|
1907
|
-
return new Error(msg);
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
// src/hooks/useSend.ts
|
|
1911
2166
|
function useSend() {
|
|
1912
2167
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1913
2168
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1914
|
-
const isBusyRef =
|
|
1915
|
-
const [result, setResult] =
|
|
1916
|
-
const [isLoading, setIsLoading] =
|
|
1917
|
-
const [stage, setStage] =
|
|
1918
|
-
const [error, setError] =
|
|
1919
|
-
const send =
|
|
2169
|
+
const isBusyRef = useRef4(false);
|
|
2170
|
+
const [result, setResult] = useState10(null);
|
|
2171
|
+
const [isLoading, setIsLoading] = useState10(false);
|
|
2172
|
+
const [stage, setStage] = useState10("idle");
|
|
2173
|
+
const [error, setError] = useState10(null);
|
|
2174
|
+
const send = useCallback12(
|
|
1920
2175
|
async (options) => {
|
|
1921
2176
|
if (!client || !isReady) {
|
|
1922
2177
|
throw new Error("Miden client is not ready");
|
|
@@ -1958,6 +2213,7 @@ function useSend() {
|
|
|
1958
2213
|
if (amount === void 0 || amount === null) {
|
|
1959
2214
|
throw new Error("Amount is required (provide amount or sendAll)");
|
|
1960
2215
|
}
|
|
2216
|
+
amount = BigInt(amount);
|
|
1961
2217
|
const assetId = options.assetId ?? options.faucetId ?? null;
|
|
1962
2218
|
if (!assetId) {
|
|
1963
2219
|
throw new Error("Asset ID is required");
|
|
@@ -1968,6 +2224,35 @@ function useSend() {
|
|
|
1968
2224
|
"recallHeight and timelockHeight are not supported when attachment is provided"
|
|
1969
2225
|
);
|
|
1970
2226
|
}
|
|
2227
|
+
if (options.returnNote === true) {
|
|
2228
|
+
const returnResult = await runExclusiveSafe(async () => {
|
|
2229
|
+
const fromId = parseAccountId(options.from);
|
|
2230
|
+
const toId = parseAccountId(options.to);
|
|
2231
|
+
const assetObj = parseAccountId(assetId);
|
|
2232
|
+
const assets = new NoteAssets([
|
|
2233
|
+
new FungibleAsset(assetObj, BigInt(amount))
|
|
2234
|
+
]);
|
|
2235
|
+
const p2idNote = Note.createP2IDNote(
|
|
2236
|
+
fromId,
|
|
2237
|
+
toId,
|
|
2238
|
+
assets,
|
|
2239
|
+
noteType,
|
|
2240
|
+
new NoteAttachment2()
|
|
2241
|
+
);
|
|
2242
|
+
const txRequest = new TransactionRequestBuilder().withOwnOutputNotes(new NoteArray([p2idNote])).build();
|
|
2243
|
+
const execFromId = parseAccountId(options.from);
|
|
2244
|
+
const txId = prover ? await client.submitNewTransactionWithProver(
|
|
2245
|
+
execFromId,
|
|
2246
|
+
txRequest,
|
|
2247
|
+
prover
|
|
2248
|
+
) : await client.submitNewTransaction(execFromId, txRequest);
|
|
2249
|
+
return { txId: txId.toString(), note: p2idNote };
|
|
2250
|
+
});
|
|
2251
|
+
setStage("complete");
|
|
2252
|
+
setResult(returnResult);
|
|
2253
|
+
await sync();
|
|
2254
|
+
return returnResult;
|
|
2255
|
+
}
|
|
1971
2256
|
const txResult = await runExclusiveSafe(async () => {
|
|
1972
2257
|
const fromAccountId = parseAccountId(options.from);
|
|
1973
2258
|
const toAccountId = parseAccountId(options.to);
|
|
@@ -1985,7 +2270,7 @@ function useSend() {
|
|
|
1985
2270
|
noteType,
|
|
1986
2271
|
attachment
|
|
1987
2272
|
);
|
|
1988
|
-
txRequest = new TransactionRequestBuilder().withOwnOutputNotes(new
|
|
2273
|
+
txRequest = new TransactionRequestBuilder().withOwnOutputNotes(new NoteArray([note])).build();
|
|
1989
2274
|
} else {
|
|
1990
2275
|
txRequest = client.newSendTransactionRequest(
|
|
1991
2276
|
fromAccountId,
|
|
@@ -2001,8 +2286,12 @@ function useSend() {
|
|
|
2001
2286
|
return await client.executeTransaction(execAccountId, txRequest);
|
|
2002
2287
|
});
|
|
2003
2288
|
setStage("proving");
|
|
2004
|
-
const
|
|
2005
|
-
|
|
2289
|
+
const proverConfig = useMidenStore.getState().config;
|
|
2290
|
+
const provenTransaction = await proveWithFallback(
|
|
2291
|
+
(resolvedProver) => runExclusiveSafe(
|
|
2292
|
+
() => client.proveTransaction(txResult, resolvedProver)
|
|
2293
|
+
),
|
|
2294
|
+
proverConfig
|
|
2006
2295
|
);
|
|
2007
2296
|
setStage("submitting");
|
|
2008
2297
|
const submissionHeight = await runExclusiveSafe(
|
|
@@ -2032,11 +2321,14 @@ function useSend() {
|
|
|
2032
2321
|
() => client.sendPrivateNote(fullNote, recipientAddress)
|
|
2033
2322
|
);
|
|
2034
2323
|
}
|
|
2035
|
-
const
|
|
2324
|
+
const sendResult = {
|
|
2325
|
+
txId: txIdString,
|
|
2326
|
+
note: null
|
|
2327
|
+
};
|
|
2036
2328
|
setStage("complete");
|
|
2037
|
-
setResult(
|
|
2329
|
+
setResult(sendResult);
|
|
2038
2330
|
await sync();
|
|
2039
|
-
return
|
|
2331
|
+
return sendResult;
|
|
2040
2332
|
} catch (err) {
|
|
2041
2333
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2042
2334
|
setError(error2);
|
|
@@ -2049,7 +2341,7 @@ function useSend() {
|
|
|
2049
2341
|
},
|
|
2050
2342
|
[client, isReady, prover, runExclusive, sync]
|
|
2051
2343
|
);
|
|
2052
|
-
const reset =
|
|
2344
|
+
const reset = useCallback12(() => {
|
|
2053
2345
|
setResult(null);
|
|
2054
2346
|
setIsLoading(false);
|
|
2055
2347
|
setStage("idle");
|
|
@@ -2076,30 +2368,29 @@ function extractFullNote(txResult) {
|
|
|
2076
2368
|
}
|
|
2077
2369
|
|
|
2078
2370
|
// src/hooks/useMultiSend.ts
|
|
2079
|
-
import { useCallback as
|
|
2371
|
+
import { useCallback as useCallback13, useRef as useRef5, useState as useState11 } from "react";
|
|
2080
2372
|
import {
|
|
2081
2373
|
FungibleAsset as FungibleAsset2,
|
|
2082
2374
|
Note as Note2,
|
|
2083
2375
|
NoteAssets as NoteAssets2,
|
|
2084
|
-
NoteAttachment as
|
|
2376
|
+
NoteAttachment as NoteAttachment3,
|
|
2085
2377
|
NoteType as NoteType3,
|
|
2086
|
-
|
|
2087
|
-
OutputNoteArray as OutputNoteArray2,
|
|
2378
|
+
NoteArray as NoteArray2,
|
|
2088
2379
|
TransactionRequestBuilder as TransactionRequestBuilder2
|
|
2089
2380
|
} from "@miden-sdk/miden-sdk";
|
|
2090
2381
|
function useMultiSend() {
|
|
2091
|
-
const { client, isReady, sync,
|
|
2092
|
-
const
|
|
2093
|
-
const
|
|
2094
|
-
const [
|
|
2095
|
-
const [
|
|
2096
|
-
const [
|
|
2097
|
-
const
|
|
2098
|
-
const sendMany = useCallback12(
|
|
2382
|
+
const { client, isReady, sync, prover, signerConnected } = useMiden();
|
|
2383
|
+
const isBusyRef = useRef5(false);
|
|
2384
|
+
const [result, setResult] = useState11(null);
|
|
2385
|
+
const [isLoading, setIsLoading] = useState11(false);
|
|
2386
|
+
const [stage, setStage] = useState11("idle");
|
|
2387
|
+
const [error, setError] = useState11(null);
|
|
2388
|
+
const sendMany = useCallback13(
|
|
2099
2389
|
async (options) => {
|
|
2100
2390
|
if (!client || !isReady) {
|
|
2101
2391
|
throw new Error("Miden client is not ready");
|
|
2102
2392
|
}
|
|
2393
|
+
assertSignerConnected(signerConnected);
|
|
2103
2394
|
if (options.recipients.length === 0) {
|
|
2104
2395
|
throw new Error("No recipients provided");
|
|
2105
2396
|
}
|
|
@@ -2124,10 +2415,10 @@ function useMultiSend() {
|
|
|
2124
2415
|
const iterAssetId = parseAccountId(options.assetId);
|
|
2125
2416
|
const receiverId = parseAccountId(to);
|
|
2126
2417
|
const assets = new NoteAssets2([
|
|
2127
|
-
new FungibleAsset2(iterAssetId, amount)
|
|
2418
|
+
new FungibleAsset2(iterAssetId, BigInt(amount))
|
|
2128
2419
|
]);
|
|
2129
2420
|
const resolvedNoteType = recipientNoteType ? getNoteType(recipientNoteType) : noteType;
|
|
2130
|
-
const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new
|
|
2421
|
+
const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new NoteAttachment3();
|
|
2131
2422
|
const note = Note2.createP2IDNote(
|
|
2132
2423
|
iterSenderId,
|
|
2133
2424
|
receiverId,
|
|
@@ -2137,44 +2428,43 @@ function useMultiSend() {
|
|
|
2137
2428
|
);
|
|
2138
2429
|
const recipientAddress = parseAddress(to, receiverId);
|
|
2139
2430
|
return {
|
|
2140
|
-
outputNote: OutputNote2.full(note),
|
|
2141
2431
|
note,
|
|
2142
2432
|
recipientAddress,
|
|
2143
2433
|
noteType: resolvedNoteType
|
|
2144
2434
|
};
|
|
2145
2435
|
}
|
|
2146
2436
|
);
|
|
2147
|
-
const txRequest = new TransactionRequestBuilder2().withOwnOutputNotes(
|
|
2148
|
-
new OutputNoteArray2(outputs.map((o) => o.outputNote))
|
|
2149
|
-
).build();
|
|
2437
|
+
const txRequest = new TransactionRequestBuilder2().withOwnOutputNotes(new NoteArray2(outputs.map((o) => o.note))).build();
|
|
2150
2438
|
const txSenderId = parseAccountId(options.from);
|
|
2151
|
-
const txResult = await
|
|
2152
|
-
() => client.executeTransaction(txSenderId, txRequest)
|
|
2153
|
-
);
|
|
2439
|
+
const txResult = await client.executeTransaction(txSenderId, txRequest);
|
|
2154
2440
|
setStage("proving");
|
|
2155
|
-
const
|
|
2156
|
-
|
|
2441
|
+
const proverConfig = useMidenStore.getState().config;
|
|
2442
|
+
const provenTransaction = await proveWithFallback(
|
|
2443
|
+
(resolvedProver) => runExclusiveDirect(
|
|
2444
|
+
() => client.proveTransaction(txResult, resolvedProver)
|
|
2445
|
+
),
|
|
2446
|
+
proverConfig
|
|
2157
2447
|
);
|
|
2158
2448
|
setStage("submitting");
|
|
2159
|
-
const submissionHeight = await
|
|
2160
|
-
|
|
2449
|
+
const submissionHeight = await client.submitProvenTransaction(
|
|
2450
|
+
provenTransaction,
|
|
2451
|
+
txResult
|
|
2161
2452
|
);
|
|
2162
2453
|
const txIdHex = txResult.id().toHex();
|
|
2163
2454
|
const txIdString = txResult.id().toString();
|
|
2164
|
-
await
|
|
2165
|
-
() => client.applyTransaction(txResult, submissionHeight)
|
|
2166
|
-
);
|
|
2455
|
+
await client.applyTransaction(txResult, submissionHeight);
|
|
2167
2456
|
const hasPrivate = outputs.some((o) => o.noteType === NoteType3.Private);
|
|
2168
2457
|
if (hasPrivate) {
|
|
2169
2458
|
await waitForTransactionCommit(
|
|
2170
2459
|
client,
|
|
2171
|
-
|
|
2460
|
+
runExclusiveDirect,
|
|
2172
2461
|
txIdHex
|
|
2173
2462
|
);
|
|
2174
2463
|
for (const output of outputs) {
|
|
2175
2464
|
if (output.noteType === NoteType3.Private) {
|
|
2176
|
-
await
|
|
2177
|
-
|
|
2465
|
+
await client.sendPrivateNote(
|
|
2466
|
+
output.note,
|
|
2467
|
+
output.recipientAddress
|
|
2178
2468
|
);
|
|
2179
2469
|
}
|
|
2180
2470
|
}
|
|
@@ -2194,154 +2484,7 @@ function useMultiSend() {
|
|
|
2194
2484
|
isBusyRef.current = false;
|
|
2195
2485
|
}
|
|
2196
2486
|
},
|
|
2197
|
-
[client, isReady, prover,
|
|
2198
|
-
);
|
|
2199
|
-
const reset = useCallback12(() => {
|
|
2200
|
-
setResult(null);
|
|
2201
|
-
setIsLoading(false);
|
|
2202
|
-
setStage("idle");
|
|
2203
|
-
setError(null);
|
|
2204
|
-
}, []);
|
|
2205
|
-
return {
|
|
2206
|
-
sendMany,
|
|
2207
|
-
result,
|
|
2208
|
-
isLoading,
|
|
2209
|
-
stage,
|
|
2210
|
-
error,
|
|
2211
|
-
reset
|
|
2212
|
-
};
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
|
-
// src/hooks/useInternalTransfer.ts
|
|
2216
|
-
import { useCallback as useCallback13, useState as useState11 } from "react";
|
|
2217
|
-
import {
|
|
2218
|
-
FungibleAsset as FungibleAsset3,
|
|
2219
|
-
Note as Note3,
|
|
2220
|
-
NoteAndArgs,
|
|
2221
|
-
NoteAndArgsArray,
|
|
2222
|
-
NoteAssets as NoteAssets3,
|
|
2223
|
-
NoteAttachment as NoteAttachment3,
|
|
2224
|
-
OutputNote as OutputNote3,
|
|
2225
|
-
OutputNoteArray as OutputNoteArray3,
|
|
2226
|
-
TransactionRequestBuilder as TransactionRequestBuilder3
|
|
2227
|
-
} from "@miden-sdk/miden-sdk";
|
|
2228
|
-
function useInternalTransfer() {
|
|
2229
|
-
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2230
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2231
|
-
const [result, setResult] = useState11(null);
|
|
2232
|
-
const [isLoading, setIsLoading] = useState11(false);
|
|
2233
|
-
const [stage, setStage] = useState11("idle");
|
|
2234
|
-
const [error, setError] = useState11(null);
|
|
2235
|
-
const transferOnce = useCallback13(
|
|
2236
|
-
async (options) => {
|
|
2237
|
-
if (!client || !isReady) {
|
|
2238
|
-
throw new Error("Miden client is not ready");
|
|
2239
|
-
}
|
|
2240
|
-
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2241
|
-
const senderId = parseAccountId(options.from);
|
|
2242
|
-
const receiverId = parseAccountId(options.to);
|
|
2243
|
-
const assetId = parseAccountId(options.assetId);
|
|
2244
|
-
const assets = new NoteAssets3([
|
|
2245
|
-
new FungibleAsset3(assetId, options.amount)
|
|
2246
|
-
]);
|
|
2247
|
-
const note = Note3.createP2IDNote(
|
|
2248
|
-
senderId,
|
|
2249
|
-
receiverId,
|
|
2250
|
-
assets,
|
|
2251
|
-
noteType,
|
|
2252
|
-
new NoteAttachment3()
|
|
2253
|
-
);
|
|
2254
|
-
const noteId = note.id().toString();
|
|
2255
|
-
const createRequest = new TransactionRequestBuilder3().withOwnOutputNotes(new OutputNoteArray3([OutputNote3.full(note)])).build();
|
|
2256
|
-
const createTxId = await runExclusiveSafe(
|
|
2257
|
-
() => prover ? client.submitNewTransactionWithProver(
|
|
2258
|
-
senderId,
|
|
2259
|
-
createRequest,
|
|
2260
|
-
prover
|
|
2261
|
-
) : client.submitNewTransaction(senderId, createRequest)
|
|
2262
|
-
);
|
|
2263
|
-
const consumeRequest = new TransactionRequestBuilder3().withInputNotes(new NoteAndArgsArray([new NoteAndArgs(note, null)])).build();
|
|
2264
|
-
const consumeTxId = await runExclusiveSafe(
|
|
2265
|
-
() => prover ? client.submitNewTransactionWithProver(
|
|
2266
|
-
receiverId,
|
|
2267
|
-
consumeRequest,
|
|
2268
|
-
prover
|
|
2269
|
-
) : client.submitNewTransaction(receiverId, consumeRequest)
|
|
2270
|
-
);
|
|
2271
|
-
return {
|
|
2272
|
-
createTransactionId: createTxId.toString(),
|
|
2273
|
-
consumeTransactionId: consumeTxId.toString(),
|
|
2274
|
-
noteId
|
|
2275
|
-
};
|
|
2276
|
-
},
|
|
2277
|
-
[client, isReady, prover, runExclusiveSafe]
|
|
2278
|
-
);
|
|
2279
|
-
const transfer = useCallback13(
|
|
2280
|
-
async (options) => {
|
|
2281
|
-
if (!client || !isReady) {
|
|
2282
|
-
throw new Error("Miden client is not ready");
|
|
2283
|
-
}
|
|
2284
|
-
setIsLoading(true);
|
|
2285
|
-
setStage("executing");
|
|
2286
|
-
setError(null);
|
|
2287
|
-
try {
|
|
2288
|
-
setStage("proving");
|
|
2289
|
-
const txResult = await transferOnce(options);
|
|
2290
|
-
setStage("complete");
|
|
2291
|
-
setResult(txResult);
|
|
2292
|
-
await sync();
|
|
2293
|
-
return txResult;
|
|
2294
|
-
} catch (err) {
|
|
2295
|
-
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2296
|
-
setError(error2);
|
|
2297
|
-
setStage("idle");
|
|
2298
|
-
throw error2;
|
|
2299
|
-
} finally {
|
|
2300
|
-
setIsLoading(false);
|
|
2301
|
-
}
|
|
2302
|
-
},
|
|
2303
|
-
[client, isReady, sync, transferOnce]
|
|
2304
|
-
);
|
|
2305
|
-
const transferChain = useCallback13(
|
|
2306
|
-
async (options) => {
|
|
2307
|
-
if (!client || !isReady) {
|
|
2308
|
-
throw new Error("Miden client is not ready");
|
|
2309
|
-
}
|
|
2310
|
-
if (options.recipients.length === 0) {
|
|
2311
|
-
throw new Error("No recipients provided");
|
|
2312
|
-
}
|
|
2313
|
-
setIsLoading(true);
|
|
2314
|
-
setStage("executing");
|
|
2315
|
-
setError(null);
|
|
2316
|
-
try {
|
|
2317
|
-
const results = [];
|
|
2318
|
-
let currentSender = options.from;
|
|
2319
|
-
for (const recipient of options.recipients) {
|
|
2320
|
-
setStage("proving");
|
|
2321
|
-
const txResult = await transferOnce({
|
|
2322
|
-
from: currentSender,
|
|
2323
|
-
to: recipient,
|
|
2324
|
-
assetId: options.assetId,
|
|
2325
|
-
amount: options.amount,
|
|
2326
|
-
noteType: options.noteType
|
|
2327
|
-
});
|
|
2328
|
-
results.push(txResult);
|
|
2329
|
-
currentSender = recipient;
|
|
2330
|
-
}
|
|
2331
|
-
setStage("complete");
|
|
2332
|
-
setResult(results);
|
|
2333
|
-
await sync();
|
|
2334
|
-
return results;
|
|
2335
|
-
} catch (err) {
|
|
2336
|
-
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2337
|
-
setError(error2);
|
|
2338
|
-
setStage("idle");
|
|
2339
|
-
throw error2;
|
|
2340
|
-
} finally {
|
|
2341
|
-
setIsLoading(false);
|
|
2342
|
-
}
|
|
2343
|
-
},
|
|
2344
|
-
[client, isReady, sync, transferOnce]
|
|
2487
|
+
[client, isReady, prover, signerConnected, sync]
|
|
2345
2488
|
);
|
|
2346
2489
|
const reset = useCallback13(() => {
|
|
2347
2490
|
setResult(null);
|
|
@@ -2350,8 +2493,7 @@ function useInternalTransfer() {
|
|
|
2350
2493
|
setError(null);
|
|
2351
2494
|
}, []);
|
|
2352
2495
|
return {
|
|
2353
|
-
|
|
2354
|
-
transferChain,
|
|
2496
|
+
sendMany,
|
|
2355
2497
|
result,
|
|
2356
2498
|
isLoading,
|
|
2357
2499
|
stage,
|
|
@@ -2364,8 +2506,7 @@ function useInternalTransfer() {
|
|
|
2364
2506
|
import { useCallback as useCallback14 } from "react";
|
|
2365
2507
|
import { TransactionFilter as TransactionFilter3 } from "@miden-sdk/miden-sdk";
|
|
2366
2508
|
function useWaitForCommit() {
|
|
2367
|
-
const { client, isReady
|
|
2368
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2509
|
+
const { client, isReady } = useMiden();
|
|
2369
2510
|
const waitForCommit = useCallback14(
|
|
2370
2511
|
async (txId, options) => {
|
|
2371
2512
|
if (!client || !isReady) {
|
|
@@ -2378,13 +2519,9 @@ function useWaitForCommit() {
|
|
|
2378
2519
|
);
|
|
2379
2520
|
const deadline = Date.now() + timeoutMs;
|
|
2380
2521
|
while (Date.now() < deadline) {
|
|
2381
|
-
await
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
const records = await runExclusiveSafe(
|
|
2385
|
-
() => client.getTransactions(
|
|
2386
|
-
typeof txId === "string" ? TransactionFilter3.all() : TransactionFilter3.ids([txId])
|
|
2387
|
-
)
|
|
2522
|
+
await client.syncState();
|
|
2523
|
+
const records = await client.getTransactions(
|
|
2524
|
+
typeof txId === "string" ? TransactionFilter3.all() : TransactionFilter3.ids([txId])
|
|
2388
2525
|
);
|
|
2389
2526
|
const record = records.find(
|
|
2390
2527
|
(item) => normalizeHex3(item.id().toHex()) === targetHex
|
|
@@ -2402,7 +2539,7 @@ function useWaitForCommit() {
|
|
|
2402
2539
|
}
|
|
2403
2540
|
throw new Error("Timeout waiting for transaction commit");
|
|
2404
2541
|
},
|
|
2405
|
-
[client, isReady
|
|
2542
|
+
[client, isReady]
|
|
2406
2543
|
);
|
|
2407
2544
|
return { waitForCommit };
|
|
2408
2545
|
}
|
|
@@ -2431,11 +2568,11 @@ function useWaitForNotes() {
|
|
|
2431
2568
|
await runExclusiveSafe(
|
|
2432
2569
|
() => client.syncState()
|
|
2433
2570
|
);
|
|
2434
|
-
const
|
|
2571
|
+
const consumable = await runExclusiveSafe(
|
|
2435
2572
|
() => client.getConsumableNotes(accountId)
|
|
2436
2573
|
);
|
|
2437
|
-
if (
|
|
2438
|
-
return
|
|
2574
|
+
if (consumable.length >= minCount) {
|
|
2575
|
+
return consumable;
|
|
2439
2576
|
}
|
|
2440
2577
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
2441
2578
|
waited += intervalMs;
|
|
@@ -2474,7 +2611,7 @@ function useMint() {
|
|
|
2474
2611
|
targetAccountIdObj,
|
|
2475
2612
|
faucetIdObj,
|
|
2476
2613
|
noteType,
|
|
2477
|
-
options.amount
|
|
2614
|
+
BigInt(options.amount)
|
|
2478
2615
|
);
|
|
2479
2616
|
const txId = prover ? await client.submitNewTransactionWithProver(
|
|
2480
2617
|
faucetIdObj,
|
|
@@ -2529,8 +2666,8 @@ function useConsume() {
|
|
|
2529
2666
|
if (!client || !isReady) {
|
|
2530
2667
|
throw new Error("Miden client is not ready");
|
|
2531
2668
|
}
|
|
2532
|
-
if (options.
|
|
2533
|
-
throw new Error("No
|
|
2669
|
+
if (options.notes.length === 0) {
|
|
2670
|
+
throw new Error("No notes provided");
|
|
2534
2671
|
}
|
|
2535
2672
|
setIsLoading(true);
|
|
2536
2673
|
setStage("executing");
|
|
@@ -2539,16 +2676,47 @@ function useConsume() {
|
|
|
2539
2676
|
const accountIdObj = parseAccountId(options.accountId);
|
|
2540
2677
|
setStage("proving");
|
|
2541
2678
|
const txResult = await runExclusiveSafe(async () => {
|
|
2542
|
-
const
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2679
|
+
const resolved = new Array(options.notes.length);
|
|
2680
|
+
const lookupIndices = [];
|
|
2681
|
+
const lookupIds = [];
|
|
2682
|
+
for (let i = 0; i < options.notes.length; i++) {
|
|
2683
|
+
const item = options.notes[i];
|
|
2684
|
+
if (typeof item === "string") {
|
|
2685
|
+
lookupIndices.push(i);
|
|
2686
|
+
lookupIds.push(NoteId.fromHex(item));
|
|
2687
|
+
} else if (item !== null && typeof item === "object" && typeof item.toNote === "function") {
|
|
2688
|
+
resolved[i] = item.toNote();
|
|
2689
|
+
} else if (item !== null && typeof item === "object" && typeof item.id === "function") {
|
|
2690
|
+
resolved[i] = item;
|
|
2691
|
+
} else {
|
|
2692
|
+
lookupIndices.push(i);
|
|
2693
|
+
lookupIds.push(item);
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
if (lookupIds.length > 0) {
|
|
2697
|
+
const filter = new NoteFilter3(NoteFilterTypes2.List, lookupIds);
|
|
2698
|
+
const noteRecords = await client.getInputNotes(filter);
|
|
2699
|
+
if (noteRecords.length !== lookupIds.length) {
|
|
2700
|
+
throw new Error("Some notes could not be found for provided IDs");
|
|
2701
|
+
}
|
|
2702
|
+
const recordById = new Map(
|
|
2703
|
+
noteRecords.map((r) => [r.id().toString(), r])
|
|
2704
|
+
);
|
|
2705
|
+
for (let j = 0; j < lookupIndices.length; j++) {
|
|
2706
|
+
const record = recordById.get(lookupIds[j].toString());
|
|
2707
|
+
if (!record) {
|
|
2708
|
+
throw new Error(
|
|
2709
|
+
"Some notes could not be found for provided IDs"
|
|
2710
|
+
);
|
|
2711
|
+
}
|
|
2712
|
+
resolved[lookupIndices[j]] = record.toNote();
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
const notes = resolved;
|
|
2548
2716
|
if (notes.length === 0) {
|
|
2549
2717
|
throw new Error("No notes found for provided IDs");
|
|
2550
2718
|
}
|
|
2551
|
-
if (notes.length !== options.
|
|
2719
|
+
if (notes.length !== options.notes.length) {
|
|
2552
2720
|
throw new Error("Some notes could not be found for provided IDs");
|
|
2553
2721
|
}
|
|
2554
2722
|
const txRequest = client.newConsumeTransactionRequest(notes);
|
|
@@ -2620,9 +2788,9 @@ function useSwap() {
|
|
|
2620
2788
|
const txRequest = client.newSwapTransactionRequest(
|
|
2621
2789
|
accountIdObj,
|
|
2622
2790
|
offeredFaucetIdObj,
|
|
2623
|
-
options.offeredAmount,
|
|
2791
|
+
BigInt(options.offeredAmount),
|
|
2624
2792
|
requestedFaucetIdObj,
|
|
2625
|
-
options.requestedAmount,
|
|
2793
|
+
BigInt(options.requestedAmount),
|
|
2626
2794
|
noteType,
|
|
2627
2795
|
paybackNoteType
|
|
2628
2796
|
);
|
|
@@ -2665,11 +2833,53 @@ function useSwap() {
|
|
|
2665
2833
|
}
|
|
2666
2834
|
|
|
2667
2835
|
// src/hooks/useTransaction.ts
|
|
2668
|
-
import { useCallback as useCallback19, useRef as
|
|
2836
|
+
import { useCallback as useCallback19, useRef as useRef6, useState as useState15 } from "react";
|
|
2837
|
+
|
|
2838
|
+
// src/utils/transactions.ts
|
|
2839
|
+
import { NoteType as NoteType4, TransactionFilter as TransactionFilter4 } from "@miden-sdk/miden-sdk";
|
|
2840
|
+
async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
|
|
2841
|
+
let waited = 0;
|
|
2842
|
+
while (waited < maxWaitMs) {
|
|
2843
|
+
await runExclusiveSafe(() => client.syncState());
|
|
2844
|
+
const [record] = await runExclusiveSafe(
|
|
2845
|
+
() => client.getTransactions(TransactionFilter4.ids([txId]))
|
|
2846
|
+
);
|
|
2847
|
+
if (record) {
|
|
2848
|
+
const status = record.transactionStatus();
|
|
2849
|
+
if (status.isCommitted()) {
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
if (status.isDiscarded()) {
|
|
2853
|
+
throw new Error("Transaction was discarded before commit");
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
2857
|
+
waited += delayMs;
|
|
2858
|
+
}
|
|
2859
|
+
throw new Error("Timeout waiting for transaction commit");
|
|
2860
|
+
}
|
|
2861
|
+
function extractFullNotes(txResult) {
|
|
2862
|
+
try {
|
|
2863
|
+
const executedTx = txResult.executedTransaction?.();
|
|
2864
|
+
const notes = executedTx?.outputNotes?.().notes?.() ?? [];
|
|
2865
|
+
const result = [];
|
|
2866
|
+
for (const note of notes) {
|
|
2867
|
+
if (note.noteType?.() === NoteType4.Private) {
|
|
2868
|
+
const full = note.intoFull?.();
|
|
2869
|
+
if (full) result.push(full);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
return result;
|
|
2873
|
+
} catch {
|
|
2874
|
+
return [];
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
// src/hooks/useTransaction.ts
|
|
2669
2879
|
function useTransaction() {
|
|
2670
|
-
const { client, isReady, sync, runExclusive
|
|
2880
|
+
const { client, isReady, sync, runExclusive } = useMiden();
|
|
2671
2881
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2672
|
-
const isBusyRef =
|
|
2882
|
+
const isBusyRef = useRef6(false);
|
|
2673
2883
|
const [result, setResult] = useState15(null);
|
|
2674
2884
|
const [isLoading, setIsLoading] = useState15(false);
|
|
2675
2885
|
const [stage, setStage] = useState15("idle");
|
|
@@ -2694,20 +2904,41 @@ function useTransaction() {
|
|
|
2694
2904
|
await sync();
|
|
2695
2905
|
}
|
|
2696
2906
|
const txRequest = await resolveRequest(options.request, client);
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
const txId = prover ? await client.submitNewTransactionWithProver(
|
|
2701
|
-
accountIdObj,
|
|
2702
|
-
txRequest,
|
|
2703
|
-
prover
|
|
2704
|
-
) : await client.submitNewTransaction(accountIdObj, txRequest);
|
|
2705
|
-
return { transactionId: txId.toString() };
|
|
2907
|
+
const txResult = await runExclusiveSafe(() => {
|
|
2908
|
+
const accountIdObj = parseAccountId(options.accountId);
|
|
2909
|
+
return client.executeTransaction(accountIdObj, txRequest);
|
|
2706
2910
|
});
|
|
2911
|
+
setStage("proving");
|
|
2912
|
+
const proverConfig = useMidenStore.getState().config;
|
|
2913
|
+
const provenTransaction = await proveWithFallback(
|
|
2914
|
+
(resolvedProver) => runExclusiveSafe(
|
|
2915
|
+
() => client.proveTransaction(txResult, resolvedProver)
|
|
2916
|
+
),
|
|
2917
|
+
proverConfig
|
|
2918
|
+
);
|
|
2919
|
+
setStage("submitting");
|
|
2920
|
+
const submissionHeight = await runExclusiveSafe(
|
|
2921
|
+
() => client.submitProvenTransaction(provenTransaction, txResult)
|
|
2922
|
+
);
|
|
2923
|
+
await runExclusiveSafe(
|
|
2924
|
+
() => client.applyTransaction(txResult, submissionHeight)
|
|
2925
|
+
);
|
|
2926
|
+
const txId = txResult.id();
|
|
2927
|
+
if (options.privateNoteTarget != null) {
|
|
2928
|
+
await waitForTransactionCommit2(client, runExclusiveSafe, txId);
|
|
2929
|
+
const targetAddress = parseAddress(options.privateNoteTarget);
|
|
2930
|
+
const fullNotes = extractFullNotes(txResult);
|
|
2931
|
+
for (const note of fullNotes) {
|
|
2932
|
+
await runExclusiveSafe(
|
|
2933
|
+
() => client.sendPrivateNote(note, targetAddress)
|
|
2934
|
+
);
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
const txSummary = { transactionId: txId.toString() };
|
|
2707
2938
|
setStage("complete");
|
|
2708
|
-
setResult(
|
|
2939
|
+
setResult(txSummary);
|
|
2709
2940
|
await sync();
|
|
2710
|
-
return
|
|
2941
|
+
return txSummary;
|
|
2711
2942
|
} catch (err) {
|
|
2712
2943
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2713
2944
|
setError(error2);
|
|
@@ -2718,7 +2949,7 @@ function useTransaction() {
|
|
|
2718
2949
|
isBusyRef.current = false;
|
|
2719
2950
|
}
|
|
2720
2951
|
},
|
|
2721
|
-
[client, isReady,
|
|
2952
|
+
[client, isReady, runExclusive, sync]
|
|
2722
2953
|
);
|
|
2723
2954
|
const reset = useCallback19(() => {
|
|
2724
2955
|
setResult(null);
|
|
@@ -2735,9 +2966,6 @@ function useTransaction() {
|
|
|
2735
2966
|
reset
|
|
2736
2967
|
};
|
|
2737
2968
|
}
|
|
2738
|
-
function resolveAccountId2(accountId) {
|
|
2739
|
-
return parseAccountId(accountId);
|
|
2740
|
-
}
|
|
2741
2969
|
async function resolveRequest(request, client) {
|
|
2742
2970
|
if (typeof request === "function") {
|
|
2743
2971
|
return await request(client);
|
|
@@ -2745,27 +2973,117 @@ async function resolveRequest(request, client) {
|
|
|
2745
2973
|
return request;
|
|
2746
2974
|
}
|
|
2747
2975
|
|
|
2976
|
+
// src/hooks/useExecuteProgram.ts
|
|
2977
|
+
import { useCallback as useCallback20, useRef as useRef7, useState as useState16 } from "react";
|
|
2978
|
+
import {
|
|
2979
|
+
AdviceInputs,
|
|
2980
|
+
ForeignAccount,
|
|
2981
|
+
ForeignAccountArray,
|
|
2982
|
+
AccountStorageRequirements
|
|
2983
|
+
} from "@miden-sdk/miden-sdk";
|
|
2984
|
+
function isForeignAccountWrapper(fa) {
|
|
2985
|
+
return fa !== null && typeof fa === "object" && "id" in fa && typeof fa.id !== "function";
|
|
2986
|
+
}
|
|
2987
|
+
function useExecuteProgram() {
|
|
2988
|
+
const { client, isReady, sync, runExclusive } = useMiden();
|
|
2989
|
+
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2990
|
+
const isBusyRef = useRef7(false);
|
|
2991
|
+
const [result, setResult] = useState16(null);
|
|
2992
|
+
const [isLoading, setIsLoading] = useState16(false);
|
|
2993
|
+
const [error, setError] = useState16(null);
|
|
2994
|
+
const execute = useCallback20(
|
|
2995
|
+
async (options) => {
|
|
2996
|
+
if (!client || !isReady) {
|
|
2997
|
+
throw new Error("Miden client is not ready");
|
|
2998
|
+
}
|
|
2999
|
+
if (isBusyRef.current) {
|
|
3000
|
+
throw new MidenError(
|
|
3001
|
+
"A program execution is already in progress. Await the previous call before starting another.",
|
|
3002
|
+
{ code: "OPERATION_BUSY" }
|
|
3003
|
+
);
|
|
3004
|
+
}
|
|
3005
|
+
isBusyRef.current = true;
|
|
3006
|
+
setIsLoading(true);
|
|
3007
|
+
setError(null);
|
|
3008
|
+
try {
|
|
3009
|
+
if (!options.skipSync) {
|
|
3010
|
+
await sync();
|
|
3011
|
+
}
|
|
3012
|
+
const programResult = await runExclusiveSafe(async () => {
|
|
3013
|
+
const accountIdObj = parseAccountId(options.accountId);
|
|
3014
|
+
const adviceInputs = options.adviceInputs ?? new AdviceInputs();
|
|
3015
|
+
let foreignAccountsArray;
|
|
3016
|
+
if (options.foreignAccounts?.length) {
|
|
3017
|
+
const accounts = options.foreignAccounts.map((fa) => {
|
|
3018
|
+
const wrapper = isForeignAccountWrapper(fa);
|
|
3019
|
+
const id = parseAccountId(wrapper ? fa.id : fa);
|
|
3020
|
+
const storage = wrapper && fa.storage ? fa.storage : new AccountStorageRequirements();
|
|
3021
|
+
return ForeignAccount.public(id, storage);
|
|
3022
|
+
});
|
|
3023
|
+
foreignAccountsArray = new ForeignAccountArray(accounts);
|
|
3024
|
+
} else {
|
|
3025
|
+
foreignAccountsArray = new ForeignAccountArray();
|
|
3026
|
+
}
|
|
3027
|
+
const feltArray = await client.executeProgram(
|
|
3028
|
+
accountIdObj,
|
|
3029
|
+
options.script,
|
|
3030
|
+
adviceInputs,
|
|
3031
|
+
foreignAccountsArray
|
|
3032
|
+
);
|
|
3033
|
+
const stack = [];
|
|
3034
|
+
const len = feltArray.length();
|
|
3035
|
+
for (let i = 0; i < len; i++) {
|
|
3036
|
+
stack.push(feltArray.get(i).asInt());
|
|
3037
|
+
}
|
|
3038
|
+
return { stack };
|
|
3039
|
+
});
|
|
3040
|
+
setResult(programResult);
|
|
3041
|
+
return programResult;
|
|
3042
|
+
} catch (err) {
|
|
3043
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
3044
|
+
setError(error2);
|
|
3045
|
+
throw error2;
|
|
3046
|
+
} finally {
|
|
3047
|
+
setIsLoading(false);
|
|
3048
|
+
isBusyRef.current = false;
|
|
3049
|
+
}
|
|
3050
|
+
},
|
|
3051
|
+
[client, isReady, runExclusive, sync]
|
|
3052
|
+
);
|
|
3053
|
+
const reset = useCallback20(() => {
|
|
3054
|
+
setResult(null);
|
|
3055
|
+
setIsLoading(false);
|
|
3056
|
+
setError(null);
|
|
3057
|
+
}, []);
|
|
3058
|
+
return {
|
|
3059
|
+
execute,
|
|
3060
|
+
result,
|
|
3061
|
+
isLoading,
|
|
3062
|
+
error,
|
|
3063
|
+
reset
|
|
3064
|
+
};
|
|
3065
|
+
}
|
|
3066
|
+
|
|
2748
3067
|
// src/hooks/useSessionAccount.ts
|
|
2749
|
-
import { useCallback as
|
|
3068
|
+
import { useCallback as useCallback21, useEffect as useEffect9, useRef as useRef8, useState as useState17 } from "react";
|
|
2750
3069
|
import { AccountStorageMode as AccountStorageMode3 } from "@miden-sdk/miden-sdk";
|
|
2751
3070
|
function useSessionAccount(options) {
|
|
2752
|
-
const { client, isReady, sync
|
|
2753
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
3071
|
+
const { client, isReady, sync } = useMiden();
|
|
2754
3072
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
2755
|
-
const [sessionAccountId, setSessionAccountId] =
|
|
2756
|
-
const [step, setStep] =
|
|
2757
|
-
const [error, setError] =
|
|
2758
|
-
const cancelledRef =
|
|
2759
|
-
const isBusyRef =
|
|
3073
|
+
const [sessionAccountId, setSessionAccountId] = useState17(null);
|
|
3074
|
+
const [step, setStep] = useState17("idle");
|
|
3075
|
+
const [error, setError] = useState17(null);
|
|
3076
|
+
const cancelledRef = useRef8(false);
|
|
3077
|
+
const isBusyRef = useRef8(false);
|
|
2760
3078
|
const storagePrefix = options.storagePrefix ?? "miden-session";
|
|
2761
3079
|
const pollIntervalMs = options.pollIntervalMs ?? 3e3;
|
|
2762
3080
|
const maxWaitMs = options.maxWaitMs ?? 6e4;
|
|
2763
3081
|
const storageMode = options.walletOptions?.storageMode ?? "public";
|
|
2764
3082
|
const mutable = options.walletOptions?.mutable ?? DEFAULTS.WALLET_MUTABLE;
|
|
2765
3083
|
const authScheme = options.walletOptions?.authScheme ?? DEFAULTS.AUTH_SCHEME;
|
|
2766
|
-
const fundRef =
|
|
3084
|
+
const fundRef = useRef8(options.fund);
|
|
2767
3085
|
fundRef.current = options.fund;
|
|
2768
|
-
|
|
3086
|
+
useEffect9(() => {
|
|
2769
3087
|
try {
|
|
2770
3088
|
const stored = localStorage.getItem(`${storagePrefix}:accountId`);
|
|
2771
3089
|
const storedReady = localStorage.getItem(`${storagePrefix}:ready`);
|
|
@@ -2782,7 +3100,7 @@ function useSessionAccount(options) {
|
|
|
2782
3100
|
localStorage.removeItem(`${storagePrefix}:ready`);
|
|
2783
3101
|
}
|
|
2784
3102
|
}, [storagePrefix]);
|
|
2785
|
-
const initialize =
|
|
3103
|
+
const initialize = useCallback21(async () => {
|
|
2786
3104
|
if (!client || !isReady) {
|
|
2787
3105
|
throw new Error("Miden client is not ready");
|
|
2788
3106
|
}
|
|
@@ -2800,17 +3118,14 @@ function useSessionAccount(options) {
|
|
|
2800
3118
|
if (!walletId) {
|
|
2801
3119
|
setStep("creating");
|
|
2802
3120
|
const resolvedStorageMode = getStorageMode3(storageMode);
|
|
2803
|
-
const wallet = await
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
setAccounts(accounts);
|
|
2812
|
-
return w;
|
|
2813
|
-
});
|
|
3121
|
+
const wallet = await client.newWallet(
|
|
3122
|
+
resolvedStorageMode,
|
|
3123
|
+
mutable,
|
|
3124
|
+
authScheme
|
|
3125
|
+
);
|
|
3126
|
+
ensureAccountBech32(wallet);
|
|
3127
|
+
const accounts = await client.getAccounts();
|
|
3128
|
+
setAccounts(accounts);
|
|
2814
3129
|
if (cancelledRef.current) return;
|
|
2815
3130
|
walletId = wallet.id().toString();
|
|
2816
3131
|
setSessionAccountId(walletId);
|
|
@@ -2822,7 +3137,6 @@ function useSessionAccount(options) {
|
|
|
2822
3137
|
setStep("consuming");
|
|
2823
3138
|
await waitAndConsume(
|
|
2824
3139
|
client,
|
|
2825
|
-
runExclusiveSafe,
|
|
2826
3140
|
walletId,
|
|
2827
3141
|
pollIntervalMs,
|
|
2828
3142
|
maxWaitMs,
|
|
@@ -2846,7 +3160,6 @@ function useSessionAccount(options) {
|
|
|
2846
3160
|
client,
|
|
2847
3161
|
isReady,
|
|
2848
3162
|
sync,
|
|
2849
|
-
runExclusiveSafe,
|
|
2850
3163
|
sessionAccountId,
|
|
2851
3164
|
storageMode,
|
|
2852
3165
|
mutable,
|
|
@@ -2856,7 +3169,7 @@ function useSessionAccount(options) {
|
|
|
2856
3169
|
maxWaitMs,
|
|
2857
3170
|
setAccounts
|
|
2858
3171
|
]);
|
|
2859
|
-
const reset =
|
|
3172
|
+
const reset = useCallback21(() => {
|
|
2860
3173
|
cancelledRef.current = true;
|
|
2861
3174
|
isBusyRef.current = false;
|
|
2862
3175
|
setSessionAccountId(null);
|
|
@@ -2884,30 +3197,202 @@ function getStorageMode3(mode) {
|
|
|
2884
3197
|
return AccountStorageMode3.public();
|
|
2885
3198
|
}
|
|
2886
3199
|
}
|
|
2887
|
-
async function waitAndConsume(client,
|
|
3200
|
+
async function waitAndConsume(client, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
|
|
2888
3201
|
const deadline = Date.now() + maxWaitMs;
|
|
2889
3202
|
while (Date.now() < deadline) {
|
|
2890
3203
|
if (cancelledRef.current) return;
|
|
2891
|
-
await
|
|
2892
|
-
() => client.syncState()
|
|
2893
|
-
);
|
|
3204
|
+
await client.syncState();
|
|
2894
3205
|
if (cancelledRef.current) return;
|
|
2895
|
-
const
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
if (consumable.length === 0) return false;
|
|
3206
|
+
const accountIdObj = parseAccountId(walletId);
|
|
3207
|
+
const consumable = await client.getConsumableNotes(accountIdObj);
|
|
3208
|
+
if (consumable.length > 0) {
|
|
2899
3209
|
const notes = consumable.map((c) => c.inputNoteRecord().toNote());
|
|
2900
3210
|
const txRequest = client.newConsumeTransactionRequest(notes);
|
|
2901
3211
|
const freshAccountId = parseAccountId(walletId);
|
|
2902
3212
|
await client.submitNewTransaction(freshAccountId, txRequest);
|
|
2903
|
-
return
|
|
2904
|
-
}
|
|
2905
|
-
if (consumed) return;
|
|
3213
|
+
return;
|
|
3214
|
+
}
|
|
2906
3215
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2907
3216
|
}
|
|
2908
3217
|
throw new Error("Timeout waiting for session wallet funding");
|
|
2909
3218
|
}
|
|
2910
3219
|
|
|
3220
|
+
// src/hooks/useExportStore.ts
|
|
3221
|
+
import { useCallback as useCallback22, useState as useState18 } from "react";
|
|
3222
|
+
import { exportStore as sdkExportStore } from "@miden-sdk/miden-sdk";
|
|
3223
|
+
function useExportStore() {
|
|
3224
|
+
const { client, isReady, runExclusive } = useMiden();
|
|
3225
|
+
const [isExporting, setIsExporting] = useState18(false);
|
|
3226
|
+
const [error, setError] = useState18(null);
|
|
3227
|
+
const exportStore = useCallback22(async () => {
|
|
3228
|
+
if (!client || !isReady) {
|
|
3229
|
+
throw new Error("Miden client is not ready");
|
|
3230
|
+
}
|
|
3231
|
+
setIsExporting(true);
|
|
3232
|
+
setError(null);
|
|
3233
|
+
try {
|
|
3234
|
+
const storeName = client.storeIdentifier();
|
|
3235
|
+
const snapshot = await runExclusive(() => sdkExportStore(storeName));
|
|
3236
|
+
return snapshot;
|
|
3237
|
+
} catch (err) {
|
|
3238
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
3239
|
+
setError(error2);
|
|
3240
|
+
throw error2;
|
|
3241
|
+
} finally {
|
|
3242
|
+
setIsExporting(false);
|
|
3243
|
+
}
|
|
3244
|
+
}, [client, isReady, runExclusive]);
|
|
3245
|
+
const reset = useCallback22(() => {
|
|
3246
|
+
setIsExporting(false);
|
|
3247
|
+
setError(null);
|
|
3248
|
+
}, []);
|
|
3249
|
+
return {
|
|
3250
|
+
exportStore,
|
|
3251
|
+
isExporting,
|
|
3252
|
+
error,
|
|
3253
|
+
reset
|
|
3254
|
+
};
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3257
|
+
// src/hooks/useImportStore.ts
|
|
3258
|
+
import { useCallback as useCallback23, useState as useState19 } from "react";
|
|
3259
|
+
import { importStore as sdkImportStore } from "@miden-sdk/miden-sdk";
|
|
3260
|
+
function useImportStore() {
|
|
3261
|
+
const { client, isReady, runExclusive, sync } = useMiden();
|
|
3262
|
+
const [isImporting, setIsImporting] = useState19(false);
|
|
3263
|
+
const [error, setError] = useState19(null);
|
|
3264
|
+
const importStore = useCallback23(
|
|
3265
|
+
async (storeDump, storeName, options) => {
|
|
3266
|
+
if (!client || !isReady) {
|
|
3267
|
+
throw new Error("Miden client is not ready");
|
|
3268
|
+
}
|
|
3269
|
+
setIsImporting(true);
|
|
3270
|
+
setError(null);
|
|
3271
|
+
try {
|
|
3272
|
+
await runExclusive(() => sdkImportStore(storeName, storeDump));
|
|
3273
|
+
if (!options?.skipSync) {
|
|
3274
|
+
await sync();
|
|
3275
|
+
}
|
|
3276
|
+
} catch (err) {
|
|
3277
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
3278
|
+
setError(error2);
|
|
3279
|
+
throw error2;
|
|
3280
|
+
} finally {
|
|
3281
|
+
setIsImporting(false);
|
|
3282
|
+
}
|
|
3283
|
+
},
|
|
3284
|
+
[client, isReady, runExclusive, sync]
|
|
3285
|
+
);
|
|
3286
|
+
const reset = useCallback23(() => {
|
|
3287
|
+
setIsImporting(false);
|
|
3288
|
+
setError(null);
|
|
3289
|
+
}, []);
|
|
3290
|
+
return {
|
|
3291
|
+
importStore,
|
|
3292
|
+
isImporting,
|
|
3293
|
+
error,
|
|
3294
|
+
reset
|
|
3295
|
+
};
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
// src/hooks/useImportNote.ts
|
|
3299
|
+
import { useCallback as useCallback24, useState as useState20 } from "react";
|
|
3300
|
+
import { NoteFile } from "@miden-sdk/miden-sdk";
|
|
3301
|
+
function useImportNote() {
|
|
3302
|
+
const { client, isReady, runExclusive, sync } = useMiden();
|
|
3303
|
+
const [isImporting, setIsImporting] = useState20(false);
|
|
3304
|
+
const [error, setError] = useState20(null);
|
|
3305
|
+
const importNote = useCallback24(
|
|
3306
|
+
async (noteBytes) => {
|
|
3307
|
+
if (!client || !isReady) {
|
|
3308
|
+
throw new Error("Miden client is not ready");
|
|
3309
|
+
}
|
|
3310
|
+
setIsImporting(true);
|
|
3311
|
+
setError(null);
|
|
3312
|
+
try {
|
|
3313
|
+
const noteFile = NoteFile.deserialize(noteBytes);
|
|
3314
|
+
const noteId = await runExclusive(
|
|
3315
|
+
() => client.importNoteFile(noteFile)
|
|
3316
|
+
);
|
|
3317
|
+
await sync();
|
|
3318
|
+
return noteId.toString();
|
|
3319
|
+
} catch (err) {
|
|
3320
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
3321
|
+
setError(error2);
|
|
3322
|
+
throw error2;
|
|
3323
|
+
} finally {
|
|
3324
|
+
setIsImporting(false);
|
|
3325
|
+
}
|
|
3326
|
+
},
|
|
3327
|
+
[client, isReady, runExclusive, sync]
|
|
3328
|
+
);
|
|
3329
|
+
const reset = useCallback24(() => {
|
|
3330
|
+
setIsImporting(false);
|
|
3331
|
+
setError(null);
|
|
3332
|
+
}, []);
|
|
3333
|
+
return {
|
|
3334
|
+
importNote,
|
|
3335
|
+
isImporting,
|
|
3336
|
+
error,
|
|
3337
|
+
reset
|
|
3338
|
+
};
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
// src/hooks/useExportNote.ts
|
|
3342
|
+
import { useCallback as useCallback25, useState as useState21 } from "react";
|
|
3343
|
+
import { NoteExportFormat } from "@miden-sdk/miden-sdk";
|
|
3344
|
+
function useExportNote() {
|
|
3345
|
+
const { client, isReady, runExclusive } = useMiden();
|
|
3346
|
+
const [isExporting, setIsExporting] = useState21(false);
|
|
3347
|
+
const [error, setError] = useState21(null);
|
|
3348
|
+
const exportNote = useCallback25(
|
|
3349
|
+
async (noteId) => {
|
|
3350
|
+
if (!client || !isReady) {
|
|
3351
|
+
throw new Error("Miden client is not ready");
|
|
3352
|
+
}
|
|
3353
|
+
setIsExporting(true);
|
|
3354
|
+
setError(null);
|
|
3355
|
+
try {
|
|
3356
|
+
const noteFile = await runExclusive(
|
|
3357
|
+
() => client.exportNoteFile(noteId, NoteExportFormat.Full)
|
|
3358
|
+
);
|
|
3359
|
+
return noteFile.serialize();
|
|
3360
|
+
} catch (err) {
|
|
3361
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
3362
|
+
setError(error2);
|
|
3363
|
+
throw error2;
|
|
3364
|
+
} finally {
|
|
3365
|
+
setIsExporting(false);
|
|
3366
|
+
}
|
|
3367
|
+
},
|
|
3368
|
+
[client, isReady, runExclusive]
|
|
3369
|
+
);
|
|
3370
|
+
const reset = useCallback25(() => {
|
|
3371
|
+
setIsExporting(false);
|
|
3372
|
+
setError(null);
|
|
3373
|
+
}, []);
|
|
3374
|
+
return {
|
|
3375
|
+
exportNote,
|
|
3376
|
+
isExporting,
|
|
3377
|
+
error,
|
|
3378
|
+
reset
|
|
3379
|
+
};
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3382
|
+
// src/hooks/useSyncControl.ts
|
|
3383
|
+
import { useCallback as useCallback26 } from "react";
|
|
3384
|
+
function useSyncControl() {
|
|
3385
|
+
const isPaused = useMidenStore((state) => state.syncPaused);
|
|
3386
|
+
const setSyncPaused = useMidenStore((state) => state.setSyncPaused);
|
|
3387
|
+
const pauseSync = useCallback26(() => setSyncPaused(true), [setSyncPaused]);
|
|
3388
|
+
const resumeSync = useCallback26(() => setSyncPaused(false), [setSyncPaused]);
|
|
3389
|
+
return {
|
|
3390
|
+
pauseSync,
|
|
3391
|
+
resumeSync,
|
|
3392
|
+
isPaused
|
|
3393
|
+
};
|
|
3394
|
+
}
|
|
3395
|
+
|
|
2911
3396
|
// src/utils/bytes.ts
|
|
2912
3397
|
function bytesToBigInt(bytes) {
|
|
2913
3398
|
let result = 0n;
|
|
@@ -3058,10 +3543,13 @@ function createMidenStorage(prefix) {
|
|
|
3058
3543
|
// src/index.ts
|
|
3059
3544
|
installAccountBech32();
|
|
3060
3545
|
export {
|
|
3546
|
+
AuthScheme,
|
|
3061
3547
|
DEFAULTS,
|
|
3062
3548
|
MidenError,
|
|
3063
3549
|
MidenProvider,
|
|
3550
|
+
MultiSignerProvider,
|
|
3064
3551
|
SignerContext,
|
|
3552
|
+
SignerSlot,
|
|
3065
3553
|
accountIdsEqual,
|
|
3066
3554
|
bigIntToBytes,
|
|
3067
3555
|
bytesToBigInt,
|
|
@@ -3083,18 +3571,24 @@ export {
|
|
|
3083
3571
|
useConsume,
|
|
3084
3572
|
useCreateFaucet,
|
|
3085
3573
|
useCreateWallet,
|
|
3574
|
+
useExecuteProgram,
|
|
3575
|
+
useExportNote,
|
|
3576
|
+
useExportStore,
|
|
3086
3577
|
useImportAccount,
|
|
3087
|
-
|
|
3578
|
+
useImportNote,
|
|
3579
|
+
useImportStore,
|
|
3088
3580
|
useMiden,
|
|
3089
3581
|
useMidenClient,
|
|
3090
3582
|
useMint,
|
|
3091
3583
|
useMultiSend,
|
|
3584
|
+
useMultiSigner,
|
|
3092
3585
|
useNoteStream,
|
|
3093
3586
|
useNotes,
|
|
3094
3587
|
useSend,
|
|
3095
3588
|
useSessionAccount,
|
|
3096
3589
|
useSigner,
|
|
3097
3590
|
useSwap,
|
|
3591
|
+
useSyncControl,
|
|
3098
3592
|
useSyncState,
|
|
3099
3593
|
useTransaction,
|
|
3100
3594
|
useTransactionHistory,
|