@miden-sdk/react 0.14.0-alpha → 0.14.1

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/dist/index.mjs CHANGED
@@ -17,24 +17,33 @@ var initialSyncState = {
17
17
  lastSyncTime: null,
18
18
  error: null
19
19
  };
20
- var initialState = {
21
- client: null,
22
- isReady: false,
23
- isInitializing: false,
24
- initError: null,
25
- config: {},
26
- sync: initialSyncState,
27
- accounts: [],
28
- accountDetails: /* @__PURE__ */ new Map(),
29
- notes: [],
30
- consumableNotes: [],
31
- assetMetadata: /* @__PURE__ */ new Map(),
32
- noteFirstSeen: /* @__PURE__ */ new Map(),
33
- isLoadingAccounts: false,
34
- isLoadingNotes: false
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
- ...initialState,
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
- reset: () => set(initialState)
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 !== "string") {
161
- return value;
172
+ if (typeof value === "string") {
173
+ return parseAccountIdFromString(normalizeAccountIdInput(value));
162
174
  }
163
- const normalized = normalizeAccountIdInput(value);
164
- return parseAccountIdFromString(normalized);
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 (typeof prover === "string") {
356
- const normalized = prover.trim().toLowerCase();
357
- if (normalized === "local") {
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
- prover,
415
+ target,
372
416
  normalizeTimeout(config.proverTimeoutMs)
373
417
  );
374
418
  }
375
- return createRemoteProver(prover, config.proverTimeoutMs);
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
- await runExclusive(async () => {
514
- try {
515
- const summary = await client.syncState();
516
- const syncHeight = summary.blockNum();
517
- setSyncState({
518
- syncHeight,
519
- isSyncing: false,
520
- lastSyncTime: Date.now(),
521
- error: null
522
- });
523
- const accounts = await client.getAccounts();
524
- useMidenStore.getState().setAccounts(accounts);
525
- } catch (error) {
526
- setSyncState({
527
- isSyncing: false,
528
- error: error instanceof Error ? error : new Error(String(error))
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
- }, [client, isReady, runExclusive, setSyncState]);
605
+ return cb(pubKey, signingInputs);
606
+ },
607
+ []
608
+ );
533
609
  useEffect(() => {
534
- if (!signerContext && isInitializedRef.current) return;
535
- if (signerContext && !signerContext.isConnected) {
536
- if (useMidenStore.getState().client) {
537
- useMidenStore.getState().reset();
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 && signerContext.isConnected) {
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
- void 0,
560
- // getKeyCb - not needed for public accounts
561
- void 0,
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
- signerContext
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
- sync();
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/hooks/useAccounts.ts
684
- import { useCallback as useCallback2, useEffect as useEffect2 } from "react";
685
-
686
- // src/utils/runExclusive.ts
687
- var runExclusiveDirect = async (fn) => fn();
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, runExclusive } = useMiden();
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 = useCallback2(async () => {
973
+ const refetch = useCallback3(async () => {
698
974
  if (!client || !isReady) return;
699
975
  setLoadingAccounts(true);
700
976
  try {
701
- const fetchedAccounts = await runExclusiveSafe(
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, runExclusive, setAccounts, setLoadingAccounts]);
711
- useEffect2(() => {
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 useCallback3, useEffect as useEffect4, useState as useState2, useMemo as useMemo3 } from "react";
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 useEffect3, useMemo as useMemo2 } from "react";
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 = useMemo2(() => getRpcClient(rpcUrl), [rpcUrl]);
781
- const uniqueAssetIds = useMemo2(
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
- useEffect3(() => {
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, runExclusive } = useMiden();
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] = useState2(false);
810
- const [error, setError] = useState2(null);
811
- const accountIdStr = useMemo3(() => {
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
- if (typeof accountId.toString === "function") {
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 = useCallback3(async () => {
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 runExclusiveSafe(
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, runExclusive, accountIdStr, setAccountDetails]);
839
- useEffect4(() => {
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
- useEffect4(() => {
1112
+ useEffect5(() => {
845
1113
  if (!isReady || !accountIdStr || !lastSyncTime) return;
846
1114
  refetch();
847
1115
  }, [isReady, accountIdStr, lastSyncTime, refetch]);
848
- const rawAssets = useMemo3(() => {
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 = useMemo3(
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 = useMemo3(
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 = useCallback3(
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 useCallback4, useEffect as useEffect5, useMemo as useMemo4, useState as useState3 } from "react";
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 amount.toString();
1174
+ return amt.toString();
906
1175
  }
907
1176
  const factor = 10n ** BigInt(decimals);
908
- const whole = amount / factor;
909
- const fraction = amount % factor;
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, runExclusive } = useMiden();
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] = useState3(null);
1078
- const refetch = useCallback4(async () => {
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 { fetchedNotes, fetchedConsumable } = await runExclusiveSafe(
1084
- async () => {
1085
- const filterType = getNoteFilterType(options?.status);
1086
- const filter = new NoteFilter(filterType);
1087
- const notesResult = await client.getInputNotes(filter);
1088
- let consumableResult;
1089
- if (options?.accountId) {
1090
- const accountIdObj = parseAccountId(options.accountId);
1091
- consumableResult = await client.getConsumableNotes(accountIdObj);
1092
- } else {
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
- useEffect5(() => {
1377
+ useEffect6(() => {
1119
1378
  if (isReady && notes.length === 0) {
1120
1379
  refetch();
1121
1380
  }
1122
1381
  }, [isReady, notes.length, refetch]);
1123
- useEffect5(() => {
1382
+ useEffect6(() => {
1124
1383
  if (!isReady || !lastSyncTime) return;
1125
1384
  refetch();
1126
1385
  }, [isReady, lastSyncTime, refetch]);
1127
- const noteAssetIds = useMemo4(() => {
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 = useCallback4(
1398
+ const getMetadata = useCallback5(
1140
1399
  (assetId) => assetMetadata.get(assetId),
1141
1400
  [assetMetadata]
1142
1401
  );
1143
- const normalizedSender = useMemo4(() => {
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 = useMemo4(() => {
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 = useCallback4(
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 = useMemo4(() => {
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 = useMemo4(() => {
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 useCallback5, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef2, useState as useState4 } from "react";
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, runExclusive } = useMiden();
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] = useState4(false);
1297
- const [error, setError] = useState4(null);
1298
- const handledIdsRef = useRef2(/* @__PURE__ */ new Set());
1299
- const [handledVersion, setHandledVersion] = useState4(0);
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 = useRef2(options.amountFilter);
1561
+ const amountFilterRef = useRef3(options.amountFilter);
1304
1562
  amountFilterRef.current = options.amountFilter;
1305
- const excludeIdsKey = useMemo5(() => {
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 = useMemo5(() => {
1569
+ const excludeIdSet = useMemo6(() => {
1312
1570
  if (!excludeIdsKey) return null;
1313
1571
  return new Set(excludeIdsKey.split("\0"));
1314
1572
  }, [excludeIdsKey]);
1315
- const refetch = useCallback5(async () => {
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 runExclusiveSafe(
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, runExclusiveSafe, status, setNotesIfChanged]);
1332
- useEffect6(() => {
1587
+ }, [client, isReady, status, setNotesIfChanged]);
1588
+ useEffect7(() => {
1333
1589
  if (isReady) {
1334
1590
  refetch();
1335
1591
  }
1336
1592
  }, [isReady, lastSyncTime, refetch]);
1337
- const streamedNotes = useMemo5(() => {
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 = useMemo5(
1618
+ const latest = useMemo6(
1363
1619
  () => streamedNotes.length > 0 ? streamedNotes[streamedNotes.length - 1] : null,
1364
1620
  [streamedNotes]
1365
1621
  );
1366
- const markHandled = useCallback5((noteId) => {
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 = useCallback5(() => {
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 = useCallback5(() => {
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 useCallback6, useEffect as useEffect7, useMemo as useMemo6, useState as useState5 } from "react";
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, runExclusive } = useMiden();
1438
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1693
+ const { client, isReady } = useMiden();
1439
1694
  const { lastSyncTime } = useSyncStateStore();
1440
- const [records, setRecords] = useState5([]);
1441
- const [isLoading, setIsLoading] = useState5(false);
1442
- const [error, setError] = useState5(null);
1443
- const rawIds = useMemo6(() => {
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 = useMemo6(() => {
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 = useCallback6(async () => {
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 runExclusiveSafe(
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, runExclusiveSafe, filter, rawIds, idsHex]);
1479
- useEffect7(() => {
1731
+ }, [client, isReady, filter, rawIds, idsHex]);
1732
+ useEffect8(() => {
1480
1733
  if (!isReady) return;
1481
1734
  refetch();
1482
1735
  }, [isReady, refetch]);
1483
- useEffect7(() => {
1736
+ useEffect8(() => {
1484
1737
  if (!isReady || !refreshOnSync || !lastSyncTime) return;
1485
1738
  refetch();
1486
1739
  }, [isReady, lastSyncTime, refreshOnSync, refetch]);
1487
- const record = useMemo6(() => {
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 = useMemo6(() => {
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 useCallback7 } from "react";
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 = useCallback7(async () => {
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 useCallback8, useState as useState6 } from "react";
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] = useState6(null);
1552
- const [isCreating, setIsCreating] = useState6(false);
1553
- const [error, setError] = useState6(null);
1554
- const createWallet = useCallback8(
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 = useCallback8(() => {
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 useCallback9, useState as useState7 } from "react";
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] = useState7(null);
1625
- const [isCreating, setIsCreating] = useState7(false);
1626
- const [error, setError] = useState7(null);
1627
- const createFaucet = useCallback9(
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 = useCallback9(() => {
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 useCallback10, useState as useState8 } from "react";
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, runExclusive } = useMiden();
1697
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2008
+ const { client, isReady, signerConnected } = useMiden();
1698
2009
  const setAccounts = useMidenStore((state) => state.setAccounts);
1699
- const [account, setAccount] = useState8(null);
1700
- const [isImporting, setIsImporting] = useState8(false);
1701
- const [error, setError] = useState8(null);
1702
- const importAccount = useCallback10(
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 runExclusiveSafe(async () => {
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 = resolveAccountId(options.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, runExclusive, setAccounts]
2107
+ [client, isReady, setAccounts, signerConnected]
1796
2108
  );
1797
- const reset = useCallback10(() => {
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 useCallback11, useRef as useRef3, useState as useState9 } from "react";
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
- OutputNote,
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 = useRef3(false);
1908
- const [result, setResult] = useState9(null);
1909
- const [isLoading, setIsLoading] = useState9(false);
1910
- const [stage, setStage] = useState9("idle");
1911
- const [error, setError] = useState9(null);
1912
- const send = useCallback11(
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,37 @@ 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 ownOutputs = new NoteArray();
2243
+ ownOutputs.push(p2idNote);
2244
+ const txRequest = new TransactionRequestBuilder().withOwnOutputNotes(ownOutputs).build();
2245
+ const execFromId = parseAccountId(options.from);
2246
+ const txId = prover ? await client.submitNewTransactionWithProver(
2247
+ execFromId,
2248
+ txRequest,
2249
+ prover
2250
+ ) : await client.submitNewTransaction(execFromId, txRequest);
2251
+ return { txId: txId.toString(), note: p2idNote };
2252
+ });
2253
+ setStage("complete");
2254
+ setResult(returnResult);
2255
+ await sync();
2256
+ return returnResult;
2257
+ }
1964
2258
  const txResult = await runExclusiveSafe(async () => {
1965
2259
  const fromAccountId = parseAccountId(options.from);
1966
2260
  const toAccountId = parseAccountId(options.to);
@@ -1978,7 +2272,7 @@ function useSend() {
1978
2272
  noteType,
1979
2273
  attachment
1980
2274
  );
1981
- txRequest = new TransactionRequestBuilder().withOwnOutputNotes(new OutputNoteArray([OutputNote.full(note)])).build();
2275
+ txRequest = new TransactionRequestBuilder().withOwnOutputNotes(new NoteArray([note])).build();
1982
2276
  } else {
1983
2277
  txRequest = client.newSendTransactionRequest(
1984
2278
  fromAccountId,
@@ -1994,8 +2288,12 @@ function useSend() {
1994
2288
  return await client.executeTransaction(execAccountId, txRequest);
1995
2289
  });
1996
2290
  setStage("proving");
1997
- const provenTransaction = await runExclusiveSafe(
1998
- () => client.proveTransaction(txResult, prover ?? void 0)
2291
+ const proverConfig = useMidenStore.getState().config;
2292
+ const provenTransaction = await proveWithFallback(
2293
+ (resolvedProver) => runExclusiveSafe(
2294
+ () => client.proveTransaction(txResult, resolvedProver)
2295
+ ),
2296
+ proverConfig
1999
2297
  );
2000
2298
  setStage("submitting");
2001
2299
  const submissionHeight = await runExclusiveSafe(
@@ -2025,11 +2323,14 @@ function useSend() {
2025
2323
  () => client.sendPrivateNote(fullNote, recipientAddress)
2026
2324
  );
2027
2325
  }
2028
- const txSummary = { transactionId: txIdString };
2326
+ const sendResult = {
2327
+ txId: txIdString,
2328
+ note: null
2329
+ };
2029
2330
  setStage("complete");
2030
- setResult(txSummary);
2331
+ setResult(sendResult);
2031
2332
  await sync();
2032
- return txSummary;
2333
+ return sendResult;
2033
2334
  } catch (err) {
2034
2335
  const error2 = err instanceof Error ? err : new Error(String(err));
2035
2336
  setError(error2);
@@ -2042,7 +2343,7 @@ function useSend() {
2042
2343
  },
2043
2344
  [client, isReady, prover, runExclusive, sync]
2044
2345
  );
2045
- const reset = useCallback11(() => {
2346
+ const reset = useCallback12(() => {
2046
2347
  setResult(null);
2047
2348
  setIsLoading(false);
2048
2349
  setStage("idle");
@@ -2069,30 +2370,29 @@ function extractFullNote(txResult) {
2069
2370
  }
2070
2371
 
2071
2372
  // src/hooks/useMultiSend.ts
2072
- import { useCallback as useCallback12, useRef as useRef4, useState as useState10 } from "react";
2373
+ import { useCallback as useCallback13, useRef as useRef5, useState as useState11 } from "react";
2073
2374
  import {
2074
2375
  FungibleAsset as FungibleAsset2,
2075
2376
  Note as Note2,
2076
2377
  NoteAssets as NoteAssets2,
2077
- NoteAttachment as NoteAttachment2,
2378
+ NoteAttachment as NoteAttachment3,
2078
2379
  NoteType as NoteType3,
2079
- OutputNote as OutputNote2,
2080
- OutputNoteArray as OutputNoteArray2,
2380
+ NoteArray as NoteArray2,
2081
2381
  TransactionRequestBuilder as TransactionRequestBuilder2
2082
2382
  } from "@miden-sdk/miden-sdk";
2083
2383
  function useMultiSend() {
2084
- const { client, isReady, sync, runExclusive, prover } = useMiden();
2085
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2086
- const isBusyRef = useRef4(false);
2087
- const [result, setResult] = useState10(null);
2088
- const [isLoading, setIsLoading] = useState10(false);
2089
- const [stage, setStage] = useState10("idle");
2090
- const [error, setError] = useState10(null);
2091
- const sendMany = useCallback12(
2384
+ const { client, isReady, sync, prover, signerConnected } = useMiden();
2385
+ const isBusyRef = useRef5(false);
2386
+ const [result, setResult] = useState11(null);
2387
+ const [isLoading, setIsLoading] = useState11(false);
2388
+ const [stage, setStage] = useState11("idle");
2389
+ const [error, setError] = useState11(null);
2390
+ const sendMany = useCallback13(
2092
2391
  async (options) => {
2093
2392
  if (!client || !isReady) {
2094
2393
  throw new Error("Miden client is not ready");
2095
2394
  }
2395
+ assertSignerConnected(signerConnected);
2096
2396
  if (options.recipients.length === 0) {
2097
2397
  throw new Error("No recipients provided");
2098
2398
  }
@@ -2117,10 +2417,10 @@ function useMultiSend() {
2117
2417
  const iterAssetId = parseAccountId(options.assetId);
2118
2418
  const receiverId = parseAccountId(to);
2119
2419
  const assets = new NoteAssets2([
2120
- new FungibleAsset2(iterAssetId, amount)
2420
+ new FungibleAsset2(iterAssetId, BigInt(amount))
2121
2421
  ]);
2122
2422
  const resolvedNoteType = recipientNoteType ? getNoteType(recipientNoteType) : noteType;
2123
- const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new NoteAttachment2();
2423
+ const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new NoteAttachment3();
2124
2424
  const note = Note2.createP2IDNote(
2125
2425
  iterSenderId,
2126
2426
  receiverId,
@@ -2130,44 +2430,43 @@ function useMultiSend() {
2130
2430
  );
2131
2431
  const recipientAddress = parseAddress(to, receiverId);
2132
2432
  return {
2133
- outputNote: OutputNote2.full(note),
2134
2433
  note,
2135
2434
  recipientAddress,
2136
2435
  noteType: resolvedNoteType
2137
2436
  };
2138
2437
  }
2139
2438
  );
2140
- const txRequest = new TransactionRequestBuilder2().withOwnOutputNotes(
2141
- new OutputNoteArray2(outputs.map((o) => o.outputNote))
2142
- ).build();
2439
+ const txRequest = new TransactionRequestBuilder2().withOwnOutputNotes(new NoteArray2(outputs.map((o) => o.note))).build();
2143
2440
  const txSenderId = parseAccountId(options.from);
2144
- const txResult = await runExclusiveSafe(
2145
- () => client.executeTransaction(txSenderId, txRequest)
2146
- );
2441
+ const txResult = await client.executeTransaction(txSenderId, txRequest);
2147
2442
  setStage("proving");
2148
- const provenTransaction = await runExclusiveSafe(
2149
- () => client.proveTransaction(txResult, prover ?? void 0)
2443
+ const proverConfig = useMidenStore.getState().config;
2444
+ const provenTransaction = await proveWithFallback(
2445
+ (resolvedProver) => runExclusiveDirect(
2446
+ () => client.proveTransaction(txResult, resolvedProver)
2447
+ ),
2448
+ proverConfig
2150
2449
  );
2151
2450
  setStage("submitting");
2152
- const submissionHeight = await runExclusiveSafe(
2153
- () => client.submitProvenTransaction(provenTransaction, txResult)
2451
+ const submissionHeight = await client.submitProvenTransaction(
2452
+ provenTransaction,
2453
+ txResult
2154
2454
  );
2155
2455
  const txIdHex = txResult.id().toHex();
2156
2456
  const txIdString = txResult.id().toString();
2157
- await runExclusiveSafe(
2158
- () => client.applyTransaction(txResult, submissionHeight)
2159
- );
2457
+ await client.applyTransaction(txResult, submissionHeight);
2160
2458
  const hasPrivate = outputs.some((o) => o.noteType === NoteType3.Private);
2161
2459
  if (hasPrivate) {
2162
2460
  await waitForTransactionCommit(
2163
2461
  client,
2164
- runExclusiveSafe,
2462
+ runExclusiveDirect,
2165
2463
  txIdHex
2166
2464
  );
2167
2465
  for (const output of outputs) {
2168
2466
  if (output.noteType === NoteType3.Private) {
2169
- await runExclusiveSafe(
2170
- () => client.sendPrivateNote(output.note, output.recipientAddress)
2467
+ await client.sendPrivateNote(
2468
+ output.note,
2469
+ output.recipientAddress
2171
2470
  );
2172
2471
  }
2173
2472
  }
@@ -2187,154 +2486,7 @@ function useMultiSend() {
2187
2486
  isBusyRef.current = false;
2188
2487
  }
2189
2488
  },
2190
- [client, isReady, prover, runExclusive, sync]
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]
2489
+ [client, isReady, prover, signerConnected, sync]
2338
2490
  );
2339
2491
  const reset = useCallback13(() => {
2340
2492
  setResult(null);
@@ -2343,8 +2495,7 @@ function useInternalTransfer() {
2343
2495
  setError(null);
2344
2496
  }, []);
2345
2497
  return {
2346
- transfer,
2347
- transferChain,
2498
+ sendMany,
2348
2499
  result,
2349
2500
  isLoading,
2350
2501
  stage,
@@ -2357,8 +2508,7 @@ function useInternalTransfer() {
2357
2508
  import { useCallback as useCallback14 } from "react";
2358
2509
  import { TransactionFilter as TransactionFilter3 } from "@miden-sdk/miden-sdk";
2359
2510
  function useWaitForCommit() {
2360
- const { client, isReady, runExclusive } = useMiden();
2361
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2511
+ const { client, isReady } = useMiden();
2362
2512
  const waitForCommit = useCallback14(
2363
2513
  async (txId, options) => {
2364
2514
  if (!client || !isReady) {
@@ -2371,13 +2521,9 @@ function useWaitForCommit() {
2371
2521
  );
2372
2522
  const deadline = Date.now() + timeoutMs;
2373
2523
  while (Date.now() < deadline) {
2374
- await runExclusiveSafe(
2375
- () => client.syncState()
2376
- );
2377
- const records = await runExclusiveSafe(
2378
- () => client.getTransactions(
2379
- typeof txId === "string" ? TransactionFilter3.all() : TransactionFilter3.ids([txId])
2380
- )
2524
+ await client.syncState();
2525
+ const records = await client.getTransactions(
2526
+ typeof txId === "string" ? TransactionFilter3.all() : TransactionFilter3.ids([txId])
2381
2527
  );
2382
2528
  const record = records.find(
2383
2529
  (item) => normalizeHex3(item.id().toHex()) === targetHex
@@ -2395,7 +2541,7 @@ function useWaitForCommit() {
2395
2541
  }
2396
2542
  throw new Error("Timeout waiting for transaction commit");
2397
2543
  },
2398
- [client, isReady, runExclusiveSafe]
2544
+ [client, isReady]
2399
2545
  );
2400
2546
  return { waitForCommit };
2401
2547
  }
@@ -2424,11 +2570,11 @@ function useWaitForNotes() {
2424
2570
  await runExclusiveSafe(
2425
2571
  () => client.syncState()
2426
2572
  );
2427
- const notes = await runExclusiveSafe(
2573
+ const consumable = await runExclusiveSafe(
2428
2574
  () => client.getConsumableNotes(accountId)
2429
2575
  );
2430
- if (notes.length >= minCount) {
2431
- return notes;
2576
+ if (consumable.length >= minCount) {
2577
+ return consumable;
2432
2578
  }
2433
2579
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
2434
2580
  waited += intervalMs;
@@ -2467,7 +2613,7 @@ function useMint() {
2467
2613
  targetAccountIdObj,
2468
2614
  faucetIdObj,
2469
2615
  noteType,
2470
- options.amount
2616
+ BigInt(options.amount)
2471
2617
  );
2472
2618
  const txId = prover ? await client.submitNewTransactionWithProver(
2473
2619
  faucetIdObj,
@@ -2522,8 +2668,8 @@ function useConsume() {
2522
2668
  if (!client || !isReady) {
2523
2669
  throw new Error("Miden client is not ready");
2524
2670
  }
2525
- if (options.noteIds.length === 0) {
2526
- throw new Error("No note IDs provided");
2671
+ if (options.notes.length === 0) {
2672
+ throw new Error("No notes provided");
2527
2673
  }
2528
2674
  setIsLoading(true);
2529
2675
  setStage("executing");
@@ -2532,16 +2678,47 @@ function useConsume() {
2532
2678
  const accountIdObj = parseAccountId(options.accountId);
2533
2679
  setStage("proving");
2534
2680
  const txResult = await runExclusiveSafe(async () => {
2535
- const noteIds = options.noteIds.map(
2536
- (noteId) => NoteId.fromHex(noteId)
2537
- );
2538
- const filter = new NoteFilter3(NoteFilterTypes2.List, noteIds);
2539
- const noteRecords = await client.getInputNotes(filter);
2540
- const notes = noteRecords.map((record) => record.toNote());
2681
+ const resolved = new Array(options.notes.length);
2682
+ const lookupIndices = [];
2683
+ const lookupIds = [];
2684
+ for (let i = 0; i < options.notes.length; i++) {
2685
+ const item = options.notes[i];
2686
+ if (typeof item === "string") {
2687
+ lookupIndices.push(i);
2688
+ lookupIds.push(NoteId.fromHex(item));
2689
+ } else if (item !== null && typeof item === "object" && typeof item.toNote === "function") {
2690
+ resolved[i] = item.toNote();
2691
+ } else if (item !== null && typeof item === "object" && typeof item.id === "function") {
2692
+ resolved[i] = item;
2693
+ } else {
2694
+ lookupIndices.push(i);
2695
+ lookupIds.push(item);
2696
+ }
2697
+ }
2698
+ if (lookupIds.length > 0) {
2699
+ const filter = new NoteFilter3(NoteFilterTypes2.List, lookupIds);
2700
+ const noteRecords = await client.getInputNotes(filter);
2701
+ if (noteRecords.length !== lookupIds.length) {
2702
+ throw new Error("Some notes could not be found for provided IDs");
2703
+ }
2704
+ const recordById = new Map(
2705
+ noteRecords.map((r) => [r.id().toString(), r])
2706
+ );
2707
+ for (let j = 0; j < lookupIndices.length; j++) {
2708
+ const record = recordById.get(lookupIds[j].toString());
2709
+ if (!record) {
2710
+ throw new Error(
2711
+ "Some notes could not be found for provided IDs"
2712
+ );
2713
+ }
2714
+ resolved[lookupIndices[j]] = record.toNote();
2715
+ }
2716
+ }
2717
+ const notes = resolved;
2541
2718
  if (notes.length === 0) {
2542
2719
  throw new Error("No notes found for provided IDs");
2543
2720
  }
2544
- if (notes.length !== options.noteIds.length) {
2721
+ if (notes.length !== options.notes.length) {
2545
2722
  throw new Error("Some notes could not be found for provided IDs");
2546
2723
  }
2547
2724
  const txRequest = client.newConsumeTransactionRequest(notes);
@@ -2613,9 +2790,9 @@ function useSwap() {
2613
2790
  const txRequest = client.newSwapTransactionRequest(
2614
2791
  accountIdObj,
2615
2792
  offeredFaucetIdObj,
2616
- options.offeredAmount,
2793
+ BigInt(options.offeredAmount),
2617
2794
  requestedFaucetIdObj,
2618
- options.requestedAmount,
2795
+ BigInt(options.requestedAmount),
2619
2796
  noteType,
2620
2797
  paybackNoteType
2621
2798
  );
@@ -2658,11 +2835,53 @@ function useSwap() {
2658
2835
  }
2659
2836
 
2660
2837
  // src/hooks/useTransaction.ts
2661
- import { useCallback as useCallback19, useRef as useRef5, useState as useState15 } from "react";
2838
+ import { useCallback as useCallback19, useRef as useRef6, useState as useState15 } from "react";
2839
+
2840
+ // src/utils/transactions.ts
2841
+ import { NoteType as NoteType4, TransactionFilter as TransactionFilter4 } from "@miden-sdk/miden-sdk";
2842
+ async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
2843
+ let waited = 0;
2844
+ while (waited < maxWaitMs) {
2845
+ await runExclusiveSafe(() => client.syncState());
2846
+ const [record] = await runExclusiveSafe(
2847
+ () => client.getTransactions(TransactionFilter4.ids([txId]))
2848
+ );
2849
+ if (record) {
2850
+ const status = record.transactionStatus();
2851
+ if (status.isCommitted()) {
2852
+ return;
2853
+ }
2854
+ if (status.isDiscarded()) {
2855
+ throw new Error("Transaction was discarded before commit");
2856
+ }
2857
+ }
2858
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
2859
+ waited += delayMs;
2860
+ }
2861
+ throw new Error("Timeout waiting for transaction commit");
2862
+ }
2863
+ function extractFullNotes(txResult) {
2864
+ try {
2865
+ const executedTx = txResult.executedTransaction?.();
2866
+ const notes = executedTx?.outputNotes?.().notes?.() ?? [];
2867
+ const result = [];
2868
+ for (const note of notes) {
2869
+ if (note.noteType?.() === NoteType4.Private) {
2870
+ const full = note.intoFull?.();
2871
+ if (full) result.push(full);
2872
+ }
2873
+ }
2874
+ return result;
2875
+ } catch {
2876
+ return [];
2877
+ }
2878
+ }
2879
+
2880
+ // src/hooks/useTransaction.ts
2662
2881
  function useTransaction() {
2663
- const { client, isReady, sync, runExclusive, prover } = useMiden();
2882
+ const { client, isReady, sync, runExclusive } = useMiden();
2664
2883
  const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2665
- const isBusyRef = useRef5(false);
2884
+ const isBusyRef = useRef6(false);
2666
2885
  const [result, setResult] = useState15(null);
2667
2886
  const [isLoading, setIsLoading] = useState15(false);
2668
2887
  const [stage, setStage] = useState15("idle");
@@ -2687,20 +2906,41 @@ function useTransaction() {
2687
2906
  await sync();
2688
2907
  }
2689
2908
  const txRequest = await resolveRequest(options.request, client);
2690
- setStage("proving");
2691
- const txResult = await runExclusiveSafe(async () => {
2692
- const accountIdObj = resolveAccountId2(options.accountId);
2693
- const txId = prover ? await client.submitNewTransactionWithProver(
2694
- accountIdObj,
2695
- txRequest,
2696
- prover
2697
- ) : await client.submitNewTransaction(accountIdObj, txRequest);
2698
- return { transactionId: txId.toString() };
2909
+ const txResult = await runExclusiveSafe(() => {
2910
+ const accountIdObj = parseAccountId(options.accountId);
2911
+ return client.executeTransaction(accountIdObj, txRequest);
2699
2912
  });
2913
+ setStage("proving");
2914
+ const proverConfig = useMidenStore.getState().config;
2915
+ const provenTransaction = await proveWithFallback(
2916
+ (resolvedProver) => runExclusiveSafe(
2917
+ () => client.proveTransaction(txResult, resolvedProver)
2918
+ ),
2919
+ proverConfig
2920
+ );
2921
+ setStage("submitting");
2922
+ const submissionHeight = await runExclusiveSafe(
2923
+ () => client.submitProvenTransaction(provenTransaction, txResult)
2924
+ );
2925
+ await runExclusiveSafe(
2926
+ () => client.applyTransaction(txResult, submissionHeight)
2927
+ );
2928
+ const txId = txResult.id();
2929
+ if (options.privateNoteTarget != null) {
2930
+ await waitForTransactionCommit2(client, runExclusiveSafe, txId);
2931
+ const targetAddress = parseAddress(options.privateNoteTarget);
2932
+ const fullNotes = extractFullNotes(txResult);
2933
+ for (const note of fullNotes) {
2934
+ await runExclusiveSafe(
2935
+ () => client.sendPrivateNote(note, targetAddress)
2936
+ );
2937
+ }
2938
+ }
2939
+ const txSummary = { transactionId: txId.toString() };
2700
2940
  setStage("complete");
2701
- setResult(txResult);
2941
+ setResult(txSummary);
2702
2942
  await sync();
2703
- return txResult;
2943
+ return txSummary;
2704
2944
  } catch (err) {
2705
2945
  const error2 = err instanceof Error ? err : new Error(String(err));
2706
2946
  setError(error2);
@@ -2711,7 +2951,7 @@ function useTransaction() {
2711
2951
  isBusyRef.current = false;
2712
2952
  }
2713
2953
  },
2714
- [client, isReady, prover, runExclusive, sync]
2954
+ [client, isReady, runExclusive, sync]
2715
2955
  );
2716
2956
  const reset = useCallback19(() => {
2717
2957
  setResult(null);
@@ -2728,9 +2968,6 @@ function useTransaction() {
2728
2968
  reset
2729
2969
  };
2730
2970
  }
2731
- function resolveAccountId2(accountId) {
2732
- return parseAccountId(accountId);
2733
- }
2734
2971
  async function resolveRequest(request, client) {
2735
2972
  if (typeof request === "function") {
2736
2973
  return await request(client);
@@ -2738,27 +2975,117 @@ async function resolveRequest(request, client) {
2738
2975
  return request;
2739
2976
  }
2740
2977
 
2978
+ // src/hooks/useExecuteProgram.ts
2979
+ import { useCallback as useCallback20, useRef as useRef7, useState as useState16 } from "react";
2980
+ import {
2981
+ AdviceInputs,
2982
+ ForeignAccount,
2983
+ ForeignAccountArray,
2984
+ AccountStorageRequirements
2985
+ } from "@miden-sdk/miden-sdk";
2986
+ function isForeignAccountWrapper(fa) {
2987
+ return fa !== null && typeof fa === "object" && "id" in fa && typeof fa.id !== "function";
2988
+ }
2989
+ function useExecuteProgram() {
2990
+ const { client, isReady, sync, runExclusive } = useMiden();
2991
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2992
+ const isBusyRef = useRef7(false);
2993
+ const [result, setResult] = useState16(null);
2994
+ const [isLoading, setIsLoading] = useState16(false);
2995
+ const [error, setError] = useState16(null);
2996
+ const execute = useCallback20(
2997
+ async (options) => {
2998
+ if (!client || !isReady) {
2999
+ throw new Error("Miden client is not ready");
3000
+ }
3001
+ if (isBusyRef.current) {
3002
+ throw new MidenError(
3003
+ "A program execution is already in progress. Await the previous call before starting another.",
3004
+ { code: "OPERATION_BUSY" }
3005
+ );
3006
+ }
3007
+ isBusyRef.current = true;
3008
+ setIsLoading(true);
3009
+ setError(null);
3010
+ try {
3011
+ if (!options.skipSync) {
3012
+ await sync();
3013
+ }
3014
+ const programResult = await runExclusiveSafe(async () => {
3015
+ const accountIdObj = parseAccountId(options.accountId);
3016
+ const adviceInputs = options.adviceInputs ?? new AdviceInputs();
3017
+ let foreignAccountsArray;
3018
+ if (options.foreignAccounts?.length) {
3019
+ const accounts = options.foreignAccounts.map((fa) => {
3020
+ const wrapper = isForeignAccountWrapper(fa);
3021
+ const id = parseAccountId(wrapper ? fa.id : fa);
3022
+ const storage = wrapper && fa.storage ? fa.storage : new AccountStorageRequirements();
3023
+ return ForeignAccount.public(id, storage);
3024
+ });
3025
+ foreignAccountsArray = new ForeignAccountArray(accounts);
3026
+ } else {
3027
+ foreignAccountsArray = new ForeignAccountArray();
3028
+ }
3029
+ const feltArray = await client.executeProgram(
3030
+ accountIdObj,
3031
+ options.script,
3032
+ adviceInputs,
3033
+ foreignAccountsArray
3034
+ );
3035
+ const stack = [];
3036
+ const len = feltArray.length();
3037
+ for (let i = 0; i < len; i++) {
3038
+ stack.push(feltArray.get(i).asInt());
3039
+ }
3040
+ return { stack };
3041
+ });
3042
+ setResult(programResult);
3043
+ return programResult;
3044
+ } catch (err) {
3045
+ const error2 = err instanceof Error ? err : new Error(String(err));
3046
+ setError(error2);
3047
+ throw error2;
3048
+ } finally {
3049
+ setIsLoading(false);
3050
+ isBusyRef.current = false;
3051
+ }
3052
+ },
3053
+ [client, isReady, runExclusive, sync]
3054
+ );
3055
+ const reset = useCallback20(() => {
3056
+ setResult(null);
3057
+ setIsLoading(false);
3058
+ setError(null);
3059
+ }, []);
3060
+ return {
3061
+ execute,
3062
+ result,
3063
+ isLoading,
3064
+ error,
3065
+ reset
3066
+ };
3067
+ }
3068
+
2741
3069
  // src/hooks/useSessionAccount.ts
2742
- import { useCallback as useCallback20, useEffect as useEffect8, useRef as useRef6, useState as useState16 } from "react";
3070
+ import { useCallback as useCallback21, useEffect as useEffect9, useRef as useRef8, useState as useState17 } from "react";
2743
3071
  import { AccountStorageMode as AccountStorageMode3 } from "@miden-sdk/miden-sdk";
2744
3072
  function useSessionAccount(options) {
2745
- const { client, isReady, sync, runExclusive } = useMiden();
2746
- const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
3073
+ const { client, isReady, sync } = useMiden();
2747
3074
  const setAccounts = useMidenStore((state) => state.setAccounts);
2748
- const [sessionAccountId, setSessionAccountId] = useState16(null);
2749
- const [step, setStep] = useState16("idle");
2750
- const [error, setError] = useState16(null);
2751
- const cancelledRef = useRef6(false);
2752
- const isBusyRef = useRef6(false);
3075
+ const [sessionAccountId, setSessionAccountId] = useState17(null);
3076
+ const [step, setStep] = useState17("idle");
3077
+ const [error, setError] = useState17(null);
3078
+ const cancelledRef = useRef8(false);
3079
+ const isBusyRef = useRef8(false);
2753
3080
  const storagePrefix = options.storagePrefix ?? "miden-session";
2754
3081
  const pollIntervalMs = options.pollIntervalMs ?? 3e3;
2755
3082
  const maxWaitMs = options.maxWaitMs ?? 6e4;
2756
3083
  const storageMode = options.walletOptions?.storageMode ?? "public";
2757
3084
  const mutable = options.walletOptions?.mutable ?? DEFAULTS.WALLET_MUTABLE;
2758
3085
  const authScheme = options.walletOptions?.authScheme ?? DEFAULTS.AUTH_SCHEME;
2759
- const fundRef = useRef6(options.fund);
3086
+ const fundRef = useRef8(options.fund);
2760
3087
  fundRef.current = options.fund;
2761
- useEffect8(() => {
3088
+ useEffect9(() => {
2762
3089
  try {
2763
3090
  const stored = localStorage.getItem(`${storagePrefix}:accountId`);
2764
3091
  const storedReady = localStorage.getItem(`${storagePrefix}:ready`);
@@ -2775,7 +3102,7 @@ function useSessionAccount(options) {
2775
3102
  localStorage.removeItem(`${storagePrefix}:ready`);
2776
3103
  }
2777
3104
  }, [storagePrefix]);
2778
- const initialize = useCallback20(async () => {
3105
+ const initialize = useCallback21(async () => {
2779
3106
  if (!client || !isReady) {
2780
3107
  throw new Error("Miden client is not ready");
2781
3108
  }
@@ -2793,17 +3120,14 @@ function useSessionAccount(options) {
2793
3120
  if (!walletId) {
2794
3121
  setStep("creating");
2795
3122
  const resolvedStorageMode = getStorageMode3(storageMode);
2796
- const wallet = await runExclusiveSafe(async () => {
2797
- const w = await client.newWallet(
2798
- resolvedStorageMode,
2799
- mutable,
2800
- authScheme
2801
- );
2802
- ensureAccountBech32(w);
2803
- const accounts = await client.getAccounts();
2804
- setAccounts(accounts);
2805
- return w;
2806
- });
3123
+ const wallet = await client.newWallet(
3124
+ resolvedStorageMode,
3125
+ mutable,
3126
+ authScheme
3127
+ );
3128
+ ensureAccountBech32(wallet);
3129
+ const accounts = await client.getAccounts();
3130
+ setAccounts(accounts);
2807
3131
  if (cancelledRef.current) return;
2808
3132
  walletId = wallet.id().toString();
2809
3133
  setSessionAccountId(walletId);
@@ -2815,7 +3139,6 @@ function useSessionAccount(options) {
2815
3139
  setStep("consuming");
2816
3140
  await waitAndConsume(
2817
3141
  client,
2818
- runExclusiveSafe,
2819
3142
  walletId,
2820
3143
  pollIntervalMs,
2821
3144
  maxWaitMs,
@@ -2839,7 +3162,6 @@ function useSessionAccount(options) {
2839
3162
  client,
2840
3163
  isReady,
2841
3164
  sync,
2842
- runExclusiveSafe,
2843
3165
  sessionAccountId,
2844
3166
  storageMode,
2845
3167
  mutable,
@@ -2849,7 +3171,7 @@ function useSessionAccount(options) {
2849
3171
  maxWaitMs,
2850
3172
  setAccounts
2851
3173
  ]);
2852
- const reset = useCallback20(() => {
3174
+ const reset = useCallback21(() => {
2853
3175
  cancelledRef.current = true;
2854
3176
  isBusyRef.current = false;
2855
3177
  setSessionAccountId(null);
@@ -2877,30 +3199,202 @@ function getStorageMode3(mode) {
2877
3199
  return AccountStorageMode3.public();
2878
3200
  }
2879
3201
  }
2880
- async function waitAndConsume(client, runExclusiveSafe, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
3202
+ async function waitAndConsume(client, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
2881
3203
  const deadline = Date.now() + maxWaitMs;
2882
3204
  while (Date.now() < deadline) {
2883
3205
  if (cancelledRef.current) return;
2884
- await runExclusiveSafe(
2885
- () => client.syncState()
2886
- );
3206
+ await client.syncState();
2887
3207
  if (cancelledRef.current) return;
2888
- const consumed = await runExclusiveSafe(async () => {
2889
- const accountIdObj = parseAccountId(walletId);
2890
- const consumable = await client.getConsumableNotes(accountIdObj);
2891
- if (consumable.length === 0) return false;
3208
+ const accountIdObj = parseAccountId(walletId);
3209
+ const consumable = await client.getConsumableNotes(accountIdObj);
3210
+ if (consumable.length > 0) {
2892
3211
  const notes = consumable.map((c) => c.inputNoteRecord().toNote());
2893
3212
  const txRequest = client.newConsumeTransactionRequest(notes);
2894
3213
  const freshAccountId = parseAccountId(walletId);
2895
3214
  await client.submitNewTransaction(freshAccountId, txRequest);
2896
- return true;
2897
- });
2898
- if (consumed) return;
3215
+ return;
3216
+ }
2899
3217
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
2900
3218
  }
2901
3219
  throw new Error("Timeout waiting for session wallet funding");
2902
3220
  }
2903
3221
 
3222
+ // src/hooks/useExportStore.ts
3223
+ import { useCallback as useCallback22, useState as useState18 } from "react";
3224
+ import { exportStore as sdkExportStore } from "@miden-sdk/miden-sdk";
3225
+ function useExportStore() {
3226
+ const { client, isReady, runExclusive } = useMiden();
3227
+ const [isExporting, setIsExporting] = useState18(false);
3228
+ const [error, setError] = useState18(null);
3229
+ const exportStore = useCallback22(async () => {
3230
+ if (!client || !isReady) {
3231
+ throw new Error("Miden client is not ready");
3232
+ }
3233
+ setIsExporting(true);
3234
+ setError(null);
3235
+ try {
3236
+ const storeName = client.storeIdentifier();
3237
+ const snapshot = await runExclusive(() => sdkExportStore(storeName));
3238
+ return snapshot;
3239
+ } catch (err) {
3240
+ const error2 = err instanceof Error ? err : new Error(String(err));
3241
+ setError(error2);
3242
+ throw error2;
3243
+ } finally {
3244
+ setIsExporting(false);
3245
+ }
3246
+ }, [client, isReady, runExclusive]);
3247
+ const reset = useCallback22(() => {
3248
+ setIsExporting(false);
3249
+ setError(null);
3250
+ }, []);
3251
+ return {
3252
+ exportStore,
3253
+ isExporting,
3254
+ error,
3255
+ reset
3256
+ };
3257
+ }
3258
+
3259
+ // src/hooks/useImportStore.ts
3260
+ import { useCallback as useCallback23, useState as useState19 } from "react";
3261
+ import { importStore as sdkImportStore } from "@miden-sdk/miden-sdk";
3262
+ function useImportStore() {
3263
+ const { client, isReady, runExclusive, sync } = useMiden();
3264
+ const [isImporting, setIsImporting] = useState19(false);
3265
+ const [error, setError] = useState19(null);
3266
+ const importStore = useCallback23(
3267
+ async (storeDump, storeName, options) => {
3268
+ if (!client || !isReady) {
3269
+ throw new Error("Miden client is not ready");
3270
+ }
3271
+ setIsImporting(true);
3272
+ setError(null);
3273
+ try {
3274
+ await runExclusive(() => sdkImportStore(storeName, storeDump));
3275
+ if (!options?.skipSync) {
3276
+ await sync();
3277
+ }
3278
+ } catch (err) {
3279
+ const error2 = err instanceof Error ? err : new Error(String(err));
3280
+ setError(error2);
3281
+ throw error2;
3282
+ } finally {
3283
+ setIsImporting(false);
3284
+ }
3285
+ },
3286
+ [client, isReady, runExclusive, sync]
3287
+ );
3288
+ const reset = useCallback23(() => {
3289
+ setIsImporting(false);
3290
+ setError(null);
3291
+ }, []);
3292
+ return {
3293
+ importStore,
3294
+ isImporting,
3295
+ error,
3296
+ reset
3297
+ };
3298
+ }
3299
+
3300
+ // src/hooks/useImportNote.ts
3301
+ import { useCallback as useCallback24, useState as useState20 } from "react";
3302
+ import { NoteFile } from "@miden-sdk/miden-sdk";
3303
+ function useImportNote() {
3304
+ const { client, isReady, runExclusive, sync } = useMiden();
3305
+ const [isImporting, setIsImporting] = useState20(false);
3306
+ const [error, setError] = useState20(null);
3307
+ const importNote = useCallback24(
3308
+ async (noteBytes) => {
3309
+ if (!client || !isReady) {
3310
+ throw new Error("Miden client is not ready");
3311
+ }
3312
+ setIsImporting(true);
3313
+ setError(null);
3314
+ try {
3315
+ const noteFile = NoteFile.deserialize(noteBytes);
3316
+ const noteId = await runExclusive(
3317
+ () => client.importNoteFile(noteFile)
3318
+ );
3319
+ await sync();
3320
+ return noteId.toString();
3321
+ } catch (err) {
3322
+ const error2 = err instanceof Error ? err : new Error(String(err));
3323
+ setError(error2);
3324
+ throw error2;
3325
+ } finally {
3326
+ setIsImporting(false);
3327
+ }
3328
+ },
3329
+ [client, isReady, runExclusive, sync]
3330
+ );
3331
+ const reset = useCallback24(() => {
3332
+ setIsImporting(false);
3333
+ setError(null);
3334
+ }, []);
3335
+ return {
3336
+ importNote,
3337
+ isImporting,
3338
+ error,
3339
+ reset
3340
+ };
3341
+ }
3342
+
3343
+ // src/hooks/useExportNote.ts
3344
+ import { useCallback as useCallback25, useState as useState21 } from "react";
3345
+ import { NoteExportFormat } from "@miden-sdk/miden-sdk";
3346
+ function useExportNote() {
3347
+ const { client, isReady, runExclusive } = useMiden();
3348
+ const [isExporting, setIsExporting] = useState21(false);
3349
+ const [error, setError] = useState21(null);
3350
+ const exportNote = useCallback25(
3351
+ async (noteId) => {
3352
+ if (!client || !isReady) {
3353
+ throw new Error("Miden client is not ready");
3354
+ }
3355
+ setIsExporting(true);
3356
+ setError(null);
3357
+ try {
3358
+ const noteFile = await runExclusive(
3359
+ () => client.exportNoteFile(noteId, NoteExportFormat.Full)
3360
+ );
3361
+ return noteFile.serialize();
3362
+ } catch (err) {
3363
+ const error2 = err instanceof Error ? err : new Error(String(err));
3364
+ setError(error2);
3365
+ throw error2;
3366
+ } finally {
3367
+ setIsExporting(false);
3368
+ }
3369
+ },
3370
+ [client, isReady, runExclusive]
3371
+ );
3372
+ const reset = useCallback25(() => {
3373
+ setIsExporting(false);
3374
+ setError(null);
3375
+ }, []);
3376
+ return {
3377
+ exportNote,
3378
+ isExporting,
3379
+ error,
3380
+ reset
3381
+ };
3382
+ }
3383
+
3384
+ // src/hooks/useSyncControl.ts
3385
+ import { useCallback as useCallback26 } from "react";
3386
+ function useSyncControl() {
3387
+ const isPaused = useMidenStore((state) => state.syncPaused);
3388
+ const setSyncPaused = useMidenStore((state) => state.setSyncPaused);
3389
+ const pauseSync = useCallback26(() => setSyncPaused(true), [setSyncPaused]);
3390
+ const resumeSync = useCallback26(() => setSyncPaused(false), [setSyncPaused]);
3391
+ return {
3392
+ pauseSync,
3393
+ resumeSync,
3394
+ isPaused
3395
+ };
3396
+ }
3397
+
2904
3398
  // src/utils/bytes.ts
2905
3399
  function bytesToBigInt(bytes) {
2906
3400
  let result = 0n;
@@ -3055,7 +3549,9 @@ export {
3055
3549
  DEFAULTS,
3056
3550
  MidenError,
3057
3551
  MidenProvider,
3552
+ MultiSignerProvider,
3058
3553
  SignerContext,
3554
+ SignerSlot,
3059
3555
  accountIdsEqual,
3060
3556
  bigIntToBytes,
3061
3557
  bytesToBigInt,
@@ -3077,18 +3573,24 @@ export {
3077
3573
  useConsume,
3078
3574
  useCreateFaucet,
3079
3575
  useCreateWallet,
3576
+ useExecuteProgram,
3577
+ useExportNote,
3578
+ useExportStore,
3080
3579
  useImportAccount,
3081
- useInternalTransfer,
3580
+ useImportNote,
3581
+ useImportStore,
3082
3582
  useMiden,
3083
3583
  useMidenClient,
3084
3584
  useMint,
3085
3585
  useMultiSend,
3586
+ useMultiSigner,
3086
3587
  useNoteStream,
3087
3588
  useNotes,
3088
3589
  useSend,
3089
3590
  useSessionAccount,
3090
3591
  useSigner,
3091
3592
  useSwap,
3593
+ useSyncControl,
3092
3594
  useSyncState,
3093
3595
  useTransaction,
3094
3596
  useTransactionHistory,