@miden-sdk/react 0.13.1 → 0.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +426 -0
- package/README.md +402 -6
- package/dist/index.d.mts +264 -12
- package/dist/index.d.ts +264 -12
- package/dist/index.js +1211 -408
- package/dist/index.mjs +1210 -407
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -31,12 +31,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
DEFAULTS: () => DEFAULTS,
|
|
34
|
+
MidenError: () => MidenError,
|
|
34
35
|
MidenProvider: () => MidenProvider,
|
|
35
36
|
SignerContext: () => SignerContext,
|
|
37
|
+
accountIdsEqual: () => accountIdsEqual,
|
|
38
|
+
bigIntToBytes: () => bigIntToBytes,
|
|
39
|
+
bytesToBigInt: () => bytesToBigInt,
|
|
40
|
+
clearMidenStorage: () => clearMidenStorage,
|
|
41
|
+
concatBytes: () => concatBytes,
|
|
42
|
+
createMidenStorage: () => createMidenStorage,
|
|
43
|
+
createNoteAttachment: () => createNoteAttachment,
|
|
36
44
|
formatAssetAmount: () => formatAssetAmount,
|
|
37
45
|
formatNoteSummary: () => formatNoteSummary,
|
|
38
46
|
getNoteSummary: () => getNoteSummary,
|
|
47
|
+
migrateStorage: () => migrateStorage,
|
|
48
|
+
normalizeAccountId: () => normalizeAccountId,
|
|
39
49
|
parseAssetAmount: () => parseAssetAmount,
|
|
50
|
+
readNoteAttachment: () => readNoteAttachment,
|
|
40
51
|
toBech32AccountId: () => toBech32AccountId,
|
|
41
52
|
useAccount: () => useAccount,
|
|
42
53
|
useAccounts: () => useAccounts,
|
|
@@ -50,15 +61,19 @@ __export(index_exports, {
|
|
|
50
61
|
useMidenClient: () => useMidenClient,
|
|
51
62
|
useMint: () => useMint,
|
|
52
63
|
useMultiSend: () => useMultiSend,
|
|
64
|
+
useNoteStream: () => useNoteStream,
|
|
53
65
|
useNotes: () => useNotes,
|
|
54
66
|
useSend: () => useSend,
|
|
67
|
+
useSessionAccount: () => useSessionAccount,
|
|
55
68
|
useSigner: () => useSigner,
|
|
56
69
|
useSwap: () => useSwap,
|
|
57
70
|
useSyncState: () => useSyncState,
|
|
58
71
|
useTransaction: () => useTransaction,
|
|
59
72
|
useTransactionHistory: () => useTransactionHistory,
|
|
60
73
|
useWaitForCommit: () => useWaitForCommit,
|
|
61
|
-
useWaitForNotes: () => useWaitForNotes
|
|
74
|
+
useWaitForNotes: () => useWaitForNotes,
|
|
75
|
+
waitForWalletDetection: () => waitForWalletDetection,
|
|
76
|
+
wrapWasmError: () => wrapWasmError
|
|
62
77
|
});
|
|
63
78
|
module.exports = __toCommonJS(index_exports);
|
|
64
79
|
|
|
@@ -88,6 +103,7 @@ var initialState = {
|
|
|
88
103
|
notes: [],
|
|
89
104
|
consumableNotes: [],
|
|
90
105
|
assetMetadata: /* @__PURE__ */ new Map(),
|
|
106
|
+
noteFirstSeen: /* @__PURE__ */ new Map(),
|
|
91
107
|
isLoadingAccounts: false,
|
|
92
108
|
isLoadingNotes: false
|
|
93
109
|
};
|
|
@@ -115,8 +131,74 @@ var useMidenStore = (0, import_zustand.create)()((set) => ({
|
|
|
115
131
|
newMap.set(accountId, account);
|
|
116
132
|
return { accountDetails: newMap };
|
|
117
133
|
}),
|
|
118
|
-
setNotes: (notes) => set(
|
|
134
|
+
setNotes: (notes) => set((state) => {
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
const newFirstSeen = /* @__PURE__ */ new Map();
|
|
137
|
+
for (const note of notes) {
|
|
138
|
+
try {
|
|
139
|
+
const id = note.id().toString();
|
|
140
|
+
newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { notes, noteFirstSeen: newFirstSeen };
|
|
145
|
+
}),
|
|
146
|
+
setNotesIfChanged: (notes) => set((state) => {
|
|
147
|
+
const safeId = (n) => {
|
|
148
|
+
try {
|
|
149
|
+
return n.id().toString();
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const prevIds = /* @__PURE__ */ new Set();
|
|
155
|
+
for (const n of state.notes) {
|
|
156
|
+
const id = safeId(n);
|
|
157
|
+
if (id) prevIds.add(id);
|
|
158
|
+
}
|
|
159
|
+
const newIds = /* @__PURE__ */ new Set();
|
|
160
|
+
for (const n of notes) {
|
|
161
|
+
const id = safeId(n);
|
|
162
|
+
if (id) newIds.add(id);
|
|
163
|
+
}
|
|
164
|
+
if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
|
|
165
|
+
return {};
|
|
166
|
+
}
|
|
167
|
+
const now = Date.now();
|
|
168
|
+
const newFirstSeen = /* @__PURE__ */ new Map();
|
|
169
|
+
for (const note of notes) {
|
|
170
|
+
try {
|
|
171
|
+
const id = note.id().toString();
|
|
172
|
+
newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return { notes, noteFirstSeen: newFirstSeen };
|
|
177
|
+
}),
|
|
119
178
|
setConsumableNotes: (consumableNotes) => set({ consumableNotes }),
|
|
179
|
+
setConsumableNotesIfChanged: (consumableNotes) => set((state) => {
|
|
180
|
+
const safeId = (n) => {
|
|
181
|
+
try {
|
|
182
|
+
return n.inputNoteRecord().id().toString();
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const prevIds = /* @__PURE__ */ new Set();
|
|
188
|
+
for (const n of state.consumableNotes) {
|
|
189
|
+
const id = safeId(n);
|
|
190
|
+
if (id) prevIds.add(id);
|
|
191
|
+
}
|
|
192
|
+
const newIds = /* @__PURE__ */ new Set();
|
|
193
|
+
for (const n of consumableNotes) {
|
|
194
|
+
const id = safeId(n);
|
|
195
|
+
if (id) newIds.add(id);
|
|
196
|
+
}
|
|
197
|
+
if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
return { consumableNotes };
|
|
201
|
+
}),
|
|
120
202
|
setAssetMetadata: (assetId, metadata) => set((state) => {
|
|
121
203
|
const newMap = new Map(state.assetMetadata);
|
|
122
204
|
newMap.set(assetId, metadata);
|
|
@@ -131,6 +213,7 @@ var useAccountsStore = () => useMidenStore((state) => state.accounts);
|
|
|
131
213
|
var useNotesStore = () => useMidenStore((state) => state.notes);
|
|
132
214
|
var useConsumableNotesStore = () => useMidenStore((state) => state.consumableNotes);
|
|
133
215
|
var useAssetMetadataStore = () => useMidenStore((state) => state.assetMetadata);
|
|
216
|
+
var useNoteFirstSeenStore = () => useMidenStore((state) => state.noteFirstSeen);
|
|
134
217
|
|
|
135
218
|
// src/utils/accountParsing.ts
|
|
136
219
|
var import_miden_sdk2 = require("@miden-sdk/miden-sdk");
|
|
@@ -154,6 +237,19 @@ var parseAccountId = (value) => {
|
|
|
154
237
|
const normalized = normalizeAccountIdInput(value);
|
|
155
238
|
return parseAccountIdFromString(normalized);
|
|
156
239
|
};
|
|
240
|
+
function isFaucetId(accountId) {
|
|
241
|
+
try {
|
|
242
|
+
let hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
|
|
243
|
+
if (hex.startsWith("0x") || hex.startsWith("0X")) {
|
|
244
|
+
hex = hex.slice(2);
|
|
245
|
+
}
|
|
246
|
+
const firstByte = parseInt(hex.slice(0, 2), 16);
|
|
247
|
+
const accountType = firstByte >> 4 & 3;
|
|
248
|
+
return accountType === 2 || accountType === 3;
|
|
249
|
+
} catch {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
157
253
|
var parseAddress = (value, accountId) => {
|
|
158
254
|
const normalized = normalizeAccountIdInput(value);
|
|
159
255
|
if (isBech32Input(normalized)) {
|
|
@@ -390,19 +486,29 @@ function isPrivateStorageMode(storageMode) {
|
|
|
390
486
|
return storageMode.toString() === "private";
|
|
391
487
|
}
|
|
392
488
|
async function initializeSignerAccount(client, config) {
|
|
393
|
-
const { AccountBuilder, AccountComponent, Word } = await import("@miden-sdk/miden-sdk");
|
|
489
|
+
const { AccountBuilder, AccountComponent, Word: Word2 } = await import("@miden-sdk/miden-sdk");
|
|
394
490
|
await client.syncState();
|
|
395
|
-
const commitmentWord =
|
|
491
|
+
const commitmentWord = Word2.deserialize(config.publicKeyCommitment);
|
|
396
492
|
const seed = config.accountSeed ?? crypto.getRandomValues(new Uint8Array(32));
|
|
397
493
|
const accountType = await getAccountType(config.accountType);
|
|
398
|
-
|
|
399
|
-
const buildResult = builder.withAuthComponent(
|
|
494
|
+
let builder = new AccountBuilder(seed).withAuthComponent(
|
|
400
495
|
AccountComponent.createAuthComponentFromCommitment(
|
|
401
496
|
commitmentWord,
|
|
402
497
|
1
|
|
403
498
|
// ECDSA auth scheme (K256/Keccak)
|
|
404
499
|
)
|
|
405
|
-
).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent()
|
|
500
|
+
).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent();
|
|
501
|
+
if (config.customComponents?.length) {
|
|
502
|
+
for (const component of config.customComponents) {
|
|
503
|
+
if (component == null || typeof component.getProcedures !== "function") {
|
|
504
|
+
throw new Error(
|
|
505
|
+
"Each entry in customComponents must be an AccountComponent instance created via AccountComponent.compile(), AccountComponent.fromPackage(), or AccountComponent.fromLibrary()."
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
builder = builder.withComponent(component);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
const buildResult = builder.build();
|
|
406
512
|
const account = buildResult.account;
|
|
407
513
|
const accountId = account.id();
|
|
408
514
|
if (!isPrivateStorageMode(config.storageMode)) {
|
|
@@ -499,63 +605,91 @@ function MidenProvider({
|
|
|
499
605
|
(0, import_react2.useEffect)(() => {
|
|
500
606
|
if (!signerContext && isInitializedRef.current) return;
|
|
501
607
|
if (signerContext && !signerContext.isConnected) {
|
|
502
|
-
if (client) {
|
|
608
|
+
if (useMidenStore.getState().client) {
|
|
503
609
|
useMidenStore.getState().reset();
|
|
504
610
|
setClient(null);
|
|
505
611
|
setSignerAccountId(null);
|
|
506
612
|
}
|
|
507
613
|
return;
|
|
508
614
|
}
|
|
509
|
-
|
|
510
|
-
isInitializedRef.current = true;
|
|
511
|
-
}
|
|
615
|
+
let cancelled = false;
|
|
512
616
|
const initClient = async () => {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
if (signerContext && signerContext.isConnected) {
|
|
518
|
-
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
519
|
-
webClient = await import_miden_sdk5.WebClient.createClientWithExternalKeystore(
|
|
520
|
-
resolvedConfig.rpcUrl,
|
|
521
|
-
resolvedConfig.noteTransportUrl,
|
|
522
|
-
resolvedConfig.seed,
|
|
523
|
-
storeName,
|
|
524
|
-
void 0,
|
|
525
|
-
// getKeyCb - not needed for public accounts
|
|
526
|
-
void 0,
|
|
527
|
-
// insertKeyCb - not needed for public accounts
|
|
528
|
-
signerContext.signCb
|
|
529
|
-
);
|
|
530
|
-
const accountId = await initializeSignerAccount(
|
|
531
|
-
webClient,
|
|
532
|
-
signerContext.accountConfig
|
|
533
|
-
);
|
|
534
|
-
setSignerAccountId(accountId);
|
|
535
|
-
} else {
|
|
536
|
-
const seed = resolvedConfig.seed;
|
|
537
|
-
webClient = await import_miden_sdk5.WebClient.createClient(
|
|
538
|
-
resolvedConfig.rpcUrl,
|
|
539
|
-
resolvedConfig.noteTransportUrl,
|
|
540
|
-
seed
|
|
541
|
-
);
|
|
542
|
-
}
|
|
543
|
-
setClient(webClient);
|
|
617
|
+
await runExclusive(async () => {
|
|
618
|
+
if (cancelled) return;
|
|
619
|
+
setInitializing(true);
|
|
620
|
+
setConfig(resolvedConfig);
|
|
544
621
|
try {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
622
|
+
let webClient;
|
|
623
|
+
let didSignerInit = false;
|
|
624
|
+
if (signerContext && signerContext.isConnected) {
|
|
625
|
+
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
626
|
+
webClient = await import_miden_sdk5.WebClient.createClientWithExternalKeystore(
|
|
627
|
+
resolvedConfig.rpcUrl,
|
|
628
|
+
resolvedConfig.noteTransportUrl,
|
|
629
|
+
resolvedConfig.seed,
|
|
630
|
+
storeName,
|
|
631
|
+
void 0,
|
|
632
|
+
// getKeyCb - not needed for public accounts
|
|
633
|
+
void 0,
|
|
634
|
+
// insertKeyCb - not needed for public accounts
|
|
635
|
+
signerContext.signCb
|
|
636
|
+
);
|
|
637
|
+
if (cancelled) return;
|
|
638
|
+
const accountId = await initializeSignerAccount(
|
|
639
|
+
webClient,
|
|
640
|
+
signerContext.accountConfig
|
|
641
|
+
);
|
|
642
|
+
if (cancelled) return;
|
|
643
|
+
setSignerAccountId(accountId);
|
|
644
|
+
didSignerInit = true;
|
|
645
|
+
} else {
|
|
646
|
+
const seed = resolvedConfig.seed;
|
|
647
|
+
webClient = await import_miden_sdk5.WebClient.createClient(
|
|
648
|
+
resolvedConfig.rpcUrl,
|
|
649
|
+
resolvedConfig.noteTransportUrl,
|
|
650
|
+
seed
|
|
651
|
+
);
|
|
652
|
+
if (cancelled) return;
|
|
653
|
+
}
|
|
654
|
+
if (!didSignerInit) {
|
|
655
|
+
try {
|
|
656
|
+
const summary = await webClient.syncState();
|
|
657
|
+
if (cancelled) return;
|
|
658
|
+
setSyncState({
|
|
659
|
+
syncHeight: summary.blockNum(),
|
|
660
|
+
lastSyncTime: Date.now()
|
|
661
|
+
});
|
|
662
|
+
} catch {
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (!cancelled) {
|
|
666
|
+
try {
|
|
667
|
+
const accounts = await webClient.getAccounts();
|
|
668
|
+
if (cancelled) return;
|
|
669
|
+
useMidenStore.getState().setAccounts(accounts);
|
|
670
|
+
} catch {
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (!cancelled) {
|
|
674
|
+
if (!signerContext) {
|
|
675
|
+
isInitializedRef.current = true;
|
|
676
|
+
}
|
|
677
|
+
setClient(webClient);
|
|
678
|
+
}
|
|
679
|
+
} catch (error) {
|
|
680
|
+
if (!cancelled) {
|
|
681
|
+
setInitError(
|
|
682
|
+
error instanceof Error ? error : new Error(String(error))
|
|
683
|
+
);
|
|
684
|
+
}
|
|
553
685
|
}
|
|
554
|
-
}
|
|
555
|
-
setInitError(error instanceof Error ? error : new Error(String(error)));
|
|
556
|
-
}
|
|
686
|
+
});
|
|
557
687
|
};
|
|
558
688
|
initClient();
|
|
689
|
+
return () => {
|
|
690
|
+
cancelled = true;
|
|
691
|
+
isInitializedRef.current = false;
|
|
692
|
+
};
|
|
559
693
|
}, [
|
|
560
694
|
runExclusive,
|
|
561
695
|
resolvedConfig,
|
|
@@ -564,8 +698,7 @@ function MidenProvider({
|
|
|
564
698
|
setInitError,
|
|
565
699
|
setInitializing,
|
|
566
700
|
setSyncState,
|
|
567
|
-
signerContext
|
|
568
|
-
client
|
|
701
|
+
signerContext
|
|
569
702
|
]);
|
|
570
703
|
(0, import_react2.useEffect)(() => {
|
|
571
704
|
if (!isReady || !client) return;
|
|
@@ -671,16 +804,6 @@ function useAccounts() {
|
|
|
671
804
|
refetch
|
|
672
805
|
};
|
|
673
806
|
}
|
|
674
|
-
function isFaucetId(accountId) {
|
|
675
|
-
try {
|
|
676
|
-
const hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
|
|
677
|
-
const firstByte = parseInt(hex.slice(0, 2), 16);
|
|
678
|
-
const accountType = firstByte >> 4 & 3;
|
|
679
|
-
return accountType === 2 || accountType === 3;
|
|
680
|
-
} catch {
|
|
681
|
-
return false;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
807
|
|
|
685
808
|
// src/hooks/useAccount.ts
|
|
686
809
|
var import_react5 = require("react");
|
|
@@ -703,17 +826,12 @@ var getRpcClient = (rpcUrl) => {
|
|
|
703
826
|
return null;
|
|
704
827
|
}
|
|
705
828
|
};
|
|
706
|
-
var fetchAssetMetadata = async (
|
|
829
|
+
var fetchAssetMetadata = async (rpcClient, assetId) => {
|
|
707
830
|
try {
|
|
708
831
|
const accountId = parseAccountId(assetId);
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
const fetched = await rpcClient.getAccountDetails(accountId);
|
|
713
|
-
account = fetched.account?.();
|
|
714
|
-
} catch {
|
|
715
|
-
}
|
|
716
|
-
}
|
|
832
|
+
if (!isFaucetId(accountId)) return null;
|
|
833
|
+
const fetched = await rpcClient.getAccountDetails(accountId);
|
|
834
|
+
const account = fetched.account?.();
|
|
717
835
|
if (!account) return null;
|
|
718
836
|
const faucet = import_miden_sdk6.BasicFungibleFaucetComponent.fromAccount(account);
|
|
719
837
|
const symbol = faucet.symbol().toString();
|
|
@@ -724,8 +842,6 @@ var fetchAssetMetadata = async (client, rpcClient, assetId) => {
|
|
|
724
842
|
}
|
|
725
843
|
};
|
|
726
844
|
function useAssetMetadata(assetIds = []) {
|
|
727
|
-
const { client, isReady, runExclusive } = useMiden();
|
|
728
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
729
845
|
const assetMetadata = useAssetMetadataStore();
|
|
730
846
|
const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
|
|
731
847
|
const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
|
|
@@ -735,32 +851,19 @@ function useAssetMetadata(assetIds = []) {
|
|
|
735
851
|
[assetIds]
|
|
736
852
|
);
|
|
737
853
|
(0, import_react4.useEffect)(() => {
|
|
738
|
-
if (!
|
|
854
|
+
if (!rpcClient || uniqueAssetIds.length === 0) return;
|
|
739
855
|
uniqueAssetIds.forEach((assetId) => {
|
|
740
856
|
const existing = assetMetadata.get(assetId);
|
|
741
857
|
const hasMetadata = existing?.symbol !== void 0 || existing?.decimals !== void 0;
|
|
742
858
|
if (hasMetadata || inflight.has(assetId)) return;
|
|
743
|
-
const promise =
|
|
744
|
-
const metadata = await fetchAssetMetadata(
|
|
745
|
-
client,
|
|
746
|
-
rpcClient,
|
|
747
|
-
assetId
|
|
748
|
-
);
|
|
859
|
+
const promise = fetchAssetMetadata(rpcClient, assetId).then((metadata) => {
|
|
749
860
|
setAssetMetadata(assetId, metadata ?? { assetId });
|
|
750
861
|
}).finally(() => {
|
|
751
862
|
inflight.delete(assetId);
|
|
752
863
|
});
|
|
753
864
|
inflight.set(assetId, promise);
|
|
754
865
|
});
|
|
755
|
-
}, [
|
|
756
|
-
client,
|
|
757
|
-
isReady,
|
|
758
|
-
uniqueAssetIds,
|
|
759
|
-
assetMetadata,
|
|
760
|
-
runExclusiveSafe,
|
|
761
|
-
setAssetMetadata,
|
|
762
|
-
rpcClient
|
|
763
|
-
]);
|
|
866
|
+
}, [uniqueAssetIds, assetMetadata, setAssetMetadata, rpcClient]);
|
|
764
867
|
return { assetMetadata };
|
|
765
868
|
}
|
|
766
869
|
|
|
@@ -862,7 +965,7 @@ function useAccount(accountId) {
|
|
|
862
965
|
|
|
863
966
|
// src/hooks/useNotes.ts
|
|
864
967
|
var import_react6 = require("react");
|
|
865
|
-
var
|
|
968
|
+
var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
|
|
866
969
|
|
|
867
970
|
// src/utils/amounts.ts
|
|
868
971
|
var formatAssetAmount = (amount, decimals) => {
|
|
@@ -946,6 +1049,82 @@ var formatNoteSummary = (summary, formatAsset = (asset) => `${formatAssetAmount(
|
|
|
946
1049
|
return summary.sender ? `${assetsText} from ${summary.sender}` : assetsText;
|
|
947
1050
|
};
|
|
948
1051
|
|
|
1052
|
+
// src/utils/accountId.ts
|
|
1053
|
+
function normalizeAccountId(id) {
|
|
1054
|
+
return toBech32AccountId(id);
|
|
1055
|
+
}
|
|
1056
|
+
function accountIdsEqual(a, b) {
|
|
1057
|
+
let idA;
|
|
1058
|
+
let idB;
|
|
1059
|
+
try {
|
|
1060
|
+
idA = parseAccountId(a);
|
|
1061
|
+
idB = parseAccountId(b);
|
|
1062
|
+
return idA.toString() === idB.toString();
|
|
1063
|
+
} catch {
|
|
1064
|
+
return a === b;
|
|
1065
|
+
} finally {
|
|
1066
|
+
idA?.free?.();
|
|
1067
|
+
idB?.free?.();
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// src/utils/noteFilters.ts
|
|
1072
|
+
var import_miden_sdk7 = require("@miden-sdk/miden-sdk");
|
|
1073
|
+
function getNoteFilterType(status) {
|
|
1074
|
+
switch (status) {
|
|
1075
|
+
case "consumed":
|
|
1076
|
+
return import_miden_sdk7.NoteFilterTypes.Consumed;
|
|
1077
|
+
case "committed":
|
|
1078
|
+
return import_miden_sdk7.NoteFilterTypes.Committed;
|
|
1079
|
+
case "expected":
|
|
1080
|
+
return import_miden_sdk7.NoteFilterTypes.Expected;
|
|
1081
|
+
case "processing":
|
|
1082
|
+
return import_miden_sdk7.NoteFilterTypes.Processing;
|
|
1083
|
+
case "all":
|
|
1084
|
+
default:
|
|
1085
|
+
return import_miden_sdk7.NoteFilterTypes.All;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
function getNoteType(type) {
|
|
1089
|
+
switch (type) {
|
|
1090
|
+
case "private":
|
|
1091
|
+
return import_miden_sdk7.NoteType.Private;
|
|
1092
|
+
case "public":
|
|
1093
|
+
return import_miden_sdk7.NoteType.Public;
|
|
1094
|
+
default:
|
|
1095
|
+
return import_miden_sdk7.NoteType.Private;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
async function waitForTransactionCommit(client, runExclusiveSafe, txIdHex, maxWaitMs = 1e4, delayMs = 1e3) {
|
|
1099
|
+
const deadline = Date.now() + maxWaitMs;
|
|
1100
|
+
const targetHex = normalizeHex(txIdHex);
|
|
1101
|
+
while (Date.now() < deadline) {
|
|
1102
|
+
await runExclusiveSafe(() => client.syncState());
|
|
1103
|
+
const records = await runExclusiveSafe(
|
|
1104
|
+
() => client.getTransactions(import_miden_sdk7.TransactionFilter.all())
|
|
1105
|
+
);
|
|
1106
|
+
const record = records.find(
|
|
1107
|
+
(r) => normalizeHex(r.id().toHex()) === targetHex
|
|
1108
|
+
);
|
|
1109
|
+
if (record) {
|
|
1110
|
+
const status = record.transactionStatus();
|
|
1111
|
+
if (status.isCommitted()) {
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
if (status.isDiscarded()) {
|
|
1115
|
+
throw new Error("Transaction was discarded before commit");
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1119
|
+
}
|
|
1120
|
+
throw new Error("Timeout waiting for transaction commit");
|
|
1121
|
+
}
|
|
1122
|
+
function normalizeHex(value) {
|
|
1123
|
+
const trimmed = value.trim();
|
|
1124
|
+
const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
|
|
1125
|
+
return normalized.toLowerCase();
|
|
1126
|
+
}
|
|
1127
|
+
|
|
949
1128
|
// src/hooks/useNotes.ts
|
|
950
1129
|
function useNotes(options) {
|
|
951
1130
|
const { client, isReady, runExclusive } = useMiden();
|
|
@@ -954,8 +1133,10 @@ function useNotes(options) {
|
|
|
954
1133
|
const consumableNotes = useConsumableNotesStore();
|
|
955
1134
|
const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
|
|
956
1135
|
const setLoadingNotes = useMidenStore((state) => state.setLoadingNotes);
|
|
957
|
-
const
|
|
958
|
-
const
|
|
1136
|
+
const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
|
|
1137
|
+
const setConsumableNotesIfChanged = useMidenStore(
|
|
1138
|
+
(state) => state.setConsumableNotesIfChanged
|
|
1139
|
+
);
|
|
959
1140
|
const { lastSyncTime } = useSyncStateStore();
|
|
960
1141
|
const [error, setError] = (0, import_react6.useState)(null);
|
|
961
1142
|
const refetch = (0, import_react6.useCallback)(async () => {
|
|
@@ -966,7 +1147,7 @@ function useNotes(options) {
|
|
|
966
1147
|
const { fetchedNotes, fetchedConsumable } = await runExclusiveSafe(
|
|
967
1148
|
async () => {
|
|
968
1149
|
const filterType = getNoteFilterType(options?.status);
|
|
969
|
-
const filter = new
|
|
1150
|
+
const filter = new import_miden_sdk8.NoteFilter(filterType);
|
|
970
1151
|
const notesResult = await client.getInputNotes(filter);
|
|
971
1152
|
let consumableResult;
|
|
972
1153
|
if (options?.accountId) {
|
|
@@ -981,8 +1162,8 @@ function useNotes(options) {
|
|
|
981
1162
|
};
|
|
982
1163
|
}
|
|
983
1164
|
);
|
|
984
|
-
|
|
985
|
-
|
|
1165
|
+
setNotesIfChanged(fetchedNotes);
|
|
1166
|
+
setConsumableNotesIfChanged(fetchedConsumable);
|
|
986
1167
|
} catch (err) {
|
|
987
1168
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
988
1169
|
} finally {
|
|
@@ -995,8 +1176,8 @@ function useNotes(options) {
|
|
|
995
1176
|
options?.status,
|
|
996
1177
|
options?.accountId,
|
|
997
1178
|
setLoadingNotes,
|
|
998
|
-
|
|
999
|
-
|
|
1179
|
+
setNotesIfChanged,
|
|
1180
|
+
setConsumableNotesIfChanged
|
|
1000
1181
|
]);
|
|
1001
1182
|
(0, import_react6.useEffect)(() => {
|
|
1002
1183
|
if (isReady && notes.length === 0) {
|
|
@@ -1023,14 +1204,65 @@ function useNotes(options) {
|
|
|
1023
1204
|
(assetId) => assetMetadata.get(assetId),
|
|
1024
1205
|
[assetMetadata]
|
|
1025
1206
|
);
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1207
|
+
const normalizedSender = (0, import_react6.useMemo)(() => {
|
|
1208
|
+
if (!options?.sender) return null;
|
|
1209
|
+
try {
|
|
1210
|
+
return normalizeAccountId(options.sender);
|
|
1211
|
+
} catch {
|
|
1212
|
+
return options.sender;
|
|
1213
|
+
}
|
|
1214
|
+
}, [options?.sender]);
|
|
1215
|
+
const excludeIdsKey = (0, import_react6.useMemo)(() => {
|
|
1216
|
+
if (!options?.excludeIds || options.excludeIds.length === 0) return "";
|
|
1217
|
+
return [...options.excludeIds].sort().join("\0");
|
|
1218
|
+
}, [options?.excludeIds]);
|
|
1219
|
+
const filterBySender = (0, import_react6.useCallback)(
|
|
1220
|
+
(summaries, target) => {
|
|
1221
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1222
|
+
return summaries.filter((s) => {
|
|
1223
|
+
if (!s.sender) return false;
|
|
1224
|
+
let normalized = cache.get(s.sender);
|
|
1225
|
+
if (normalized === void 0) {
|
|
1226
|
+
try {
|
|
1227
|
+
normalized = normalizeAccountId(s.sender);
|
|
1228
|
+
} catch {
|
|
1229
|
+
normalized = s.sender;
|
|
1230
|
+
}
|
|
1231
|
+
cache.set(s.sender, normalized);
|
|
1232
|
+
}
|
|
1233
|
+
return normalized === target;
|
|
1234
|
+
});
|
|
1235
|
+
},
|
|
1236
|
+
[]
|
|
1033
1237
|
);
|
|
1238
|
+
const noteSummaries = (0, import_react6.useMemo)(() => {
|
|
1239
|
+
let summaries = notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1240
|
+
if (normalizedSender) {
|
|
1241
|
+
summaries = filterBySender(summaries, normalizedSender);
|
|
1242
|
+
}
|
|
1243
|
+
if (excludeIdsKey) {
|
|
1244
|
+
const excludeSet = new Set(excludeIdsKey.split("\0"));
|
|
1245
|
+
summaries = summaries.filter((s) => !excludeSet.has(s.id));
|
|
1246
|
+
}
|
|
1247
|
+
return summaries;
|
|
1248
|
+
}, [notes, getMetadata, normalizedSender, excludeIdsKey, filterBySender]);
|
|
1249
|
+
const consumableNoteSummaries = (0, import_react6.useMemo)(() => {
|
|
1250
|
+
let summaries = consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1251
|
+
if (normalizedSender) {
|
|
1252
|
+
summaries = filterBySender(summaries, normalizedSender);
|
|
1253
|
+
}
|
|
1254
|
+
if (excludeIdsKey) {
|
|
1255
|
+
const excludeSet = new Set(excludeIdsKey.split("\0"));
|
|
1256
|
+
summaries = summaries.filter((s) => !excludeSet.has(s.id));
|
|
1257
|
+
}
|
|
1258
|
+
return summaries;
|
|
1259
|
+
}, [
|
|
1260
|
+
consumableNotes,
|
|
1261
|
+
getMetadata,
|
|
1262
|
+
normalizedSender,
|
|
1263
|
+
excludeIdsKey,
|
|
1264
|
+
filterBySender
|
|
1265
|
+
]);
|
|
1034
1266
|
return {
|
|
1035
1267
|
notes,
|
|
1036
1268
|
consumableNotes,
|
|
@@ -1041,46 +1273,246 @@ function useNotes(options) {
|
|
|
1041
1273
|
refetch
|
|
1042
1274
|
};
|
|
1043
1275
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1276
|
+
|
|
1277
|
+
// src/hooks/useNoteStream.ts
|
|
1278
|
+
var import_react7 = require("react");
|
|
1279
|
+
var import_miden_sdk10 = require("@miden-sdk/miden-sdk");
|
|
1280
|
+
|
|
1281
|
+
// src/utils/noteAttachment.ts
|
|
1282
|
+
var import_miden_sdk9 = require("@miden-sdk/miden-sdk");
|
|
1283
|
+
function readNoteAttachment(note) {
|
|
1284
|
+
try {
|
|
1285
|
+
const metadata = note.metadata?.();
|
|
1286
|
+
if (!metadata) return null;
|
|
1287
|
+
const attachment = metadata.attachment?.();
|
|
1288
|
+
if (!attachment) return null;
|
|
1289
|
+
const kind = attachment.kind?.();
|
|
1290
|
+
if (!kind) return null;
|
|
1291
|
+
if (kind === import_miden_sdk9.NoteAttachmentKind.None) return null;
|
|
1292
|
+
if (kind === import_miden_sdk9.NoteAttachmentKind.Word) {
|
|
1293
|
+
const word = attachment.asWord?.();
|
|
1294
|
+
if (!word) return null;
|
|
1295
|
+
const u64s = word.toU64s();
|
|
1296
|
+
const values = Array.from(u64s).map(
|
|
1297
|
+
(v) => BigInt(v)
|
|
1298
|
+
);
|
|
1299
|
+
return { values, kind: "word" };
|
|
1300
|
+
}
|
|
1301
|
+
if (kind === import_miden_sdk9.NoteAttachmentKind.Array) {
|
|
1302
|
+
const arr = attachment.asArray?.();
|
|
1303
|
+
if (!arr) return null;
|
|
1304
|
+
const u64s = arr.toU64s();
|
|
1305
|
+
const values = Array.from(u64s).map(
|
|
1306
|
+
(v) => BigInt(v)
|
|
1307
|
+
);
|
|
1308
|
+
return { values, kind: "array" };
|
|
1309
|
+
}
|
|
1310
|
+
return null;
|
|
1311
|
+
} catch {
|
|
1312
|
+
return null;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
function createNoteAttachment(values) {
|
|
1316
|
+
const bigints = [];
|
|
1317
|
+
for (let i = 0; i < values.length; i++) {
|
|
1318
|
+
bigints.push(BigInt(values[i]));
|
|
1319
|
+
}
|
|
1320
|
+
if (bigints.length === 0) {
|
|
1321
|
+
return new import_miden_sdk9.NoteAttachment();
|
|
1322
|
+
}
|
|
1323
|
+
const scheme = import_miden_sdk9.NoteAttachmentScheme.none();
|
|
1324
|
+
if (bigints.length <= 4) {
|
|
1325
|
+
while (bigints.length < 4) {
|
|
1326
|
+
bigints.push(0n);
|
|
1327
|
+
}
|
|
1328
|
+
const word = new import_miden_sdk9.Word(BigUint64Array.from(bigints));
|
|
1329
|
+
return import_miden_sdk9.NoteAttachment.newWord(scheme, word);
|
|
1330
|
+
}
|
|
1331
|
+
while (bigints.length % 4 !== 0) {
|
|
1332
|
+
bigints.push(0n);
|
|
1333
|
+
}
|
|
1334
|
+
const words = [];
|
|
1335
|
+
for (let i = 0; i < bigints.length; i += 4) {
|
|
1336
|
+
words.push(new import_miden_sdk9.Word(BigUint64Array.from(bigints.slice(i, i + 4))));
|
|
1337
|
+
}
|
|
1338
|
+
const newArray = import_miden_sdk9.NoteAttachment["newArray"];
|
|
1339
|
+
if (typeof newArray !== "function") {
|
|
1340
|
+
throw new Error(
|
|
1341
|
+
"NoteAttachment.newArray is not available. Ensure @miden-sdk/miden-sdk >= 0.13.1."
|
|
1342
|
+
);
|
|
1057
1343
|
}
|
|
1344
|
+
return newArray.call(import_miden_sdk9.NoteAttachment, scheme, words);
|
|
1058
1345
|
}
|
|
1059
1346
|
|
|
1060
|
-
// src/hooks/
|
|
1061
|
-
|
|
1062
|
-
var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
|
|
1063
|
-
function useTransactionHistory(options = {}) {
|
|
1347
|
+
// src/hooks/useNoteStream.ts
|
|
1348
|
+
function useNoteStream(options = {}) {
|
|
1064
1349
|
const { client, isReady, runExclusive } = useMiden();
|
|
1065
1350
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1351
|
+
const allNotes = useNotesStore();
|
|
1352
|
+
const noteFirstSeen = useNoteFirstSeenStore();
|
|
1066
1353
|
const { lastSyncTime } = useSyncStateStore();
|
|
1067
|
-
const
|
|
1354
|
+
const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
|
|
1068
1355
|
const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
|
|
1069
1356
|
const [error, setError] = (0, import_react7.useState)(null);
|
|
1070
|
-
const
|
|
1357
|
+
const handledIdsRef = (0, import_react7.useRef)(/* @__PURE__ */ new Set());
|
|
1358
|
+
const [handledVersion, setHandledVersion] = (0, import_react7.useState)(0);
|
|
1359
|
+
const status = options.status ?? "committed";
|
|
1360
|
+
const sender = options.sender ?? null;
|
|
1361
|
+
const since = options.since;
|
|
1362
|
+
const amountFilterRef = (0, import_react7.useRef)(options.amountFilter);
|
|
1363
|
+
amountFilterRef.current = options.amountFilter;
|
|
1364
|
+
const excludeIdsKey = (0, import_react7.useMemo)(() => {
|
|
1365
|
+
if (!options.excludeIds) return "";
|
|
1366
|
+
if (options.excludeIds instanceof Set)
|
|
1367
|
+
return Array.from(options.excludeIds).sort().join("\0");
|
|
1368
|
+
return [...options.excludeIds].sort().join("\0");
|
|
1369
|
+
}, [options.excludeIds]);
|
|
1370
|
+
const excludeIdSet = (0, import_react7.useMemo)(() => {
|
|
1371
|
+
if (!excludeIdsKey) return null;
|
|
1372
|
+
return new Set(excludeIdsKey.split("\0"));
|
|
1373
|
+
}, [excludeIdsKey]);
|
|
1374
|
+
const refetch = (0, import_react7.useCallback)(async () => {
|
|
1375
|
+
if (!client || !isReady) return;
|
|
1376
|
+
setIsLoading(true);
|
|
1377
|
+
setError(null);
|
|
1378
|
+
try {
|
|
1379
|
+
const filterType = getNoteFilterType(status);
|
|
1380
|
+
const filter = new import_miden_sdk10.NoteFilter(filterType);
|
|
1381
|
+
const fetched = await runExclusiveSafe(
|
|
1382
|
+
() => client.getInputNotes(filter)
|
|
1383
|
+
);
|
|
1384
|
+
setNotesIfChanged(fetched);
|
|
1385
|
+
} catch (err) {
|
|
1386
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1387
|
+
} finally {
|
|
1388
|
+
setIsLoading(false);
|
|
1389
|
+
}
|
|
1390
|
+
}, [client, isReady, runExclusiveSafe, status, setNotesIfChanged]);
|
|
1391
|
+
(0, import_react7.useEffect)(() => {
|
|
1392
|
+
if (isReady) {
|
|
1393
|
+
refetch();
|
|
1394
|
+
}
|
|
1395
|
+
}, [isReady, lastSyncTime, refetch]);
|
|
1396
|
+
const streamedNotes = (0, import_react7.useMemo)(() => {
|
|
1397
|
+
void handledVersion;
|
|
1398
|
+
const result = [];
|
|
1399
|
+
let normalizedSender = null;
|
|
1400
|
+
if (sender) {
|
|
1401
|
+
try {
|
|
1402
|
+
normalizedSender = normalizeAccountId(sender);
|
|
1403
|
+
} catch {
|
|
1404
|
+
normalizedSender = sender;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
for (const record of allNotes) {
|
|
1408
|
+
const note = buildStreamedNote(record, noteFirstSeen);
|
|
1409
|
+
if (!note) continue;
|
|
1410
|
+
if (handledIdsRef.current.has(note.id)) continue;
|
|
1411
|
+
if (excludeIdSet && excludeIdSet.has(note.id)) continue;
|
|
1412
|
+
if (normalizedSender && note.sender !== normalizedSender) continue;
|
|
1413
|
+
if (since !== void 0 && note.firstSeenAt < since) continue;
|
|
1414
|
+
if (amountFilterRef.current && !amountFilterRef.current(note.amount))
|
|
1415
|
+
continue;
|
|
1416
|
+
result.push(note);
|
|
1417
|
+
}
|
|
1418
|
+
result.sort((a, b) => a.firstSeenAt - b.firstSeenAt);
|
|
1419
|
+
return result;
|
|
1420
|
+
}, [allNotes, noteFirstSeen, excludeIdSet, sender, since, handledVersion]);
|
|
1421
|
+
const latest = (0, import_react7.useMemo)(
|
|
1422
|
+
() => streamedNotes.length > 0 ? streamedNotes[streamedNotes.length - 1] : null,
|
|
1423
|
+
[streamedNotes]
|
|
1424
|
+
);
|
|
1425
|
+
const markHandled = (0, import_react7.useCallback)((noteId) => {
|
|
1426
|
+
handledIdsRef.current = new Set(handledIdsRef.current).add(noteId);
|
|
1427
|
+
setHandledVersion((v) => v + 1);
|
|
1428
|
+
}, []);
|
|
1429
|
+
const markAllHandled = (0, import_react7.useCallback)(() => {
|
|
1430
|
+
const newSet = new Set(handledIdsRef.current);
|
|
1431
|
+
for (const note of streamedNotes) {
|
|
1432
|
+
newSet.add(note.id);
|
|
1433
|
+
}
|
|
1434
|
+
handledIdsRef.current = newSet;
|
|
1435
|
+
setHandledVersion((v) => v + 1);
|
|
1436
|
+
}, [streamedNotes]);
|
|
1437
|
+
const snapshot = (0, import_react7.useCallback)(() => {
|
|
1438
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1439
|
+
for (const note of streamedNotes) {
|
|
1440
|
+
ids.add(note.id);
|
|
1441
|
+
}
|
|
1442
|
+
return { ids, timestamp: Date.now() };
|
|
1443
|
+
}, [streamedNotes]);
|
|
1444
|
+
return {
|
|
1445
|
+
notes: streamedNotes,
|
|
1446
|
+
latest,
|
|
1447
|
+
markHandled,
|
|
1448
|
+
markAllHandled,
|
|
1449
|
+
snapshot,
|
|
1450
|
+
isLoading,
|
|
1451
|
+
error
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
function buildStreamedNote(record, noteFirstSeen) {
|
|
1455
|
+
try {
|
|
1456
|
+
const id = record.id().toString();
|
|
1457
|
+
const metadata = record.metadata?.();
|
|
1458
|
+
const senderHex = metadata?.sender?.()?.toString?.();
|
|
1459
|
+
const sender = senderHex ? toBech32AccountId(senderHex) : "";
|
|
1460
|
+
const assets = [];
|
|
1461
|
+
let primaryAmount = 0n;
|
|
1462
|
+
try {
|
|
1463
|
+
const details = record.details();
|
|
1464
|
+
const assetsList = details?.assets?.().fungibleAssets?.() ?? [];
|
|
1465
|
+
for (const asset of assetsList) {
|
|
1466
|
+
const assetId = asset.faucetId().toString();
|
|
1467
|
+
const amount = BigInt(asset.amount());
|
|
1468
|
+
assets.push({ assetId, amount });
|
|
1469
|
+
if (primaryAmount === 0n) {
|
|
1470
|
+
primaryAmount = amount;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
} catch {
|
|
1474
|
+
}
|
|
1475
|
+
const attachmentData = readNoteAttachment(record);
|
|
1476
|
+
const attachment = attachmentData ? attachmentData.values : null;
|
|
1477
|
+
const firstSeenAt = noteFirstSeen.get(id) ?? Date.now();
|
|
1478
|
+
return {
|
|
1479
|
+
id,
|
|
1480
|
+
sender,
|
|
1481
|
+
amount: primaryAmount,
|
|
1482
|
+
assets,
|
|
1483
|
+
record,
|
|
1484
|
+
firstSeenAt,
|
|
1485
|
+
attachment
|
|
1486
|
+
};
|
|
1487
|
+
} catch {
|
|
1488
|
+
return null;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// src/hooks/useTransactionHistory.ts
|
|
1493
|
+
var import_react8 = require("react");
|
|
1494
|
+
var import_miden_sdk11 = require("@miden-sdk/miden-sdk");
|
|
1495
|
+
function useTransactionHistory(options = {}) {
|
|
1496
|
+
const { client, isReady, runExclusive } = useMiden();
|
|
1497
|
+
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1498
|
+
const { lastSyncTime } = useSyncStateStore();
|
|
1499
|
+
const [records, setRecords] = (0, import_react8.useState)([]);
|
|
1500
|
+
const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
|
|
1501
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1502
|
+
const rawIds = (0, import_react8.useMemo)(() => {
|
|
1071
1503
|
if (options.id) return [options.id];
|
|
1072
1504
|
if (options.ids && options.ids.length > 0) return options.ids;
|
|
1073
1505
|
return null;
|
|
1074
1506
|
}, [options.id, options.ids]);
|
|
1075
|
-
const idsHex = (0,
|
|
1507
|
+
const idsHex = (0, import_react8.useMemo)(() => {
|
|
1076
1508
|
if (!rawIds) return null;
|
|
1077
1509
|
return rawIds.map(
|
|
1078
|
-
(id) =>
|
|
1510
|
+
(id) => normalizeHex2(typeof id === "string" ? id : id.toHex())
|
|
1079
1511
|
);
|
|
1080
1512
|
}, [rawIds]);
|
|
1081
1513
|
const filter = options.filter;
|
|
1082
1514
|
const refreshOnSync = options.refreshOnSync !== false;
|
|
1083
|
-
const refetch = (0,
|
|
1515
|
+
const refetch = (0, import_react8.useCallback)(async () => {
|
|
1084
1516
|
if (!client || !isReady) return;
|
|
1085
1517
|
setIsLoading(true);
|
|
1086
1518
|
setError(null);
|
|
@@ -1094,7 +1526,7 @@ function useTransactionHistory(options = {}) {
|
|
|
1094
1526
|
() => client.getTransactions(resolvedFilter)
|
|
1095
1527
|
);
|
|
1096
1528
|
const filtered = localFilterHexes ? fetched.filter(
|
|
1097
|
-
(record2) => localFilterHexes.includes(
|
|
1529
|
+
(record2) => localFilterHexes.includes(normalizeHex2(record2.id().toHex()))
|
|
1098
1530
|
) : fetched;
|
|
1099
1531
|
setRecords(filtered);
|
|
1100
1532
|
} catch (err) {
|
|
@@ -1103,19 +1535,19 @@ function useTransactionHistory(options = {}) {
|
|
|
1103
1535
|
setIsLoading(false);
|
|
1104
1536
|
}
|
|
1105
1537
|
}, [client, isReady, runExclusiveSafe, filter, rawIds, idsHex]);
|
|
1106
|
-
(0,
|
|
1538
|
+
(0, import_react8.useEffect)(() => {
|
|
1107
1539
|
if (!isReady) return;
|
|
1108
1540
|
refetch();
|
|
1109
1541
|
}, [isReady, refetch]);
|
|
1110
|
-
(0,
|
|
1542
|
+
(0, import_react8.useEffect)(() => {
|
|
1111
1543
|
if (!isReady || !refreshOnSync || !lastSyncTime) return;
|
|
1112
1544
|
refetch();
|
|
1113
1545
|
}, [isReady, lastSyncTime, refreshOnSync, refetch]);
|
|
1114
|
-
const record = (0,
|
|
1546
|
+
const record = (0, import_react8.useMemo)(() => {
|
|
1115
1547
|
if (!idsHex || idsHex.length !== 1) return null;
|
|
1116
|
-
return records.find((item) =>
|
|
1548
|
+
return records.find((item) => normalizeHex2(item.id().toHex()) === idsHex[0]) ?? null;
|
|
1117
1549
|
}, [records, idsHex]);
|
|
1118
|
-
const status = (0,
|
|
1550
|
+
const status = (0, import_react8.useMemo)(() => {
|
|
1119
1551
|
if (!record) return null;
|
|
1120
1552
|
const current = record.transactionStatus();
|
|
1121
1553
|
if (current.isCommitted()) return "committed";
|
|
@@ -1137,29 +1569,29 @@ function buildFilter(filter, ids, idsHex) {
|
|
|
1137
1569
|
return { filter };
|
|
1138
1570
|
}
|
|
1139
1571
|
if (!ids || ids.length === 0) {
|
|
1140
|
-
return { filter:
|
|
1572
|
+
return { filter: import_miden_sdk11.TransactionFilter.all() };
|
|
1141
1573
|
}
|
|
1142
1574
|
const allTransactionIds = ids.every((id) => typeof id !== "string");
|
|
1143
1575
|
if (allTransactionIds) {
|
|
1144
|
-
return { filter:
|
|
1576
|
+
return { filter: import_miden_sdk11.TransactionFilter.ids(ids) };
|
|
1145
1577
|
}
|
|
1146
1578
|
return {
|
|
1147
|
-
filter:
|
|
1579
|
+
filter: import_miden_sdk11.TransactionFilter.all(),
|
|
1148
1580
|
localFilterHexes: idsHex ?? []
|
|
1149
1581
|
};
|
|
1150
1582
|
}
|
|
1151
|
-
function
|
|
1583
|
+
function normalizeHex2(value) {
|
|
1152
1584
|
const trimmed = value.trim();
|
|
1153
1585
|
const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
|
|
1154
1586
|
return normalized.toLowerCase();
|
|
1155
1587
|
}
|
|
1156
1588
|
|
|
1157
1589
|
// src/hooks/useSyncState.ts
|
|
1158
|
-
var
|
|
1590
|
+
var import_react9 = require("react");
|
|
1159
1591
|
function useSyncState() {
|
|
1160
1592
|
const { sync: triggerSync } = useMiden();
|
|
1161
1593
|
const syncState = useSyncStateStore();
|
|
1162
|
-
const sync = (0,
|
|
1594
|
+
const sync = (0, import_react9.useCallback)(async () => {
|
|
1163
1595
|
await triggerSync();
|
|
1164
1596
|
}, [triggerSync]);
|
|
1165
1597
|
return {
|
|
@@ -1169,16 +1601,16 @@ function useSyncState() {
|
|
|
1169
1601
|
}
|
|
1170
1602
|
|
|
1171
1603
|
// src/hooks/useCreateWallet.ts
|
|
1172
|
-
var
|
|
1173
|
-
var
|
|
1604
|
+
var import_react10 = require("react");
|
|
1605
|
+
var import_miden_sdk12 = require("@miden-sdk/miden-sdk");
|
|
1174
1606
|
function useCreateWallet() {
|
|
1175
1607
|
const { client, isReady, sync, runExclusive } = useMiden();
|
|
1176
1608
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1177
1609
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1178
|
-
const [wallet, setWallet] = (0,
|
|
1179
|
-
const [isCreating, setIsCreating] = (0,
|
|
1180
|
-
const [error, setError] = (0,
|
|
1181
|
-
const createWallet = (0,
|
|
1610
|
+
const [wallet, setWallet] = (0, import_react10.useState)(null);
|
|
1611
|
+
const [isCreating, setIsCreating] = (0, import_react10.useState)(false);
|
|
1612
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
1613
|
+
const createWallet = (0, import_react10.useCallback)(
|
|
1182
1614
|
async (options = {}) => {
|
|
1183
1615
|
if (!client || !isReady) {
|
|
1184
1616
|
throw new Error("Miden client is not ready");
|
|
@@ -1216,7 +1648,7 @@ function useCreateWallet() {
|
|
|
1216
1648
|
},
|
|
1217
1649
|
[client, isReady, runExclusive, setAccounts]
|
|
1218
1650
|
);
|
|
1219
|
-
const reset = (0,
|
|
1651
|
+
const reset = (0, import_react10.useCallback)(() => {
|
|
1220
1652
|
setWallet(null);
|
|
1221
1653
|
setIsCreating(false);
|
|
1222
1654
|
setError(null);
|
|
@@ -1232,27 +1664,27 @@ function useCreateWallet() {
|
|
|
1232
1664
|
function getStorageMode(mode) {
|
|
1233
1665
|
switch (mode) {
|
|
1234
1666
|
case "private":
|
|
1235
|
-
return
|
|
1667
|
+
return import_miden_sdk12.AccountStorageMode.private();
|
|
1236
1668
|
case "public":
|
|
1237
|
-
return
|
|
1669
|
+
return import_miden_sdk12.AccountStorageMode.public();
|
|
1238
1670
|
case "network":
|
|
1239
|
-
return
|
|
1671
|
+
return import_miden_sdk12.AccountStorageMode.network();
|
|
1240
1672
|
default:
|
|
1241
|
-
return
|
|
1673
|
+
return import_miden_sdk12.AccountStorageMode.private();
|
|
1242
1674
|
}
|
|
1243
1675
|
}
|
|
1244
1676
|
|
|
1245
1677
|
// src/hooks/useCreateFaucet.ts
|
|
1246
|
-
var
|
|
1247
|
-
var
|
|
1678
|
+
var import_react11 = require("react");
|
|
1679
|
+
var import_miden_sdk13 = require("@miden-sdk/miden-sdk");
|
|
1248
1680
|
function useCreateFaucet() {
|
|
1249
1681
|
const { client, isReady, runExclusive } = useMiden();
|
|
1250
1682
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1251
1683
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1252
|
-
const [faucet, setFaucet] = (0,
|
|
1253
|
-
const [isCreating, setIsCreating] = (0,
|
|
1254
|
-
const [error, setError] = (0,
|
|
1255
|
-
const createFaucet = (0,
|
|
1684
|
+
const [faucet, setFaucet] = (0, import_react11.useState)(null);
|
|
1685
|
+
const [isCreating, setIsCreating] = (0, import_react11.useState)(false);
|
|
1686
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
1687
|
+
const createFaucet = (0, import_react11.useCallback)(
|
|
1256
1688
|
async (options) => {
|
|
1257
1689
|
if (!client || !isReady) {
|
|
1258
1690
|
throw new Error("Miden client is not ready");
|
|
@@ -1291,7 +1723,7 @@ function useCreateFaucet() {
|
|
|
1291
1723
|
},
|
|
1292
1724
|
[client, isReady, runExclusive, setAccounts]
|
|
1293
1725
|
);
|
|
1294
|
-
const reset = (0,
|
|
1726
|
+
const reset = (0, import_react11.useCallback)(() => {
|
|
1295
1727
|
setFaucet(null);
|
|
1296
1728
|
setIsCreating(false);
|
|
1297
1729
|
setError(null);
|
|
@@ -1307,27 +1739,27 @@ function useCreateFaucet() {
|
|
|
1307
1739
|
function getStorageMode2(mode) {
|
|
1308
1740
|
switch (mode) {
|
|
1309
1741
|
case "private":
|
|
1310
|
-
return
|
|
1742
|
+
return import_miden_sdk13.AccountStorageMode.private();
|
|
1311
1743
|
case "public":
|
|
1312
|
-
return
|
|
1744
|
+
return import_miden_sdk13.AccountStorageMode.public();
|
|
1313
1745
|
case "network":
|
|
1314
|
-
return
|
|
1746
|
+
return import_miden_sdk13.AccountStorageMode.network();
|
|
1315
1747
|
default:
|
|
1316
|
-
return
|
|
1748
|
+
return import_miden_sdk13.AccountStorageMode.private();
|
|
1317
1749
|
}
|
|
1318
1750
|
}
|
|
1319
1751
|
|
|
1320
1752
|
// src/hooks/useImportAccount.ts
|
|
1321
|
-
var
|
|
1322
|
-
var
|
|
1753
|
+
var import_react12 = require("react");
|
|
1754
|
+
var import_miden_sdk14 = require("@miden-sdk/miden-sdk");
|
|
1323
1755
|
function useImportAccount() {
|
|
1324
1756
|
const { client, isReady, runExclusive } = useMiden();
|
|
1325
1757
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1326
1758
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1327
|
-
const [account, setAccount] = (0,
|
|
1328
|
-
const [isImporting, setIsImporting] = (0,
|
|
1329
|
-
const [error, setError] = (0,
|
|
1330
|
-
const importAccount = (0,
|
|
1759
|
+
const [account, setAccount] = (0, import_react12.useState)(null);
|
|
1760
|
+
const [isImporting, setIsImporting] = (0, import_react12.useState)(false);
|
|
1761
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
1762
|
+
const importAccount = (0, import_react12.useCallback)(
|
|
1331
1763
|
async (options) => {
|
|
1332
1764
|
if (!client || !isReady) {
|
|
1333
1765
|
throw new Error("Miden client is not ready");
|
|
@@ -1422,7 +1854,7 @@ function useImportAccount() {
|
|
|
1422
1854
|
},
|
|
1423
1855
|
[client, isReady, runExclusive, setAccounts]
|
|
1424
1856
|
);
|
|
1425
|
-
const reset = (0,
|
|
1857
|
+
const reset = (0, import_react12.useCallback)(() => {
|
|
1426
1858
|
setAccount(null);
|
|
1427
1859
|
setIsImporting(false);
|
|
1428
1860
|
setError(null);
|
|
@@ -1440,10 +1872,10 @@ function resolveAccountId(accountId) {
|
|
|
1440
1872
|
}
|
|
1441
1873
|
async function resolveAccountFile(file) {
|
|
1442
1874
|
if (file instanceof Uint8Array) {
|
|
1443
|
-
return
|
|
1875
|
+
return import_miden_sdk14.AccountFile.deserialize(file);
|
|
1444
1876
|
}
|
|
1445
1877
|
if (file instanceof ArrayBuffer) {
|
|
1446
|
-
return
|
|
1878
|
+
return import_miden_sdk14.AccountFile.deserialize(new Uint8Array(file));
|
|
1447
1879
|
}
|
|
1448
1880
|
return file;
|
|
1449
1881
|
}
|
|
@@ -1472,43 +1904,146 @@ function bytesEqual(left, right) {
|
|
|
1472
1904
|
}
|
|
1473
1905
|
|
|
1474
1906
|
// src/hooks/useSend.ts
|
|
1475
|
-
var
|
|
1476
|
-
var
|
|
1907
|
+
var import_react13 = require("react");
|
|
1908
|
+
var import_miden_sdk15 = require("@miden-sdk/miden-sdk");
|
|
1909
|
+
|
|
1910
|
+
// src/utils/errors.ts
|
|
1911
|
+
var MidenError = class extends Error {
|
|
1912
|
+
constructor(message, options) {
|
|
1913
|
+
super(message);
|
|
1914
|
+
this.name = "MidenError";
|
|
1915
|
+
this.code = options?.code ?? "UNKNOWN";
|
|
1916
|
+
if (options?.cause !== void 0) {
|
|
1917
|
+
this.cause = options.cause;
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1921
|
+
var ERROR_PATTERNS = [
|
|
1922
|
+
{
|
|
1923
|
+
test: (msg) => msg.includes("_assertClass") || msg.includes("expected instance of"),
|
|
1924
|
+
code: "WASM_CLASS_MISMATCH",
|
|
1925
|
+
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."
|
|
1926
|
+
},
|
|
1927
|
+
{
|
|
1928
|
+
test: (msg) => msg.includes("null pointer") || msg.includes("already been freed") || msg.includes("dereferencing a null"),
|
|
1929
|
+
code: "WASM_POINTER_CONSUMED",
|
|
1930
|
+
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."
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
test: (msg) => msg.includes("not initialized") || msg.includes("Cannot read properties of null"),
|
|
1934
|
+
code: "WASM_NOT_INITIALIZED",
|
|
1935
|
+
message: "Miden client is not initialized. Ensure you are inside a <MidenProvider> and the client is ready before calling SDK methods."
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
test: (msg) => msg.includes("state commitment mismatch") || msg.includes("stale state"),
|
|
1939
|
+
code: "WASM_SYNC_REQUIRED",
|
|
1940
|
+
message: "Account state is stale. Call sync() before executing transactions, or ensure no concurrent transactions are running against the same account."
|
|
1941
|
+
}
|
|
1942
|
+
];
|
|
1943
|
+
function wrapWasmError(e) {
|
|
1944
|
+
if (e instanceof MidenError) return e;
|
|
1945
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1946
|
+
for (const pattern of ERROR_PATTERNS) {
|
|
1947
|
+
if (pattern.test(msg)) {
|
|
1948
|
+
return new MidenError(pattern.message, { cause: e, code: pattern.code });
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
if (e instanceof Error) return e;
|
|
1952
|
+
return new Error(msg);
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
// src/hooks/useSend.ts
|
|
1477
1956
|
function useSend() {
|
|
1478
1957
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1479
1958
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1480
|
-
const
|
|
1481
|
-
const [
|
|
1482
|
-
const [
|
|
1483
|
-
const [
|
|
1484
|
-
const
|
|
1959
|
+
const isBusyRef = (0, import_react13.useRef)(false);
|
|
1960
|
+
const [result, setResult] = (0, import_react13.useState)(null);
|
|
1961
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
|
|
1962
|
+
const [stage, setStage] = (0, import_react13.useState)("idle");
|
|
1963
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1964
|
+
const send = (0, import_react13.useCallback)(
|
|
1485
1965
|
async (options) => {
|
|
1486
1966
|
if (!client || !isReady) {
|
|
1487
1967
|
throw new Error("Miden client is not ready");
|
|
1488
1968
|
}
|
|
1969
|
+
if (isBusyRef.current) {
|
|
1970
|
+
throw new MidenError(
|
|
1971
|
+
"A send is already in progress. Await the previous send before starting another.",
|
|
1972
|
+
{ code: "SEND_BUSY" }
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
isBusyRef.current = true;
|
|
1489
1976
|
setIsLoading(true);
|
|
1490
1977
|
setStage("executing");
|
|
1491
1978
|
setError(null);
|
|
1492
1979
|
try {
|
|
1980
|
+
if (!options.skipSync) {
|
|
1981
|
+
await sync();
|
|
1982
|
+
}
|
|
1493
1983
|
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
1494
|
-
|
|
1495
|
-
|
|
1984
|
+
let amount = options.amount;
|
|
1985
|
+
if (options.sendAll) {
|
|
1986
|
+
const resolvedAmount = await runExclusiveSafe(async () => {
|
|
1987
|
+
const fromId = parseAccountId(options.from);
|
|
1988
|
+
const account = await client.getAccount(fromId);
|
|
1989
|
+
if (!account) throw new Error("Account not found");
|
|
1990
|
+
const assetIdObj = parseAccountId(options.assetId);
|
|
1991
|
+
const balance = account.vault?.()?.getBalance?.(assetIdObj);
|
|
1992
|
+
if (balance === void 0 || balance === null) {
|
|
1993
|
+
throw new Error("Could not query account balance");
|
|
1994
|
+
}
|
|
1995
|
+
const bal = BigInt(balance);
|
|
1996
|
+
if (bal === 0n) {
|
|
1997
|
+
throw new Error("Account has zero balance for this asset");
|
|
1998
|
+
}
|
|
1999
|
+
return bal;
|
|
2000
|
+
});
|
|
2001
|
+
amount = resolvedAmount;
|
|
2002
|
+
}
|
|
2003
|
+
if (amount === void 0 || amount === null) {
|
|
2004
|
+
throw new Error("Amount is required (provide amount or sendAll)");
|
|
2005
|
+
}
|
|
1496
2006
|
const assetId = options.assetId ?? options.faucetId ?? null;
|
|
1497
2007
|
if (!assetId) {
|
|
1498
2008
|
throw new Error("Asset ID is required");
|
|
1499
2009
|
}
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
toAccountId,
|
|
1505
|
-
assetIdObj,
|
|
1506
|
-
noteType,
|
|
1507
|
-
options.amount,
|
|
1508
|
-
options.recallHeight ?? null,
|
|
1509
|
-
options.timelockHeight ?? null
|
|
2010
|
+
const hasAttachment = options.attachment !== void 0 && options.attachment !== null;
|
|
2011
|
+
if (hasAttachment && (options.recallHeight != null || options.timelockHeight != null)) {
|
|
2012
|
+
throw new Error(
|
|
2013
|
+
"recallHeight and timelockHeight are not supported when attachment is provided"
|
|
1510
2014
|
);
|
|
1511
|
-
|
|
2015
|
+
}
|
|
2016
|
+
const txResult = await runExclusiveSafe(async () => {
|
|
2017
|
+
const fromAccountId = parseAccountId(options.from);
|
|
2018
|
+
const toAccountId = parseAccountId(options.to);
|
|
2019
|
+
const assetIdObj = parseAccountId(assetId);
|
|
2020
|
+
let txRequest;
|
|
2021
|
+
if (hasAttachment) {
|
|
2022
|
+
const attachment = createNoteAttachment(options.attachment);
|
|
2023
|
+
const assets = new import_miden_sdk15.NoteAssets([
|
|
2024
|
+
new import_miden_sdk15.FungibleAsset(assetIdObj, amount)
|
|
2025
|
+
]);
|
|
2026
|
+
const note = import_miden_sdk15.Note.createP2IDNote(
|
|
2027
|
+
fromAccountId,
|
|
2028
|
+
toAccountId,
|
|
2029
|
+
assets,
|
|
2030
|
+
noteType,
|
|
2031
|
+
attachment
|
|
2032
|
+
);
|
|
2033
|
+
txRequest = new import_miden_sdk15.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk15.OutputNoteArray([import_miden_sdk15.OutputNote.full(note)])).build();
|
|
2034
|
+
} else {
|
|
2035
|
+
txRequest = client.newSendTransactionRequest(
|
|
2036
|
+
fromAccountId,
|
|
2037
|
+
toAccountId,
|
|
2038
|
+
assetIdObj,
|
|
2039
|
+
noteType,
|
|
2040
|
+
amount,
|
|
2041
|
+
options.recallHeight ?? null,
|
|
2042
|
+
options.timelockHeight ?? null
|
|
2043
|
+
);
|
|
2044
|
+
}
|
|
2045
|
+
const execAccountId = parseAccountId(options.from);
|
|
2046
|
+
return await client.executeTransaction(execAccountId, txRequest);
|
|
1512
2047
|
});
|
|
1513
2048
|
setStage("proving");
|
|
1514
2049
|
const provenTransaction = await runExclusiveSafe(
|
|
@@ -1518,22 +2053,31 @@ function useSend() {
|
|
|
1518
2053
|
const submissionHeight = await runExclusiveSafe(
|
|
1519
2054
|
() => client.submitProvenTransaction(provenTransaction, txResult)
|
|
1520
2055
|
);
|
|
2056
|
+
const txIdHex = txResult.id().toHex();
|
|
2057
|
+
const txIdString = txResult.id().toString();
|
|
2058
|
+
let fullNote = null;
|
|
2059
|
+
if (noteType === import_miden_sdk15.NoteType.Private) {
|
|
2060
|
+
fullNote = extractFullNote(txResult);
|
|
2061
|
+
}
|
|
1521
2062
|
await runExclusiveSafe(
|
|
1522
2063
|
() => client.applyTransaction(txResult, submissionHeight)
|
|
1523
2064
|
);
|
|
1524
|
-
|
|
1525
|
-
await waitForTransactionCommit(client, runExclusiveSafe, txId);
|
|
1526
|
-
if (noteType === import_miden_sdk12.NoteType.Private) {
|
|
1527
|
-
const fullNote = extractFullNote(txResult);
|
|
2065
|
+
if (noteType === import_miden_sdk15.NoteType.Private) {
|
|
1528
2066
|
if (!fullNote) {
|
|
1529
2067
|
throw new Error("Missing full note for private send");
|
|
1530
2068
|
}
|
|
1531
|
-
|
|
2069
|
+
await waitForTransactionCommit(
|
|
2070
|
+
client,
|
|
2071
|
+
runExclusiveSafe,
|
|
2072
|
+
txIdHex
|
|
2073
|
+
);
|
|
2074
|
+
const recipientAccountId = parseAccountId(options.to);
|
|
2075
|
+
const recipientAddress = parseAddress(options.to, recipientAccountId);
|
|
1532
2076
|
await runExclusiveSafe(
|
|
1533
2077
|
() => client.sendPrivateNote(fullNote, recipientAddress)
|
|
1534
2078
|
);
|
|
1535
2079
|
}
|
|
1536
|
-
const txSummary = { transactionId:
|
|
2080
|
+
const txSummary = { transactionId: txIdString };
|
|
1537
2081
|
setStage("complete");
|
|
1538
2082
|
setResult(txSummary);
|
|
1539
2083
|
await sync();
|
|
@@ -1545,11 +2089,12 @@ function useSend() {
|
|
|
1545
2089
|
throw error2;
|
|
1546
2090
|
} finally {
|
|
1547
2091
|
setIsLoading(false);
|
|
2092
|
+
isBusyRef.current = false;
|
|
1548
2093
|
}
|
|
1549
2094
|
},
|
|
1550
2095
|
[client, isReady, prover, runExclusive, sync]
|
|
1551
2096
|
);
|
|
1552
|
-
const reset = (0,
|
|
2097
|
+
const reset = (0, import_react13.useCallback)(() => {
|
|
1553
2098
|
setResult(null);
|
|
1554
2099
|
setIsLoading(false);
|
|
1555
2100
|
setStage("idle");
|
|
@@ -1564,39 +2109,6 @@ function useSend() {
|
|
|
1564
2109
|
reset
|
|
1565
2110
|
};
|
|
1566
2111
|
}
|
|
1567
|
-
function getNoteType(type) {
|
|
1568
|
-
switch (type) {
|
|
1569
|
-
case "private":
|
|
1570
|
-
return import_miden_sdk12.NoteType.Private;
|
|
1571
|
-
case "public":
|
|
1572
|
-
return import_miden_sdk12.NoteType.Public;
|
|
1573
|
-
case "encrypted":
|
|
1574
|
-
return import_miden_sdk12.NoteType.Encrypted;
|
|
1575
|
-
default:
|
|
1576
|
-
return import_miden_sdk12.NoteType.Private;
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
async function waitForTransactionCommit(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
|
|
1580
|
-
let waited = 0;
|
|
1581
|
-
while (waited < maxWaitMs) {
|
|
1582
|
-
await runExclusiveSafe(() => client.syncState());
|
|
1583
|
-
const [record] = await runExclusiveSafe(
|
|
1584
|
-
() => client.getTransactions(import_miden_sdk12.TransactionFilter.ids([txId]))
|
|
1585
|
-
);
|
|
1586
|
-
if (record) {
|
|
1587
|
-
const status = record.transactionStatus();
|
|
1588
|
-
if (status.isCommitted()) {
|
|
1589
|
-
return;
|
|
1590
|
-
}
|
|
1591
|
-
if (status.isDiscarded()) {
|
|
1592
|
-
throw new Error("Transaction was discarded before commit");
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1596
|
-
waited += delayMs;
|
|
1597
|
-
}
|
|
1598
|
-
throw new Error("Timeout waiting for transaction commit");
|
|
1599
|
-
}
|
|
1600
2112
|
function extractFullNote(txResult) {
|
|
1601
2113
|
try {
|
|
1602
2114
|
const executedTx = txResult.executedTransaction?.();
|
|
@@ -1609,16 +2121,17 @@ function extractFullNote(txResult) {
|
|
|
1609
2121
|
}
|
|
1610
2122
|
|
|
1611
2123
|
// src/hooks/useMultiSend.ts
|
|
1612
|
-
var
|
|
1613
|
-
var
|
|
2124
|
+
var import_react14 = require("react");
|
|
2125
|
+
var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
|
|
1614
2126
|
function useMultiSend() {
|
|
1615
2127
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1616
2128
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1617
|
-
const
|
|
1618
|
-
const [
|
|
1619
|
-
const [
|
|
1620
|
-
const [
|
|
1621
|
-
const
|
|
2129
|
+
const isBusyRef = (0, import_react14.useRef)(false);
|
|
2130
|
+
const [result, setResult] = (0, import_react14.useState)(null);
|
|
2131
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
|
|
2132
|
+
const [stage, setStage] = (0, import_react14.useState)("idle");
|
|
2133
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
2134
|
+
const sendMany = (0, import_react14.useCallback)(
|
|
1622
2135
|
async (options) => {
|
|
1623
2136
|
if (!client || !isReady) {
|
|
1624
2137
|
throw new Error("Miden client is not ready");
|
|
@@ -1626,35 +2139,53 @@ function useMultiSend() {
|
|
|
1626
2139
|
if (options.recipients.length === 0) {
|
|
1627
2140
|
throw new Error("No recipients provided");
|
|
1628
2141
|
}
|
|
2142
|
+
if (isBusyRef.current) {
|
|
2143
|
+
throw new MidenError(
|
|
2144
|
+
"A send is already in progress. Await the previous send before starting another.",
|
|
2145
|
+
{ code: "SEND_BUSY" }
|
|
2146
|
+
);
|
|
2147
|
+
}
|
|
2148
|
+
isBusyRef.current = true;
|
|
1629
2149
|
setIsLoading(true);
|
|
1630
2150
|
setStage("executing");
|
|
1631
2151
|
setError(null);
|
|
1632
2152
|
try {
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
const
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
receiverId
|
|
1642
|
-
assets
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
2153
|
+
if (!options.skipSync) {
|
|
2154
|
+
await sync();
|
|
2155
|
+
}
|
|
2156
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2157
|
+
const outputs = options.recipients.map(
|
|
2158
|
+
({ to, amount, attachment, noteType: recipientNoteType }) => {
|
|
2159
|
+
const iterSenderId = parseAccountId(options.from);
|
|
2160
|
+
const iterAssetId = parseAccountId(options.assetId);
|
|
2161
|
+
const receiverId = parseAccountId(to);
|
|
2162
|
+
const assets = new import_miden_sdk16.NoteAssets([
|
|
2163
|
+
new import_miden_sdk16.FungibleAsset(iterAssetId, amount)
|
|
2164
|
+
]);
|
|
2165
|
+
const resolvedNoteType = recipientNoteType ? getNoteType(recipientNoteType) : noteType;
|
|
2166
|
+
const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new import_miden_sdk16.NoteAttachment();
|
|
2167
|
+
const note = import_miden_sdk16.Note.createP2IDNote(
|
|
2168
|
+
iterSenderId,
|
|
2169
|
+
receiverId,
|
|
2170
|
+
assets,
|
|
2171
|
+
resolvedNoteType,
|
|
2172
|
+
noteAttachment
|
|
2173
|
+
);
|
|
2174
|
+
const recipientAddress = parseAddress(to, receiverId);
|
|
2175
|
+
return {
|
|
2176
|
+
outputNote: import_miden_sdk16.OutputNote.full(note),
|
|
2177
|
+
note,
|
|
2178
|
+
recipientAddress,
|
|
2179
|
+
noteType: resolvedNoteType
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
2182
|
+
);
|
|
2183
|
+
const txRequest = new import_miden_sdk16.TransactionRequestBuilder().withOwnOutputNotes(
|
|
2184
|
+
new import_miden_sdk16.OutputNoteArray(outputs.map((o) => o.outputNote))
|
|
1655
2185
|
).build();
|
|
2186
|
+
const txSenderId = parseAccountId(options.from);
|
|
1656
2187
|
const txResult = await runExclusiveSafe(
|
|
1657
|
-
() => client.executeTransaction(
|
|
2188
|
+
() => client.executeTransaction(txSenderId, txRequest)
|
|
1658
2189
|
);
|
|
1659
2190
|
setStage("proving");
|
|
1660
2191
|
const provenTransaction = await runExclusiveSafe(
|
|
@@ -1664,23 +2195,27 @@ function useMultiSend() {
|
|
|
1664
2195
|
const submissionHeight = await runExclusiveSafe(
|
|
1665
2196
|
() => client.submitProvenTransaction(provenTransaction, txResult)
|
|
1666
2197
|
);
|
|
2198
|
+
const txIdHex = txResult.id().toHex();
|
|
2199
|
+
const txIdString = txResult.id().toString();
|
|
1667
2200
|
await runExclusiveSafe(
|
|
1668
2201
|
() => client.applyTransaction(txResult, submissionHeight)
|
|
1669
2202
|
);
|
|
1670
|
-
const
|
|
1671
|
-
if (
|
|
1672
|
-
await
|
|
2203
|
+
const hasPrivate = outputs.some((o) => o.noteType === import_miden_sdk16.NoteType.Private);
|
|
2204
|
+
if (hasPrivate) {
|
|
2205
|
+
await waitForTransactionCommit(
|
|
1673
2206
|
client,
|
|
1674
2207
|
runExclusiveSafe,
|
|
1675
|
-
|
|
2208
|
+
txIdHex
|
|
1676
2209
|
);
|
|
1677
2210
|
for (const output of outputs) {
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
2211
|
+
if (output.noteType === import_miden_sdk16.NoteType.Private) {
|
|
2212
|
+
await runExclusiveSafe(
|
|
2213
|
+
() => client.sendPrivateNote(output.note, output.recipientAddress)
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
1681
2216
|
}
|
|
1682
2217
|
}
|
|
1683
|
-
const txSummary = { transactionId:
|
|
2218
|
+
const txSummary = { transactionId: txIdString };
|
|
1684
2219
|
setStage("complete");
|
|
1685
2220
|
setResult(txSummary);
|
|
1686
2221
|
await sync();
|
|
@@ -1692,11 +2227,12 @@ function useMultiSend() {
|
|
|
1692
2227
|
throw error2;
|
|
1693
2228
|
} finally {
|
|
1694
2229
|
setIsLoading(false);
|
|
2230
|
+
isBusyRef.current = false;
|
|
1695
2231
|
}
|
|
1696
2232
|
},
|
|
1697
2233
|
[client, isReady, prover, runExclusive, sync]
|
|
1698
2234
|
);
|
|
1699
|
-
const reset = (0,
|
|
2235
|
+
const reset = (0, import_react14.useCallback)(() => {
|
|
1700
2236
|
setResult(null);
|
|
1701
2237
|
setIsLoading(false);
|
|
1702
2238
|
setStage("idle");
|
|
@@ -1711,71 +2247,38 @@ function useMultiSend() {
|
|
|
1711
2247
|
reset
|
|
1712
2248
|
};
|
|
1713
2249
|
}
|
|
1714
|
-
function getNoteType2(type) {
|
|
1715
|
-
switch (type) {
|
|
1716
|
-
case "private":
|
|
1717
|
-
return import_miden_sdk13.NoteType.Private;
|
|
1718
|
-
case "public":
|
|
1719
|
-
return import_miden_sdk13.NoteType.Public;
|
|
1720
|
-
case "encrypted":
|
|
1721
|
-
return import_miden_sdk13.NoteType.Encrypted;
|
|
1722
|
-
default:
|
|
1723
|
-
return import_miden_sdk13.NoteType.Private;
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
|
|
1727
|
-
let waited = 0;
|
|
1728
|
-
while (waited < maxWaitMs) {
|
|
1729
|
-
await runExclusiveSafe(() => client.syncState());
|
|
1730
|
-
const [record] = await runExclusiveSafe(
|
|
1731
|
-
() => client.getTransactions(import_miden_sdk13.TransactionFilter.ids([txId]))
|
|
1732
|
-
);
|
|
1733
|
-
if (record) {
|
|
1734
|
-
const status = record.transactionStatus();
|
|
1735
|
-
if (status.isCommitted()) {
|
|
1736
|
-
return;
|
|
1737
|
-
}
|
|
1738
|
-
if (status.isDiscarded()) {
|
|
1739
|
-
throw new Error("Transaction was discarded before commit");
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1743
|
-
waited += delayMs;
|
|
1744
|
-
}
|
|
1745
|
-
throw new Error("Timeout waiting for transaction commit");
|
|
1746
|
-
}
|
|
1747
2250
|
|
|
1748
2251
|
// src/hooks/useInternalTransfer.ts
|
|
1749
|
-
var
|
|
1750
|
-
var
|
|
2252
|
+
var import_react15 = require("react");
|
|
2253
|
+
var import_miden_sdk17 = require("@miden-sdk/miden-sdk");
|
|
1751
2254
|
function useInternalTransfer() {
|
|
1752
2255
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1753
2256
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1754
|
-
const [result, setResult] = (0,
|
|
1755
|
-
const [isLoading, setIsLoading] = (0,
|
|
1756
|
-
const [stage, setStage] = (0,
|
|
1757
|
-
const [error, setError] = (0,
|
|
1758
|
-
const transferOnce = (0,
|
|
2257
|
+
const [result, setResult] = (0, import_react15.useState)(null);
|
|
2258
|
+
const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
|
|
2259
|
+
const [stage, setStage] = (0, import_react15.useState)("idle");
|
|
2260
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
2261
|
+
const transferOnce = (0, import_react15.useCallback)(
|
|
1759
2262
|
async (options) => {
|
|
1760
2263
|
if (!client || !isReady) {
|
|
1761
2264
|
throw new Error("Miden client is not ready");
|
|
1762
2265
|
}
|
|
1763
|
-
const noteType =
|
|
2266
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
1764
2267
|
const senderId = parseAccountId(options.from);
|
|
1765
2268
|
const receiverId = parseAccountId(options.to);
|
|
1766
2269
|
const assetId = parseAccountId(options.assetId);
|
|
1767
|
-
const assets = new
|
|
1768
|
-
new
|
|
2270
|
+
const assets = new import_miden_sdk17.NoteAssets([
|
|
2271
|
+
new import_miden_sdk17.FungibleAsset(assetId, options.amount)
|
|
1769
2272
|
]);
|
|
1770
|
-
const note =
|
|
2273
|
+
const note = import_miden_sdk17.Note.createP2IDNote(
|
|
1771
2274
|
senderId,
|
|
1772
2275
|
receiverId,
|
|
1773
2276
|
assets,
|
|
1774
2277
|
noteType,
|
|
1775
|
-
new
|
|
2278
|
+
new import_miden_sdk17.NoteAttachment()
|
|
1776
2279
|
);
|
|
1777
2280
|
const noteId = note.id().toString();
|
|
1778
|
-
const createRequest = new
|
|
2281
|
+
const createRequest = new import_miden_sdk17.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk17.OutputNoteArray([import_miden_sdk17.OutputNote.full(note)])).build();
|
|
1779
2282
|
const createTxId = await runExclusiveSafe(
|
|
1780
2283
|
() => prover ? client.submitNewTransactionWithProver(
|
|
1781
2284
|
senderId,
|
|
@@ -1783,7 +2286,7 @@ function useInternalTransfer() {
|
|
|
1783
2286
|
prover
|
|
1784
2287
|
) : client.submitNewTransaction(senderId, createRequest)
|
|
1785
2288
|
);
|
|
1786
|
-
const consumeRequest = new
|
|
2289
|
+
const consumeRequest = new import_miden_sdk17.TransactionRequestBuilder().withInputNotes(new import_miden_sdk17.NoteAndArgsArray([new import_miden_sdk17.NoteAndArgs(note, null)])).build();
|
|
1787
2290
|
const consumeTxId = await runExclusiveSafe(
|
|
1788
2291
|
() => prover ? client.submitNewTransactionWithProver(
|
|
1789
2292
|
receiverId,
|
|
@@ -1799,7 +2302,7 @@ function useInternalTransfer() {
|
|
|
1799
2302
|
},
|
|
1800
2303
|
[client, isReady, prover, runExclusiveSafe]
|
|
1801
2304
|
);
|
|
1802
|
-
const transfer = (0,
|
|
2305
|
+
const transfer = (0, import_react15.useCallback)(
|
|
1803
2306
|
async (options) => {
|
|
1804
2307
|
if (!client || !isReady) {
|
|
1805
2308
|
throw new Error("Miden client is not ready");
|
|
@@ -1825,7 +2328,7 @@ function useInternalTransfer() {
|
|
|
1825
2328
|
},
|
|
1826
2329
|
[client, isReady, sync, transferOnce]
|
|
1827
2330
|
);
|
|
1828
|
-
const transferChain = (0,
|
|
2331
|
+
const transferChain = (0, import_react15.useCallback)(
|
|
1829
2332
|
async (options) => {
|
|
1830
2333
|
if (!client || !isReady) {
|
|
1831
2334
|
throw new Error("Miden client is not ready");
|
|
@@ -1866,7 +2369,7 @@ function useInternalTransfer() {
|
|
|
1866
2369
|
},
|
|
1867
2370
|
[client, isReady, sync, transferOnce]
|
|
1868
2371
|
);
|
|
1869
|
-
const reset = (0,
|
|
2372
|
+
const reset = (0, import_react15.useCallback)(() => {
|
|
1870
2373
|
setResult(null);
|
|
1871
2374
|
setIsLoading(false);
|
|
1872
2375
|
setStage("idle");
|
|
@@ -1882,47 +2385,35 @@ function useInternalTransfer() {
|
|
|
1882
2385
|
reset
|
|
1883
2386
|
};
|
|
1884
2387
|
}
|
|
1885
|
-
function getNoteType3(type) {
|
|
1886
|
-
switch (type) {
|
|
1887
|
-
case "private":
|
|
1888
|
-
return import_miden_sdk14.NoteType.Private;
|
|
1889
|
-
case "public":
|
|
1890
|
-
return import_miden_sdk14.NoteType.Public;
|
|
1891
|
-
case "encrypted":
|
|
1892
|
-
return import_miden_sdk14.NoteType.Encrypted;
|
|
1893
|
-
default:
|
|
1894
|
-
return import_miden_sdk14.NoteType.Private;
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
2388
|
|
|
1898
2389
|
// src/hooks/useWaitForCommit.ts
|
|
1899
|
-
var
|
|
1900
|
-
var
|
|
2390
|
+
var import_react16 = require("react");
|
|
2391
|
+
var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
|
|
1901
2392
|
function useWaitForCommit() {
|
|
1902
2393
|
const { client, isReady, runExclusive } = useMiden();
|
|
1903
2394
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1904
|
-
const waitForCommit = (0,
|
|
2395
|
+
const waitForCommit = (0, import_react16.useCallback)(
|
|
1905
2396
|
async (txId, options) => {
|
|
1906
2397
|
if (!client || !isReady) {
|
|
1907
2398
|
throw new Error("Miden client is not ready");
|
|
1908
2399
|
}
|
|
1909
2400
|
const timeoutMs = Math.max(0, options?.timeoutMs ?? 1e4);
|
|
1910
2401
|
const intervalMs = Math.max(1, options?.intervalMs ?? 1e3);
|
|
1911
|
-
const targetHex =
|
|
2402
|
+
const targetHex = normalizeHex3(
|
|
1912
2403
|
typeof txId === "string" ? txId : txId.toHex()
|
|
1913
2404
|
);
|
|
1914
|
-
|
|
1915
|
-
while (
|
|
2405
|
+
const deadline = Date.now() + timeoutMs;
|
|
2406
|
+
while (Date.now() < deadline) {
|
|
1916
2407
|
await runExclusiveSafe(
|
|
1917
2408
|
() => client.syncState()
|
|
1918
2409
|
);
|
|
1919
2410
|
const records = await runExclusiveSafe(
|
|
1920
2411
|
() => client.getTransactions(
|
|
1921
|
-
typeof txId === "string" ?
|
|
2412
|
+
typeof txId === "string" ? import_miden_sdk18.TransactionFilter.all() : import_miden_sdk18.TransactionFilter.ids([txId])
|
|
1922
2413
|
)
|
|
1923
2414
|
);
|
|
1924
2415
|
const record = records.find(
|
|
1925
|
-
(item) =>
|
|
2416
|
+
(item) => normalizeHex3(item.id().toHex()) === targetHex
|
|
1926
2417
|
);
|
|
1927
2418
|
if (record) {
|
|
1928
2419
|
const status = record.transactionStatus();
|
|
@@ -1934,7 +2425,6 @@ function useWaitForCommit() {
|
|
|
1934
2425
|
}
|
|
1935
2426
|
}
|
|
1936
2427
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
1937
|
-
waited += intervalMs;
|
|
1938
2428
|
}
|
|
1939
2429
|
throw new Error("Timeout waiting for transaction commit");
|
|
1940
2430
|
},
|
|
@@ -1942,18 +2432,18 @@ function useWaitForCommit() {
|
|
|
1942
2432
|
);
|
|
1943
2433
|
return { waitForCommit };
|
|
1944
2434
|
}
|
|
1945
|
-
function
|
|
2435
|
+
function normalizeHex3(value) {
|
|
1946
2436
|
const trimmed = value.trim();
|
|
1947
2437
|
const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
|
|
1948
2438
|
return normalized.toLowerCase();
|
|
1949
2439
|
}
|
|
1950
2440
|
|
|
1951
2441
|
// src/hooks/useWaitForNotes.ts
|
|
1952
|
-
var
|
|
2442
|
+
var import_react17 = require("react");
|
|
1953
2443
|
function useWaitForNotes() {
|
|
1954
2444
|
const { client, isReady, runExclusive } = useMiden();
|
|
1955
2445
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1956
|
-
const waitForConsumableNotes = (0,
|
|
2446
|
+
const waitForConsumableNotes = (0, import_react17.useCallback)(
|
|
1957
2447
|
async (options) => {
|
|
1958
2448
|
if (!client || !isReady) {
|
|
1959
2449
|
throw new Error("Miden client is not ready");
|
|
@@ -1964,7 +2454,9 @@ function useWaitForNotes() {
|
|
|
1964
2454
|
const accountId = parseAccountId(options.accountId);
|
|
1965
2455
|
let waited = 0;
|
|
1966
2456
|
while (waited < timeoutMs) {
|
|
1967
|
-
await runExclusiveSafe(
|
|
2457
|
+
await runExclusiveSafe(
|
|
2458
|
+
() => client.syncState()
|
|
2459
|
+
);
|
|
1968
2460
|
const notes = await runExclusiveSafe(
|
|
1969
2461
|
() => client.getConsumableNotes(accountId)
|
|
1970
2462
|
);
|
|
@@ -1982,16 +2474,15 @@ function useWaitForNotes() {
|
|
|
1982
2474
|
}
|
|
1983
2475
|
|
|
1984
2476
|
// src/hooks/useMint.ts
|
|
1985
|
-
var
|
|
1986
|
-
var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
|
|
2477
|
+
var import_react18 = require("react");
|
|
1987
2478
|
function useMint() {
|
|
1988
2479
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1989
2480
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1990
|
-
const [result, setResult] = (0,
|
|
1991
|
-
const [isLoading, setIsLoading] = (0,
|
|
1992
|
-
const [stage, setStage] = (0,
|
|
1993
|
-
const [error, setError] = (0,
|
|
1994
|
-
const mint = (0,
|
|
2481
|
+
const [result, setResult] = (0, import_react18.useState)(null);
|
|
2482
|
+
const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
|
|
2483
|
+
const [stage, setStage] = (0, import_react18.useState)("idle");
|
|
2484
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
2485
|
+
const mint = (0, import_react18.useCallback)(
|
|
1995
2486
|
async (options) => {
|
|
1996
2487
|
if (!client || !isReady) {
|
|
1997
2488
|
throw new Error("Miden client is not ready");
|
|
@@ -2000,7 +2491,7 @@ function useMint() {
|
|
|
2000
2491
|
setStage("executing");
|
|
2001
2492
|
setError(null);
|
|
2002
2493
|
try {
|
|
2003
|
-
const noteType =
|
|
2494
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2004
2495
|
const targetAccountIdObj = parseAccountId(options.targetAccountId);
|
|
2005
2496
|
const faucetIdObj = parseAccountId(options.faucetId);
|
|
2006
2497
|
setStage("proving");
|
|
@@ -2033,7 +2524,7 @@ function useMint() {
|
|
|
2033
2524
|
},
|
|
2034
2525
|
[client, isReady, prover, runExclusive, sync]
|
|
2035
2526
|
);
|
|
2036
|
-
const reset = (0,
|
|
2527
|
+
const reset = (0, import_react18.useCallback)(() => {
|
|
2037
2528
|
setResult(null);
|
|
2038
2529
|
setIsLoading(false);
|
|
2039
2530
|
setStage("idle");
|
|
@@ -2048,30 +2539,18 @@ function useMint() {
|
|
|
2048
2539
|
reset
|
|
2049
2540
|
};
|
|
2050
2541
|
}
|
|
2051
|
-
function getNoteType4(type) {
|
|
2052
|
-
switch (type) {
|
|
2053
|
-
case "private":
|
|
2054
|
-
return import_miden_sdk16.NoteType.Private;
|
|
2055
|
-
case "public":
|
|
2056
|
-
return import_miden_sdk16.NoteType.Public;
|
|
2057
|
-
case "encrypted":
|
|
2058
|
-
return import_miden_sdk16.NoteType.Encrypted;
|
|
2059
|
-
default:
|
|
2060
|
-
return import_miden_sdk16.NoteType.Private;
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
2542
|
|
|
2064
2543
|
// src/hooks/useConsume.ts
|
|
2065
|
-
var
|
|
2066
|
-
var
|
|
2544
|
+
var import_react19 = require("react");
|
|
2545
|
+
var import_miden_sdk19 = require("@miden-sdk/miden-sdk");
|
|
2067
2546
|
function useConsume() {
|
|
2068
2547
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2069
2548
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2070
|
-
const [result, setResult] = (0,
|
|
2071
|
-
const [isLoading, setIsLoading] = (0,
|
|
2072
|
-
const [stage, setStage] = (0,
|
|
2073
|
-
const [error, setError] = (0,
|
|
2074
|
-
const consume = (0,
|
|
2549
|
+
const [result, setResult] = (0, import_react19.useState)(null);
|
|
2550
|
+
const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
|
|
2551
|
+
const [stage, setStage] = (0, import_react19.useState)("idle");
|
|
2552
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
2553
|
+
const consume = (0, import_react19.useCallback)(
|
|
2075
2554
|
async (options) => {
|
|
2076
2555
|
if (!client || !isReady) {
|
|
2077
2556
|
throw new Error("Miden client is not ready");
|
|
@@ -2087,9 +2566,9 @@ function useConsume() {
|
|
|
2087
2566
|
setStage("proving");
|
|
2088
2567
|
const txResult = await runExclusiveSafe(async () => {
|
|
2089
2568
|
const noteIds = options.noteIds.map(
|
|
2090
|
-
(noteId) =>
|
|
2569
|
+
(noteId) => import_miden_sdk19.NoteId.fromHex(noteId)
|
|
2091
2570
|
);
|
|
2092
|
-
const filter = new
|
|
2571
|
+
const filter = new import_miden_sdk19.NoteFilter(import_miden_sdk19.NoteFilterTypes.List, noteIds);
|
|
2093
2572
|
const noteRecords = await client.getInputNotes(filter);
|
|
2094
2573
|
const notes = noteRecords.map((record) => record.toNote());
|
|
2095
2574
|
if (notes.length === 0) {
|
|
@@ -2121,7 +2600,7 @@ function useConsume() {
|
|
|
2121
2600
|
},
|
|
2122
2601
|
[client, isReady, prover, runExclusive, sync]
|
|
2123
2602
|
);
|
|
2124
|
-
const reset = (0,
|
|
2603
|
+
const reset = (0, import_react19.useCallback)(() => {
|
|
2125
2604
|
setResult(null);
|
|
2126
2605
|
setIsLoading(false);
|
|
2127
2606
|
setStage("idle");
|
|
@@ -2138,16 +2617,15 @@ function useConsume() {
|
|
|
2138
2617
|
}
|
|
2139
2618
|
|
|
2140
2619
|
// src/hooks/useSwap.ts
|
|
2141
|
-
var
|
|
2142
|
-
var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
|
|
2620
|
+
var import_react20 = require("react");
|
|
2143
2621
|
function useSwap() {
|
|
2144
2622
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2145
2623
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2146
|
-
const [result, setResult] = (0,
|
|
2147
|
-
const [isLoading, setIsLoading] = (0,
|
|
2148
|
-
const [stage, setStage] = (0,
|
|
2149
|
-
const [error, setError] = (0,
|
|
2150
|
-
const swap = (0,
|
|
2624
|
+
const [result, setResult] = (0, import_react20.useState)(null);
|
|
2625
|
+
const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
|
|
2626
|
+
const [stage, setStage] = (0, import_react20.useState)("idle");
|
|
2627
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
2628
|
+
const swap = (0, import_react20.useCallback)(
|
|
2151
2629
|
async (options) => {
|
|
2152
2630
|
if (!client || !isReady) {
|
|
2153
2631
|
throw new Error("Miden client is not ready");
|
|
@@ -2156,8 +2634,8 @@ function useSwap() {
|
|
|
2156
2634
|
setStage("executing");
|
|
2157
2635
|
setError(null);
|
|
2158
2636
|
try {
|
|
2159
|
-
const noteType =
|
|
2160
|
-
const paybackNoteType =
|
|
2637
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2638
|
+
const paybackNoteType = getNoteType(
|
|
2161
2639
|
options.paybackNoteType ?? DEFAULTS.NOTE_TYPE
|
|
2162
2640
|
);
|
|
2163
2641
|
const accountIdObj = parseAccountId(options.accountId);
|
|
@@ -2196,7 +2674,7 @@ function useSwap() {
|
|
|
2196
2674
|
},
|
|
2197
2675
|
[client, isReady, prover, runExclusive, sync]
|
|
2198
2676
|
);
|
|
2199
|
-
const reset = (0,
|
|
2677
|
+
const reset = (0, import_react20.useCallback)(() => {
|
|
2200
2678
|
setResult(null);
|
|
2201
2679
|
setIsLoading(false);
|
|
2202
2680
|
setStage("idle");
|
|
@@ -2211,41 +2689,40 @@ function useSwap() {
|
|
|
2211
2689
|
reset
|
|
2212
2690
|
};
|
|
2213
2691
|
}
|
|
2214
|
-
function getNoteType5(type) {
|
|
2215
|
-
switch (type) {
|
|
2216
|
-
case "private":
|
|
2217
|
-
return import_miden_sdk18.NoteType.Private;
|
|
2218
|
-
case "public":
|
|
2219
|
-
return import_miden_sdk18.NoteType.Public;
|
|
2220
|
-
case "encrypted":
|
|
2221
|
-
return import_miden_sdk18.NoteType.Encrypted;
|
|
2222
|
-
default:
|
|
2223
|
-
return import_miden_sdk18.NoteType.Private;
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
2692
|
|
|
2227
2693
|
// src/hooks/useTransaction.ts
|
|
2228
|
-
var
|
|
2694
|
+
var import_react21 = require("react");
|
|
2229
2695
|
function useTransaction() {
|
|
2230
2696
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2231
2697
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2232
|
-
const
|
|
2233
|
-
const [
|
|
2234
|
-
const [
|
|
2235
|
-
const [
|
|
2236
|
-
const
|
|
2698
|
+
const isBusyRef = (0, import_react21.useRef)(false);
|
|
2699
|
+
const [result, setResult] = (0, import_react21.useState)(null);
|
|
2700
|
+
const [isLoading, setIsLoading] = (0, import_react21.useState)(false);
|
|
2701
|
+
const [stage, setStage] = (0, import_react21.useState)("idle");
|
|
2702
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
2703
|
+
const execute = (0, import_react21.useCallback)(
|
|
2237
2704
|
async (options) => {
|
|
2238
2705
|
if (!client || !isReady) {
|
|
2239
2706
|
throw new Error("Miden client is not ready");
|
|
2240
2707
|
}
|
|
2708
|
+
if (isBusyRef.current) {
|
|
2709
|
+
throw new MidenError(
|
|
2710
|
+
"A transaction is already in progress. Await the previous transaction before starting another.",
|
|
2711
|
+
{ code: "SEND_BUSY" }
|
|
2712
|
+
);
|
|
2713
|
+
}
|
|
2714
|
+
isBusyRef.current = true;
|
|
2241
2715
|
setIsLoading(true);
|
|
2242
2716
|
setStage("executing");
|
|
2243
2717
|
setError(null);
|
|
2244
2718
|
try {
|
|
2719
|
+
if (!options.skipSync) {
|
|
2720
|
+
await sync();
|
|
2721
|
+
}
|
|
2722
|
+
const txRequest = await resolveRequest(options.request, client);
|
|
2245
2723
|
setStage("proving");
|
|
2246
2724
|
const txResult = await runExclusiveSafe(async () => {
|
|
2247
2725
|
const accountIdObj = resolveAccountId2(options.accountId);
|
|
2248
|
-
const txRequest = await resolveRequest(options.request, client);
|
|
2249
2726
|
const txId = prover ? await client.submitNewTransactionWithProver(
|
|
2250
2727
|
accountIdObj,
|
|
2251
2728
|
txRequest,
|
|
@@ -2264,11 +2741,12 @@ function useTransaction() {
|
|
|
2264
2741
|
throw error2;
|
|
2265
2742
|
} finally {
|
|
2266
2743
|
setIsLoading(false);
|
|
2744
|
+
isBusyRef.current = false;
|
|
2267
2745
|
}
|
|
2268
2746
|
},
|
|
2269
2747
|
[client, isReady, prover, runExclusive, sync]
|
|
2270
2748
|
);
|
|
2271
|
-
const reset = (0,
|
|
2749
|
+
const reset = (0, import_react21.useCallback)(() => {
|
|
2272
2750
|
setResult(null);
|
|
2273
2751
|
setIsLoading(false);
|
|
2274
2752
|
setStage("idle");
|
|
@@ -2293,17 +2771,338 @@ async function resolveRequest(request, client) {
|
|
|
2293
2771
|
return request;
|
|
2294
2772
|
}
|
|
2295
2773
|
|
|
2774
|
+
// src/hooks/useSessionAccount.ts
|
|
2775
|
+
var import_react22 = require("react");
|
|
2776
|
+
var import_miden_sdk20 = require("@miden-sdk/miden-sdk");
|
|
2777
|
+
function useSessionAccount(options) {
|
|
2778
|
+
const { client, isReady, sync, runExclusive } = useMiden();
|
|
2779
|
+
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2780
|
+
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
2781
|
+
const [sessionAccountId, setSessionAccountId] = (0, import_react22.useState)(null);
|
|
2782
|
+
const [step, setStep] = (0, import_react22.useState)("idle");
|
|
2783
|
+
const [error, setError] = (0, import_react22.useState)(null);
|
|
2784
|
+
const cancelledRef = (0, import_react22.useRef)(false);
|
|
2785
|
+
const isBusyRef = (0, import_react22.useRef)(false);
|
|
2786
|
+
const storagePrefix = options.storagePrefix ?? "miden-session";
|
|
2787
|
+
const pollIntervalMs = options.pollIntervalMs ?? 3e3;
|
|
2788
|
+
const maxWaitMs = options.maxWaitMs ?? 6e4;
|
|
2789
|
+
const storageMode = options.walletOptions?.storageMode ?? "public";
|
|
2790
|
+
const mutable = options.walletOptions?.mutable ?? DEFAULTS.WALLET_MUTABLE;
|
|
2791
|
+
const authScheme = options.walletOptions?.authScheme ?? DEFAULTS.AUTH_SCHEME;
|
|
2792
|
+
const fundRef = (0, import_react22.useRef)(options.fund);
|
|
2793
|
+
fundRef.current = options.fund;
|
|
2794
|
+
(0, import_react22.useEffect)(() => {
|
|
2795
|
+
try {
|
|
2796
|
+
const stored = localStorage.getItem(`${storagePrefix}:accountId`);
|
|
2797
|
+
const storedReady = localStorage.getItem(`${storagePrefix}:ready`);
|
|
2798
|
+
if (stored && stored.length > 0) {
|
|
2799
|
+
const validationId = parseAccountId(stored);
|
|
2800
|
+
validationId?.free?.();
|
|
2801
|
+
setSessionAccountId(stored);
|
|
2802
|
+
if (storedReady === "true") {
|
|
2803
|
+
setStep("ready");
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
} catch {
|
|
2807
|
+
localStorage.removeItem(`${storagePrefix}:accountId`);
|
|
2808
|
+
localStorage.removeItem(`${storagePrefix}:ready`);
|
|
2809
|
+
}
|
|
2810
|
+
}, [storagePrefix]);
|
|
2811
|
+
const initialize = (0, import_react22.useCallback)(async () => {
|
|
2812
|
+
if (!client || !isReady) {
|
|
2813
|
+
throw new Error("Miden client is not ready");
|
|
2814
|
+
}
|
|
2815
|
+
if (isBusyRef.current) {
|
|
2816
|
+
throw new MidenError(
|
|
2817
|
+
"Session account initialization is already in progress.",
|
|
2818
|
+
{ code: "OPERATION_BUSY" }
|
|
2819
|
+
);
|
|
2820
|
+
}
|
|
2821
|
+
isBusyRef.current = true;
|
|
2822
|
+
cancelledRef.current = false;
|
|
2823
|
+
setError(null);
|
|
2824
|
+
try {
|
|
2825
|
+
let walletId = sessionAccountId;
|
|
2826
|
+
if (!walletId) {
|
|
2827
|
+
setStep("creating");
|
|
2828
|
+
const resolvedStorageMode = getStorageMode3(storageMode);
|
|
2829
|
+
const wallet = await runExclusiveSafe(async () => {
|
|
2830
|
+
const w = await client.newWallet(
|
|
2831
|
+
resolvedStorageMode,
|
|
2832
|
+
mutable,
|
|
2833
|
+
authScheme
|
|
2834
|
+
);
|
|
2835
|
+
ensureAccountBech32(w);
|
|
2836
|
+
const accounts = await client.getAccounts();
|
|
2837
|
+
setAccounts(accounts);
|
|
2838
|
+
return w;
|
|
2839
|
+
});
|
|
2840
|
+
if (cancelledRef.current) return;
|
|
2841
|
+
walletId = wallet.id().toString();
|
|
2842
|
+
setSessionAccountId(walletId);
|
|
2843
|
+
localStorage.setItem(`${storagePrefix}:accountId`, walletId);
|
|
2844
|
+
}
|
|
2845
|
+
setStep("funding");
|
|
2846
|
+
await fundRef.current(walletId);
|
|
2847
|
+
if (cancelledRef.current) return;
|
|
2848
|
+
setStep("consuming");
|
|
2849
|
+
await waitAndConsume(
|
|
2850
|
+
client,
|
|
2851
|
+
runExclusiveSafe,
|
|
2852
|
+
walletId,
|
|
2853
|
+
pollIntervalMs,
|
|
2854
|
+
maxWaitMs,
|
|
2855
|
+
cancelledRef
|
|
2856
|
+
);
|
|
2857
|
+
if (cancelledRef.current) return;
|
|
2858
|
+
setStep("ready");
|
|
2859
|
+
localStorage.setItem(`${storagePrefix}:ready`, "true");
|
|
2860
|
+
await sync();
|
|
2861
|
+
} catch (err) {
|
|
2862
|
+
if (!cancelledRef.current) {
|
|
2863
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2864
|
+
setError(error2);
|
|
2865
|
+
setStep("idle");
|
|
2866
|
+
throw error2;
|
|
2867
|
+
}
|
|
2868
|
+
} finally {
|
|
2869
|
+
isBusyRef.current = false;
|
|
2870
|
+
}
|
|
2871
|
+
}, [
|
|
2872
|
+
client,
|
|
2873
|
+
isReady,
|
|
2874
|
+
sync,
|
|
2875
|
+
runExclusiveSafe,
|
|
2876
|
+
sessionAccountId,
|
|
2877
|
+
storageMode,
|
|
2878
|
+
mutable,
|
|
2879
|
+
authScheme,
|
|
2880
|
+
storagePrefix,
|
|
2881
|
+
pollIntervalMs,
|
|
2882
|
+
maxWaitMs,
|
|
2883
|
+
setAccounts
|
|
2884
|
+
]);
|
|
2885
|
+
const reset = (0, import_react22.useCallback)(() => {
|
|
2886
|
+
cancelledRef.current = true;
|
|
2887
|
+
isBusyRef.current = false;
|
|
2888
|
+
setSessionAccountId(null);
|
|
2889
|
+
setStep("idle");
|
|
2890
|
+
setError(null);
|
|
2891
|
+
localStorage.removeItem(`${storagePrefix}:accountId`);
|
|
2892
|
+
localStorage.removeItem(`${storagePrefix}:ready`);
|
|
2893
|
+
}, [storagePrefix]);
|
|
2894
|
+
return {
|
|
2895
|
+
initialize,
|
|
2896
|
+
sessionAccountId,
|
|
2897
|
+
isReady: step === "ready",
|
|
2898
|
+
step,
|
|
2899
|
+
error,
|
|
2900
|
+
reset
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2903
|
+
function getStorageMode3(mode) {
|
|
2904
|
+
switch (mode) {
|
|
2905
|
+
case "private":
|
|
2906
|
+
return import_miden_sdk20.AccountStorageMode.private();
|
|
2907
|
+
case "public":
|
|
2908
|
+
return import_miden_sdk20.AccountStorageMode.public();
|
|
2909
|
+
default:
|
|
2910
|
+
return import_miden_sdk20.AccountStorageMode.public();
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
async function waitAndConsume(client, runExclusiveSafe, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
|
|
2914
|
+
const deadline = Date.now() + maxWaitMs;
|
|
2915
|
+
while (Date.now() < deadline) {
|
|
2916
|
+
if (cancelledRef.current) return;
|
|
2917
|
+
await runExclusiveSafe(
|
|
2918
|
+
() => client.syncState()
|
|
2919
|
+
);
|
|
2920
|
+
if (cancelledRef.current) return;
|
|
2921
|
+
const consumed = await runExclusiveSafe(async () => {
|
|
2922
|
+
const accountIdObj = parseAccountId(walletId);
|
|
2923
|
+
const consumable = await client.getConsumableNotes(accountIdObj);
|
|
2924
|
+
if (consumable.length === 0) return false;
|
|
2925
|
+
const notes = consumable.map((c) => c.inputNoteRecord().toNote());
|
|
2926
|
+
const txRequest = client.newConsumeTransactionRequest(notes);
|
|
2927
|
+
const freshAccountId = parseAccountId(walletId);
|
|
2928
|
+
await client.submitNewTransaction(freshAccountId, txRequest);
|
|
2929
|
+
return true;
|
|
2930
|
+
});
|
|
2931
|
+
if (consumed) return;
|
|
2932
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2933
|
+
}
|
|
2934
|
+
throw new Error("Timeout waiting for session wallet funding");
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
// src/utils/bytes.ts
|
|
2938
|
+
function bytesToBigInt(bytes) {
|
|
2939
|
+
let result = 0n;
|
|
2940
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2941
|
+
result = result << 8n | BigInt(bytes[i]);
|
|
2942
|
+
}
|
|
2943
|
+
return result;
|
|
2944
|
+
}
|
|
2945
|
+
function bigIntToBytes(value, length) {
|
|
2946
|
+
if (value < 0n) {
|
|
2947
|
+
throw new RangeError("bigIntToBytes: value must be non-negative");
|
|
2948
|
+
}
|
|
2949
|
+
const maxValue = (1n << BigInt(length * 8)) - 1n;
|
|
2950
|
+
if (value > maxValue) {
|
|
2951
|
+
throw new RangeError(
|
|
2952
|
+
`bigIntToBytes: value ${value} does not fit in ${length} byte(s) (max ${maxValue})`
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
const bytes = new Uint8Array(length);
|
|
2956
|
+
let remaining = value;
|
|
2957
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
2958
|
+
bytes[i] = Number(remaining & 0xffn);
|
|
2959
|
+
remaining >>= 8n;
|
|
2960
|
+
}
|
|
2961
|
+
return bytes;
|
|
2962
|
+
}
|
|
2963
|
+
function concatBytes(...arrays) {
|
|
2964
|
+
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
|
2965
|
+
const result = new Uint8Array(totalLength);
|
|
2966
|
+
let offset = 0;
|
|
2967
|
+
for (const arr of arrays) {
|
|
2968
|
+
result.set(arr, offset);
|
|
2969
|
+
offset += arr.length;
|
|
2970
|
+
}
|
|
2971
|
+
return result;
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2974
|
+
// src/utils/walletDetection.ts
|
|
2975
|
+
async function waitForWalletDetection(adapter, timeoutMs = 5e3) {
|
|
2976
|
+
if (adapter.readyState === "Installed") return;
|
|
2977
|
+
return new Promise((resolve, reject) => {
|
|
2978
|
+
let settled = false;
|
|
2979
|
+
const settle = () => {
|
|
2980
|
+
if (settled) return;
|
|
2981
|
+
settled = true;
|
|
2982
|
+
clearTimeout(timer);
|
|
2983
|
+
adapter.off("readyStateChange", onReady);
|
|
2984
|
+
resolve();
|
|
2985
|
+
};
|
|
2986
|
+
const timer = setTimeout(() => {
|
|
2987
|
+
if (settled) return;
|
|
2988
|
+
settled = true;
|
|
2989
|
+
adapter.off("readyStateChange", onReady);
|
|
2990
|
+
reject(
|
|
2991
|
+
new Error(
|
|
2992
|
+
`Wallet extension not detected within ${timeoutMs}ms. Is the browser extension installed and enabled?`
|
|
2993
|
+
)
|
|
2994
|
+
);
|
|
2995
|
+
}, timeoutMs);
|
|
2996
|
+
const onReady = (state) => {
|
|
2997
|
+
if (state === "Installed") settle();
|
|
2998
|
+
};
|
|
2999
|
+
adapter.on("readyStateChange", onReady);
|
|
3000
|
+
if (adapter.readyState === "Installed") settle();
|
|
3001
|
+
});
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
// src/utils/storage.ts
|
|
3005
|
+
async function migrateStorage(options) {
|
|
3006
|
+
if (typeof window === "undefined") return false;
|
|
3007
|
+
const versionKey = options.versionKey ?? "miden:storageVersion";
|
|
3008
|
+
const stored = localStorage.getItem(versionKey);
|
|
3009
|
+
if (stored === options.version) return false;
|
|
3010
|
+
if (options.onBeforeClear) {
|
|
3011
|
+
await options.onBeforeClear();
|
|
3012
|
+
}
|
|
3013
|
+
await clearMidenStorage();
|
|
3014
|
+
localStorage.setItem(versionKey, options.version);
|
|
3015
|
+
if (options.reloadOnClear !== false) {
|
|
3016
|
+
window.location.reload();
|
|
3017
|
+
}
|
|
3018
|
+
return true;
|
|
3019
|
+
}
|
|
3020
|
+
async function clearMidenStorage() {
|
|
3021
|
+
if (typeof indexedDB === "undefined") return;
|
|
3022
|
+
try {
|
|
3023
|
+
const databases = await indexedDB.databases();
|
|
3024
|
+
const midenDbs = databases.filter(
|
|
3025
|
+
(db) => db.name?.toLowerCase().includes("miden")
|
|
3026
|
+
);
|
|
3027
|
+
await Promise.all(
|
|
3028
|
+
midenDbs.map(
|
|
3029
|
+
(db) => new Promise((resolve, reject) => {
|
|
3030
|
+
if (!db.name) {
|
|
3031
|
+
resolve();
|
|
3032
|
+
return;
|
|
3033
|
+
}
|
|
3034
|
+
const req = indexedDB.deleteDatabase(db.name);
|
|
3035
|
+
req.onsuccess = () => resolve();
|
|
3036
|
+
req.onerror = () => reject(req.error);
|
|
3037
|
+
req.onblocked = () => {
|
|
3038
|
+
console.warn(
|
|
3039
|
+
`IndexedDB "${db.name}" delete was blocked \u2014 close other tabs using this database.`
|
|
3040
|
+
);
|
|
3041
|
+
resolve();
|
|
3042
|
+
};
|
|
3043
|
+
})
|
|
3044
|
+
)
|
|
3045
|
+
);
|
|
3046
|
+
} catch {
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
function createMidenStorage(prefix) {
|
|
3050
|
+
const fullKey = (key) => `${prefix}:${key}`;
|
|
3051
|
+
return {
|
|
3052
|
+
get(key) {
|
|
3053
|
+
try {
|
|
3054
|
+
const raw = localStorage.getItem(fullKey(key));
|
|
3055
|
+
if (raw === null) return null;
|
|
3056
|
+
return JSON.parse(raw);
|
|
3057
|
+
} catch {
|
|
3058
|
+
return null;
|
|
3059
|
+
}
|
|
3060
|
+
},
|
|
3061
|
+
set(key, value) {
|
|
3062
|
+
try {
|
|
3063
|
+
localStorage.setItem(fullKey(key), JSON.stringify(value));
|
|
3064
|
+
} catch (e) {
|
|
3065
|
+
console.warn(`Failed to write localStorage key "${fullKey(key)}":`, e);
|
|
3066
|
+
}
|
|
3067
|
+
},
|
|
3068
|
+
remove(key) {
|
|
3069
|
+
localStorage.removeItem(fullKey(key));
|
|
3070
|
+
},
|
|
3071
|
+
clear() {
|
|
3072
|
+
const keysToRemove = [];
|
|
3073
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
3074
|
+
const k = localStorage.key(i);
|
|
3075
|
+
if (k?.startsWith(`${prefix}:`)) {
|
|
3076
|
+
keysToRemove.push(k);
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
keysToRemove.forEach((k) => localStorage.removeItem(k));
|
|
3080
|
+
}
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
|
|
2296
3084
|
// src/index.ts
|
|
2297
3085
|
installAccountBech32();
|
|
2298
3086
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2299
3087
|
0 && (module.exports = {
|
|
2300
3088
|
DEFAULTS,
|
|
3089
|
+
MidenError,
|
|
2301
3090
|
MidenProvider,
|
|
2302
3091
|
SignerContext,
|
|
3092
|
+
accountIdsEqual,
|
|
3093
|
+
bigIntToBytes,
|
|
3094
|
+
bytesToBigInt,
|
|
3095
|
+
clearMidenStorage,
|
|
3096
|
+
concatBytes,
|
|
3097
|
+
createMidenStorage,
|
|
3098
|
+
createNoteAttachment,
|
|
2303
3099
|
formatAssetAmount,
|
|
2304
3100
|
formatNoteSummary,
|
|
2305
3101
|
getNoteSummary,
|
|
3102
|
+
migrateStorage,
|
|
3103
|
+
normalizeAccountId,
|
|
2306
3104
|
parseAssetAmount,
|
|
3105
|
+
readNoteAttachment,
|
|
2307
3106
|
toBech32AccountId,
|
|
2308
3107
|
useAccount,
|
|
2309
3108
|
useAccounts,
|
|
@@ -2317,13 +3116,17 @@ installAccountBech32();
|
|
|
2317
3116
|
useMidenClient,
|
|
2318
3117
|
useMint,
|
|
2319
3118
|
useMultiSend,
|
|
3119
|
+
useNoteStream,
|
|
2320
3120
|
useNotes,
|
|
2321
3121
|
useSend,
|
|
3122
|
+
useSessionAccount,
|
|
2322
3123
|
useSigner,
|
|
2323
3124
|
useSwap,
|
|
2324
3125
|
useSyncState,
|
|
2325
3126
|
useTransaction,
|
|
2326
3127
|
useTransactionHistory,
|
|
2327
3128
|
useWaitForCommit,
|
|
2328
|
-
useWaitForNotes
|
|
3129
|
+
useWaitForNotes,
|
|
3130
|
+
waitForWalletDetection,
|
|
3131
|
+
wrapWasmError
|
|
2329
3132
|
});
|