@miden-sdk/react 0.14.0-alpha → 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 +328 -113
- package/dist/index.d.ts +328 -113
- package/dist/index.js +1019 -513
- package/dist/index.mjs +1027 -527
- package/package.json +1 -1
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 {
|
|
@@ -352,9 +370,35 @@ function resolveTransactionProver(config) {
|
|
|
352
370
|
if (!prover) {
|
|
353
371
|
return null;
|
|
354
372
|
}
|
|
355
|
-
if (
|
|
356
|
-
|
|
357
|
-
|
|
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") {
|
|
358
402
|
return TransactionProver.newLocalProver();
|
|
359
403
|
}
|
|
360
404
|
if (normalized === "devnet" || normalized === "testnet") {
|
|
@@ -368,11 +412,11 @@ function resolveTransactionProver(config) {
|
|
|
368
412
|
);
|
|
369
413
|
}
|
|
370
414
|
return TransactionProver.newRemoteProver(
|
|
371
|
-
|
|
415
|
+
target,
|
|
372
416
|
normalizeTimeout(config.proverTimeoutMs)
|
|
373
417
|
);
|
|
374
418
|
}
|
|
375
|
-
return createRemoteProver(
|
|
419
|
+
return createRemoteProver(target, config.proverTimeoutMs);
|
|
376
420
|
}
|
|
377
421
|
function createRemoteProver(config, fallbackTimeout) {
|
|
378
422
|
const { url, timeoutMs } = config;
|
|
@@ -417,6 +461,19 @@ function isPrivateStorageMode(storageMode) {
|
|
|
417
461
|
async function initializeSignerAccount(client, config) {
|
|
418
462
|
const { AccountBuilder, AccountComponent, AuthScheme: AuthScheme2, Word: Word2 } = await import("@miden-sdk/miden-sdk");
|
|
419
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
|
+
}
|
|
420
477
|
const commitmentWord = Word2.deserialize(config.publicKeyCommitment);
|
|
421
478
|
const seed = config.accountSeed ?? crypto.getRandomValues(new Uint8Array(32));
|
|
422
479
|
const accountType = getAccountType(config.accountType);
|
|
@@ -474,15 +531,19 @@ function MidenProvider({
|
|
|
474
531
|
isReady,
|
|
475
532
|
isInitializing,
|
|
476
533
|
initError,
|
|
534
|
+
signerConnected,
|
|
477
535
|
setClient,
|
|
478
536
|
setInitializing,
|
|
479
537
|
setInitError,
|
|
480
538
|
setConfig,
|
|
481
|
-
setSyncState
|
|
539
|
+
setSyncState,
|
|
540
|
+
setSignerConnected
|
|
482
541
|
} = useMidenStore();
|
|
483
542
|
const syncIntervalRef = useRef(null);
|
|
484
543
|
const isInitializedRef = useRef(false);
|
|
485
544
|
const clientLockRef = useRef(new AsyncLock());
|
|
545
|
+
const currentStoreNameRef = useRef(null);
|
|
546
|
+
const signCbRef = useRef(null);
|
|
486
547
|
const signerContext = useSigner();
|
|
487
548
|
const [signerAccountId, setSignerAccountId] = useState(null);
|
|
488
549
|
const resolvedConfig = useMemo(
|
|
@@ -510,35 +571,62 @@ function MidenProvider({
|
|
|
510
571
|
const store = useMidenStore.getState();
|
|
511
572
|
if (store.sync.isSyncing) return;
|
|
512
573
|
setSyncState({ isSyncing: true, error: null });
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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.");
|
|
530
604
|
}
|
|
531
|
-
|
|
532
|
-
|
|
605
|
+
return cb(pubKey, signingInputs);
|
|
606
|
+
},
|
|
607
|
+
[]
|
|
608
|
+
);
|
|
533
609
|
useEffect(() => {
|
|
534
|
-
if (
|
|
535
|
-
if (
|
|
536
|
-
|
|
537
|
-
|
|
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();
|
|
538
627
|
setClient(null);
|
|
539
628
|
setSignerAccountId(null);
|
|
540
629
|
}
|
|
541
|
-
return;
|
|
542
630
|
}
|
|
543
631
|
let cancelled = false;
|
|
544
632
|
const initClient = async () => {
|
|
@@ -549,18 +637,17 @@ function MidenProvider({
|
|
|
549
637
|
try {
|
|
550
638
|
let webClient;
|
|
551
639
|
let didSignerInit = false;
|
|
552
|
-
if (signerContext &&
|
|
640
|
+
if (signerContext && signerIsConnected === true) {
|
|
553
641
|
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
642
|
+
signCbRef.current = signerContext.signCb;
|
|
554
643
|
webClient = await WebClient.createClientWithExternalKeystore(
|
|
555
644
|
resolvedConfig.rpcUrl,
|
|
556
645
|
resolvedConfig.noteTransportUrl,
|
|
557
646
|
resolvedConfig.seed,
|
|
558
647
|
storeName,
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
// insertKeyCb - not needed for public accounts
|
|
563
|
-
signerContext.signCb
|
|
648
|
+
signerContext.getKeyCb,
|
|
649
|
+
signerContext.insertKeyCb,
|
|
650
|
+
wrappedSignCb
|
|
564
651
|
);
|
|
565
652
|
if (cancelled) return;
|
|
566
653
|
const accountId = await initializeSignerAccount(
|
|
@@ -570,6 +657,7 @@ function MidenProvider({
|
|
|
570
657
|
if (cancelled) return;
|
|
571
658
|
setSignerAccountId(accountId);
|
|
572
659
|
didSignerInit = true;
|
|
660
|
+
currentStoreNameRef.current = signerContext.storeName;
|
|
573
661
|
} else {
|
|
574
662
|
const seed = resolvedConfig.seed;
|
|
575
663
|
webClient = await WebClient.createClient(
|
|
@@ -603,6 +691,9 @@ function MidenProvider({
|
|
|
603
691
|
isInitializedRef.current = true;
|
|
604
692
|
}
|
|
605
693
|
setClient(webClient);
|
|
694
|
+
if (signerIsConnected === true) {
|
|
695
|
+
setSignerConnected(true);
|
|
696
|
+
}
|
|
606
697
|
}
|
|
607
698
|
} catch (error) {
|
|
608
699
|
if (!cancelled) {
|
|
@@ -626,14 +717,26 @@ function MidenProvider({
|
|
|
626
717
|
setInitError,
|
|
627
718
|
setInitializing,
|
|
628
719
|
setSyncState,
|
|
629
|
-
|
|
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.
|
|
630
731
|
]);
|
|
631
732
|
useEffect(() => {
|
|
632
733
|
if (!isReady || !client) return;
|
|
633
734
|
const interval = config.autoSyncInterval ?? DEFAULTS.AUTO_SYNC_INTERVAL;
|
|
634
735
|
if (interval <= 0) return;
|
|
635
736
|
syncIntervalRef.current = setInterval(() => {
|
|
636
|
-
|
|
737
|
+
if (!useMidenStore.getState().syncPaused) {
|
|
738
|
+
sync();
|
|
739
|
+
}
|
|
637
740
|
}, interval);
|
|
638
741
|
return () => {
|
|
639
742
|
if (syncIntervalRef.current) {
|
|
@@ -642,6 +745,20 @@ function MidenProvider({
|
|
|
642
745
|
}
|
|
643
746
|
};
|
|
644
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]);
|
|
645
762
|
if (isInitializing && loadingComponent) {
|
|
646
763
|
return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent });
|
|
647
764
|
}
|
|
@@ -659,7 +776,8 @@ function MidenProvider({
|
|
|
659
776
|
sync,
|
|
660
777
|
runExclusive,
|
|
661
778
|
prover: defaultProver,
|
|
662
|
-
signerAccountId
|
|
779
|
+
signerAccountId,
|
|
780
|
+
signerConnected
|
|
663
781
|
};
|
|
664
782
|
return /* @__PURE__ */ jsx(MidenContext.Provider, { value: contextValue, children });
|
|
665
783
|
}
|
|
@@ -680,35 +798,191 @@ function useMidenClient() {
|
|
|
680
798
|
return client;
|
|
681
799
|
}
|
|
682
800
|
|
|
683
|
-
// src/
|
|
684
|
-
import {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
+
}
|
|
688
964
|
|
|
689
965
|
// src/hooks/useAccounts.ts
|
|
966
|
+
import { useCallback as useCallback3, useEffect as useEffect3 } from "react";
|
|
690
967
|
function useAccounts() {
|
|
691
|
-
const { client, isReady
|
|
692
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
968
|
+
const { client, isReady } = useMiden();
|
|
693
969
|
const accounts = useAccountsStore();
|
|
694
970
|
const isLoadingAccounts = useMidenStore((state) => state.isLoadingAccounts);
|
|
695
971
|
const setLoadingAccounts = useMidenStore((state) => state.setLoadingAccounts);
|
|
696
972
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
697
|
-
const refetch =
|
|
973
|
+
const refetch = useCallback3(async () => {
|
|
698
974
|
if (!client || !isReady) return;
|
|
699
975
|
setLoadingAccounts(true);
|
|
700
976
|
try {
|
|
701
|
-
const fetchedAccounts = await
|
|
702
|
-
() => client.getAccounts()
|
|
703
|
-
);
|
|
977
|
+
const fetchedAccounts = await client.getAccounts();
|
|
704
978
|
setAccounts(fetchedAccounts);
|
|
705
979
|
} catch (error) {
|
|
706
980
|
console.error("Failed to fetch accounts:", error);
|
|
707
981
|
} finally {
|
|
708
982
|
setLoadingAccounts(false);
|
|
709
983
|
}
|
|
710
|
-
}, [client, isReady,
|
|
711
|
-
|
|
984
|
+
}, [client, isReady, setAccounts, setLoadingAccounts]);
|
|
985
|
+
useEffect3(() => {
|
|
712
986
|
if (isReady && accounts.length === 0) {
|
|
713
987
|
refetch();
|
|
714
988
|
}
|
|
@@ -734,10 +1008,10 @@ function useAccounts() {
|
|
|
734
1008
|
}
|
|
735
1009
|
|
|
736
1010
|
// src/hooks/useAccount.ts
|
|
737
|
-
import { useCallback as
|
|
1011
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useState as useState3, useMemo as useMemo4 } from "react";
|
|
738
1012
|
|
|
739
1013
|
// src/hooks/useAssetMetadata.ts
|
|
740
|
-
import { useEffect as
|
|
1014
|
+
import { useEffect as useEffect4, useMemo as useMemo3 } from "react";
|
|
741
1015
|
import {
|
|
742
1016
|
BasicFungibleFaucetComponent,
|
|
743
1017
|
Endpoint,
|
|
@@ -777,12 +1051,12 @@ function useAssetMetadata(assetIds = []) {
|
|
|
777
1051
|
const assetMetadata = useAssetMetadataStore();
|
|
778
1052
|
const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
|
|
779
1053
|
const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
|
|
780
|
-
const rpcClient =
|
|
781
|
-
const uniqueAssetIds =
|
|
1054
|
+
const rpcClient = useMemo3(() => getRpcClient(rpcUrl), [rpcUrl]);
|
|
1055
|
+
const uniqueAssetIds = useMemo3(
|
|
782
1056
|
() => Array.from(new Set(assetIds.filter(Boolean))),
|
|
783
1057
|
[assetIds]
|
|
784
1058
|
);
|
|
785
|
-
|
|
1059
|
+
useEffect4(() => {
|
|
786
1060
|
if (!rpcClient || uniqueAssetIds.length === 0) return;
|
|
787
1061
|
uniqueAssetIds.forEach((assetId) => {
|
|
788
1062
|
const existing = assetMetadata.get(assetId);
|
|
@@ -801,31 +1075,25 @@ function useAssetMetadata(assetIds = []) {
|
|
|
801
1075
|
|
|
802
1076
|
// src/hooks/useAccount.ts
|
|
803
1077
|
function useAccount(accountId) {
|
|
804
|
-
const { client, isReady
|
|
805
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1078
|
+
const { client, isReady } = useMiden();
|
|
806
1079
|
const accountDetails = useMidenStore((state) => state.accountDetails);
|
|
807
1080
|
const setAccountDetails = useMidenStore((state) => state.setAccountDetails);
|
|
808
1081
|
const { lastSyncTime } = useSyncStateStore();
|
|
809
|
-
const [isLoading, setIsLoading] =
|
|
810
|
-
const [error, setError] =
|
|
811
|
-
const accountIdStr =
|
|
1082
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
1083
|
+
const [error, setError] = useState3(null);
|
|
1084
|
+
const accountIdStr = useMemo4(() => {
|
|
812
1085
|
if (!accountId) return void 0;
|
|
813
1086
|
if (typeof accountId === "string") return accountId;
|
|
814
|
-
|
|
815
|
-
return accountId.toString();
|
|
816
|
-
}
|
|
817
|
-
return String(accountId);
|
|
1087
|
+
return parseAccountId(accountId).toString();
|
|
818
1088
|
}, [accountId]);
|
|
819
1089
|
const account = accountIdStr ? accountDetails.get(accountIdStr) ?? null : null;
|
|
820
|
-
const refetch =
|
|
1090
|
+
const refetch = useCallback4(async () => {
|
|
821
1091
|
if (!client || !isReady || !accountIdStr) return;
|
|
822
1092
|
setIsLoading(true);
|
|
823
1093
|
setError(null);
|
|
824
1094
|
try {
|
|
825
1095
|
const accountIdObj = parseAccountId(accountIdStr);
|
|
826
|
-
const fetchedAccount = await
|
|
827
|
-
() => client.getAccount(accountIdObj)
|
|
828
|
-
);
|
|
1096
|
+
const fetchedAccount = await client.getAccount(accountIdObj);
|
|
829
1097
|
if (fetchedAccount) {
|
|
830
1098
|
ensureAccountBech32(fetchedAccount);
|
|
831
1099
|
setAccountDetails(accountIdStr, fetchedAccount);
|
|
@@ -835,17 +1103,17 @@ function useAccount(accountId) {
|
|
|
835
1103
|
} finally {
|
|
836
1104
|
setIsLoading(false);
|
|
837
1105
|
}
|
|
838
|
-
}, [client, isReady,
|
|
839
|
-
|
|
1106
|
+
}, [client, isReady, accountIdStr, setAccountDetails]);
|
|
1107
|
+
useEffect5(() => {
|
|
840
1108
|
if (isReady && accountIdStr && !account) {
|
|
841
1109
|
refetch();
|
|
842
1110
|
}
|
|
843
1111
|
}, [isReady, accountIdStr, account, refetch]);
|
|
844
|
-
|
|
1112
|
+
useEffect5(() => {
|
|
845
1113
|
if (!isReady || !accountIdStr || !lastSyncTime) return;
|
|
846
1114
|
refetch();
|
|
847
1115
|
}, [isReady, accountIdStr, lastSyncTime, refetch]);
|
|
848
|
-
const rawAssets =
|
|
1116
|
+
const rawAssets = useMemo4(() => {
|
|
849
1117
|
if (!account) return [];
|
|
850
1118
|
try {
|
|
851
1119
|
const vault = account.vault();
|
|
@@ -862,12 +1130,12 @@ function useAccount(accountId) {
|
|
|
862
1130
|
return [];
|
|
863
1131
|
}
|
|
864
1132
|
}, [account]);
|
|
865
|
-
const assetIds =
|
|
1133
|
+
const assetIds = useMemo4(
|
|
866
1134
|
() => rawAssets.map((asset) => asset.assetId),
|
|
867
1135
|
[rawAssets]
|
|
868
1136
|
);
|
|
869
1137
|
const { assetMetadata } = useAssetMetadata(assetIds);
|
|
870
|
-
const assets =
|
|
1138
|
+
const assets = useMemo4(
|
|
871
1139
|
() => rawAssets.map((asset) => {
|
|
872
1140
|
const metadata = assetMetadata.get(asset.assetId);
|
|
873
1141
|
return {
|
|
@@ -878,7 +1146,7 @@ function useAccount(accountId) {
|
|
|
878
1146
|
}),
|
|
879
1147
|
[rawAssets, assetMetadata]
|
|
880
1148
|
);
|
|
881
|
-
const getBalance =
|
|
1149
|
+
const getBalance = useCallback4(
|
|
882
1150
|
(assetId) => {
|
|
883
1151
|
const asset = assets.find((a) => a.assetId === assetId);
|
|
884
1152
|
return asset?.amount ?? 0n;
|
|
@@ -896,17 +1164,18 @@ function useAccount(accountId) {
|
|
|
896
1164
|
}
|
|
897
1165
|
|
|
898
1166
|
// src/hooks/useNotes.ts
|
|
899
|
-
import { useCallback as
|
|
1167
|
+
import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useState as useState4 } from "react";
|
|
900
1168
|
import { NoteFilter } from "@miden-sdk/miden-sdk";
|
|
901
1169
|
|
|
902
1170
|
// src/utils/amounts.ts
|
|
903
1171
|
var formatAssetAmount = (amount, decimals) => {
|
|
1172
|
+
const amt = BigInt(amount);
|
|
904
1173
|
if (!decimals || decimals <= 0) {
|
|
905
|
-
return
|
|
1174
|
+
return amt.toString();
|
|
906
1175
|
}
|
|
907
1176
|
const factor = 10n ** BigInt(decimals);
|
|
908
|
-
const whole =
|
|
909
|
-
const fraction =
|
|
1177
|
+
const whole = amt / factor;
|
|
1178
|
+
const fraction = amt % factor;
|
|
910
1179
|
if (fraction === 0n) {
|
|
911
1180
|
return whole.toString();
|
|
912
1181
|
}
|
|
@@ -1063,8 +1332,7 @@ function normalizeHex(value) {
|
|
|
1063
1332
|
|
|
1064
1333
|
// src/hooks/useNotes.ts
|
|
1065
1334
|
function useNotes(options) {
|
|
1066
|
-
const { client, isReady
|
|
1067
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1335
|
+
const { client, isReady } = useMiden();
|
|
1068
1336
|
const notes = useNotesStore();
|
|
1069
1337
|
const consumableNotes = useConsumableNotesStore();
|
|
1070
1338
|
const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
|
|
@@ -1074,30 +1342,22 @@ function useNotes(options) {
|
|
|
1074
1342
|
(state) => state.setConsumableNotesIfChanged
|
|
1075
1343
|
);
|
|
1076
1344
|
const { lastSyncTime } = useSyncStateStore();
|
|
1077
|
-
const [error, setError] =
|
|
1078
|
-
const refetch =
|
|
1345
|
+
const [error, setError] = useState4(null);
|
|
1346
|
+
const refetch = useCallback5(async () => {
|
|
1079
1347
|
if (!client || !isReady) return;
|
|
1080
1348
|
setLoadingNotes(true);
|
|
1081
1349
|
setError(null);
|
|
1082
1350
|
try {
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
consumableResult = await client.getConsumableNotes();
|
|
1094
|
-
}
|
|
1095
|
-
return {
|
|
1096
|
-
fetchedNotes: notesResult,
|
|
1097
|
-
fetchedConsumable: consumableResult
|
|
1098
|
-
};
|
|
1099
|
-
}
|
|
1100
|
-
);
|
|
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
|
+
}
|
|
1101
1361
|
setNotesIfChanged(fetchedNotes);
|
|
1102
1362
|
setConsumableNotesIfChanged(fetchedConsumable);
|
|
1103
1363
|
} catch (err) {
|
|
@@ -1108,23 +1368,22 @@ function useNotes(options) {
|
|
|
1108
1368
|
}, [
|
|
1109
1369
|
client,
|
|
1110
1370
|
isReady,
|
|
1111
|
-
runExclusive,
|
|
1112
1371
|
options?.status,
|
|
1113
1372
|
options?.accountId,
|
|
1114
1373
|
setLoadingNotes,
|
|
1115
1374
|
setNotesIfChanged,
|
|
1116
1375
|
setConsumableNotesIfChanged
|
|
1117
1376
|
]);
|
|
1118
|
-
|
|
1377
|
+
useEffect6(() => {
|
|
1119
1378
|
if (isReady && notes.length === 0) {
|
|
1120
1379
|
refetch();
|
|
1121
1380
|
}
|
|
1122
1381
|
}, [isReady, notes.length, refetch]);
|
|
1123
|
-
|
|
1382
|
+
useEffect6(() => {
|
|
1124
1383
|
if (!isReady || !lastSyncTime) return;
|
|
1125
1384
|
refetch();
|
|
1126
1385
|
}, [isReady, lastSyncTime, refetch]);
|
|
1127
|
-
const noteAssetIds =
|
|
1386
|
+
const noteAssetIds = useMemo5(() => {
|
|
1128
1387
|
const ids = /* @__PURE__ */ new Set();
|
|
1129
1388
|
const collect = (note) => {
|
|
1130
1389
|
const summary = getNoteSummary(note);
|
|
@@ -1136,11 +1395,11 @@ function useNotes(options) {
|
|
|
1136
1395
|
return Array.from(ids);
|
|
1137
1396
|
}, [notes, consumableNotes]);
|
|
1138
1397
|
const { assetMetadata } = useAssetMetadata(noteAssetIds);
|
|
1139
|
-
const getMetadata =
|
|
1398
|
+
const getMetadata = useCallback5(
|
|
1140
1399
|
(assetId) => assetMetadata.get(assetId),
|
|
1141
1400
|
[assetMetadata]
|
|
1142
1401
|
);
|
|
1143
|
-
const normalizedSender =
|
|
1402
|
+
const normalizedSender = useMemo5(() => {
|
|
1144
1403
|
if (!options?.sender) return null;
|
|
1145
1404
|
try {
|
|
1146
1405
|
return normalizeAccountId(options.sender);
|
|
@@ -1148,11 +1407,11 @@ function useNotes(options) {
|
|
|
1148
1407
|
return options.sender;
|
|
1149
1408
|
}
|
|
1150
1409
|
}, [options?.sender]);
|
|
1151
|
-
const excludeIdsKey =
|
|
1410
|
+
const excludeIdsKey = useMemo5(() => {
|
|
1152
1411
|
if (!options?.excludeIds || options.excludeIds.length === 0) return "";
|
|
1153
1412
|
return [...options.excludeIds].sort().join("\0");
|
|
1154
1413
|
}, [options?.excludeIds]);
|
|
1155
|
-
const filterBySender =
|
|
1414
|
+
const filterBySender = useCallback5(
|
|
1156
1415
|
(summaries, target) => {
|
|
1157
1416
|
const cache = /* @__PURE__ */ new Map();
|
|
1158
1417
|
return summaries.filter((s) => {
|
|
@@ -1171,7 +1430,7 @@ function useNotes(options) {
|
|
|
1171
1430
|
},
|
|
1172
1431
|
[]
|
|
1173
1432
|
);
|
|
1174
|
-
const noteSummaries =
|
|
1433
|
+
const noteSummaries = useMemo5(() => {
|
|
1175
1434
|
let summaries = notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1176
1435
|
if (normalizedSender) {
|
|
1177
1436
|
summaries = filterBySender(summaries, normalizedSender);
|
|
@@ -1182,7 +1441,7 @@ function useNotes(options) {
|
|
|
1182
1441
|
}
|
|
1183
1442
|
return summaries;
|
|
1184
1443
|
}, [notes, getMetadata, normalizedSender, excludeIdsKey, filterBySender]);
|
|
1185
|
-
const consumableNoteSummaries =
|
|
1444
|
+
const consumableNoteSummaries = useMemo5(() => {
|
|
1186
1445
|
let summaries = consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1187
1446
|
if (normalizedSender) {
|
|
1188
1447
|
summaries = filterBySender(summaries, normalizedSender);
|
|
@@ -1211,7 +1470,7 @@ function useNotes(options) {
|
|
|
1211
1470
|
}
|
|
1212
1471
|
|
|
1213
1472
|
// src/hooks/useNoteStream.ts
|
|
1214
|
-
import { useCallback as
|
|
1473
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3, useState as useState5 } from "react";
|
|
1215
1474
|
import { NoteFilter as NoteFilter2 } from "@miden-sdk/miden-sdk";
|
|
1216
1475
|
|
|
1217
1476
|
// src/utils/noteAttachment.ts
|
|
@@ -1287,54 +1546,51 @@ function createNoteAttachment(values) {
|
|
|
1287
1546
|
|
|
1288
1547
|
// src/hooks/useNoteStream.ts
|
|
1289
1548
|
function useNoteStream(options = {}) {
|
|
1290
|
-
const { client, isReady
|
|
1291
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1549
|
+
const { client, isReady } = useMiden();
|
|
1292
1550
|
const allNotes = useNotesStore();
|
|
1293
1551
|
const noteFirstSeen = useNoteFirstSeenStore();
|
|
1294
1552
|
const { lastSyncTime } = useSyncStateStore();
|
|
1295
1553
|
const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
|
|
1296
|
-
const [isLoading, setIsLoading] =
|
|
1297
|
-
const [error, setError] =
|
|
1298
|
-
const handledIdsRef =
|
|
1299
|
-
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);
|
|
1300
1558
|
const status = options.status ?? "committed";
|
|
1301
1559
|
const sender = options.sender ?? null;
|
|
1302
1560
|
const since = options.since;
|
|
1303
|
-
const amountFilterRef =
|
|
1561
|
+
const amountFilterRef = useRef3(options.amountFilter);
|
|
1304
1562
|
amountFilterRef.current = options.amountFilter;
|
|
1305
|
-
const excludeIdsKey =
|
|
1563
|
+
const excludeIdsKey = useMemo6(() => {
|
|
1306
1564
|
if (!options.excludeIds) return "";
|
|
1307
1565
|
if (options.excludeIds instanceof Set)
|
|
1308
1566
|
return Array.from(options.excludeIds).sort().join("\0");
|
|
1309
1567
|
return [...options.excludeIds].sort().join("\0");
|
|
1310
1568
|
}, [options.excludeIds]);
|
|
1311
|
-
const excludeIdSet =
|
|
1569
|
+
const excludeIdSet = useMemo6(() => {
|
|
1312
1570
|
if (!excludeIdsKey) return null;
|
|
1313
1571
|
return new Set(excludeIdsKey.split("\0"));
|
|
1314
1572
|
}, [excludeIdsKey]);
|
|
1315
|
-
const refetch =
|
|
1573
|
+
const refetch = useCallback6(async () => {
|
|
1316
1574
|
if (!client || !isReady) return;
|
|
1317
1575
|
setIsLoading(true);
|
|
1318
1576
|
setError(null);
|
|
1319
1577
|
try {
|
|
1320
1578
|
const filterType = getNoteFilterType(status);
|
|
1321
1579
|
const filter = new NoteFilter2(filterType);
|
|
1322
|
-
const fetched = await
|
|
1323
|
-
() => client.getInputNotes(filter)
|
|
1324
|
-
);
|
|
1580
|
+
const fetched = await client.getInputNotes(filter);
|
|
1325
1581
|
setNotesIfChanged(fetched);
|
|
1326
1582
|
} catch (err) {
|
|
1327
1583
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1328
1584
|
} finally {
|
|
1329
1585
|
setIsLoading(false);
|
|
1330
1586
|
}
|
|
1331
|
-
}, [client, isReady,
|
|
1332
|
-
|
|
1587
|
+
}, [client, isReady, status, setNotesIfChanged]);
|
|
1588
|
+
useEffect7(() => {
|
|
1333
1589
|
if (isReady) {
|
|
1334
1590
|
refetch();
|
|
1335
1591
|
}
|
|
1336
1592
|
}, [isReady, lastSyncTime, refetch]);
|
|
1337
|
-
const streamedNotes =
|
|
1593
|
+
const streamedNotes = useMemo6(() => {
|
|
1338
1594
|
void handledVersion;
|
|
1339
1595
|
const result = [];
|
|
1340
1596
|
let normalizedSender = null;
|
|
@@ -1359,15 +1615,15 @@ function useNoteStream(options = {}) {
|
|
|
1359
1615
|
result.sort((a, b) => a.firstSeenAt - b.firstSeenAt);
|
|
1360
1616
|
return result;
|
|
1361
1617
|
}, [allNotes, noteFirstSeen, excludeIdSet, sender, since, handledVersion]);
|
|
1362
|
-
const latest =
|
|
1618
|
+
const latest = useMemo6(
|
|
1363
1619
|
() => streamedNotes.length > 0 ? streamedNotes[streamedNotes.length - 1] : null,
|
|
1364
1620
|
[streamedNotes]
|
|
1365
1621
|
);
|
|
1366
|
-
const markHandled =
|
|
1622
|
+
const markHandled = useCallback6((noteId) => {
|
|
1367
1623
|
handledIdsRef.current = new Set(handledIdsRef.current).add(noteId);
|
|
1368
1624
|
setHandledVersion((v) => v + 1);
|
|
1369
1625
|
}, []);
|
|
1370
|
-
const markAllHandled =
|
|
1626
|
+
const markAllHandled = useCallback6(() => {
|
|
1371
1627
|
const newSet = new Set(handledIdsRef.current);
|
|
1372
1628
|
for (const note of streamedNotes) {
|
|
1373
1629
|
newSet.add(note.id);
|
|
@@ -1375,7 +1631,7 @@ function useNoteStream(options = {}) {
|
|
|
1375
1631
|
handledIdsRef.current = newSet;
|
|
1376
1632
|
setHandledVersion((v) => v + 1);
|
|
1377
1633
|
}, [streamedNotes]);
|
|
1378
|
-
const snapshot =
|
|
1634
|
+
const snapshot = useCallback6(() => {
|
|
1379
1635
|
const ids = /* @__PURE__ */ new Set();
|
|
1380
1636
|
for (const note of streamedNotes) {
|
|
1381
1637
|
ids.add(note.id);
|
|
@@ -1431,21 +1687,20 @@ function buildStreamedNote(record, noteFirstSeen) {
|
|
|
1431
1687
|
}
|
|
1432
1688
|
|
|
1433
1689
|
// src/hooks/useTransactionHistory.ts
|
|
1434
|
-
import { useCallback as
|
|
1690
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo7, useState as useState6 } from "react";
|
|
1435
1691
|
import { TransactionFilter as TransactionFilter2 } from "@miden-sdk/miden-sdk";
|
|
1436
1692
|
function useTransactionHistory(options = {}) {
|
|
1437
|
-
const { client, isReady
|
|
1438
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1693
|
+
const { client, isReady } = useMiden();
|
|
1439
1694
|
const { lastSyncTime } = useSyncStateStore();
|
|
1440
|
-
const [records, setRecords] =
|
|
1441
|
-
const [isLoading, setIsLoading] =
|
|
1442
|
-
const [error, setError] =
|
|
1443
|
-
const rawIds =
|
|
1695
|
+
const [records, setRecords] = useState6([]);
|
|
1696
|
+
const [isLoading, setIsLoading] = useState6(false);
|
|
1697
|
+
const [error, setError] = useState6(null);
|
|
1698
|
+
const rawIds = useMemo7(() => {
|
|
1444
1699
|
if (options.id) return [options.id];
|
|
1445
1700
|
if (options.ids && options.ids.length > 0) return options.ids;
|
|
1446
1701
|
return null;
|
|
1447
1702
|
}, [options.id, options.ids]);
|
|
1448
|
-
const idsHex =
|
|
1703
|
+
const idsHex = useMemo7(() => {
|
|
1449
1704
|
if (!rawIds) return null;
|
|
1450
1705
|
return rawIds.map(
|
|
1451
1706
|
(id) => normalizeHex2(typeof id === "string" ? id : id.toHex())
|
|
@@ -1453,7 +1708,7 @@ function useTransactionHistory(options = {}) {
|
|
|
1453
1708
|
}, [rawIds]);
|
|
1454
1709
|
const filter = options.filter;
|
|
1455
1710
|
const refreshOnSync = options.refreshOnSync !== false;
|
|
1456
|
-
const refetch =
|
|
1711
|
+
const refetch = useCallback7(async () => {
|
|
1457
1712
|
if (!client || !isReady) return;
|
|
1458
1713
|
setIsLoading(true);
|
|
1459
1714
|
setError(null);
|
|
@@ -1463,9 +1718,7 @@ function useTransactionHistory(options = {}) {
|
|
|
1463
1718
|
rawIds,
|
|
1464
1719
|
idsHex
|
|
1465
1720
|
);
|
|
1466
|
-
const fetched = await
|
|
1467
|
-
() => client.getTransactions(resolvedFilter)
|
|
1468
|
-
);
|
|
1721
|
+
const fetched = await client.getTransactions(resolvedFilter);
|
|
1469
1722
|
const filtered = localFilterHexes ? fetched.filter(
|
|
1470
1723
|
(record2) => localFilterHexes.includes(normalizeHex2(record2.id().toHex()))
|
|
1471
1724
|
) : fetched;
|
|
@@ -1475,20 +1728,20 @@ function useTransactionHistory(options = {}) {
|
|
|
1475
1728
|
} finally {
|
|
1476
1729
|
setIsLoading(false);
|
|
1477
1730
|
}
|
|
1478
|
-
}, [client, isReady,
|
|
1479
|
-
|
|
1731
|
+
}, [client, isReady, filter, rawIds, idsHex]);
|
|
1732
|
+
useEffect8(() => {
|
|
1480
1733
|
if (!isReady) return;
|
|
1481
1734
|
refetch();
|
|
1482
1735
|
}, [isReady, refetch]);
|
|
1483
|
-
|
|
1736
|
+
useEffect8(() => {
|
|
1484
1737
|
if (!isReady || !refreshOnSync || !lastSyncTime) return;
|
|
1485
1738
|
refetch();
|
|
1486
1739
|
}, [isReady, lastSyncTime, refreshOnSync, refetch]);
|
|
1487
|
-
const record =
|
|
1740
|
+
const record = useMemo7(() => {
|
|
1488
1741
|
if (!idsHex || idsHex.length !== 1) return null;
|
|
1489
1742
|
return records.find((item) => normalizeHex2(item.id().toHex()) === idsHex[0]) ?? null;
|
|
1490
1743
|
}, [records, idsHex]);
|
|
1491
|
-
const status =
|
|
1744
|
+
const status = useMemo7(() => {
|
|
1492
1745
|
if (!record) return null;
|
|
1493
1746
|
const current = record.transactionStatus();
|
|
1494
1747
|
if (current.isCommitted()) return "committed";
|
|
@@ -1528,11 +1781,11 @@ function normalizeHex2(value) {
|
|
|
1528
1781
|
}
|
|
1529
1782
|
|
|
1530
1783
|
// src/hooks/useSyncState.ts
|
|
1531
|
-
import { useCallback as
|
|
1784
|
+
import { useCallback as useCallback8 } from "react";
|
|
1532
1785
|
function useSyncState() {
|
|
1533
1786
|
const { sync: triggerSync } = useMiden();
|
|
1534
1787
|
const syncState = useSyncStateStore();
|
|
1535
|
-
const sync =
|
|
1788
|
+
const sync = useCallback8(async () => {
|
|
1536
1789
|
await triggerSync();
|
|
1537
1790
|
}, [triggerSync]);
|
|
1538
1791
|
return {
|
|
@@ -1542,16 +1795,21 @@ function useSyncState() {
|
|
|
1542
1795
|
}
|
|
1543
1796
|
|
|
1544
1797
|
// src/hooks/useCreateWallet.ts
|
|
1545
|
-
import { useCallback as
|
|
1798
|
+
import { useCallback as useCallback9, useState as useState7 } from "react";
|
|
1546
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
|
|
1547
1805
|
function useCreateWallet() {
|
|
1548
1806
|
const { client, isReady, runExclusive } = useMiden();
|
|
1549
1807
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1550
1808
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1551
|
-
const [wallet, setWallet] =
|
|
1552
|
-
const [isCreating, setIsCreating] =
|
|
1553
|
-
const [error, setError] =
|
|
1554
|
-
const createWallet =
|
|
1809
|
+
const [wallet, setWallet] = useState7(null);
|
|
1810
|
+
const [isCreating, setIsCreating] = useState7(false);
|
|
1811
|
+
const [error, setError] = useState7(null);
|
|
1812
|
+
const createWallet = useCallback9(
|
|
1555
1813
|
async (options = {}) => {
|
|
1556
1814
|
if (!client || !isReady) {
|
|
1557
1815
|
throw new Error("Miden client is not ready");
|
|
@@ -1588,7 +1846,7 @@ function useCreateWallet() {
|
|
|
1588
1846
|
},
|
|
1589
1847
|
[client, isReady, runExclusive, setAccounts]
|
|
1590
1848
|
);
|
|
1591
|
-
const reset =
|
|
1849
|
+
const reset = useCallback9(() => {
|
|
1592
1850
|
setWallet(null);
|
|
1593
1851
|
setIsCreating(false);
|
|
1594
1852
|
setError(null);
|
|
@@ -1615,16 +1873,16 @@ function getStorageMode(mode) {
|
|
|
1615
1873
|
}
|
|
1616
1874
|
|
|
1617
1875
|
// src/hooks/useCreateFaucet.ts
|
|
1618
|
-
import { useCallback as
|
|
1876
|
+
import { useCallback as useCallback10, useState as useState8 } from "react";
|
|
1619
1877
|
import { AccountStorageMode as AccountStorageMode2 } from "@miden-sdk/miden-sdk";
|
|
1620
1878
|
function useCreateFaucet() {
|
|
1621
1879
|
const { client, isReady, runExclusive } = useMiden();
|
|
1622
1880
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1623
1881
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1624
|
-
const [faucet, setFaucet] =
|
|
1625
|
-
const [isCreating, setIsCreating] =
|
|
1626
|
-
const [error, setError] =
|
|
1627
|
-
const createFaucet =
|
|
1882
|
+
const [faucet, setFaucet] = useState8(null);
|
|
1883
|
+
const [isCreating, setIsCreating] = useState8(false);
|
|
1884
|
+
const [error, setError] = useState8(null);
|
|
1885
|
+
const createFaucet = useCallback10(
|
|
1628
1886
|
async (options) => {
|
|
1629
1887
|
if (!client || !isReady) {
|
|
1630
1888
|
throw new Error("Miden client is not ready");
|
|
@@ -1644,7 +1902,7 @@ function useCreateFaucet() {
|
|
|
1644
1902
|
// nonFungible - currently only fungible faucets supported
|
|
1645
1903
|
options.tokenSymbol,
|
|
1646
1904
|
decimals,
|
|
1647
|
-
options.maxSupply,
|
|
1905
|
+
BigInt(options.maxSupply),
|
|
1648
1906
|
authScheme
|
|
1649
1907
|
);
|
|
1650
1908
|
const accounts = await client.getAccounts();
|
|
@@ -1663,7 +1921,7 @@ function useCreateFaucet() {
|
|
|
1663
1921
|
},
|
|
1664
1922
|
[client, isReady, runExclusive, setAccounts]
|
|
1665
1923
|
);
|
|
1666
|
-
const reset =
|
|
1924
|
+
const reset = useCallback10(() => {
|
|
1667
1925
|
setFaucet(null);
|
|
1668
1926
|
setIsCreating(false);
|
|
1669
1927
|
setError(null);
|
|
@@ -1690,25 +1948,79 @@ function getStorageMode2(mode) {
|
|
|
1690
1948
|
}
|
|
1691
1949
|
|
|
1692
1950
|
// src/hooks/useImportAccount.ts
|
|
1693
|
-
import { useCallback as
|
|
1951
|
+
import { useCallback as useCallback11, useState as useState9 } from "react";
|
|
1694
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
|
|
1695
2007
|
function useImportAccount() {
|
|
1696
|
-
const { client, isReady,
|
|
1697
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2008
|
+
const { client, isReady, signerConnected } = useMiden();
|
|
1698
2009
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1699
|
-
const [account, setAccount] =
|
|
1700
|
-
const [isImporting, setIsImporting] =
|
|
1701
|
-
const [error, setError] =
|
|
1702
|
-
const importAccount =
|
|
2010
|
+
const [account, setAccount] = useState9(null);
|
|
2011
|
+
const [isImporting, setIsImporting] = useState9(false);
|
|
2012
|
+
const [error, setError] = useState9(null);
|
|
2013
|
+
const importAccount = useCallback11(
|
|
1703
2014
|
async (options) => {
|
|
1704
2015
|
if (!client || !isReady) {
|
|
1705
2016
|
throw new Error("Miden client is not ready");
|
|
1706
2017
|
}
|
|
2018
|
+
assertSignerConnected(signerConnected);
|
|
1707
2019
|
setIsImporting(true);
|
|
1708
2020
|
setError(null);
|
|
1709
2021
|
try {
|
|
1710
2022
|
let accountsAfter = null;
|
|
1711
|
-
const imported = await
|
|
2023
|
+
const imported = await (async () => {
|
|
1712
2024
|
switch (options.type) {
|
|
1713
2025
|
case "file": {
|
|
1714
2026
|
const accountsBefore = await client.getAccounts();
|
|
@@ -1760,7 +2072,7 @@ function useImportAccount() {
|
|
|
1760
2072
|
throw new Error("Account not found after import");
|
|
1761
2073
|
}
|
|
1762
2074
|
case "id": {
|
|
1763
|
-
const accountId =
|
|
2075
|
+
const accountId = parseAccountId(options.accountId);
|
|
1764
2076
|
await client.importAccountById(accountId);
|
|
1765
2077
|
const fetchedAccount = await client.getAccount(accountId);
|
|
1766
2078
|
if (!fetchedAccount) {
|
|
@@ -1778,7 +2090,7 @@ function useImportAccount() {
|
|
|
1778
2090
|
);
|
|
1779
2091
|
}
|
|
1780
2092
|
}
|
|
1781
|
-
});
|
|
2093
|
+
})();
|
|
1782
2094
|
ensureAccountBech32(imported);
|
|
1783
2095
|
const accounts = accountsAfter ?? await client.getAccounts();
|
|
1784
2096
|
setAccounts(accounts);
|
|
@@ -1792,9 +2104,9 @@ function useImportAccount() {
|
|
|
1792
2104
|
setIsImporting(false);
|
|
1793
2105
|
}
|
|
1794
2106
|
},
|
|
1795
|
-
[client, isReady,
|
|
2107
|
+
[client, isReady, setAccounts, signerConnected]
|
|
1796
2108
|
);
|
|
1797
|
-
const reset =
|
|
2109
|
+
const reset = useCallback11(() => {
|
|
1798
2110
|
setAccount(null);
|
|
1799
2111
|
setIsImporting(false);
|
|
1800
2112
|
setError(null);
|
|
@@ -1807,9 +2119,6 @@ function useImportAccount() {
|
|
|
1807
2119
|
reset
|
|
1808
2120
|
};
|
|
1809
2121
|
}
|
|
1810
|
-
function resolveAccountId(accountId) {
|
|
1811
|
-
return parseAccountId(accountId);
|
|
1812
|
-
}
|
|
1813
2122
|
async function resolveAccountFile(file) {
|
|
1814
2123
|
if (file instanceof Uint8Array) {
|
|
1815
2124
|
return AccountFile.deserialize(file);
|
|
@@ -1844,72 +2153,25 @@ function bytesEqual(left, right) {
|
|
|
1844
2153
|
}
|
|
1845
2154
|
|
|
1846
2155
|
// src/hooks/useSend.ts
|
|
1847
|
-
import { useCallback as
|
|
2156
|
+
import { useCallback as useCallback12, useRef as useRef4, useState as useState10 } from "react";
|
|
1848
2157
|
import {
|
|
1849
2158
|
FungibleAsset,
|
|
1850
2159
|
Note,
|
|
1851
2160
|
NoteAssets,
|
|
2161
|
+
NoteAttachment as NoteAttachment2,
|
|
1852
2162
|
NoteType as NoteType2,
|
|
1853
|
-
|
|
1854
|
-
OutputNoteArray,
|
|
2163
|
+
NoteArray,
|
|
1855
2164
|
TransactionRequestBuilder
|
|
1856
2165
|
} from "@miden-sdk/miden-sdk";
|
|
1857
|
-
|
|
1858
|
-
// src/utils/errors.ts
|
|
1859
|
-
var MidenError = class extends Error {
|
|
1860
|
-
constructor(message, options) {
|
|
1861
|
-
super(message);
|
|
1862
|
-
this.name = "MidenError";
|
|
1863
|
-
this.code = options?.code ?? "UNKNOWN";
|
|
1864
|
-
if (options?.cause !== void 0) {
|
|
1865
|
-
this.cause = options.cause;
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
};
|
|
1869
|
-
var ERROR_PATTERNS = [
|
|
1870
|
-
{
|
|
1871
|
-
test: (msg) => msg.includes("_assertClass") || msg.includes("expected instance of"),
|
|
1872
|
-
code: "WASM_CLASS_MISMATCH",
|
|
1873
|
-
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."
|
|
1874
|
-
},
|
|
1875
|
-
{
|
|
1876
|
-
test: (msg) => msg.includes("null pointer") || msg.includes("already been freed") || msg.includes("dereferencing a null"),
|
|
1877
|
-
code: "WASM_POINTER_CONSUMED",
|
|
1878
|
-
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."
|
|
1879
|
-
},
|
|
1880
|
-
{
|
|
1881
|
-
test: (msg) => msg.includes("not initialized") || msg.includes("Cannot read properties of null"),
|
|
1882
|
-
code: "WASM_NOT_INITIALIZED",
|
|
1883
|
-
message: "Miden client is not initialized. Ensure you are inside a <MidenProvider> and the client is ready before calling SDK methods."
|
|
1884
|
-
},
|
|
1885
|
-
{
|
|
1886
|
-
test: (msg) => msg.includes("state commitment mismatch") || msg.includes("stale state"),
|
|
1887
|
-
code: "WASM_SYNC_REQUIRED",
|
|
1888
|
-
message: "Account state is stale. Call sync() before executing transactions, or ensure no concurrent transactions are running against the same account."
|
|
1889
|
-
}
|
|
1890
|
-
];
|
|
1891
|
-
function wrapWasmError(e) {
|
|
1892
|
-
if (e instanceof MidenError) return e;
|
|
1893
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
1894
|
-
for (const pattern of ERROR_PATTERNS) {
|
|
1895
|
-
if (pattern.test(msg)) {
|
|
1896
|
-
return new MidenError(pattern.message, { cause: e, code: pattern.code });
|
|
1897
|
-
}
|
|
1898
|
-
}
|
|
1899
|
-
if (e instanceof Error) return e;
|
|
1900
|
-
return new Error(msg);
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
// src/hooks/useSend.ts
|
|
1904
2166
|
function useSend() {
|
|
1905
2167
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1906
2168
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1907
|
-
const isBusyRef =
|
|
1908
|
-
const [result, setResult] =
|
|
1909
|
-
const [isLoading, setIsLoading] =
|
|
1910
|
-
const [stage, setStage] =
|
|
1911
|
-
const [error, setError] =
|
|
1912
|
-
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(
|
|
1913
2175
|
async (options) => {
|
|
1914
2176
|
if (!client || !isReady) {
|
|
1915
2177
|
throw new Error("Miden client is not ready");
|
|
@@ -1951,6 +2213,7 @@ function useSend() {
|
|
|
1951
2213
|
if (amount === void 0 || amount === null) {
|
|
1952
2214
|
throw new Error("Amount is required (provide amount or sendAll)");
|
|
1953
2215
|
}
|
|
2216
|
+
amount = BigInt(amount);
|
|
1954
2217
|
const assetId = options.assetId ?? options.faucetId ?? null;
|
|
1955
2218
|
if (!assetId) {
|
|
1956
2219
|
throw new Error("Asset ID is required");
|
|
@@ -1961,6 +2224,35 @@ function useSend() {
|
|
|
1961
2224
|
"recallHeight and timelockHeight are not supported when attachment is provided"
|
|
1962
2225
|
);
|
|
1963
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
|
+
}
|
|
1964
2256
|
const txResult = await runExclusiveSafe(async () => {
|
|
1965
2257
|
const fromAccountId = parseAccountId(options.from);
|
|
1966
2258
|
const toAccountId = parseAccountId(options.to);
|
|
@@ -1978,7 +2270,7 @@ function useSend() {
|
|
|
1978
2270
|
noteType,
|
|
1979
2271
|
attachment
|
|
1980
2272
|
);
|
|
1981
|
-
txRequest = new TransactionRequestBuilder().withOwnOutputNotes(new
|
|
2273
|
+
txRequest = new TransactionRequestBuilder().withOwnOutputNotes(new NoteArray([note])).build();
|
|
1982
2274
|
} else {
|
|
1983
2275
|
txRequest = client.newSendTransactionRequest(
|
|
1984
2276
|
fromAccountId,
|
|
@@ -1994,8 +2286,12 @@ function useSend() {
|
|
|
1994
2286
|
return await client.executeTransaction(execAccountId, txRequest);
|
|
1995
2287
|
});
|
|
1996
2288
|
setStage("proving");
|
|
1997
|
-
const
|
|
1998
|
-
|
|
2289
|
+
const proverConfig = useMidenStore.getState().config;
|
|
2290
|
+
const provenTransaction = await proveWithFallback(
|
|
2291
|
+
(resolvedProver) => runExclusiveSafe(
|
|
2292
|
+
() => client.proveTransaction(txResult, resolvedProver)
|
|
2293
|
+
),
|
|
2294
|
+
proverConfig
|
|
1999
2295
|
);
|
|
2000
2296
|
setStage("submitting");
|
|
2001
2297
|
const submissionHeight = await runExclusiveSafe(
|
|
@@ -2025,11 +2321,14 @@ function useSend() {
|
|
|
2025
2321
|
() => client.sendPrivateNote(fullNote, recipientAddress)
|
|
2026
2322
|
);
|
|
2027
2323
|
}
|
|
2028
|
-
const
|
|
2324
|
+
const sendResult = {
|
|
2325
|
+
txId: txIdString,
|
|
2326
|
+
note: null
|
|
2327
|
+
};
|
|
2029
2328
|
setStage("complete");
|
|
2030
|
-
setResult(
|
|
2329
|
+
setResult(sendResult);
|
|
2031
2330
|
await sync();
|
|
2032
|
-
return
|
|
2331
|
+
return sendResult;
|
|
2033
2332
|
} catch (err) {
|
|
2034
2333
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2035
2334
|
setError(error2);
|
|
@@ -2042,7 +2341,7 @@ function useSend() {
|
|
|
2042
2341
|
},
|
|
2043
2342
|
[client, isReady, prover, runExclusive, sync]
|
|
2044
2343
|
);
|
|
2045
|
-
const reset =
|
|
2344
|
+
const reset = useCallback12(() => {
|
|
2046
2345
|
setResult(null);
|
|
2047
2346
|
setIsLoading(false);
|
|
2048
2347
|
setStage("idle");
|
|
@@ -2069,30 +2368,29 @@ function extractFullNote(txResult) {
|
|
|
2069
2368
|
}
|
|
2070
2369
|
|
|
2071
2370
|
// src/hooks/useMultiSend.ts
|
|
2072
|
-
import { useCallback as
|
|
2371
|
+
import { useCallback as useCallback13, useRef as useRef5, useState as useState11 } from "react";
|
|
2073
2372
|
import {
|
|
2074
2373
|
FungibleAsset as FungibleAsset2,
|
|
2075
2374
|
Note as Note2,
|
|
2076
2375
|
NoteAssets as NoteAssets2,
|
|
2077
|
-
NoteAttachment as
|
|
2376
|
+
NoteAttachment as NoteAttachment3,
|
|
2078
2377
|
NoteType as NoteType3,
|
|
2079
|
-
|
|
2080
|
-
OutputNoteArray as OutputNoteArray2,
|
|
2378
|
+
NoteArray as NoteArray2,
|
|
2081
2379
|
TransactionRequestBuilder as TransactionRequestBuilder2
|
|
2082
2380
|
} from "@miden-sdk/miden-sdk";
|
|
2083
2381
|
function useMultiSend() {
|
|
2084
|
-
const { client, isReady, sync,
|
|
2085
|
-
const
|
|
2086
|
-
const
|
|
2087
|
-
const [
|
|
2088
|
-
const [
|
|
2089
|
-
const [
|
|
2090
|
-
const
|
|
2091
|
-
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(
|
|
2092
2389
|
async (options) => {
|
|
2093
2390
|
if (!client || !isReady) {
|
|
2094
2391
|
throw new Error("Miden client is not ready");
|
|
2095
2392
|
}
|
|
2393
|
+
assertSignerConnected(signerConnected);
|
|
2096
2394
|
if (options.recipients.length === 0) {
|
|
2097
2395
|
throw new Error("No recipients provided");
|
|
2098
2396
|
}
|
|
@@ -2117,10 +2415,10 @@ function useMultiSend() {
|
|
|
2117
2415
|
const iterAssetId = parseAccountId(options.assetId);
|
|
2118
2416
|
const receiverId = parseAccountId(to);
|
|
2119
2417
|
const assets = new NoteAssets2([
|
|
2120
|
-
new FungibleAsset2(iterAssetId, amount)
|
|
2418
|
+
new FungibleAsset2(iterAssetId, BigInt(amount))
|
|
2121
2419
|
]);
|
|
2122
2420
|
const resolvedNoteType = recipientNoteType ? getNoteType(recipientNoteType) : noteType;
|
|
2123
|
-
const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new
|
|
2421
|
+
const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new NoteAttachment3();
|
|
2124
2422
|
const note = Note2.createP2IDNote(
|
|
2125
2423
|
iterSenderId,
|
|
2126
2424
|
receiverId,
|
|
@@ -2130,44 +2428,43 @@ function useMultiSend() {
|
|
|
2130
2428
|
);
|
|
2131
2429
|
const recipientAddress = parseAddress(to, receiverId);
|
|
2132
2430
|
return {
|
|
2133
|
-
outputNote: OutputNote2.full(note),
|
|
2134
2431
|
note,
|
|
2135
2432
|
recipientAddress,
|
|
2136
2433
|
noteType: resolvedNoteType
|
|
2137
2434
|
};
|
|
2138
2435
|
}
|
|
2139
2436
|
);
|
|
2140
|
-
const txRequest = new TransactionRequestBuilder2().withOwnOutputNotes(
|
|
2141
|
-
new OutputNoteArray2(outputs.map((o) => o.outputNote))
|
|
2142
|
-
).build();
|
|
2437
|
+
const txRequest = new TransactionRequestBuilder2().withOwnOutputNotes(new NoteArray2(outputs.map((o) => o.note))).build();
|
|
2143
2438
|
const txSenderId = parseAccountId(options.from);
|
|
2144
|
-
const txResult = await
|
|
2145
|
-
() => client.executeTransaction(txSenderId, txRequest)
|
|
2146
|
-
);
|
|
2439
|
+
const txResult = await client.executeTransaction(txSenderId, txRequest);
|
|
2147
2440
|
setStage("proving");
|
|
2148
|
-
const
|
|
2149
|
-
|
|
2441
|
+
const proverConfig = useMidenStore.getState().config;
|
|
2442
|
+
const provenTransaction = await proveWithFallback(
|
|
2443
|
+
(resolvedProver) => runExclusiveDirect(
|
|
2444
|
+
() => client.proveTransaction(txResult, resolvedProver)
|
|
2445
|
+
),
|
|
2446
|
+
proverConfig
|
|
2150
2447
|
);
|
|
2151
2448
|
setStage("submitting");
|
|
2152
|
-
const submissionHeight = await
|
|
2153
|
-
|
|
2449
|
+
const submissionHeight = await client.submitProvenTransaction(
|
|
2450
|
+
provenTransaction,
|
|
2451
|
+
txResult
|
|
2154
2452
|
);
|
|
2155
2453
|
const txIdHex = txResult.id().toHex();
|
|
2156
2454
|
const txIdString = txResult.id().toString();
|
|
2157
|
-
await
|
|
2158
|
-
() => client.applyTransaction(txResult, submissionHeight)
|
|
2159
|
-
);
|
|
2455
|
+
await client.applyTransaction(txResult, submissionHeight);
|
|
2160
2456
|
const hasPrivate = outputs.some((o) => o.noteType === NoteType3.Private);
|
|
2161
2457
|
if (hasPrivate) {
|
|
2162
2458
|
await waitForTransactionCommit(
|
|
2163
2459
|
client,
|
|
2164
|
-
|
|
2460
|
+
runExclusiveDirect,
|
|
2165
2461
|
txIdHex
|
|
2166
2462
|
);
|
|
2167
2463
|
for (const output of outputs) {
|
|
2168
2464
|
if (output.noteType === NoteType3.Private) {
|
|
2169
|
-
await
|
|
2170
|
-
|
|
2465
|
+
await client.sendPrivateNote(
|
|
2466
|
+
output.note,
|
|
2467
|
+
output.recipientAddress
|
|
2171
2468
|
);
|
|
2172
2469
|
}
|
|
2173
2470
|
}
|
|
@@ -2187,154 +2484,7 @@ function useMultiSend() {
|
|
|
2187
2484
|
isBusyRef.current = false;
|
|
2188
2485
|
}
|
|
2189
2486
|
},
|
|
2190
|
-
[client, isReady, prover,
|
|
2191
|
-
);
|
|
2192
|
-
const reset = useCallback12(() => {
|
|
2193
|
-
setResult(null);
|
|
2194
|
-
setIsLoading(false);
|
|
2195
|
-
setStage("idle");
|
|
2196
|
-
setError(null);
|
|
2197
|
-
}, []);
|
|
2198
|
-
return {
|
|
2199
|
-
sendMany,
|
|
2200
|
-
result,
|
|
2201
|
-
isLoading,
|
|
2202
|
-
stage,
|
|
2203
|
-
error,
|
|
2204
|
-
reset
|
|
2205
|
-
};
|
|
2206
|
-
}
|
|
2207
|
-
|
|
2208
|
-
// src/hooks/useInternalTransfer.ts
|
|
2209
|
-
import { useCallback as useCallback13, useState as useState11 } from "react";
|
|
2210
|
-
import {
|
|
2211
|
-
FungibleAsset as FungibleAsset3,
|
|
2212
|
-
Note as Note3,
|
|
2213
|
-
NoteAndArgs,
|
|
2214
|
-
NoteAndArgsArray,
|
|
2215
|
-
NoteAssets as NoteAssets3,
|
|
2216
|
-
NoteAttachment as NoteAttachment3,
|
|
2217
|
-
OutputNote as OutputNote3,
|
|
2218
|
-
OutputNoteArray as OutputNoteArray3,
|
|
2219
|
-
TransactionRequestBuilder as TransactionRequestBuilder3
|
|
2220
|
-
} from "@miden-sdk/miden-sdk";
|
|
2221
|
-
function useInternalTransfer() {
|
|
2222
|
-
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2223
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2224
|
-
const [result, setResult] = useState11(null);
|
|
2225
|
-
const [isLoading, setIsLoading] = useState11(false);
|
|
2226
|
-
const [stage, setStage] = useState11("idle");
|
|
2227
|
-
const [error, setError] = useState11(null);
|
|
2228
|
-
const transferOnce = useCallback13(
|
|
2229
|
-
async (options) => {
|
|
2230
|
-
if (!client || !isReady) {
|
|
2231
|
-
throw new Error("Miden client is not ready");
|
|
2232
|
-
}
|
|
2233
|
-
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2234
|
-
const senderId = parseAccountId(options.from);
|
|
2235
|
-
const receiverId = parseAccountId(options.to);
|
|
2236
|
-
const assetId = parseAccountId(options.assetId);
|
|
2237
|
-
const assets = new NoteAssets3([
|
|
2238
|
-
new FungibleAsset3(assetId, options.amount)
|
|
2239
|
-
]);
|
|
2240
|
-
const note = Note3.createP2IDNote(
|
|
2241
|
-
senderId,
|
|
2242
|
-
receiverId,
|
|
2243
|
-
assets,
|
|
2244
|
-
noteType,
|
|
2245
|
-
new NoteAttachment3()
|
|
2246
|
-
);
|
|
2247
|
-
const noteId = note.id().toString();
|
|
2248
|
-
const createRequest = new TransactionRequestBuilder3().withOwnOutputNotes(new OutputNoteArray3([OutputNote3.full(note)])).build();
|
|
2249
|
-
const createTxId = await runExclusiveSafe(
|
|
2250
|
-
() => prover ? client.submitNewTransactionWithProver(
|
|
2251
|
-
senderId,
|
|
2252
|
-
createRequest,
|
|
2253
|
-
prover
|
|
2254
|
-
) : client.submitNewTransaction(senderId, createRequest)
|
|
2255
|
-
);
|
|
2256
|
-
const consumeRequest = new TransactionRequestBuilder3().withInputNotes(new NoteAndArgsArray([new NoteAndArgs(note, null)])).build();
|
|
2257
|
-
const consumeTxId = await runExclusiveSafe(
|
|
2258
|
-
() => prover ? client.submitNewTransactionWithProver(
|
|
2259
|
-
receiverId,
|
|
2260
|
-
consumeRequest,
|
|
2261
|
-
prover
|
|
2262
|
-
) : client.submitNewTransaction(receiverId, consumeRequest)
|
|
2263
|
-
);
|
|
2264
|
-
return {
|
|
2265
|
-
createTransactionId: createTxId.toString(),
|
|
2266
|
-
consumeTransactionId: consumeTxId.toString(),
|
|
2267
|
-
noteId
|
|
2268
|
-
};
|
|
2269
|
-
},
|
|
2270
|
-
[client, isReady, prover, runExclusiveSafe]
|
|
2271
|
-
);
|
|
2272
|
-
const transfer = useCallback13(
|
|
2273
|
-
async (options) => {
|
|
2274
|
-
if (!client || !isReady) {
|
|
2275
|
-
throw new Error("Miden client is not ready");
|
|
2276
|
-
}
|
|
2277
|
-
setIsLoading(true);
|
|
2278
|
-
setStage("executing");
|
|
2279
|
-
setError(null);
|
|
2280
|
-
try {
|
|
2281
|
-
setStage("proving");
|
|
2282
|
-
const txResult = await transferOnce(options);
|
|
2283
|
-
setStage("complete");
|
|
2284
|
-
setResult(txResult);
|
|
2285
|
-
await sync();
|
|
2286
|
-
return txResult;
|
|
2287
|
-
} catch (err) {
|
|
2288
|
-
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2289
|
-
setError(error2);
|
|
2290
|
-
setStage("idle");
|
|
2291
|
-
throw error2;
|
|
2292
|
-
} finally {
|
|
2293
|
-
setIsLoading(false);
|
|
2294
|
-
}
|
|
2295
|
-
},
|
|
2296
|
-
[client, isReady, sync, transferOnce]
|
|
2297
|
-
);
|
|
2298
|
-
const transferChain = useCallback13(
|
|
2299
|
-
async (options) => {
|
|
2300
|
-
if (!client || !isReady) {
|
|
2301
|
-
throw new Error("Miden client is not ready");
|
|
2302
|
-
}
|
|
2303
|
-
if (options.recipients.length === 0) {
|
|
2304
|
-
throw new Error("No recipients provided");
|
|
2305
|
-
}
|
|
2306
|
-
setIsLoading(true);
|
|
2307
|
-
setStage("executing");
|
|
2308
|
-
setError(null);
|
|
2309
|
-
try {
|
|
2310
|
-
const results = [];
|
|
2311
|
-
let currentSender = options.from;
|
|
2312
|
-
for (const recipient of options.recipients) {
|
|
2313
|
-
setStage("proving");
|
|
2314
|
-
const txResult = await transferOnce({
|
|
2315
|
-
from: currentSender,
|
|
2316
|
-
to: recipient,
|
|
2317
|
-
assetId: options.assetId,
|
|
2318
|
-
amount: options.amount,
|
|
2319
|
-
noteType: options.noteType
|
|
2320
|
-
});
|
|
2321
|
-
results.push(txResult);
|
|
2322
|
-
currentSender = recipient;
|
|
2323
|
-
}
|
|
2324
|
-
setStage("complete");
|
|
2325
|
-
setResult(results);
|
|
2326
|
-
await sync();
|
|
2327
|
-
return results;
|
|
2328
|
-
} catch (err) {
|
|
2329
|
-
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2330
|
-
setError(error2);
|
|
2331
|
-
setStage("idle");
|
|
2332
|
-
throw error2;
|
|
2333
|
-
} finally {
|
|
2334
|
-
setIsLoading(false);
|
|
2335
|
-
}
|
|
2336
|
-
},
|
|
2337
|
-
[client, isReady, sync, transferOnce]
|
|
2487
|
+
[client, isReady, prover, signerConnected, sync]
|
|
2338
2488
|
);
|
|
2339
2489
|
const reset = useCallback13(() => {
|
|
2340
2490
|
setResult(null);
|
|
@@ -2343,8 +2493,7 @@ function useInternalTransfer() {
|
|
|
2343
2493
|
setError(null);
|
|
2344
2494
|
}, []);
|
|
2345
2495
|
return {
|
|
2346
|
-
|
|
2347
|
-
transferChain,
|
|
2496
|
+
sendMany,
|
|
2348
2497
|
result,
|
|
2349
2498
|
isLoading,
|
|
2350
2499
|
stage,
|
|
@@ -2357,8 +2506,7 @@ function useInternalTransfer() {
|
|
|
2357
2506
|
import { useCallback as useCallback14 } from "react";
|
|
2358
2507
|
import { TransactionFilter as TransactionFilter3 } from "@miden-sdk/miden-sdk";
|
|
2359
2508
|
function useWaitForCommit() {
|
|
2360
|
-
const { client, isReady
|
|
2361
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2509
|
+
const { client, isReady } = useMiden();
|
|
2362
2510
|
const waitForCommit = useCallback14(
|
|
2363
2511
|
async (txId, options) => {
|
|
2364
2512
|
if (!client || !isReady) {
|
|
@@ -2371,13 +2519,9 @@ function useWaitForCommit() {
|
|
|
2371
2519
|
);
|
|
2372
2520
|
const deadline = Date.now() + timeoutMs;
|
|
2373
2521
|
while (Date.now() < deadline) {
|
|
2374
|
-
await
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
const records = await runExclusiveSafe(
|
|
2378
|
-
() => client.getTransactions(
|
|
2379
|
-
typeof txId === "string" ? TransactionFilter3.all() : TransactionFilter3.ids([txId])
|
|
2380
|
-
)
|
|
2522
|
+
await client.syncState();
|
|
2523
|
+
const records = await client.getTransactions(
|
|
2524
|
+
typeof txId === "string" ? TransactionFilter3.all() : TransactionFilter3.ids([txId])
|
|
2381
2525
|
);
|
|
2382
2526
|
const record = records.find(
|
|
2383
2527
|
(item) => normalizeHex3(item.id().toHex()) === targetHex
|
|
@@ -2395,7 +2539,7 @@ function useWaitForCommit() {
|
|
|
2395
2539
|
}
|
|
2396
2540
|
throw new Error("Timeout waiting for transaction commit");
|
|
2397
2541
|
},
|
|
2398
|
-
[client, isReady
|
|
2542
|
+
[client, isReady]
|
|
2399
2543
|
);
|
|
2400
2544
|
return { waitForCommit };
|
|
2401
2545
|
}
|
|
@@ -2424,11 +2568,11 @@ function useWaitForNotes() {
|
|
|
2424
2568
|
await runExclusiveSafe(
|
|
2425
2569
|
() => client.syncState()
|
|
2426
2570
|
);
|
|
2427
|
-
const
|
|
2571
|
+
const consumable = await runExclusiveSafe(
|
|
2428
2572
|
() => client.getConsumableNotes(accountId)
|
|
2429
2573
|
);
|
|
2430
|
-
if (
|
|
2431
|
-
return
|
|
2574
|
+
if (consumable.length >= minCount) {
|
|
2575
|
+
return consumable;
|
|
2432
2576
|
}
|
|
2433
2577
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
2434
2578
|
waited += intervalMs;
|
|
@@ -2467,7 +2611,7 @@ function useMint() {
|
|
|
2467
2611
|
targetAccountIdObj,
|
|
2468
2612
|
faucetIdObj,
|
|
2469
2613
|
noteType,
|
|
2470
|
-
options.amount
|
|
2614
|
+
BigInt(options.amount)
|
|
2471
2615
|
);
|
|
2472
2616
|
const txId = prover ? await client.submitNewTransactionWithProver(
|
|
2473
2617
|
faucetIdObj,
|
|
@@ -2522,8 +2666,8 @@ function useConsume() {
|
|
|
2522
2666
|
if (!client || !isReady) {
|
|
2523
2667
|
throw new Error("Miden client is not ready");
|
|
2524
2668
|
}
|
|
2525
|
-
if (options.
|
|
2526
|
-
throw new Error("No
|
|
2669
|
+
if (options.notes.length === 0) {
|
|
2670
|
+
throw new Error("No notes provided");
|
|
2527
2671
|
}
|
|
2528
2672
|
setIsLoading(true);
|
|
2529
2673
|
setStage("executing");
|
|
@@ -2532,16 +2676,47 @@ function useConsume() {
|
|
|
2532
2676
|
const accountIdObj = parseAccountId(options.accountId);
|
|
2533
2677
|
setStage("proving");
|
|
2534
2678
|
const txResult = await runExclusiveSafe(async () => {
|
|
2535
|
-
const
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
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;
|
|
2541
2716
|
if (notes.length === 0) {
|
|
2542
2717
|
throw new Error("No notes found for provided IDs");
|
|
2543
2718
|
}
|
|
2544
|
-
if (notes.length !== options.
|
|
2719
|
+
if (notes.length !== options.notes.length) {
|
|
2545
2720
|
throw new Error("Some notes could not be found for provided IDs");
|
|
2546
2721
|
}
|
|
2547
2722
|
const txRequest = client.newConsumeTransactionRequest(notes);
|
|
@@ -2613,9 +2788,9 @@ function useSwap() {
|
|
|
2613
2788
|
const txRequest = client.newSwapTransactionRequest(
|
|
2614
2789
|
accountIdObj,
|
|
2615
2790
|
offeredFaucetIdObj,
|
|
2616
|
-
options.offeredAmount,
|
|
2791
|
+
BigInt(options.offeredAmount),
|
|
2617
2792
|
requestedFaucetIdObj,
|
|
2618
|
-
options.requestedAmount,
|
|
2793
|
+
BigInt(options.requestedAmount),
|
|
2619
2794
|
noteType,
|
|
2620
2795
|
paybackNoteType
|
|
2621
2796
|
);
|
|
@@ -2658,11 +2833,53 @@ function useSwap() {
|
|
|
2658
2833
|
}
|
|
2659
2834
|
|
|
2660
2835
|
// src/hooks/useTransaction.ts
|
|
2661
|
-
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
|
|
2662
2879
|
function useTransaction() {
|
|
2663
|
-
const { client, isReady, sync, runExclusive
|
|
2880
|
+
const { client, isReady, sync, runExclusive } = useMiden();
|
|
2664
2881
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2665
|
-
const isBusyRef =
|
|
2882
|
+
const isBusyRef = useRef6(false);
|
|
2666
2883
|
const [result, setResult] = useState15(null);
|
|
2667
2884
|
const [isLoading, setIsLoading] = useState15(false);
|
|
2668
2885
|
const [stage, setStage] = useState15("idle");
|
|
@@ -2687,20 +2904,41 @@ function useTransaction() {
|
|
|
2687
2904
|
await sync();
|
|
2688
2905
|
}
|
|
2689
2906
|
const txRequest = await resolveRequest(options.request, client);
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
const txId = prover ? await client.submitNewTransactionWithProver(
|
|
2694
|
-
accountIdObj,
|
|
2695
|
-
txRequest,
|
|
2696
|
-
prover
|
|
2697
|
-
) : await client.submitNewTransaction(accountIdObj, txRequest);
|
|
2698
|
-
return { transactionId: txId.toString() };
|
|
2907
|
+
const txResult = await runExclusiveSafe(() => {
|
|
2908
|
+
const accountIdObj = parseAccountId(options.accountId);
|
|
2909
|
+
return client.executeTransaction(accountIdObj, txRequest);
|
|
2699
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() };
|
|
2700
2938
|
setStage("complete");
|
|
2701
|
-
setResult(
|
|
2939
|
+
setResult(txSummary);
|
|
2702
2940
|
await sync();
|
|
2703
|
-
return
|
|
2941
|
+
return txSummary;
|
|
2704
2942
|
} catch (err) {
|
|
2705
2943
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2706
2944
|
setError(error2);
|
|
@@ -2711,7 +2949,7 @@ function useTransaction() {
|
|
|
2711
2949
|
isBusyRef.current = false;
|
|
2712
2950
|
}
|
|
2713
2951
|
},
|
|
2714
|
-
[client, isReady,
|
|
2952
|
+
[client, isReady, runExclusive, sync]
|
|
2715
2953
|
);
|
|
2716
2954
|
const reset = useCallback19(() => {
|
|
2717
2955
|
setResult(null);
|
|
@@ -2728,9 +2966,6 @@ function useTransaction() {
|
|
|
2728
2966
|
reset
|
|
2729
2967
|
};
|
|
2730
2968
|
}
|
|
2731
|
-
function resolveAccountId2(accountId) {
|
|
2732
|
-
return parseAccountId(accountId);
|
|
2733
|
-
}
|
|
2734
2969
|
async function resolveRequest(request, client) {
|
|
2735
2970
|
if (typeof request === "function") {
|
|
2736
2971
|
return await request(client);
|
|
@@ -2738,27 +2973,117 @@ async function resolveRequest(request, client) {
|
|
|
2738
2973
|
return request;
|
|
2739
2974
|
}
|
|
2740
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
|
+
|
|
2741
3067
|
// src/hooks/useSessionAccount.ts
|
|
2742
|
-
import { useCallback as
|
|
3068
|
+
import { useCallback as useCallback21, useEffect as useEffect9, useRef as useRef8, useState as useState17 } from "react";
|
|
2743
3069
|
import { AccountStorageMode as AccountStorageMode3 } from "@miden-sdk/miden-sdk";
|
|
2744
3070
|
function useSessionAccount(options) {
|
|
2745
|
-
const { client, isReady, sync
|
|
2746
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
3071
|
+
const { client, isReady, sync } = useMiden();
|
|
2747
3072
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
2748
|
-
const [sessionAccountId, setSessionAccountId] =
|
|
2749
|
-
const [step, setStep] =
|
|
2750
|
-
const [error, setError] =
|
|
2751
|
-
const cancelledRef =
|
|
2752
|
-
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);
|
|
2753
3078
|
const storagePrefix = options.storagePrefix ?? "miden-session";
|
|
2754
3079
|
const pollIntervalMs = options.pollIntervalMs ?? 3e3;
|
|
2755
3080
|
const maxWaitMs = options.maxWaitMs ?? 6e4;
|
|
2756
3081
|
const storageMode = options.walletOptions?.storageMode ?? "public";
|
|
2757
3082
|
const mutable = options.walletOptions?.mutable ?? DEFAULTS.WALLET_MUTABLE;
|
|
2758
3083
|
const authScheme = options.walletOptions?.authScheme ?? DEFAULTS.AUTH_SCHEME;
|
|
2759
|
-
const fundRef =
|
|
3084
|
+
const fundRef = useRef8(options.fund);
|
|
2760
3085
|
fundRef.current = options.fund;
|
|
2761
|
-
|
|
3086
|
+
useEffect9(() => {
|
|
2762
3087
|
try {
|
|
2763
3088
|
const stored = localStorage.getItem(`${storagePrefix}:accountId`);
|
|
2764
3089
|
const storedReady = localStorage.getItem(`${storagePrefix}:ready`);
|
|
@@ -2775,7 +3100,7 @@ function useSessionAccount(options) {
|
|
|
2775
3100
|
localStorage.removeItem(`${storagePrefix}:ready`);
|
|
2776
3101
|
}
|
|
2777
3102
|
}, [storagePrefix]);
|
|
2778
|
-
const initialize =
|
|
3103
|
+
const initialize = useCallback21(async () => {
|
|
2779
3104
|
if (!client || !isReady) {
|
|
2780
3105
|
throw new Error("Miden client is not ready");
|
|
2781
3106
|
}
|
|
@@ -2793,17 +3118,14 @@ function useSessionAccount(options) {
|
|
|
2793
3118
|
if (!walletId) {
|
|
2794
3119
|
setStep("creating");
|
|
2795
3120
|
const resolvedStorageMode = getStorageMode3(storageMode);
|
|
2796
|
-
const wallet = await
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
setAccounts(accounts);
|
|
2805
|
-
return w;
|
|
2806
|
-
});
|
|
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);
|
|
2807
3129
|
if (cancelledRef.current) return;
|
|
2808
3130
|
walletId = wallet.id().toString();
|
|
2809
3131
|
setSessionAccountId(walletId);
|
|
@@ -2815,7 +3137,6 @@ function useSessionAccount(options) {
|
|
|
2815
3137
|
setStep("consuming");
|
|
2816
3138
|
await waitAndConsume(
|
|
2817
3139
|
client,
|
|
2818
|
-
runExclusiveSafe,
|
|
2819
3140
|
walletId,
|
|
2820
3141
|
pollIntervalMs,
|
|
2821
3142
|
maxWaitMs,
|
|
@@ -2839,7 +3160,6 @@ function useSessionAccount(options) {
|
|
|
2839
3160
|
client,
|
|
2840
3161
|
isReady,
|
|
2841
3162
|
sync,
|
|
2842
|
-
runExclusiveSafe,
|
|
2843
3163
|
sessionAccountId,
|
|
2844
3164
|
storageMode,
|
|
2845
3165
|
mutable,
|
|
@@ -2849,7 +3169,7 @@ function useSessionAccount(options) {
|
|
|
2849
3169
|
maxWaitMs,
|
|
2850
3170
|
setAccounts
|
|
2851
3171
|
]);
|
|
2852
|
-
const reset =
|
|
3172
|
+
const reset = useCallback21(() => {
|
|
2853
3173
|
cancelledRef.current = true;
|
|
2854
3174
|
isBusyRef.current = false;
|
|
2855
3175
|
setSessionAccountId(null);
|
|
@@ -2877,30 +3197,202 @@ function getStorageMode3(mode) {
|
|
|
2877
3197
|
return AccountStorageMode3.public();
|
|
2878
3198
|
}
|
|
2879
3199
|
}
|
|
2880
|
-
async function waitAndConsume(client,
|
|
3200
|
+
async function waitAndConsume(client, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
|
|
2881
3201
|
const deadline = Date.now() + maxWaitMs;
|
|
2882
3202
|
while (Date.now() < deadline) {
|
|
2883
3203
|
if (cancelledRef.current) return;
|
|
2884
|
-
await
|
|
2885
|
-
() => client.syncState()
|
|
2886
|
-
);
|
|
3204
|
+
await client.syncState();
|
|
2887
3205
|
if (cancelledRef.current) return;
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
if (consumable.length === 0) return false;
|
|
3206
|
+
const accountIdObj = parseAccountId(walletId);
|
|
3207
|
+
const consumable = await client.getConsumableNotes(accountIdObj);
|
|
3208
|
+
if (consumable.length > 0) {
|
|
2892
3209
|
const notes = consumable.map((c) => c.inputNoteRecord().toNote());
|
|
2893
3210
|
const txRequest = client.newConsumeTransactionRequest(notes);
|
|
2894
3211
|
const freshAccountId = parseAccountId(walletId);
|
|
2895
3212
|
await client.submitNewTransaction(freshAccountId, txRequest);
|
|
2896
|
-
return
|
|
2897
|
-
}
|
|
2898
|
-
if (consumed) return;
|
|
3213
|
+
return;
|
|
3214
|
+
}
|
|
2899
3215
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2900
3216
|
}
|
|
2901
3217
|
throw new Error("Timeout waiting for session wallet funding");
|
|
2902
3218
|
}
|
|
2903
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
|
+
|
|
2904
3396
|
// src/utils/bytes.ts
|
|
2905
3397
|
function bytesToBigInt(bytes) {
|
|
2906
3398
|
let result = 0n;
|
|
@@ -3055,7 +3547,9 @@ export {
|
|
|
3055
3547
|
DEFAULTS,
|
|
3056
3548
|
MidenError,
|
|
3057
3549
|
MidenProvider,
|
|
3550
|
+
MultiSignerProvider,
|
|
3058
3551
|
SignerContext,
|
|
3552
|
+
SignerSlot,
|
|
3059
3553
|
accountIdsEqual,
|
|
3060
3554
|
bigIntToBytes,
|
|
3061
3555
|
bytesToBigInt,
|
|
@@ -3077,18 +3571,24 @@ export {
|
|
|
3077
3571
|
useConsume,
|
|
3078
3572
|
useCreateFaucet,
|
|
3079
3573
|
useCreateWallet,
|
|
3574
|
+
useExecuteProgram,
|
|
3575
|
+
useExportNote,
|
|
3576
|
+
useExportStore,
|
|
3080
3577
|
useImportAccount,
|
|
3081
|
-
|
|
3578
|
+
useImportNote,
|
|
3579
|
+
useImportStore,
|
|
3082
3580
|
useMiden,
|
|
3083
3581
|
useMidenClient,
|
|
3084
3582
|
useMint,
|
|
3085
3583
|
useMultiSend,
|
|
3584
|
+
useMultiSigner,
|
|
3086
3585
|
useNoteStream,
|
|
3087
3586
|
useNotes,
|
|
3088
3587
|
useSend,
|
|
3089
3588
|
useSessionAccount,
|
|
3090
3589
|
useSigner,
|
|
3091
3590
|
useSwap,
|
|
3591
|
+
useSyncControl,
|
|
3092
3592
|
useSyncState,
|
|
3093
3593
|
useTransaction,
|
|
3094
3594
|
useTransactionHistory,
|