@miden-sdk/react 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2198 @@
1
+ // src/types/augmentations.ts
2
+ import "@miden-sdk/miden-sdk";
3
+
4
+ // src/utils/accountBech32.ts
5
+ import {
6
+ Account,
7
+ AccountInterface,
8
+ Address as Address2,
9
+ NetworkId
10
+ } from "@miden-sdk/miden-sdk";
11
+
12
+ // src/store/MidenStore.ts
13
+ import { create } from "zustand";
14
+ var initialSyncState = {
15
+ syncHeight: 0,
16
+ isSyncing: false,
17
+ lastSyncTime: null,
18
+ error: null
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
+ isLoadingAccounts: false,
33
+ isLoadingNotes: false
34
+ };
35
+ var useMidenStore = create()((set) => ({
36
+ ...initialState,
37
+ setClient: (client) => set({
38
+ client,
39
+ isReady: true,
40
+ isInitializing: false,
41
+ initError: null
42
+ }),
43
+ setInitializing: (isInitializing) => set({ isInitializing }),
44
+ setInitError: (initError) => set({
45
+ initError,
46
+ isInitializing: false,
47
+ isReady: false
48
+ }),
49
+ setConfig: (config) => set({ config }),
50
+ setSyncState: (sync) => set((state) => ({
51
+ sync: { ...state.sync, ...sync }
52
+ })),
53
+ setAccounts: (accounts) => set({ accounts }),
54
+ setAccountDetails: (accountId, account) => set((state) => {
55
+ const newMap = new Map(state.accountDetails);
56
+ newMap.set(accountId, account);
57
+ return { accountDetails: newMap };
58
+ }),
59
+ setNotes: (notes) => set({ notes }),
60
+ setConsumableNotes: (consumableNotes) => set({ consumableNotes }),
61
+ setAssetMetadata: (assetId, metadata) => set((state) => {
62
+ const newMap = new Map(state.assetMetadata);
63
+ newMap.set(assetId, metadata);
64
+ return { assetMetadata: newMap };
65
+ }),
66
+ setLoadingAccounts: (isLoadingAccounts) => set({ isLoadingAccounts }),
67
+ setLoadingNotes: (isLoadingNotes) => set({ isLoadingNotes }),
68
+ reset: () => set(initialState)
69
+ }));
70
+ var useSyncStateStore = () => useMidenStore((state) => state.sync);
71
+ var useAccountsStore = () => useMidenStore((state) => state.accounts);
72
+ var useNotesStore = () => useMidenStore((state) => state.notes);
73
+ var useConsumableNotesStore = () => useMidenStore((state) => state.consumableNotes);
74
+ var useAssetMetadataStore = () => useMidenStore((state) => state.assetMetadata);
75
+
76
+ // src/utils/accountParsing.ts
77
+ import { AccountId, Address } from "@miden-sdk/miden-sdk";
78
+ var normalizeAccountIdInput = (value) => value.trim().replace(/^miden:/i, "");
79
+ var isBech32Input = (value) => value.startsWith("m") || value.startsWith("M");
80
+ var normalizeHexInput = (value) => value.startsWith("0x") || value.startsWith("0X") ? value : `0x${value}`;
81
+ var parseAccountIdFromString = (value) => {
82
+ if (isBech32Input(value)) {
83
+ try {
84
+ return Address.fromBech32(value).accountId();
85
+ } catch {
86
+ return AccountId.fromBech32(value);
87
+ }
88
+ }
89
+ return AccountId.fromHex(normalizeHexInput(value));
90
+ };
91
+ var parseAccountId = (value) => {
92
+ if (typeof value !== "string") {
93
+ return value;
94
+ }
95
+ const normalized = normalizeAccountIdInput(value);
96
+ return parseAccountIdFromString(normalized);
97
+ };
98
+ var parseAddress = (value, accountId) => {
99
+ const normalized = normalizeAccountIdInput(value);
100
+ if (isBech32Input(normalized)) {
101
+ try {
102
+ return Address.fromBech32(normalized);
103
+ } catch {
104
+ const resolvedAccountId2 = accountId ?? AccountId.fromBech32(normalized);
105
+ return Address.fromAccountId(resolvedAccountId2, "BasicWallet");
106
+ }
107
+ }
108
+ const resolvedAccountId = accountId ?? AccountId.fromHex(normalizeHexInput(normalized));
109
+ return Address.fromAccountId(resolvedAccountId, "BasicWallet");
110
+ };
111
+
112
+ // src/utils/accountBech32.ts
113
+ var inferNetworkId = () => {
114
+ const { rpcUrl } = useMidenStore.getState().config;
115
+ if (!rpcUrl) {
116
+ return NetworkId.testnet();
117
+ }
118
+ const url = rpcUrl.toLowerCase();
119
+ if (url.includes("devnet") || url.includes("mdev")) {
120
+ return NetworkId.devnet();
121
+ }
122
+ if (url.includes("mainnet")) {
123
+ return NetworkId.mainnet();
124
+ }
125
+ if (url.includes("testnet") || url.includes("mtst")) {
126
+ return NetworkId.testnet();
127
+ }
128
+ return NetworkId.testnet();
129
+ };
130
+ var toBech32FromAccountId = (id) => {
131
+ try {
132
+ const address = Address2.fromAccountId(id, "BasicWallet");
133
+ return address.toBech32(inferNetworkId());
134
+ } catch {
135
+ }
136
+ try {
137
+ const maybeBech32 = id.toBech32?.(
138
+ inferNetworkId(),
139
+ AccountInterface.BasicWallet
140
+ );
141
+ if (typeof maybeBech32 === "string") {
142
+ return maybeBech32;
143
+ }
144
+ } catch {
145
+ }
146
+ return id.toString();
147
+ };
148
+ var defineBech32 = (target) => {
149
+ try {
150
+ Object.defineProperty(target, "bech32id", {
151
+ value: function bech32id() {
152
+ try {
153
+ const id = this.id?.();
154
+ if (id) {
155
+ return toBech32FromAccountId(id);
156
+ }
157
+ } catch {
158
+ }
159
+ const fallback = typeof this.toString === "function" ? this.toString() : "";
160
+ return fallback ? toBech32AccountId(fallback) : "";
161
+ }
162
+ });
163
+ return true;
164
+ } catch {
165
+ return false;
166
+ }
167
+ };
168
+ var installAccountBech32 = () => {
169
+ const proto = Account.prototype;
170
+ if (proto.bech32id) {
171
+ return;
172
+ }
173
+ defineBech32(proto);
174
+ };
175
+ var ensureAccountBech32 = (account) => {
176
+ if (!account) {
177
+ return;
178
+ }
179
+ if (typeof account.bech32id === "function") {
180
+ return;
181
+ }
182
+ const proto = Object.getPrototypeOf(account);
183
+ if (proto?.bech32id) {
184
+ return;
185
+ }
186
+ if (proto && defineBech32(proto)) {
187
+ return;
188
+ }
189
+ defineBech32(account);
190
+ };
191
+ var toBech32AccountId = (accountId) => {
192
+ try {
193
+ const id = parseAccountId(accountId);
194
+ return toBech32FromAccountId(id);
195
+ } catch {
196
+ return accountId;
197
+ }
198
+ };
199
+
200
+ // src/context/MidenProvider.tsx
201
+ import {
202
+ createContext,
203
+ useContext,
204
+ useEffect,
205
+ useRef,
206
+ useCallback,
207
+ useMemo
208
+ } from "react";
209
+ import { WebClient } from "@miden-sdk/miden-sdk";
210
+
211
+ // src/types/index.ts
212
+ var DEFAULTS = {
213
+ RPC_URL: void 0,
214
+ // Will use SDK's testnet default
215
+ AUTO_SYNC_INTERVAL: 15e3,
216
+ STORAGE_MODE: "private",
217
+ WALLET_MUTABLE: true,
218
+ AUTH_SCHEME: 0,
219
+ NOTE_TYPE: "private",
220
+ FAUCET_DECIMALS: 8
221
+ };
222
+
223
+ // src/utils/asyncLock.ts
224
+ var AsyncLock = class {
225
+ constructor() {
226
+ this.pending = Promise.resolve();
227
+ }
228
+ runExclusive(fn) {
229
+ const run = this.pending.then(fn, fn);
230
+ this.pending = run.then(
231
+ () => void 0,
232
+ () => void 0
233
+ );
234
+ return run;
235
+ }
236
+ };
237
+
238
+ // src/utils/network.ts
239
+ var RPC_URLS = {
240
+ testnet: "https://rpc.testnet.miden.io",
241
+ devnet: "https://rpc.devnet.miden.io",
242
+ localhost: "http://localhost:57291"
243
+ };
244
+ function resolveRpcUrl(rpcUrl) {
245
+ if (!rpcUrl) {
246
+ return void 0;
247
+ }
248
+ const normalized = rpcUrl.trim().toLowerCase();
249
+ if (normalized === "testnet") {
250
+ return RPC_URLS.testnet;
251
+ }
252
+ if (normalized === "devnet") {
253
+ return RPC_URLS.devnet;
254
+ }
255
+ if (normalized === "localhost" || normalized === "local") {
256
+ return RPC_URLS.localhost;
257
+ }
258
+ return rpcUrl;
259
+ }
260
+
261
+ // src/utils/prover.ts
262
+ import { TransactionProver } from "@miden-sdk/miden-sdk";
263
+ var DEFAULT_PROVER_URLS = {
264
+ devnet: "https://tx-prover.devnet.miden.io",
265
+ testnet: "https://tx-prover.testnet.miden.io"
266
+ };
267
+ function resolveTransactionProver(config) {
268
+ const { prover } = config;
269
+ if (!prover) {
270
+ return null;
271
+ }
272
+ if (typeof prover === "string") {
273
+ const normalized = prover.trim().toLowerCase();
274
+ if (normalized === "local") {
275
+ return TransactionProver.newLocalProver();
276
+ }
277
+ if (normalized === "devnet" || normalized === "testnet") {
278
+ const url = config.proverUrls?.[normalized] ?? DEFAULT_PROVER_URLS[normalized] ?? null;
279
+ if (!url) {
280
+ throw new Error(`Missing ${normalized} prover URL`);
281
+ }
282
+ return TransactionProver.newRemoteProver(
283
+ url,
284
+ normalizeTimeout(config.proverTimeoutMs)
285
+ );
286
+ }
287
+ return TransactionProver.newRemoteProver(
288
+ prover,
289
+ normalizeTimeout(config.proverTimeoutMs)
290
+ );
291
+ }
292
+ return createRemoteProver(prover, config.proverTimeoutMs);
293
+ }
294
+ function createRemoteProver(config, fallbackTimeout) {
295
+ const { url, timeoutMs } = config;
296
+ if (!url) {
297
+ throw new Error("Remote prover requires a URL");
298
+ }
299
+ return TransactionProver.newRemoteProver(
300
+ url,
301
+ normalizeTimeout(timeoutMs ?? fallbackTimeout)
302
+ );
303
+ }
304
+ function normalizeTimeout(timeoutMs) {
305
+ if (timeoutMs === void 0) {
306
+ return void 0;
307
+ }
308
+ if (timeoutMs === null) {
309
+ return null;
310
+ }
311
+ return typeof timeoutMs === "bigint" ? timeoutMs : BigInt(timeoutMs);
312
+ }
313
+
314
+ // src/context/MidenProvider.tsx
315
+ import { Fragment, jsx } from "react/jsx-runtime";
316
+ var MidenContext = createContext(null);
317
+ function MidenProvider({
318
+ children,
319
+ config = {},
320
+ loadingComponent,
321
+ errorComponent
322
+ }) {
323
+ const {
324
+ client,
325
+ isReady,
326
+ isInitializing,
327
+ initError,
328
+ setClient,
329
+ setInitializing,
330
+ setInitError,
331
+ setConfig,
332
+ setSyncState
333
+ } = useMidenStore();
334
+ const syncIntervalRef = useRef(null);
335
+ const isInitializedRef = useRef(false);
336
+ const clientLockRef = useRef(new AsyncLock());
337
+ const resolvedConfig = useMemo(
338
+ () => ({
339
+ ...config,
340
+ rpcUrl: resolveRpcUrl(config.rpcUrl)
341
+ }),
342
+ [config]
343
+ );
344
+ const defaultProver = useMemo(
345
+ () => resolveTransactionProver(resolvedConfig),
346
+ [
347
+ resolvedConfig.prover,
348
+ resolvedConfig.proverTimeoutMs,
349
+ resolvedConfig.proverUrls?.devnet,
350
+ resolvedConfig.proverUrls?.testnet
351
+ ]
352
+ );
353
+ const runExclusive = useCallback(
354
+ async (fn) => clientLockRef.current.runExclusive(fn),
355
+ []
356
+ );
357
+ const sync = useCallback(async () => {
358
+ if (!client || !isReady) return;
359
+ const store = useMidenStore.getState();
360
+ if (store.sync.isSyncing) return;
361
+ setSyncState({ isSyncing: true, error: null });
362
+ await runExclusive(async () => {
363
+ try {
364
+ const summary = await client.syncState();
365
+ const syncHeight = summary.blockNum();
366
+ setSyncState({
367
+ syncHeight,
368
+ isSyncing: false,
369
+ lastSyncTime: Date.now(),
370
+ error: null
371
+ });
372
+ const accounts = await client.getAccounts();
373
+ useMidenStore.getState().setAccounts(accounts);
374
+ } catch (error) {
375
+ setSyncState({
376
+ isSyncing: false,
377
+ error: error instanceof Error ? error : new Error(String(error))
378
+ });
379
+ }
380
+ });
381
+ }, [client, isReady, runExclusive, setSyncState]);
382
+ useEffect(() => {
383
+ if (isInitializedRef.current) return;
384
+ isInitializedRef.current = true;
385
+ const initClient = async () => {
386
+ setInitializing(true);
387
+ setConfig(resolvedConfig);
388
+ try {
389
+ const seed = resolvedConfig.seed;
390
+ const webClient = await WebClient.createClient(
391
+ resolvedConfig.rpcUrl,
392
+ resolvedConfig.noteTransportUrl,
393
+ seed
394
+ );
395
+ setClient(webClient);
396
+ try {
397
+ const summary = await runExclusive(() => webClient.syncState());
398
+ setSyncState({
399
+ syncHeight: summary.blockNum(),
400
+ lastSyncTime: Date.now()
401
+ });
402
+ } catch {
403
+ }
404
+ } catch (error) {
405
+ setInitError(error instanceof Error ? error : new Error(String(error)));
406
+ }
407
+ };
408
+ initClient();
409
+ }, [
410
+ runExclusive,
411
+ resolvedConfig,
412
+ setClient,
413
+ setConfig,
414
+ setInitError,
415
+ setInitializing,
416
+ setSyncState
417
+ ]);
418
+ useEffect(() => {
419
+ if (!isReady || !client) return;
420
+ const interval = config.autoSyncInterval ?? DEFAULTS.AUTO_SYNC_INTERVAL;
421
+ if (interval <= 0) return;
422
+ syncIntervalRef.current = setInterval(() => {
423
+ sync();
424
+ }, interval);
425
+ return () => {
426
+ if (syncIntervalRef.current) {
427
+ clearInterval(syncIntervalRef.current);
428
+ syncIntervalRef.current = null;
429
+ }
430
+ };
431
+ }, [isReady, client, config.autoSyncInterval, sync]);
432
+ if (isInitializing && loadingComponent) {
433
+ return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent });
434
+ }
435
+ if (initError && errorComponent) {
436
+ if (typeof errorComponent === "function") {
437
+ return /* @__PURE__ */ jsx(Fragment, { children: errorComponent(initError) });
438
+ }
439
+ return /* @__PURE__ */ jsx(Fragment, { children: errorComponent });
440
+ }
441
+ const contextValue = {
442
+ client,
443
+ isReady,
444
+ isInitializing,
445
+ error: initError,
446
+ sync,
447
+ runExclusive,
448
+ prover: defaultProver
449
+ };
450
+ return /* @__PURE__ */ jsx(MidenContext.Provider, { value: contextValue, children });
451
+ }
452
+ function useMiden() {
453
+ const context = useContext(MidenContext);
454
+ if (!context) {
455
+ throw new Error("useMiden must be used within a MidenProvider");
456
+ }
457
+ return context;
458
+ }
459
+ function useMidenClient() {
460
+ const { client, isReady } = useMiden();
461
+ if (!client || !isReady) {
462
+ throw new Error(
463
+ "Miden client is not ready. Make sure you are inside a MidenProvider and the client has initialized."
464
+ );
465
+ }
466
+ return client;
467
+ }
468
+
469
+ // src/hooks/useAccounts.ts
470
+ import { useCallback as useCallback2, useEffect as useEffect2 } from "react";
471
+
472
+ // src/utils/runExclusive.ts
473
+ var runExclusiveDirect = async (fn) => fn();
474
+
475
+ // src/hooks/useAccounts.ts
476
+ function useAccounts() {
477
+ const { client, isReady, runExclusive } = useMiden();
478
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
479
+ const accounts = useAccountsStore();
480
+ const isLoadingAccounts = useMidenStore((state) => state.isLoadingAccounts);
481
+ const setLoadingAccounts = useMidenStore((state) => state.setLoadingAccounts);
482
+ const setAccounts = useMidenStore((state) => state.setAccounts);
483
+ const refetch = useCallback2(async () => {
484
+ if (!client || !isReady) return;
485
+ setLoadingAccounts(true);
486
+ try {
487
+ const fetchedAccounts = await runExclusiveSafe(
488
+ () => client.getAccounts()
489
+ );
490
+ setAccounts(fetchedAccounts);
491
+ } catch (error) {
492
+ console.error("Failed to fetch accounts:", error);
493
+ } finally {
494
+ setLoadingAccounts(false);
495
+ }
496
+ }, [client, isReady, runExclusive, setAccounts, setLoadingAccounts]);
497
+ useEffect2(() => {
498
+ if (isReady && accounts.length === 0) {
499
+ refetch();
500
+ }
501
+ }, [isReady, accounts.length, refetch]);
502
+ const wallets = [];
503
+ const faucets = [];
504
+ for (const account of accounts) {
505
+ const accountId = account.id();
506
+ if (isFaucetId(accountId)) {
507
+ faucets.push(account);
508
+ } else {
509
+ wallets.push(account);
510
+ }
511
+ }
512
+ return {
513
+ accounts,
514
+ wallets,
515
+ faucets,
516
+ isLoading: isLoadingAccounts,
517
+ error: null,
518
+ refetch
519
+ };
520
+ }
521
+ function isFaucetId(accountId) {
522
+ try {
523
+ const hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
524
+ const firstByte = parseInt(hex.slice(0, 2), 16);
525
+ const accountType = firstByte >> 4 & 3;
526
+ return accountType === 2 || accountType === 3;
527
+ } catch {
528
+ return false;
529
+ }
530
+ }
531
+
532
+ // src/hooks/useAccount.ts
533
+ import { useCallback as useCallback3, useEffect as useEffect4, useState, useMemo as useMemo3 } from "react";
534
+
535
+ // src/hooks/useAssetMetadata.ts
536
+ import { useEffect as useEffect3, useMemo as useMemo2 } from "react";
537
+ import {
538
+ BasicFungibleFaucetComponent,
539
+ Endpoint,
540
+ RpcClient
541
+ } from "@miden-sdk/miden-sdk";
542
+ var inflight = /* @__PURE__ */ new Map();
543
+ var rpcClients = /* @__PURE__ */ new Map();
544
+ var getRpcClient = (rpcUrl) => {
545
+ const key = rpcUrl ?? "__default__";
546
+ const existing = rpcClients.get(key);
547
+ if (existing) return existing;
548
+ try {
549
+ const endpoint = rpcUrl ? new Endpoint(rpcUrl) : Endpoint.testnet();
550
+ const client = new RpcClient(endpoint);
551
+ rpcClients.set(key, client);
552
+ return client;
553
+ } catch {
554
+ return null;
555
+ }
556
+ };
557
+ var fetchAssetMetadata = async (client, rpcClient, assetId) => {
558
+ try {
559
+ const accountId = parseAccountId(assetId);
560
+ let account = await client.getAccount(accountId);
561
+ if (!account && rpcClient) {
562
+ try {
563
+ const fetched = await rpcClient.getAccountDetails(accountId);
564
+ account = fetched.account?.();
565
+ } catch {
566
+ }
567
+ }
568
+ if (!account) return null;
569
+ const faucet = BasicFungibleFaucetComponent.fromAccount(account);
570
+ const symbol = faucet.symbol().toString();
571
+ const decimals = faucet.decimals();
572
+ return { assetId, symbol, decimals };
573
+ } catch {
574
+ return null;
575
+ }
576
+ };
577
+ function useAssetMetadata(assetIds = []) {
578
+ const { client, isReady, runExclusive } = useMiden();
579
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
580
+ const assetMetadata = useAssetMetadataStore();
581
+ const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
582
+ const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
583
+ const rpcClient = useMemo2(() => getRpcClient(rpcUrl), [rpcUrl]);
584
+ const uniqueAssetIds = useMemo2(
585
+ () => Array.from(new Set(assetIds.filter(Boolean))),
586
+ [assetIds]
587
+ );
588
+ useEffect3(() => {
589
+ if (!client || !isReady || uniqueAssetIds.length === 0) return;
590
+ uniqueAssetIds.forEach((assetId) => {
591
+ const existing = assetMetadata.get(assetId);
592
+ const hasMetadata = existing?.symbol !== void 0 || existing?.decimals !== void 0;
593
+ if (hasMetadata || inflight.has(assetId)) return;
594
+ const promise = runExclusiveSafe(async () => {
595
+ const metadata = await fetchAssetMetadata(
596
+ client,
597
+ rpcClient,
598
+ assetId
599
+ );
600
+ setAssetMetadata(assetId, metadata ?? { assetId });
601
+ }).finally(() => {
602
+ inflight.delete(assetId);
603
+ });
604
+ inflight.set(assetId, promise);
605
+ });
606
+ }, [
607
+ client,
608
+ isReady,
609
+ uniqueAssetIds,
610
+ assetMetadata,
611
+ runExclusiveSafe,
612
+ setAssetMetadata,
613
+ rpcClient
614
+ ]);
615
+ return { assetMetadata };
616
+ }
617
+
618
+ // src/hooks/useAccount.ts
619
+ function useAccount(accountId) {
620
+ const { client, isReady, runExclusive } = useMiden();
621
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
622
+ const accountDetails = useMidenStore((state) => state.accountDetails);
623
+ const setAccountDetails = useMidenStore((state) => state.setAccountDetails);
624
+ const { lastSyncTime } = useSyncStateStore();
625
+ const [isLoading, setIsLoading] = useState(false);
626
+ const [error, setError] = useState(null);
627
+ const accountIdStr = useMemo3(() => {
628
+ if (!accountId) return void 0;
629
+ if (typeof accountId === "string") return accountId;
630
+ if (typeof accountId.toString === "function") {
631
+ return accountId.toString();
632
+ }
633
+ return String(accountId);
634
+ }, [accountId]);
635
+ const account = accountIdStr ? accountDetails.get(accountIdStr) ?? null : null;
636
+ const refetch = useCallback3(async () => {
637
+ if (!client || !isReady || !accountIdStr) return;
638
+ setIsLoading(true);
639
+ setError(null);
640
+ try {
641
+ const accountIdObj = parseAccountId(accountIdStr);
642
+ const fetchedAccount = await runExclusiveSafe(
643
+ () => client.getAccount(accountIdObj)
644
+ );
645
+ if (fetchedAccount) {
646
+ ensureAccountBech32(fetchedAccount);
647
+ setAccountDetails(accountIdStr, fetchedAccount);
648
+ }
649
+ } catch (err) {
650
+ setError(err instanceof Error ? err : new Error(String(err)));
651
+ } finally {
652
+ setIsLoading(false);
653
+ }
654
+ }, [client, isReady, runExclusive, accountIdStr, setAccountDetails]);
655
+ useEffect4(() => {
656
+ if (isReady && accountIdStr && !account) {
657
+ refetch();
658
+ }
659
+ }, [isReady, accountIdStr, account, refetch]);
660
+ useEffect4(() => {
661
+ if (!isReady || !accountIdStr || !lastSyncTime) return;
662
+ refetch();
663
+ }, [isReady, accountIdStr, lastSyncTime, refetch]);
664
+ const rawAssets = useMemo3(() => {
665
+ if (!account) return [];
666
+ try {
667
+ const vault = account.vault();
668
+ const assetsList = [];
669
+ const vaultAssets = vault.fungibleAssets();
670
+ for (const asset of vaultAssets) {
671
+ assetsList.push({
672
+ assetId: asset.faucetId().toString(),
673
+ amount: asset.amount()
674
+ });
675
+ }
676
+ return assetsList;
677
+ } catch {
678
+ return [];
679
+ }
680
+ }, [account]);
681
+ const assetIds = useMemo3(
682
+ () => rawAssets.map((asset) => asset.assetId),
683
+ [rawAssets]
684
+ );
685
+ const { assetMetadata } = useAssetMetadata(assetIds);
686
+ const assets = useMemo3(
687
+ () => rawAssets.map((asset) => {
688
+ const metadata = assetMetadata.get(asset.assetId);
689
+ return {
690
+ ...asset,
691
+ symbol: metadata?.symbol,
692
+ decimals: metadata?.decimals
693
+ };
694
+ }),
695
+ [rawAssets, assetMetadata]
696
+ );
697
+ const getBalance = useCallback3(
698
+ (assetId) => {
699
+ const asset = assets.find((a) => a.assetId === assetId);
700
+ return asset?.amount ?? 0n;
701
+ },
702
+ [assets]
703
+ );
704
+ return {
705
+ account,
706
+ assets,
707
+ isLoading,
708
+ error,
709
+ refetch,
710
+ getBalance
711
+ };
712
+ }
713
+
714
+ // src/hooks/useNotes.ts
715
+ import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo4, useState as useState2 } from "react";
716
+ import { NoteFilter, NoteFilterTypes } from "@miden-sdk/miden-sdk";
717
+
718
+ // src/utils/amounts.ts
719
+ var formatAssetAmount = (amount, decimals) => {
720
+ if (!decimals || decimals <= 0) {
721
+ return amount.toString();
722
+ }
723
+ const factor = 10n ** BigInt(decimals);
724
+ const whole = amount / factor;
725
+ const fraction = amount % factor;
726
+ if (fraction === 0n) {
727
+ return whole.toString();
728
+ }
729
+ const fractionText = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
730
+ return `${whole.toString()}.${fractionText}`;
731
+ };
732
+ var parseAssetAmount = (input, decimals) => {
733
+ const value = input.trim();
734
+ if (!value) {
735
+ throw new Error("Amount is required");
736
+ }
737
+ if (!decimals || decimals <= 0) {
738
+ if (value.includes(".")) {
739
+ throw new Error("Amount must be a whole number");
740
+ }
741
+ return BigInt(value);
742
+ }
743
+ const [wholeText, fractionText = ""] = value.split(".");
744
+ if (value.split(".").length > 2) {
745
+ throw new Error("Amount has too many decimal points");
746
+ }
747
+ const normalizedWhole = wholeText.length ? wholeText : "0";
748
+ if (fractionText.length > decimals) {
749
+ throw new Error("Amount has too many decimal places");
750
+ }
751
+ const paddedFraction = fractionText.padEnd(decimals, "0");
752
+ const factor = 10n ** BigInt(decimals);
753
+ return BigInt(normalizedWhole) * factor + BigInt(paddedFraction || "0");
754
+ };
755
+
756
+ // src/utils/notes.ts
757
+ var getInputNoteRecord = (note) => {
758
+ const maybeConsumable = note;
759
+ if (typeof maybeConsumable.inputNoteRecord === "function") {
760
+ return maybeConsumable.inputNoteRecord();
761
+ }
762
+ return note;
763
+ };
764
+ var getNoteSummary = (note, getAssetMetadata) => {
765
+ try {
766
+ const record = getInputNoteRecord(note);
767
+ const id = record.id().toString();
768
+ const assets = [];
769
+ try {
770
+ const details = record.details();
771
+ const assetsList = details?.assets?.().fungibleAssets?.() ?? [];
772
+ for (const asset of assetsList) {
773
+ const assetId = asset.faucetId().toString();
774
+ const metadata2 = getAssetMetadata?.(assetId);
775
+ assets.push({
776
+ assetId,
777
+ amount: BigInt(asset.amount()),
778
+ symbol: metadata2?.symbol,
779
+ decimals: metadata2?.decimals
780
+ });
781
+ }
782
+ } catch {
783
+ }
784
+ const metadata = record.metadata?.();
785
+ const senderHex = metadata?.sender?.()?.toString?.();
786
+ const sender = senderHex ? toBech32AccountId(senderHex) : void 0;
787
+ return { id, assets, sender };
788
+ } catch {
789
+ return null;
790
+ }
791
+ };
792
+ var formatNoteSummary = (summary, formatAsset = (asset) => `${formatAssetAmount(asset.amount, asset.decimals)} ${asset.symbol ?? asset.assetId}`) => {
793
+ if (!summary.assets.length) {
794
+ return summary.id;
795
+ }
796
+ const assetsText = summary.assets.map(formatAsset).join(" + ");
797
+ return summary.sender ? `${assetsText} from ${summary.sender}` : assetsText;
798
+ };
799
+
800
+ // src/hooks/useNotes.ts
801
+ function useNotes(options) {
802
+ const { client, isReady, runExclusive } = useMiden();
803
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
804
+ const notes = useNotesStore();
805
+ const consumableNotes = useConsumableNotesStore();
806
+ const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
807
+ const setLoadingNotes = useMidenStore((state) => state.setLoadingNotes);
808
+ const setNotes = useMidenStore((state) => state.setNotes);
809
+ const setConsumableNotes = useMidenStore((state) => state.setConsumableNotes);
810
+ const { lastSyncTime } = useSyncStateStore();
811
+ const [error, setError] = useState2(null);
812
+ const refetch = useCallback4(async () => {
813
+ if (!client || !isReady) return;
814
+ setLoadingNotes(true);
815
+ setError(null);
816
+ try {
817
+ const { fetchedNotes, fetchedConsumable } = await runExclusiveSafe(
818
+ async () => {
819
+ const filterType = getNoteFilterType(options?.status);
820
+ const filter = new NoteFilter(filterType);
821
+ const notesResult = await client.getInputNotes(filter);
822
+ let consumableResult;
823
+ if (options?.accountId) {
824
+ const accountIdObj = parseAccountId(options.accountId);
825
+ consumableResult = await client.getConsumableNotes(accountIdObj);
826
+ } else {
827
+ consumableResult = await client.getConsumableNotes();
828
+ }
829
+ return {
830
+ fetchedNotes: notesResult,
831
+ fetchedConsumable: consumableResult
832
+ };
833
+ }
834
+ );
835
+ setNotes(fetchedNotes);
836
+ setConsumableNotes(fetchedConsumable);
837
+ } catch (err) {
838
+ setError(err instanceof Error ? err : new Error(String(err)));
839
+ } finally {
840
+ setLoadingNotes(false);
841
+ }
842
+ }, [
843
+ client,
844
+ isReady,
845
+ runExclusive,
846
+ options?.status,
847
+ options?.accountId,
848
+ setLoadingNotes,
849
+ setNotes,
850
+ setConsumableNotes
851
+ ]);
852
+ useEffect5(() => {
853
+ if (isReady && notes.length === 0) {
854
+ refetch();
855
+ }
856
+ }, [isReady, notes.length, refetch]);
857
+ useEffect5(() => {
858
+ if (!isReady || !lastSyncTime) return;
859
+ refetch();
860
+ }, [isReady, lastSyncTime, refetch]);
861
+ const noteAssetIds = useMemo4(() => {
862
+ const ids = /* @__PURE__ */ new Set();
863
+ const collect = (note) => {
864
+ const summary = getNoteSummary(note);
865
+ if (!summary) return;
866
+ summary.assets.forEach((asset) => ids.add(asset.assetId));
867
+ };
868
+ notes.forEach(collect);
869
+ consumableNotes.forEach(collect);
870
+ return Array.from(ids);
871
+ }, [notes, consumableNotes]);
872
+ const { assetMetadata } = useAssetMetadata(noteAssetIds);
873
+ const getMetadata = useCallback4(
874
+ (assetId) => assetMetadata.get(assetId),
875
+ [assetMetadata]
876
+ );
877
+ const noteSummaries = useMemo4(
878
+ () => notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
879
+ [notes, getMetadata]
880
+ );
881
+ const consumableNoteSummaries = useMemo4(
882
+ () => consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean),
883
+ [consumableNotes, getMetadata]
884
+ );
885
+ return {
886
+ notes,
887
+ consumableNotes,
888
+ noteSummaries,
889
+ consumableNoteSummaries,
890
+ isLoading: isLoadingNotes,
891
+ error,
892
+ refetch
893
+ };
894
+ }
895
+ function getNoteFilterType(status) {
896
+ switch (status) {
897
+ case "consumed":
898
+ return NoteFilterTypes.Consumed;
899
+ case "committed":
900
+ return NoteFilterTypes.Committed;
901
+ case "expected":
902
+ return NoteFilterTypes.Expected;
903
+ case "processing":
904
+ return NoteFilterTypes.Processing;
905
+ case "all":
906
+ default:
907
+ return NoteFilterTypes.All;
908
+ }
909
+ }
910
+
911
+ // src/hooks/useTransactionHistory.ts
912
+ import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useState as useState3 } from "react";
913
+ import { TransactionFilter } from "@miden-sdk/miden-sdk";
914
+ function useTransactionHistory(options = {}) {
915
+ const { client, isReady, runExclusive } = useMiden();
916
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
917
+ const { lastSyncTime } = useSyncStateStore();
918
+ const [records, setRecords] = useState3([]);
919
+ const [isLoading, setIsLoading] = useState3(false);
920
+ const [error, setError] = useState3(null);
921
+ const rawIds = useMemo5(() => {
922
+ if (options.id) return [options.id];
923
+ if (options.ids && options.ids.length > 0) return options.ids;
924
+ return null;
925
+ }, [options.id, options.ids]);
926
+ const idsHex = useMemo5(() => {
927
+ if (!rawIds) return null;
928
+ return rawIds.map(
929
+ (id) => normalizeHex(typeof id === "string" ? id : id.toHex())
930
+ );
931
+ }, [rawIds]);
932
+ const filter = options.filter;
933
+ const refreshOnSync = options.refreshOnSync !== false;
934
+ const refetch = useCallback5(async () => {
935
+ if (!client || !isReady) return;
936
+ setIsLoading(true);
937
+ setError(null);
938
+ try {
939
+ const { filter: resolvedFilter, localFilterHexes } = buildFilter(
940
+ filter,
941
+ rawIds,
942
+ idsHex
943
+ );
944
+ const fetched = await runExclusiveSafe(
945
+ () => client.getTransactions(resolvedFilter)
946
+ );
947
+ const filtered = localFilterHexes ? fetched.filter(
948
+ (record2) => localFilterHexes.includes(normalizeHex(record2.id().toHex()))
949
+ ) : fetched;
950
+ setRecords(filtered);
951
+ } catch (err) {
952
+ setError(err instanceof Error ? err : new Error(String(err)));
953
+ } finally {
954
+ setIsLoading(false);
955
+ }
956
+ }, [client, isReady, runExclusiveSafe, filter, rawIds, idsHex]);
957
+ useEffect6(() => {
958
+ if (!isReady) return;
959
+ refetch();
960
+ }, [isReady, refetch]);
961
+ useEffect6(() => {
962
+ if (!isReady || !refreshOnSync || !lastSyncTime) return;
963
+ refetch();
964
+ }, [isReady, lastSyncTime, refreshOnSync, refetch]);
965
+ const record = useMemo5(() => {
966
+ if (!idsHex || idsHex.length !== 1) return null;
967
+ return records.find((item) => normalizeHex(item.id().toHex()) === idsHex[0]) ?? null;
968
+ }, [records, idsHex]);
969
+ const status = useMemo5(() => {
970
+ if (!record) return null;
971
+ const current = record.transactionStatus();
972
+ if (current.isCommitted()) return "committed";
973
+ if (current.isDiscarded()) return "discarded";
974
+ if (current.isPending()) return "pending";
975
+ return null;
976
+ }, [record]);
977
+ return {
978
+ records,
979
+ record,
980
+ status,
981
+ isLoading,
982
+ error,
983
+ refetch
984
+ };
985
+ }
986
+ function buildFilter(filter, ids, idsHex) {
987
+ if (filter) {
988
+ return { filter };
989
+ }
990
+ if (!ids || ids.length === 0) {
991
+ return { filter: TransactionFilter.all() };
992
+ }
993
+ const allTransactionIds = ids.every((id) => typeof id !== "string");
994
+ if (allTransactionIds) {
995
+ return { filter: TransactionFilter.ids(ids) };
996
+ }
997
+ return {
998
+ filter: TransactionFilter.all(),
999
+ localFilterHexes: idsHex ?? []
1000
+ };
1001
+ }
1002
+ function normalizeHex(value) {
1003
+ const trimmed = value.trim();
1004
+ const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1005
+ return normalized.toLowerCase();
1006
+ }
1007
+
1008
+ // src/hooks/useSyncState.ts
1009
+ import { useCallback as useCallback6 } from "react";
1010
+ function useSyncState() {
1011
+ const { sync: triggerSync } = useMiden();
1012
+ const syncState = useSyncStateStore();
1013
+ const sync = useCallback6(async () => {
1014
+ await triggerSync();
1015
+ }, [triggerSync]);
1016
+ return {
1017
+ ...syncState,
1018
+ sync
1019
+ };
1020
+ }
1021
+
1022
+ // src/hooks/useCreateWallet.ts
1023
+ import { useCallback as useCallback7, useState as useState4 } from "react";
1024
+ import { AccountStorageMode } from "@miden-sdk/miden-sdk";
1025
+ function useCreateWallet() {
1026
+ const { client, isReady, sync, runExclusive } = useMiden();
1027
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1028
+ const setAccounts = useMidenStore((state) => state.setAccounts);
1029
+ const [wallet, setWallet] = useState4(null);
1030
+ const [isCreating, setIsCreating] = useState4(false);
1031
+ const [error, setError] = useState4(null);
1032
+ const createWallet = useCallback7(
1033
+ async (options = {}) => {
1034
+ if (!client || !isReady) {
1035
+ throw new Error("Miden client is not ready");
1036
+ }
1037
+ await sync();
1038
+ setIsCreating(true);
1039
+ setError(null);
1040
+ try {
1041
+ const storageMode = getStorageMode(
1042
+ options.storageMode ?? DEFAULTS.STORAGE_MODE
1043
+ );
1044
+ const mutable = options.mutable ?? DEFAULTS.WALLET_MUTABLE;
1045
+ const authScheme = options.authScheme ?? DEFAULTS.AUTH_SCHEME;
1046
+ const newWallet = await runExclusiveSafe(async () => {
1047
+ const createdWallet = await client.newWallet(
1048
+ storageMode,
1049
+ mutable,
1050
+ authScheme,
1051
+ options.initSeed
1052
+ );
1053
+ ensureAccountBech32(createdWallet);
1054
+ const accounts = await client.getAccounts();
1055
+ setAccounts(accounts);
1056
+ return createdWallet;
1057
+ });
1058
+ setWallet(newWallet);
1059
+ return newWallet;
1060
+ } catch (err) {
1061
+ const error2 = err instanceof Error ? err : new Error(String(err));
1062
+ setError(error2);
1063
+ throw error2;
1064
+ } finally {
1065
+ setIsCreating(false);
1066
+ }
1067
+ },
1068
+ [client, isReady, runExclusive, setAccounts]
1069
+ );
1070
+ const reset = useCallback7(() => {
1071
+ setWallet(null);
1072
+ setIsCreating(false);
1073
+ setError(null);
1074
+ }, []);
1075
+ return {
1076
+ createWallet,
1077
+ wallet,
1078
+ isCreating,
1079
+ error,
1080
+ reset
1081
+ };
1082
+ }
1083
+ function getStorageMode(mode) {
1084
+ switch (mode) {
1085
+ case "private":
1086
+ return AccountStorageMode.private();
1087
+ case "public":
1088
+ return AccountStorageMode.public();
1089
+ case "network":
1090
+ return AccountStorageMode.network();
1091
+ default:
1092
+ return AccountStorageMode.private();
1093
+ }
1094
+ }
1095
+
1096
+ // src/hooks/useCreateFaucet.ts
1097
+ import { useCallback as useCallback8, useState as useState5 } from "react";
1098
+ import { AccountStorageMode as AccountStorageMode2 } from "@miden-sdk/miden-sdk";
1099
+ function useCreateFaucet() {
1100
+ const { client, isReady, runExclusive } = useMiden();
1101
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1102
+ const setAccounts = useMidenStore((state) => state.setAccounts);
1103
+ const [faucet, setFaucet] = useState5(null);
1104
+ const [isCreating, setIsCreating] = useState5(false);
1105
+ const [error, setError] = useState5(null);
1106
+ const createFaucet = useCallback8(
1107
+ async (options) => {
1108
+ if (!client || !isReady) {
1109
+ throw new Error("Miden client is not ready");
1110
+ }
1111
+ setIsCreating(true);
1112
+ setError(null);
1113
+ try {
1114
+ const storageMode = getStorageMode2(
1115
+ options.storageMode ?? DEFAULTS.STORAGE_MODE
1116
+ );
1117
+ const decimals = options.decimals ?? DEFAULTS.FAUCET_DECIMALS;
1118
+ const authScheme = options.authScheme ?? DEFAULTS.AUTH_SCHEME;
1119
+ const newFaucet = await runExclusiveSafe(async () => {
1120
+ const createdFaucet = await client.newFaucet(
1121
+ storageMode,
1122
+ false,
1123
+ // nonFungible - currently only fungible faucets supported
1124
+ options.tokenSymbol,
1125
+ decimals,
1126
+ options.maxSupply,
1127
+ authScheme
1128
+ );
1129
+ const accounts = await client.getAccounts();
1130
+ setAccounts(accounts);
1131
+ return createdFaucet;
1132
+ });
1133
+ setFaucet(newFaucet);
1134
+ return newFaucet;
1135
+ } catch (err) {
1136
+ const error2 = err instanceof Error ? err : new Error(String(err));
1137
+ setError(error2);
1138
+ throw error2;
1139
+ } finally {
1140
+ setIsCreating(false);
1141
+ }
1142
+ },
1143
+ [client, isReady, runExclusive, setAccounts]
1144
+ );
1145
+ const reset = useCallback8(() => {
1146
+ setFaucet(null);
1147
+ setIsCreating(false);
1148
+ setError(null);
1149
+ }, []);
1150
+ return {
1151
+ createFaucet,
1152
+ faucet,
1153
+ isCreating,
1154
+ error,
1155
+ reset
1156
+ };
1157
+ }
1158
+ function getStorageMode2(mode) {
1159
+ switch (mode) {
1160
+ case "private":
1161
+ return AccountStorageMode2.private();
1162
+ case "public":
1163
+ return AccountStorageMode2.public();
1164
+ case "network":
1165
+ return AccountStorageMode2.network();
1166
+ default:
1167
+ return AccountStorageMode2.private();
1168
+ }
1169
+ }
1170
+
1171
+ // src/hooks/useImportAccount.ts
1172
+ import { useCallback as useCallback9, useState as useState6 } from "react";
1173
+ import { AccountFile } from "@miden-sdk/miden-sdk";
1174
+ function useImportAccount() {
1175
+ const { client, isReady, runExclusive } = useMiden();
1176
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1177
+ const setAccounts = useMidenStore((state) => state.setAccounts);
1178
+ const [account, setAccount] = useState6(null);
1179
+ const [isImporting, setIsImporting] = useState6(false);
1180
+ const [error, setError] = useState6(null);
1181
+ const importAccount = useCallback9(
1182
+ async (options) => {
1183
+ if (!client || !isReady) {
1184
+ throw new Error("Miden client is not ready");
1185
+ }
1186
+ setIsImporting(true);
1187
+ setError(null);
1188
+ try {
1189
+ let accountsAfter = null;
1190
+ const imported = await runExclusiveSafe(async () => {
1191
+ switch (options.type) {
1192
+ case "file": {
1193
+ const accountsBefore = await client.getAccounts();
1194
+ const accountFile = await resolveAccountFile(options.file);
1195
+ const accountFileWithAccount = accountFile;
1196
+ const fileBytes = getAccountFileBytes(
1197
+ accountFileWithAccount,
1198
+ options.file
1199
+ );
1200
+ const accountFromFile = typeof accountFileWithAccount.account === "function" ? accountFileWithAccount.account() : null;
1201
+ const accountIdFromFile = accountFromFile === null && typeof accountFileWithAccount.accountId === "function" ? accountFileWithAccount.accountId() : null;
1202
+ try {
1203
+ await client.importAccountFile(accountFile);
1204
+ } catch (err) {
1205
+ const message = err instanceof Error ? err.message : String(err);
1206
+ if (!message.includes("already being tracked")) {
1207
+ throw err;
1208
+ }
1209
+ }
1210
+ accountsAfter = await client.getAccounts();
1211
+ if (accountFromFile) {
1212
+ return accountFromFile;
1213
+ }
1214
+ const beforeIds = new Set(
1215
+ accountsBefore.map((account2) => account2.id().toString())
1216
+ );
1217
+ const newAccountHeader = accountsAfter.find(
1218
+ (account2) => !beforeIds.has(account2.id().toString())
1219
+ );
1220
+ const accountId = accountIdFromFile ?? newAccountHeader?.id();
1221
+ if (accountId) {
1222
+ const fetchedAccount = await client.getAccount(accountId);
1223
+ if (fetchedAccount) {
1224
+ return fetchedAccount;
1225
+ }
1226
+ }
1227
+ if (fileBytes) {
1228
+ for (const header of accountsAfter) {
1229
+ const exported = await client.exportAccountFile(header.id());
1230
+ const exportedBytes = getAccountFileBytes(exported, exported);
1231
+ if (exportedBytes && bytesEqual(exportedBytes, fileBytes)) {
1232
+ const fetchedAccount = await client.getAccount(header.id());
1233
+ if (fetchedAccount) {
1234
+ return fetchedAccount;
1235
+ }
1236
+ }
1237
+ }
1238
+ }
1239
+ throw new Error("Account not found after import");
1240
+ }
1241
+ case "id": {
1242
+ const accountId = resolveAccountId(options.accountId);
1243
+ await client.importAccountById(accountId);
1244
+ const fetchedAccount = await client.getAccount(accountId);
1245
+ if (!fetchedAccount) {
1246
+ throw new Error("Account not found after import");
1247
+ }
1248
+ return fetchedAccount;
1249
+ }
1250
+ case "seed": {
1251
+ const mutable = options.mutable ?? DEFAULTS.WALLET_MUTABLE;
1252
+ const authScheme = options.authScheme ?? DEFAULTS.AUTH_SCHEME;
1253
+ return await client.importPublicAccountFromSeed(
1254
+ options.seed,
1255
+ mutable,
1256
+ authScheme
1257
+ );
1258
+ }
1259
+ }
1260
+ });
1261
+ ensureAccountBech32(imported);
1262
+ const accounts = accountsAfter ?? await client.getAccounts();
1263
+ setAccounts(accounts);
1264
+ setAccount(imported);
1265
+ return imported;
1266
+ } catch (err) {
1267
+ const error2 = err instanceof Error ? err : new Error(String(err));
1268
+ setError(error2);
1269
+ throw error2;
1270
+ } finally {
1271
+ setIsImporting(false);
1272
+ }
1273
+ },
1274
+ [client, isReady, runExclusive, setAccounts]
1275
+ );
1276
+ const reset = useCallback9(() => {
1277
+ setAccount(null);
1278
+ setIsImporting(false);
1279
+ setError(null);
1280
+ }, []);
1281
+ return {
1282
+ importAccount,
1283
+ account,
1284
+ isImporting,
1285
+ error,
1286
+ reset
1287
+ };
1288
+ }
1289
+ function resolveAccountId(accountId) {
1290
+ return parseAccountId(accountId);
1291
+ }
1292
+ async function resolveAccountFile(file) {
1293
+ if (file instanceof Uint8Array) {
1294
+ return AccountFile.deserialize(file);
1295
+ }
1296
+ if (file instanceof ArrayBuffer) {
1297
+ return AccountFile.deserialize(new Uint8Array(file));
1298
+ }
1299
+ return file;
1300
+ }
1301
+ function getAccountFileBytes(accountFile, original) {
1302
+ if (original instanceof Uint8Array) {
1303
+ return original;
1304
+ }
1305
+ if (original instanceof ArrayBuffer) {
1306
+ return new Uint8Array(original);
1307
+ }
1308
+ if (typeof accountFile.serialize === "function") {
1309
+ return accountFile.serialize();
1310
+ }
1311
+ return null;
1312
+ }
1313
+ function bytesEqual(left, right) {
1314
+ if (left.length !== right.length) {
1315
+ return false;
1316
+ }
1317
+ for (let i = 0; i < left.length; i += 1) {
1318
+ if (left[i] !== right[i]) {
1319
+ return false;
1320
+ }
1321
+ }
1322
+ return true;
1323
+ }
1324
+
1325
+ // src/hooks/useSend.ts
1326
+ import { useCallback as useCallback10, useState as useState7 } from "react";
1327
+ import { NoteType, TransactionFilter as TransactionFilter2 } from "@miden-sdk/miden-sdk";
1328
+ function useSend() {
1329
+ const { client, isReady, sync, runExclusive, prover } = useMiden();
1330
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1331
+ const [result, setResult] = useState7(null);
1332
+ const [isLoading, setIsLoading] = useState7(false);
1333
+ const [stage, setStage] = useState7("idle");
1334
+ const [error, setError] = useState7(null);
1335
+ const send = useCallback10(
1336
+ async (options) => {
1337
+ if (!client || !isReady) {
1338
+ throw new Error("Miden client is not ready");
1339
+ }
1340
+ setIsLoading(true);
1341
+ setStage("executing");
1342
+ setError(null);
1343
+ try {
1344
+ const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
1345
+ const fromAccountId = parseAccountId(options.from);
1346
+ const toAccountId = parseAccountId(options.to);
1347
+ const assetId = options.assetId ?? options.faucetId ?? null;
1348
+ if (!assetId) {
1349
+ throw new Error("Asset ID is required");
1350
+ }
1351
+ const assetIdObj = parseAccountId(assetId);
1352
+ const txResult = await runExclusiveSafe(async () => {
1353
+ const txRequest = client.newSendTransactionRequest(
1354
+ fromAccountId,
1355
+ toAccountId,
1356
+ assetIdObj,
1357
+ noteType,
1358
+ options.amount,
1359
+ options.recallHeight ?? null,
1360
+ options.timelockHeight ?? null
1361
+ );
1362
+ return await client.executeTransaction(fromAccountId, txRequest);
1363
+ });
1364
+ setStage("proving");
1365
+ const provenTransaction = await runExclusiveSafe(
1366
+ () => client.proveTransaction(txResult, prover ?? void 0)
1367
+ );
1368
+ setStage("submitting");
1369
+ const submissionHeight = await runExclusiveSafe(
1370
+ () => client.submitProvenTransaction(provenTransaction, txResult)
1371
+ );
1372
+ await runExclusiveSafe(
1373
+ () => client.applyTransaction(txResult, submissionHeight)
1374
+ );
1375
+ const txId = txResult.id();
1376
+ await waitForTransactionCommit(client, runExclusiveSafe, txId);
1377
+ if (noteType === NoteType.Private) {
1378
+ const fullNote = extractFullNote(txResult);
1379
+ if (!fullNote) {
1380
+ throw new Error("Missing full note for private send");
1381
+ }
1382
+ const recipientAddress = parseAddress(options.to, toAccountId);
1383
+ await runExclusiveSafe(
1384
+ () => client.sendPrivateNote(fullNote, recipientAddress)
1385
+ );
1386
+ }
1387
+ const txSummary = { transactionId: txResult.id().toString() };
1388
+ setStage("complete");
1389
+ setResult(txSummary);
1390
+ await sync();
1391
+ return txSummary;
1392
+ } catch (err) {
1393
+ const error2 = err instanceof Error ? err : new Error(String(err));
1394
+ setError(error2);
1395
+ setStage("idle");
1396
+ throw error2;
1397
+ } finally {
1398
+ setIsLoading(false);
1399
+ }
1400
+ },
1401
+ [client, isReady, prover, runExclusive, sync]
1402
+ );
1403
+ const reset = useCallback10(() => {
1404
+ setResult(null);
1405
+ setIsLoading(false);
1406
+ setStage("idle");
1407
+ setError(null);
1408
+ }, []);
1409
+ return {
1410
+ send,
1411
+ result,
1412
+ isLoading,
1413
+ stage,
1414
+ error,
1415
+ reset
1416
+ };
1417
+ }
1418
+ function getNoteType(type) {
1419
+ switch (type) {
1420
+ case "private":
1421
+ return NoteType.Private;
1422
+ case "public":
1423
+ return NoteType.Public;
1424
+ case "encrypted":
1425
+ return NoteType.Encrypted;
1426
+ default:
1427
+ return NoteType.Private;
1428
+ }
1429
+ }
1430
+ async function waitForTransactionCommit(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1431
+ let waited = 0;
1432
+ while (waited < maxWaitMs) {
1433
+ await runExclusiveSafe(() => client.syncState());
1434
+ const [record] = await runExclusiveSafe(
1435
+ () => client.getTransactions(TransactionFilter2.ids([txId]))
1436
+ );
1437
+ if (record) {
1438
+ const status = record.transactionStatus();
1439
+ if (status.isCommitted()) {
1440
+ return;
1441
+ }
1442
+ if (status.isDiscarded()) {
1443
+ throw new Error("Transaction was discarded before commit");
1444
+ }
1445
+ }
1446
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1447
+ waited += delayMs;
1448
+ }
1449
+ throw new Error("Timeout waiting for transaction commit");
1450
+ }
1451
+ function extractFullNote(txResult) {
1452
+ try {
1453
+ const executedTx = txResult.executedTransaction?.();
1454
+ const notes = executedTx?.outputNotes?.().notes?.() ?? [];
1455
+ const note = notes[0];
1456
+ return note?.intoFull?.() ?? null;
1457
+ } catch {
1458
+ return null;
1459
+ }
1460
+ }
1461
+
1462
+ // src/hooks/useMultiSend.ts
1463
+ import { useCallback as useCallback11, useState as useState8 } from "react";
1464
+ import {
1465
+ FungibleAsset,
1466
+ Note,
1467
+ NoteAssets,
1468
+ NoteAttachment,
1469
+ NoteType as NoteType2,
1470
+ OutputNote,
1471
+ OutputNoteArray,
1472
+ TransactionFilter as TransactionFilter3,
1473
+ TransactionRequestBuilder
1474
+ } from "@miden-sdk/miden-sdk";
1475
+ function useMultiSend() {
1476
+ const { client, isReady, sync, runExclusive, prover } = useMiden();
1477
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1478
+ const [result, setResult] = useState8(null);
1479
+ const [isLoading, setIsLoading] = useState8(false);
1480
+ const [stage, setStage] = useState8("idle");
1481
+ const [error, setError] = useState8(null);
1482
+ const sendMany = useCallback11(
1483
+ async (options) => {
1484
+ if (!client || !isReady) {
1485
+ throw new Error("Miden client is not ready");
1486
+ }
1487
+ if (options.recipients.length === 0) {
1488
+ throw new Error("No recipients provided");
1489
+ }
1490
+ setIsLoading(true);
1491
+ setStage("executing");
1492
+ setError(null);
1493
+ try {
1494
+ const noteType = getNoteType2(options.noteType ?? DEFAULTS.NOTE_TYPE);
1495
+ const senderId = parseAccountId(options.from);
1496
+ const assetId = parseAccountId(options.assetId);
1497
+ const outputs = options.recipients.map(({ to, amount }) => {
1498
+ const receiverId = parseAccountId(to);
1499
+ const assets = new NoteAssets([new FungibleAsset(assetId, amount)]);
1500
+ const note = Note.createP2IDNote(
1501
+ senderId,
1502
+ receiverId,
1503
+ assets,
1504
+ noteType,
1505
+ new NoteAttachment()
1506
+ );
1507
+ const recipientAddress = parseAddress(to, receiverId);
1508
+ return {
1509
+ outputNote: OutputNote.full(note),
1510
+ note,
1511
+ recipientAddress
1512
+ };
1513
+ });
1514
+ const txRequest = new TransactionRequestBuilder().withOwnOutputNotes(
1515
+ new OutputNoteArray(outputs.map((o) => o.outputNote))
1516
+ ).build();
1517
+ const txResult = await runExclusiveSafe(
1518
+ () => client.executeTransaction(senderId, txRequest)
1519
+ );
1520
+ setStage("proving");
1521
+ const provenTransaction = await runExclusiveSafe(
1522
+ () => client.proveTransaction(txResult, prover ?? void 0)
1523
+ );
1524
+ setStage("submitting");
1525
+ const submissionHeight = await runExclusiveSafe(
1526
+ () => client.submitProvenTransaction(provenTransaction, txResult)
1527
+ );
1528
+ await runExclusiveSafe(
1529
+ () => client.applyTransaction(txResult, submissionHeight)
1530
+ );
1531
+ const txId = txResult.id();
1532
+ if (noteType === NoteType2.Private) {
1533
+ await waitForTransactionCommit2(
1534
+ client,
1535
+ runExclusiveSafe,
1536
+ txId
1537
+ );
1538
+ for (const output of outputs) {
1539
+ await runExclusiveSafe(
1540
+ () => client.sendPrivateNote(output.note, output.recipientAddress)
1541
+ );
1542
+ }
1543
+ }
1544
+ const txSummary = { transactionId: txId.toString() };
1545
+ setStage("complete");
1546
+ setResult(txSummary);
1547
+ await sync();
1548
+ return txSummary;
1549
+ } catch (err) {
1550
+ const error2 = err instanceof Error ? err : new Error(String(err));
1551
+ setError(error2);
1552
+ setStage("idle");
1553
+ throw error2;
1554
+ } finally {
1555
+ setIsLoading(false);
1556
+ }
1557
+ },
1558
+ [client, isReady, prover, runExclusive, sync]
1559
+ );
1560
+ const reset = useCallback11(() => {
1561
+ setResult(null);
1562
+ setIsLoading(false);
1563
+ setStage("idle");
1564
+ setError(null);
1565
+ }, []);
1566
+ return {
1567
+ sendMany,
1568
+ result,
1569
+ isLoading,
1570
+ stage,
1571
+ error,
1572
+ reset
1573
+ };
1574
+ }
1575
+ function getNoteType2(type) {
1576
+ switch (type) {
1577
+ case "private":
1578
+ return NoteType2.Private;
1579
+ case "public":
1580
+ return NoteType2.Public;
1581
+ case "encrypted":
1582
+ return NoteType2.Encrypted;
1583
+ default:
1584
+ return NoteType2.Private;
1585
+ }
1586
+ }
1587
+ async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
1588
+ let waited = 0;
1589
+ while (waited < maxWaitMs) {
1590
+ await runExclusiveSafe(() => client.syncState());
1591
+ const [record] = await runExclusiveSafe(
1592
+ () => client.getTransactions(TransactionFilter3.ids([txId]))
1593
+ );
1594
+ if (record) {
1595
+ const status = record.transactionStatus();
1596
+ if (status.isCommitted()) {
1597
+ return;
1598
+ }
1599
+ if (status.isDiscarded()) {
1600
+ throw new Error("Transaction was discarded before commit");
1601
+ }
1602
+ }
1603
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1604
+ waited += delayMs;
1605
+ }
1606
+ throw new Error("Timeout waiting for transaction commit");
1607
+ }
1608
+
1609
+ // src/hooks/useInternalTransfer.ts
1610
+ import { useCallback as useCallback12, useState as useState9 } from "react";
1611
+ import {
1612
+ FungibleAsset as FungibleAsset2,
1613
+ Note as Note2,
1614
+ NoteAndArgs,
1615
+ NoteAndArgsArray,
1616
+ NoteAssets as NoteAssets2,
1617
+ NoteAttachment as NoteAttachment2,
1618
+ NoteType as NoteType3,
1619
+ OutputNote as OutputNote2,
1620
+ OutputNoteArray as OutputNoteArray2,
1621
+ TransactionRequestBuilder as TransactionRequestBuilder2
1622
+ } from "@miden-sdk/miden-sdk";
1623
+ function useInternalTransfer() {
1624
+ const { client, isReady, sync, runExclusive, prover } = useMiden();
1625
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1626
+ const [result, setResult] = useState9(null);
1627
+ const [isLoading, setIsLoading] = useState9(false);
1628
+ const [stage, setStage] = useState9("idle");
1629
+ const [error, setError] = useState9(null);
1630
+ const transferOnce = useCallback12(
1631
+ async (options) => {
1632
+ if (!client || !isReady) {
1633
+ throw new Error("Miden client is not ready");
1634
+ }
1635
+ const noteType = getNoteType3(options.noteType ?? DEFAULTS.NOTE_TYPE);
1636
+ const senderId = parseAccountId(options.from);
1637
+ const receiverId = parseAccountId(options.to);
1638
+ const assetId = parseAccountId(options.assetId);
1639
+ const assets = new NoteAssets2([
1640
+ new FungibleAsset2(assetId, options.amount)
1641
+ ]);
1642
+ const note = Note2.createP2IDNote(
1643
+ senderId,
1644
+ receiverId,
1645
+ assets,
1646
+ noteType,
1647
+ new NoteAttachment2()
1648
+ );
1649
+ const noteId = note.id().toString();
1650
+ const createRequest = new TransactionRequestBuilder2().withOwnOutputNotes(new OutputNoteArray2([OutputNote2.full(note)])).build();
1651
+ const createTxId = await runExclusiveSafe(
1652
+ () => prover ? client.submitNewTransactionWithProver(
1653
+ senderId,
1654
+ createRequest,
1655
+ prover
1656
+ ) : client.submitNewTransaction(senderId, createRequest)
1657
+ );
1658
+ const consumeRequest = new TransactionRequestBuilder2().withInputNotes(new NoteAndArgsArray([new NoteAndArgs(note, null)])).build();
1659
+ const consumeTxId = await runExclusiveSafe(
1660
+ () => prover ? client.submitNewTransactionWithProver(
1661
+ receiverId,
1662
+ consumeRequest,
1663
+ prover
1664
+ ) : client.submitNewTransaction(receiverId, consumeRequest)
1665
+ );
1666
+ return {
1667
+ createTransactionId: createTxId.toString(),
1668
+ consumeTransactionId: consumeTxId.toString(),
1669
+ noteId
1670
+ };
1671
+ },
1672
+ [client, isReady, prover, runExclusiveSafe]
1673
+ );
1674
+ const transfer = useCallback12(
1675
+ async (options) => {
1676
+ if (!client || !isReady) {
1677
+ throw new Error("Miden client is not ready");
1678
+ }
1679
+ setIsLoading(true);
1680
+ setStage("executing");
1681
+ setError(null);
1682
+ try {
1683
+ setStage("proving");
1684
+ const txResult = await transferOnce(options);
1685
+ setStage("complete");
1686
+ setResult(txResult);
1687
+ await sync();
1688
+ return txResult;
1689
+ } catch (err) {
1690
+ const error2 = err instanceof Error ? err : new Error(String(err));
1691
+ setError(error2);
1692
+ setStage("idle");
1693
+ throw error2;
1694
+ } finally {
1695
+ setIsLoading(false);
1696
+ }
1697
+ },
1698
+ [client, isReady, sync, transferOnce]
1699
+ );
1700
+ const transferChain = useCallback12(
1701
+ async (options) => {
1702
+ if (!client || !isReady) {
1703
+ throw new Error("Miden client is not ready");
1704
+ }
1705
+ if (options.recipients.length === 0) {
1706
+ throw new Error("No recipients provided");
1707
+ }
1708
+ setIsLoading(true);
1709
+ setStage("executing");
1710
+ setError(null);
1711
+ try {
1712
+ const results = [];
1713
+ let currentSender = options.from;
1714
+ for (const recipient of options.recipients) {
1715
+ setStage("proving");
1716
+ const txResult = await transferOnce({
1717
+ from: currentSender,
1718
+ to: recipient,
1719
+ assetId: options.assetId,
1720
+ amount: options.amount,
1721
+ noteType: options.noteType
1722
+ });
1723
+ results.push(txResult);
1724
+ currentSender = recipient;
1725
+ }
1726
+ setStage("complete");
1727
+ setResult(results);
1728
+ await sync();
1729
+ return results;
1730
+ } catch (err) {
1731
+ const error2 = err instanceof Error ? err : new Error(String(err));
1732
+ setError(error2);
1733
+ setStage("idle");
1734
+ throw error2;
1735
+ } finally {
1736
+ setIsLoading(false);
1737
+ }
1738
+ },
1739
+ [client, isReady, sync, transferOnce]
1740
+ );
1741
+ const reset = useCallback12(() => {
1742
+ setResult(null);
1743
+ setIsLoading(false);
1744
+ setStage("idle");
1745
+ setError(null);
1746
+ }, []);
1747
+ return {
1748
+ transfer,
1749
+ transferChain,
1750
+ result,
1751
+ isLoading,
1752
+ stage,
1753
+ error,
1754
+ reset
1755
+ };
1756
+ }
1757
+ function getNoteType3(type) {
1758
+ switch (type) {
1759
+ case "private":
1760
+ return NoteType3.Private;
1761
+ case "public":
1762
+ return NoteType3.Public;
1763
+ case "encrypted":
1764
+ return NoteType3.Encrypted;
1765
+ default:
1766
+ return NoteType3.Private;
1767
+ }
1768
+ }
1769
+
1770
+ // src/hooks/useWaitForCommit.ts
1771
+ import { useCallback as useCallback13 } from "react";
1772
+ import { TransactionFilter as TransactionFilter4 } from "@miden-sdk/miden-sdk";
1773
+ function useWaitForCommit() {
1774
+ const { client, isReady, runExclusive } = useMiden();
1775
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1776
+ const waitForCommit = useCallback13(
1777
+ async (txId, options) => {
1778
+ if (!client || !isReady) {
1779
+ throw new Error("Miden client is not ready");
1780
+ }
1781
+ const timeoutMs = Math.max(0, options?.timeoutMs ?? 1e4);
1782
+ const intervalMs = Math.max(1, options?.intervalMs ?? 1e3);
1783
+ const targetHex = normalizeHex2(
1784
+ typeof txId === "string" ? txId : txId.toHex()
1785
+ );
1786
+ let waited = 0;
1787
+ while (waited < timeoutMs) {
1788
+ await runExclusiveSafe(
1789
+ () => client.syncState()
1790
+ );
1791
+ const records = await runExclusiveSafe(
1792
+ () => client.getTransactions(
1793
+ typeof txId === "string" ? TransactionFilter4.all() : TransactionFilter4.ids([txId])
1794
+ )
1795
+ );
1796
+ const record = records.find(
1797
+ (item) => normalizeHex2(item.id().toHex()) === targetHex
1798
+ );
1799
+ if (record) {
1800
+ const status = record.transactionStatus();
1801
+ if (status.isCommitted()) {
1802
+ return;
1803
+ }
1804
+ if (status.isDiscarded()) {
1805
+ throw new Error("Transaction was discarded before commit");
1806
+ }
1807
+ }
1808
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
1809
+ waited += intervalMs;
1810
+ }
1811
+ throw new Error("Timeout waiting for transaction commit");
1812
+ },
1813
+ [client, isReady, runExclusiveSafe]
1814
+ );
1815
+ return { waitForCommit };
1816
+ }
1817
+ function normalizeHex2(value) {
1818
+ const trimmed = value.trim();
1819
+ const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
1820
+ return normalized.toLowerCase();
1821
+ }
1822
+
1823
+ // src/hooks/useWaitForNotes.ts
1824
+ import { useCallback as useCallback14 } from "react";
1825
+ function useWaitForNotes() {
1826
+ const { client, isReady, runExclusive } = useMiden();
1827
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1828
+ const waitForConsumableNotes = useCallback14(
1829
+ async (options) => {
1830
+ if (!client || !isReady) {
1831
+ throw new Error("Miden client is not ready");
1832
+ }
1833
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 1e4);
1834
+ const intervalMs = Math.max(1, options.intervalMs ?? 1e3);
1835
+ const minCount = Math.max(1, options.minCount ?? 1);
1836
+ const accountId = parseAccountId(options.accountId);
1837
+ let waited = 0;
1838
+ while (waited < timeoutMs) {
1839
+ await runExclusiveSafe(() => client.syncState());
1840
+ const notes = await runExclusiveSafe(
1841
+ () => client.getConsumableNotes(accountId)
1842
+ );
1843
+ if (notes.length >= minCount) {
1844
+ return notes;
1845
+ }
1846
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
1847
+ waited += intervalMs;
1848
+ }
1849
+ throw new Error("Timeout waiting for consumable notes");
1850
+ },
1851
+ [client, isReady, runExclusiveSafe]
1852
+ );
1853
+ return { waitForConsumableNotes };
1854
+ }
1855
+
1856
+ // src/hooks/useMint.ts
1857
+ import { useCallback as useCallback15, useState as useState10 } from "react";
1858
+ import { NoteType as NoteType4 } from "@miden-sdk/miden-sdk";
1859
+ function useMint() {
1860
+ const { client, isReady, sync, runExclusive, prover } = useMiden();
1861
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1862
+ const [result, setResult] = useState10(null);
1863
+ const [isLoading, setIsLoading] = useState10(false);
1864
+ const [stage, setStage] = useState10("idle");
1865
+ const [error, setError] = useState10(null);
1866
+ const mint = useCallback15(
1867
+ async (options) => {
1868
+ if (!client || !isReady) {
1869
+ throw new Error("Miden client is not ready");
1870
+ }
1871
+ setIsLoading(true);
1872
+ setStage("executing");
1873
+ setError(null);
1874
+ try {
1875
+ const noteType = getNoteType4(options.noteType ?? DEFAULTS.NOTE_TYPE);
1876
+ const targetAccountIdObj = parseAccountId(options.targetAccountId);
1877
+ const faucetIdObj = parseAccountId(options.faucetId);
1878
+ setStage("proving");
1879
+ const txResult = await runExclusiveSafe(async () => {
1880
+ const txRequest = client.newMintTransactionRequest(
1881
+ targetAccountIdObj,
1882
+ faucetIdObj,
1883
+ noteType,
1884
+ options.amount
1885
+ );
1886
+ const txId = prover ? await client.submitNewTransactionWithProver(
1887
+ faucetIdObj,
1888
+ txRequest,
1889
+ prover
1890
+ ) : await client.submitNewTransaction(faucetIdObj, txRequest);
1891
+ return { transactionId: txId.toString() };
1892
+ });
1893
+ setStage("complete");
1894
+ setResult(txResult);
1895
+ await sync();
1896
+ return txResult;
1897
+ } catch (err) {
1898
+ const error2 = err instanceof Error ? err : new Error(String(err));
1899
+ setError(error2);
1900
+ setStage("idle");
1901
+ throw error2;
1902
+ } finally {
1903
+ setIsLoading(false);
1904
+ }
1905
+ },
1906
+ [client, isReady, prover, runExclusive, sync]
1907
+ );
1908
+ const reset = useCallback15(() => {
1909
+ setResult(null);
1910
+ setIsLoading(false);
1911
+ setStage("idle");
1912
+ setError(null);
1913
+ }, []);
1914
+ return {
1915
+ mint,
1916
+ result,
1917
+ isLoading,
1918
+ stage,
1919
+ error,
1920
+ reset
1921
+ };
1922
+ }
1923
+ function getNoteType4(type) {
1924
+ switch (type) {
1925
+ case "private":
1926
+ return NoteType4.Private;
1927
+ case "public":
1928
+ return NoteType4.Public;
1929
+ case "encrypted":
1930
+ return NoteType4.Encrypted;
1931
+ default:
1932
+ return NoteType4.Private;
1933
+ }
1934
+ }
1935
+
1936
+ // src/hooks/useConsume.ts
1937
+ import { useCallback as useCallback16, useState as useState11 } from "react";
1938
+ import { NoteFilter as NoteFilter2, NoteFilterTypes as NoteFilterTypes2, NoteId } from "@miden-sdk/miden-sdk";
1939
+ function useConsume() {
1940
+ const { client, isReady, sync, runExclusive, prover } = useMiden();
1941
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
1942
+ const [result, setResult] = useState11(null);
1943
+ const [isLoading, setIsLoading] = useState11(false);
1944
+ const [stage, setStage] = useState11("idle");
1945
+ const [error, setError] = useState11(null);
1946
+ const consume = useCallback16(
1947
+ async (options) => {
1948
+ if (!client || !isReady) {
1949
+ throw new Error("Miden client is not ready");
1950
+ }
1951
+ if (options.noteIds.length === 0) {
1952
+ throw new Error("No note IDs provided");
1953
+ }
1954
+ setIsLoading(true);
1955
+ setStage("executing");
1956
+ setError(null);
1957
+ try {
1958
+ const accountIdObj = parseAccountId(options.accountId);
1959
+ setStage("proving");
1960
+ const txResult = await runExclusiveSafe(async () => {
1961
+ const noteIds = options.noteIds.map(
1962
+ (noteId) => NoteId.fromHex(noteId)
1963
+ );
1964
+ const filter = new NoteFilter2(NoteFilterTypes2.List, noteIds);
1965
+ const noteRecords = await client.getInputNotes(filter);
1966
+ const notes = noteRecords.map((record) => record.toNote());
1967
+ if (notes.length === 0) {
1968
+ throw new Error("No notes found for provided IDs");
1969
+ }
1970
+ if (notes.length !== options.noteIds.length) {
1971
+ throw new Error("Some notes could not be found for provided IDs");
1972
+ }
1973
+ const txRequest = client.newConsumeTransactionRequest(notes);
1974
+ const txId = prover ? await client.submitNewTransactionWithProver(
1975
+ accountIdObj,
1976
+ txRequest,
1977
+ prover
1978
+ ) : await client.submitNewTransaction(accountIdObj, txRequest);
1979
+ return { transactionId: txId.toString() };
1980
+ });
1981
+ setStage("complete");
1982
+ setResult(txResult);
1983
+ await sync();
1984
+ return txResult;
1985
+ } catch (err) {
1986
+ const error2 = err instanceof Error ? err : new Error(String(err));
1987
+ setError(error2);
1988
+ setStage("idle");
1989
+ throw error2;
1990
+ } finally {
1991
+ setIsLoading(false);
1992
+ }
1993
+ },
1994
+ [client, isReady, prover, runExclusive, sync]
1995
+ );
1996
+ const reset = useCallback16(() => {
1997
+ setResult(null);
1998
+ setIsLoading(false);
1999
+ setStage("idle");
2000
+ setError(null);
2001
+ }, []);
2002
+ return {
2003
+ consume,
2004
+ result,
2005
+ isLoading,
2006
+ stage,
2007
+ error,
2008
+ reset
2009
+ };
2010
+ }
2011
+
2012
+ // src/hooks/useSwap.ts
2013
+ import { useCallback as useCallback17, useState as useState12 } from "react";
2014
+ import { NoteType as NoteType5 } from "@miden-sdk/miden-sdk";
2015
+ function useSwap() {
2016
+ const { client, isReady, sync, runExclusive, prover } = useMiden();
2017
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2018
+ const [result, setResult] = useState12(null);
2019
+ const [isLoading, setIsLoading] = useState12(false);
2020
+ const [stage, setStage] = useState12("idle");
2021
+ const [error, setError] = useState12(null);
2022
+ const swap = useCallback17(
2023
+ async (options) => {
2024
+ if (!client || !isReady) {
2025
+ throw new Error("Miden client is not ready");
2026
+ }
2027
+ setIsLoading(true);
2028
+ setStage("executing");
2029
+ setError(null);
2030
+ try {
2031
+ const noteType = getNoteType5(options.noteType ?? DEFAULTS.NOTE_TYPE);
2032
+ const paybackNoteType = getNoteType5(
2033
+ options.paybackNoteType ?? DEFAULTS.NOTE_TYPE
2034
+ );
2035
+ const accountIdObj = parseAccountId(options.accountId);
2036
+ const offeredFaucetIdObj = parseAccountId(options.offeredFaucetId);
2037
+ const requestedFaucetIdObj = parseAccountId(options.requestedFaucetId);
2038
+ setStage("proving");
2039
+ const txResult = await runExclusiveSafe(async () => {
2040
+ const txRequest = client.newSwapTransactionRequest(
2041
+ accountIdObj,
2042
+ offeredFaucetIdObj,
2043
+ options.offeredAmount,
2044
+ requestedFaucetIdObj,
2045
+ options.requestedAmount,
2046
+ noteType,
2047
+ paybackNoteType
2048
+ );
2049
+ const txId = prover ? await client.submitNewTransactionWithProver(
2050
+ accountIdObj,
2051
+ txRequest,
2052
+ prover
2053
+ ) : await client.submitNewTransaction(accountIdObj, txRequest);
2054
+ return { transactionId: txId.toString() };
2055
+ });
2056
+ setStage("complete");
2057
+ setResult(txResult);
2058
+ await sync();
2059
+ return txResult;
2060
+ } catch (err) {
2061
+ const error2 = err instanceof Error ? err : new Error(String(err));
2062
+ setError(error2);
2063
+ setStage("idle");
2064
+ throw error2;
2065
+ } finally {
2066
+ setIsLoading(false);
2067
+ }
2068
+ },
2069
+ [client, isReady, prover, runExclusive, sync]
2070
+ );
2071
+ const reset = useCallback17(() => {
2072
+ setResult(null);
2073
+ setIsLoading(false);
2074
+ setStage("idle");
2075
+ setError(null);
2076
+ }, []);
2077
+ return {
2078
+ swap,
2079
+ result,
2080
+ isLoading,
2081
+ stage,
2082
+ error,
2083
+ reset
2084
+ };
2085
+ }
2086
+ function getNoteType5(type) {
2087
+ switch (type) {
2088
+ case "private":
2089
+ return NoteType5.Private;
2090
+ case "public":
2091
+ return NoteType5.Public;
2092
+ case "encrypted":
2093
+ return NoteType5.Encrypted;
2094
+ default:
2095
+ return NoteType5.Private;
2096
+ }
2097
+ }
2098
+
2099
+ // src/hooks/useTransaction.ts
2100
+ import { useCallback as useCallback18, useState as useState13 } from "react";
2101
+ function useTransaction() {
2102
+ const { client, isReady, sync, runExclusive, prover } = useMiden();
2103
+ const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
2104
+ const [result, setResult] = useState13(null);
2105
+ const [isLoading, setIsLoading] = useState13(false);
2106
+ const [stage, setStage] = useState13("idle");
2107
+ const [error, setError] = useState13(null);
2108
+ const execute = useCallback18(
2109
+ async (options) => {
2110
+ if (!client || !isReady) {
2111
+ throw new Error("Miden client is not ready");
2112
+ }
2113
+ setIsLoading(true);
2114
+ setStage("executing");
2115
+ setError(null);
2116
+ try {
2117
+ setStage("proving");
2118
+ const txResult = await runExclusiveSafe(async () => {
2119
+ const accountIdObj = resolveAccountId2(options.accountId);
2120
+ const txRequest = await resolveRequest(options.request, client);
2121
+ const txId = prover ? await client.submitNewTransactionWithProver(
2122
+ accountIdObj,
2123
+ txRequest,
2124
+ prover
2125
+ ) : await client.submitNewTransaction(accountIdObj, txRequest);
2126
+ return { transactionId: txId.toString() };
2127
+ });
2128
+ setStage("complete");
2129
+ setResult(txResult);
2130
+ await sync();
2131
+ return txResult;
2132
+ } catch (err) {
2133
+ const error2 = err instanceof Error ? err : new Error(String(err));
2134
+ setError(error2);
2135
+ setStage("idle");
2136
+ throw error2;
2137
+ } finally {
2138
+ setIsLoading(false);
2139
+ }
2140
+ },
2141
+ [client, isReady, prover, runExclusive, sync]
2142
+ );
2143
+ const reset = useCallback18(() => {
2144
+ setResult(null);
2145
+ setIsLoading(false);
2146
+ setStage("idle");
2147
+ setError(null);
2148
+ }, []);
2149
+ return {
2150
+ execute,
2151
+ result,
2152
+ isLoading,
2153
+ stage,
2154
+ error,
2155
+ reset
2156
+ };
2157
+ }
2158
+ function resolveAccountId2(accountId) {
2159
+ return parseAccountId(accountId);
2160
+ }
2161
+ async function resolveRequest(request, client) {
2162
+ if (typeof request === "function") {
2163
+ return await request(client);
2164
+ }
2165
+ return request;
2166
+ }
2167
+
2168
+ // src/index.ts
2169
+ installAccountBech32();
2170
+ export {
2171
+ DEFAULTS,
2172
+ MidenProvider,
2173
+ formatAssetAmount,
2174
+ formatNoteSummary,
2175
+ getNoteSummary,
2176
+ parseAssetAmount,
2177
+ toBech32AccountId,
2178
+ useAccount,
2179
+ useAccounts,
2180
+ useAssetMetadata,
2181
+ useConsume,
2182
+ useCreateFaucet,
2183
+ useCreateWallet,
2184
+ useImportAccount,
2185
+ useInternalTransfer,
2186
+ useMiden,
2187
+ useMidenClient,
2188
+ useMint,
2189
+ useMultiSend,
2190
+ useNotes,
2191
+ useSend,
2192
+ useSwap,
2193
+ useSyncState,
2194
+ useTransaction,
2195
+ useTransactionHistory,
2196
+ useWaitForCommit,
2197
+ useWaitForNotes
2198
+ };