@miden-sdk/react 0.13.2 → 0.14.0-alpha
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 +28 -0
- package/README.md +402 -6
- package/dist/index.d.mts +275 -23
- package/dist/index.d.ts +275 -23
- package/dist/index.js +1168 -396
- package/dist/index.mjs +1154 -383
- package/package.json +9 -2
package/dist/index.js
CHANGED
|
@@ -30,13 +30,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
AuthScheme: () => import_miden_sdk4.AuthScheme,
|
|
33
34
|
DEFAULTS: () => DEFAULTS,
|
|
35
|
+
MidenError: () => MidenError,
|
|
34
36
|
MidenProvider: () => MidenProvider,
|
|
35
37
|
SignerContext: () => SignerContext,
|
|
38
|
+
accountIdsEqual: () => accountIdsEqual,
|
|
39
|
+
bigIntToBytes: () => bigIntToBytes,
|
|
40
|
+
bytesToBigInt: () => bytesToBigInt,
|
|
41
|
+
clearMidenStorage: () => clearMidenStorage,
|
|
42
|
+
concatBytes: () => concatBytes,
|
|
43
|
+
createMidenStorage: () => createMidenStorage,
|
|
44
|
+
createNoteAttachment: () => createNoteAttachment,
|
|
36
45
|
formatAssetAmount: () => formatAssetAmount,
|
|
37
46
|
formatNoteSummary: () => formatNoteSummary,
|
|
38
47
|
getNoteSummary: () => getNoteSummary,
|
|
48
|
+
migrateStorage: () => migrateStorage,
|
|
49
|
+
normalizeAccountId: () => normalizeAccountId,
|
|
39
50
|
parseAssetAmount: () => parseAssetAmount,
|
|
51
|
+
readNoteAttachment: () => readNoteAttachment,
|
|
40
52
|
toBech32AccountId: () => toBech32AccountId,
|
|
41
53
|
useAccount: () => useAccount,
|
|
42
54
|
useAccounts: () => useAccounts,
|
|
@@ -50,15 +62,19 @@ __export(index_exports, {
|
|
|
50
62
|
useMidenClient: () => useMidenClient,
|
|
51
63
|
useMint: () => useMint,
|
|
52
64
|
useMultiSend: () => useMultiSend,
|
|
65
|
+
useNoteStream: () => useNoteStream,
|
|
53
66
|
useNotes: () => useNotes,
|
|
54
67
|
useSend: () => useSend,
|
|
68
|
+
useSessionAccount: () => useSessionAccount,
|
|
55
69
|
useSigner: () => useSigner,
|
|
56
70
|
useSwap: () => useSwap,
|
|
57
71
|
useSyncState: () => useSyncState,
|
|
58
72
|
useTransaction: () => useTransaction,
|
|
59
73
|
useTransactionHistory: () => useTransactionHistory,
|
|
60
74
|
useWaitForCommit: () => useWaitForCommit,
|
|
61
|
-
useWaitForNotes: () => useWaitForNotes
|
|
75
|
+
useWaitForNotes: () => useWaitForNotes,
|
|
76
|
+
waitForWalletDetection: () => waitForWalletDetection,
|
|
77
|
+
wrapWasmError: () => wrapWasmError
|
|
62
78
|
});
|
|
63
79
|
module.exports = __toCommonJS(index_exports);
|
|
64
80
|
|
|
@@ -88,6 +104,7 @@ var initialState = {
|
|
|
88
104
|
notes: [],
|
|
89
105
|
consumableNotes: [],
|
|
90
106
|
assetMetadata: /* @__PURE__ */ new Map(),
|
|
107
|
+
noteFirstSeen: /* @__PURE__ */ new Map(),
|
|
91
108
|
isLoadingAccounts: false,
|
|
92
109
|
isLoadingNotes: false
|
|
93
110
|
};
|
|
@@ -115,8 +132,74 @@ var useMidenStore = (0, import_zustand.create)()((set) => ({
|
|
|
115
132
|
newMap.set(accountId, account);
|
|
116
133
|
return { accountDetails: newMap };
|
|
117
134
|
}),
|
|
118
|
-
setNotes: (notes) => set(
|
|
135
|
+
setNotes: (notes) => set((state) => {
|
|
136
|
+
const now = Date.now();
|
|
137
|
+
const newFirstSeen = /* @__PURE__ */ new Map();
|
|
138
|
+
for (const note of notes) {
|
|
139
|
+
try {
|
|
140
|
+
const id = note.id().toString();
|
|
141
|
+
newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { notes, noteFirstSeen: newFirstSeen };
|
|
146
|
+
}),
|
|
147
|
+
setNotesIfChanged: (notes) => set((state) => {
|
|
148
|
+
const safeId = (n) => {
|
|
149
|
+
try {
|
|
150
|
+
return n.id().toString();
|
|
151
|
+
} catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const prevIds = /* @__PURE__ */ new Set();
|
|
156
|
+
for (const n of state.notes) {
|
|
157
|
+
const id = safeId(n);
|
|
158
|
+
if (id) prevIds.add(id);
|
|
159
|
+
}
|
|
160
|
+
const newIds = /* @__PURE__ */ new Set();
|
|
161
|
+
for (const n of notes) {
|
|
162
|
+
const id = safeId(n);
|
|
163
|
+
if (id) newIds.add(id);
|
|
164
|
+
}
|
|
165
|
+
if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
|
|
166
|
+
return {};
|
|
167
|
+
}
|
|
168
|
+
const now = Date.now();
|
|
169
|
+
const newFirstSeen = /* @__PURE__ */ new Map();
|
|
170
|
+
for (const note of notes) {
|
|
171
|
+
try {
|
|
172
|
+
const id = note.id().toString();
|
|
173
|
+
newFirstSeen.set(id, state.noteFirstSeen.get(id) ?? now);
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return { notes, noteFirstSeen: newFirstSeen };
|
|
178
|
+
}),
|
|
119
179
|
setConsumableNotes: (consumableNotes) => set({ consumableNotes }),
|
|
180
|
+
setConsumableNotesIfChanged: (consumableNotes) => set((state) => {
|
|
181
|
+
const safeId = (n) => {
|
|
182
|
+
try {
|
|
183
|
+
return n.inputNoteRecord().id().toString();
|
|
184
|
+
} catch {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const prevIds = /* @__PURE__ */ new Set();
|
|
189
|
+
for (const n of state.consumableNotes) {
|
|
190
|
+
const id = safeId(n);
|
|
191
|
+
if (id) prevIds.add(id);
|
|
192
|
+
}
|
|
193
|
+
const newIds = /* @__PURE__ */ new Set();
|
|
194
|
+
for (const n of consumableNotes) {
|
|
195
|
+
const id = safeId(n);
|
|
196
|
+
if (id) newIds.add(id);
|
|
197
|
+
}
|
|
198
|
+
if (prevIds.size === newIds.size && [...prevIds].every((id) => newIds.has(id))) {
|
|
199
|
+
return {};
|
|
200
|
+
}
|
|
201
|
+
return { consumableNotes };
|
|
202
|
+
}),
|
|
120
203
|
setAssetMetadata: (assetId, metadata) => set((state) => {
|
|
121
204
|
const newMap = new Map(state.assetMetadata);
|
|
122
205
|
newMap.set(assetId, metadata);
|
|
@@ -131,6 +214,7 @@ var useAccountsStore = () => useMidenStore((state) => state.accounts);
|
|
|
131
214
|
var useNotesStore = () => useMidenStore((state) => state.notes);
|
|
132
215
|
var useConsumableNotesStore = () => useMidenStore((state) => state.consumableNotes);
|
|
133
216
|
var useAssetMetadataStore = () => useMidenStore((state) => state.assetMetadata);
|
|
217
|
+
var useNoteFirstSeenStore = () => useMidenStore((state) => state.noteFirstSeen);
|
|
134
218
|
|
|
135
219
|
// src/utils/accountParsing.ts
|
|
136
220
|
var import_miden_sdk2 = require("@miden-sdk/miden-sdk");
|
|
@@ -154,6 +238,19 @@ var parseAccountId = (value) => {
|
|
|
154
238
|
const normalized = normalizeAccountIdInput(value);
|
|
155
239
|
return parseAccountIdFromString(normalized);
|
|
156
240
|
};
|
|
241
|
+
function isFaucetId(accountId) {
|
|
242
|
+
try {
|
|
243
|
+
let hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
|
|
244
|
+
if (hex.startsWith("0x") || hex.startsWith("0X")) {
|
|
245
|
+
hex = hex.slice(2);
|
|
246
|
+
}
|
|
247
|
+
const firstByte = parseInt(hex.slice(0, 2), 16);
|
|
248
|
+
const accountType = firstByte >> 4 & 3;
|
|
249
|
+
return accountType === 2 || accountType === 3;
|
|
250
|
+
} catch {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
157
254
|
var parseAddress = (value, accountId) => {
|
|
158
255
|
const normalized = normalizeAccountIdInput(value);
|
|
159
256
|
if (isBech32Input(normalized)) {
|
|
@@ -258,16 +355,17 @@ var toBech32AccountId = (accountId) => {
|
|
|
258
355
|
|
|
259
356
|
// src/context/MidenProvider.tsx
|
|
260
357
|
var import_react2 = require("react");
|
|
261
|
-
var
|
|
358
|
+
var import_miden_sdk6 = require("@miden-sdk/miden-sdk");
|
|
262
359
|
|
|
263
360
|
// src/types/index.ts
|
|
361
|
+
var import_miden_sdk4 = require("@miden-sdk/miden-sdk");
|
|
264
362
|
var DEFAULTS = {
|
|
265
363
|
RPC_URL: void 0,
|
|
266
364
|
// Will use SDK's testnet default
|
|
267
365
|
AUTO_SYNC_INTERVAL: 15e3,
|
|
268
366
|
STORAGE_MODE: "private",
|
|
269
367
|
WALLET_MUTABLE: true,
|
|
270
|
-
AUTH_SCHEME:
|
|
368
|
+
AUTH_SCHEME: import_miden_sdk4.AuthScheme.AuthRpoFalcon512,
|
|
271
369
|
NOTE_TYPE: "private",
|
|
272
370
|
FAUCET_DECIMALS: 8
|
|
273
371
|
};
|
|
@@ -311,7 +409,7 @@ function resolveRpcUrl(rpcUrl) {
|
|
|
311
409
|
}
|
|
312
410
|
|
|
313
411
|
// src/utils/prover.ts
|
|
314
|
-
var
|
|
412
|
+
var import_miden_sdk5 = require("@miden-sdk/miden-sdk");
|
|
315
413
|
var DEFAULT_PROVER_URLS = {
|
|
316
414
|
devnet: "https://tx-prover.devnet.miden.io",
|
|
317
415
|
testnet: "https://tx-prover.testnet.miden.io"
|
|
@@ -324,19 +422,19 @@ function resolveTransactionProver(config) {
|
|
|
324
422
|
if (typeof prover === "string") {
|
|
325
423
|
const normalized = prover.trim().toLowerCase();
|
|
326
424
|
if (normalized === "local") {
|
|
327
|
-
return
|
|
425
|
+
return import_miden_sdk5.TransactionProver.newLocalProver();
|
|
328
426
|
}
|
|
329
427
|
if (normalized === "devnet" || normalized === "testnet") {
|
|
330
428
|
const url = config.proverUrls?.[normalized] ?? DEFAULT_PROVER_URLS[normalized] ?? null;
|
|
331
429
|
if (!url) {
|
|
332
430
|
throw new Error(`Missing ${normalized} prover URL`);
|
|
333
431
|
}
|
|
334
|
-
return
|
|
432
|
+
return import_miden_sdk5.TransactionProver.newRemoteProver(
|
|
335
433
|
url,
|
|
336
434
|
normalizeTimeout(config.proverTimeoutMs)
|
|
337
435
|
);
|
|
338
436
|
}
|
|
339
|
-
return
|
|
437
|
+
return import_miden_sdk5.TransactionProver.newRemoteProver(
|
|
340
438
|
prover,
|
|
341
439
|
normalizeTimeout(config.proverTimeoutMs)
|
|
342
440
|
);
|
|
@@ -348,7 +446,7 @@ function createRemoteProver(config, fallbackTimeout) {
|
|
|
348
446
|
if (!url) {
|
|
349
447
|
throw new Error("Remote prover requires a URL");
|
|
350
448
|
}
|
|
351
|
-
return
|
|
449
|
+
return import_miden_sdk5.TransactionProver.newRemoteProver(
|
|
352
450
|
url,
|
|
353
451
|
normalizeTimeout(timeoutMs ?? fallbackTimeout)
|
|
354
452
|
);
|
|
@@ -371,38 +469,41 @@ function useSigner() {
|
|
|
371
469
|
}
|
|
372
470
|
|
|
373
471
|
// src/utils/signerAccount.ts
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
return AccountType.FungibleFaucet;
|
|
383
|
-
case "NonFungibleFaucet":
|
|
384
|
-
return AccountType.NonFungibleFaucet;
|
|
385
|
-
default:
|
|
386
|
-
return AccountType.RegularAccountImmutableCode;
|
|
387
|
-
}
|
|
472
|
+
var WASM_ACCOUNT_TYPE = {
|
|
473
|
+
FungibleFaucet: 0,
|
|
474
|
+
NonFungibleFaucet: 1,
|
|
475
|
+
RegularAccountImmutableCode: 2,
|
|
476
|
+
RegularAccountUpdatableCode: 3
|
|
477
|
+
};
|
|
478
|
+
function getAccountType(accountType) {
|
|
479
|
+
return WASM_ACCOUNT_TYPE[accountType] ?? WASM_ACCOUNT_TYPE.RegularAccountImmutableCode;
|
|
388
480
|
}
|
|
389
481
|
function isPrivateStorageMode(storageMode) {
|
|
390
482
|
return storageMode.toString() === "private";
|
|
391
483
|
}
|
|
392
484
|
async function initializeSignerAccount(client, config) {
|
|
393
|
-
const { AccountBuilder, AccountComponent, Word } = await import("@miden-sdk/miden-sdk");
|
|
485
|
+
const { AccountBuilder, AccountComponent, AuthScheme: AuthScheme2, Word: Word2 } = await import("@miden-sdk/miden-sdk");
|
|
394
486
|
await client.syncState();
|
|
395
|
-
const commitmentWord =
|
|
487
|
+
const commitmentWord = Word2.deserialize(config.publicKeyCommitment);
|
|
396
488
|
const seed = config.accountSeed ?? crypto.getRandomValues(new Uint8Array(32));
|
|
397
|
-
const accountType =
|
|
398
|
-
|
|
399
|
-
const buildResult = builder.withAuthComponent(
|
|
489
|
+
const accountType = getAccountType(config.accountType);
|
|
490
|
+
let builder = new AccountBuilder(seed).withAuthComponent(
|
|
400
491
|
AccountComponent.createAuthComponentFromCommitment(
|
|
401
492
|
commitmentWord,
|
|
402
|
-
|
|
403
|
-
// ECDSA auth scheme (K256/Keccak)
|
|
493
|
+
AuthScheme2.AuthEcdsaK256Keccak
|
|
404
494
|
)
|
|
405
|
-
).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent()
|
|
495
|
+
).accountType(accountType).storageMode(config.storageMode).withBasicWalletComponent();
|
|
496
|
+
if (config.customComponents?.length) {
|
|
497
|
+
for (const component of config.customComponents) {
|
|
498
|
+
if (component == null || typeof component.getProcedures !== "function") {
|
|
499
|
+
throw new Error(
|
|
500
|
+
"Each entry in customComponents must be an AccountComponent instance created via AccountComponent.compile(), AccountComponent.fromPackage(), or AccountComponent.fromLibrary()."
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
builder = builder.withComponent(component);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const buildResult = builder.build();
|
|
406
507
|
const account = buildResult.account;
|
|
407
508
|
const accountId = account.id();
|
|
408
509
|
if (!isPrivateStorageMode(config.storageMode)) {
|
|
@@ -506,9 +607,6 @@ function MidenProvider({
|
|
|
506
607
|
}
|
|
507
608
|
return;
|
|
508
609
|
}
|
|
509
|
-
if (!signerContext) {
|
|
510
|
-
isInitializedRef.current = true;
|
|
511
|
-
}
|
|
512
610
|
let cancelled = false;
|
|
513
611
|
const initClient = async () => {
|
|
514
612
|
await runExclusive(async () => {
|
|
@@ -520,7 +618,7 @@ function MidenProvider({
|
|
|
520
618
|
let didSignerInit = false;
|
|
521
619
|
if (signerContext && signerContext.isConnected) {
|
|
522
620
|
const storeName = `MidenClientDB_${signerContext.storeName}`;
|
|
523
|
-
webClient = await
|
|
621
|
+
webClient = await import_miden_sdk6.WasmWebClient.createClientWithExternalKeystore(
|
|
524
622
|
resolvedConfig.rpcUrl,
|
|
525
623
|
resolvedConfig.noteTransportUrl,
|
|
526
624
|
resolvedConfig.seed,
|
|
@@ -541,7 +639,7 @@ function MidenProvider({
|
|
|
541
639
|
didSignerInit = true;
|
|
542
640
|
} else {
|
|
543
641
|
const seed = resolvedConfig.seed;
|
|
544
|
-
webClient = await
|
|
642
|
+
webClient = await import_miden_sdk6.WasmWebClient.createClient(
|
|
545
643
|
resolvedConfig.rpcUrl,
|
|
546
644
|
resolvedConfig.noteTransportUrl,
|
|
547
645
|
seed
|
|
@@ -568,6 +666,9 @@ function MidenProvider({
|
|
|
568
666
|
}
|
|
569
667
|
}
|
|
570
668
|
if (!cancelled) {
|
|
669
|
+
if (!signerContext) {
|
|
670
|
+
isInitializedRef.current = true;
|
|
671
|
+
}
|
|
571
672
|
setClient(webClient);
|
|
572
673
|
}
|
|
573
674
|
} catch (error) {
|
|
@@ -582,6 +683,7 @@ function MidenProvider({
|
|
|
582
683
|
initClient();
|
|
583
684
|
return () => {
|
|
584
685
|
cancelled = true;
|
|
686
|
+
isInitializedRef.current = false;
|
|
585
687
|
};
|
|
586
688
|
}, [
|
|
587
689
|
runExclusive,
|
|
@@ -697,23 +799,13 @@ function useAccounts() {
|
|
|
697
799
|
refetch
|
|
698
800
|
};
|
|
699
801
|
}
|
|
700
|
-
function isFaucetId(accountId) {
|
|
701
|
-
try {
|
|
702
|
-
const hex = typeof accountId.toHex === "function" ? accountId.toHex() : String(accountId);
|
|
703
|
-
const firstByte = parseInt(hex.slice(0, 2), 16);
|
|
704
|
-
const accountType = firstByte >> 4 & 3;
|
|
705
|
-
return accountType === 2 || accountType === 3;
|
|
706
|
-
} catch {
|
|
707
|
-
return false;
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
802
|
|
|
711
803
|
// src/hooks/useAccount.ts
|
|
712
804
|
var import_react5 = require("react");
|
|
713
805
|
|
|
714
806
|
// src/hooks/useAssetMetadata.ts
|
|
715
807
|
var import_react4 = require("react");
|
|
716
|
-
var
|
|
808
|
+
var import_miden_sdk7 = require("@miden-sdk/miden-sdk");
|
|
717
809
|
var inflight = /* @__PURE__ */ new Map();
|
|
718
810
|
var rpcClients = /* @__PURE__ */ new Map();
|
|
719
811
|
var getRpcClient = (rpcUrl) => {
|
|
@@ -721,27 +813,22 @@ var getRpcClient = (rpcUrl) => {
|
|
|
721
813
|
const existing = rpcClients.get(key);
|
|
722
814
|
if (existing) return existing;
|
|
723
815
|
try {
|
|
724
|
-
const endpoint = rpcUrl ? new
|
|
725
|
-
const client = new
|
|
816
|
+
const endpoint = rpcUrl ? new import_miden_sdk7.Endpoint(rpcUrl) : import_miden_sdk7.Endpoint.testnet();
|
|
817
|
+
const client = new import_miden_sdk7.RpcClient(endpoint);
|
|
726
818
|
rpcClients.set(key, client);
|
|
727
819
|
return client;
|
|
728
820
|
} catch {
|
|
729
821
|
return null;
|
|
730
822
|
}
|
|
731
823
|
};
|
|
732
|
-
var fetchAssetMetadata = async (
|
|
824
|
+
var fetchAssetMetadata = async (rpcClient, assetId) => {
|
|
733
825
|
try {
|
|
734
826
|
const accountId = parseAccountId(assetId);
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const fetched = await rpcClient.getAccountDetails(accountId);
|
|
739
|
-
account = fetched.account?.();
|
|
740
|
-
} catch {
|
|
741
|
-
}
|
|
742
|
-
}
|
|
827
|
+
if (!isFaucetId(accountId)) return null;
|
|
828
|
+
const fetched = await rpcClient.getAccountDetails(accountId);
|
|
829
|
+
const account = fetched.account?.();
|
|
743
830
|
if (!account) return null;
|
|
744
|
-
const faucet =
|
|
831
|
+
const faucet = import_miden_sdk7.BasicFungibleFaucetComponent.fromAccount(account);
|
|
745
832
|
const symbol = faucet.symbol().toString();
|
|
746
833
|
const decimals = faucet.decimals();
|
|
747
834
|
return { assetId, symbol, decimals };
|
|
@@ -750,8 +837,6 @@ var fetchAssetMetadata = async (client, rpcClient, assetId) => {
|
|
|
750
837
|
}
|
|
751
838
|
};
|
|
752
839
|
function useAssetMetadata(assetIds = []) {
|
|
753
|
-
const { client, isReady, runExclusive } = useMiden();
|
|
754
|
-
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
755
840
|
const assetMetadata = useAssetMetadataStore();
|
|
756
841
|
const setAssetMetadata = useMidenStore((state) => state.setAssetMetadata);
|
|
757
842
|
const rpcUrl = useMidenStore((state) => state.config.rpcUrl);
|
|
@@ -761,32 +846,19 @@ function useAssetMetadata(assetIds = []) {
|
|
|
761
846
|
[assetIds]
|
|
762
847
|
);
|
|
763
848
|
(0, import_react4.useEffect)(() => {
|
|
764
|
-
if (!
|
|
849
|
+
if (!rpcClient || uniqueAssetIds.length === 0) return;
|
|
765
850
|
uniqueAssetIds.forEach((assetId) => {
|
|
766
851
|
const existing = assetMetadata.get(assetId);
|
|
767
852
|
const hasMetadata = existing?.symbol !== void 0 || existing?.decimals !== void 0;
|
|
768
853
|
if (hasMetadata || inflight.has(assetId)) return;
|
|
769
|
-
const promise =
|
|
770
|
-
const metadata = await fetchAssetMetadata(
|
|
771
|
-
client,
|
|
772
|
-
rpcClient,
|
|
773
|
-
assetId
|
|
774
|
-
);
|
|
854
|
+
const promise = fetchAssetMetadata(rpcClient, assetId).then((metadata) => {
|
|
775
855
|
setAssetMetadata(assetId, metadata ?? { assetId });
|
|
776
856
|
}).finally(() => {
|
|
777
857
|
inflight.delete(assetId);
|
|
778
858
|
});
|
|
779
859
|
inflight.set(assetId, promise);
|
|
780
860
|
});
|
|
781
|
-
}, [
|
|
782
|
-
client,
|
|
783
|
-
isReady,
|
|
784
|
-
uniqueAssetIds,
|
|
785
|
-
assetMetadata,
|
|
786
|
-
runExclusiveSafe,
|
|
787
|
-
setAssetMetadata,
|
|
788
|
-
rpcClient
|
|
789
|
-
]);
|
|
861
|
+
}, [uniqueAssetIds, assetMetadata, setAssetMetadata, rpcClient]);
|
|
790
862
|
return { assetMetadata };
|
|
791
863
|
}
|
|
792
864
|
|
|
@@ -888,7 +960,7 @@ function useAccount(accountId) {
|
|
|
888
960
|
|
|
889
961
|
// src/hooks/useNotes.ts
|
|
890
962
|
var import_react6 = require("react");
|
|
891
|
-
var
|
|
963
|
+
var import_miden_sdk9 = require("@miden-sdk/miden-sdk");
|
|
892
964
|
|
|
893
965
|
// src/utils/amounts.ts
|
|
894
966
|
var formatAssetAmount = (amount, decimals) => {
|
|
@@ -972,6 +1044,82 @@ var formatNoteSummary = (summary, formatAsset = (asset) => `${formatAssetAmount(
|
|
|
972
1044
|
return summary.sender ? `${assetsText} from ${summary.sender}` : assetsText;
|
|
973
1045
|
};
|
|
974
1046
|
|
|
1047
|
+
// src/utils/accountId.ts
|
|
1048
|
+
function normalizeAccountId(id) {
|
|
1049
|
+
return toBech32AccountId(id);
|
|
1050
|
+
}
|
|
1051
|
+
function accountIdsEqual(a, b) {
|
|
1052
|
+
let idA;
|
|
1053
|
+
let idB;
|
|
1054
|
+
try {
|
|
1055
|
+
idA = parseAccountId(a);
|
|
1056
|
+
idB = parseAccountId(b);
|
|
1057
|
+
return idA.toString() === idB.toString();
|
|
1058
|
+
} catch {
|
|
1059
|
+
return a === b;
|
|
1060
|
+
} finally {
|
|
1061
|
+
idA?.free?.();
|
|
1062
|
+
idB?.free?.();
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// src/utils/noteFilters.ts
|
|
1067
|
+
var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
|
|
1068
|
+
function getNoteFilterType(status) {
|
|
1069
|
+
switch (status) {
|
|
1070
|
+
case "consumed":
|
|
1071
|
+
return import_miden_sdk8.NoteFilterTypes.Consumed;
|
|
1072
|
+
case "committed":
|
|
1073
|
+
return import_miden_sdk8.NoteFilterTypes.Committed;
|
|
1074
|
+
case "expected":
|
|
1075
|
+
return import_miden_sdk8.NoteFilterTypes.Expected;
|
|
1076
|
+
case "processing":
|
|
1077
|
+
return import_miden_sdk8.NoteFilterTypes.Processing;
|
|
1078
|
+
case "all":
|
|
1079
|
+
default:
|
|
1080
|
+
return import_miden_sdk8.NoteFilterTypes.All;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
function getNoteType(type) {
|
|
1084
|
+
switch (type) {
|
|
1085
|
+
case "private":
|
|
1086
|
+
return import_miden_sdk8.NoteType.Private;
|
|
1087
|
+
case "public":
|
|
1088
|
+
return import_miden_sdk8.NoteType.Public;
|
|
1089
|
+
default:
|
|
1090
|
+
return import_miden_sdk8.NoteType.Private;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
async function waitForTransactionCommit(client, runExclusiveSafe, txIdHex, maxWaitMs = 1e4, delayMs = 1e3) {
|
|
1094
|
+
const deadline = Date.now() + maxWaitMs;
|
|
1095
|
+
const targetHex = normalizeHex(txIdHex);
|
|
1096
|
+
while (Date.now() < deadline) {
|
|
1097
|
+
await runExclusiveSafe(() => client.syncState());
|
|
1098
|
+
const records = await runExclusiveSafe(
|
|
1099
|
+
() => client.getTransactions(import_miden_sdk8.TransactionFilter.all())
|
|
1100
|
+
);
|
|
1101
|
+
const record = records.find(
|
|
1102
|
+
(r) => normalizeHex(r.id().toHex()) === targetHex
|
|
1103
|
+
);
|
|
1104
|
+
if (record) {
|
|
1105
|
+
const status = record.transactionStatus();
|
|
1106
|
+
if (status.isCommitted()) {
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
if (status.isDiscarded()) {
|
|
1110
|
+
throw new Error("Transaction was discarded before commit");
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1114
|
+
}
|
|
1115
|
+
throw new Error("Timeout waiting for transaction commit");
|
|
1116
|
+
}
|
|
1117
|
+
function normalizeHex(value) {
|
|
1118
|
+
const trimmed = value.trim();
|
|
1119
|
+
const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
|
|
1120
|
+
return normalized.toLowerCase();
|
|
1121
|
+
}
|
|
1122
|
+
|
|
975
1123
|
// src/hooks/useNotes.ts
|
|
976
1124
|
function useNotes(options) {
|
|
977
1125
|
const { client, isReady, runExclusive } = useMiden();
|
|
@@ -980,8 +1128,10 @@ function useNotes(options) {
|
|
|
980
1128
|
const consumableNotes = useConsumableNotesStore();
|
|
981
1129
|
const isLoadingNotes = useMidenStore((state) => state.isLoadingNotes);
|
|
982
1130
|
const setLoadingNotes = useMidenStore((state) => state.setLoadingNotes);
|
|
983
|
-
const
|
|
984
|
-
const
|
|
1131
|
+
const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
|
|
1132
|
+
const setConsumableNotesIfChanged = useMidenStore(
|
|
1133
|
+
(state) => state.setConsumableNotesIfChanged
|
|
1134
|
+
);
|
|
985
1135
|
const { lastSyncTime } = useSyncStateStore();
|
|
986
1136
|
const [error, setError] = (0, import_react6.useState)(null);
|
|
987
1137
|
const refetch = (0, import_react6.useCallback)(async () => {
|
|
@@ -992,7 +1142,7 @@ function useNotes(options) {
|
|
|
992
1142
|
const { fetchedNotes, fetchedConsumable } = await runExclusiveSafe(
|
|
993
1143
|
async () => {
|
|
994
1144
|
const filterType = getNoteFilterType(options?.status);
|
|
995
|
-
const filter = new
|
|
1145
|
+
const filter = new import_miden_sdk9.NoteFilter(filterType);
|
|
996
1146
|
const notesResult = await client.getInputNotes(filter);
|
|
997
1147
|
let consumableResult;
|
|
998
1148
|
if (options?.accountId) {
|
|
@@ -1007,8 +1157,8 @@ function useNotes(options) {
|
|
|
1007
1157
|
};
|
|
1008
1158
|
}
|
|
1009
1159
|
);
|
|
1010
|
-
|
|
1011
|
-
|
|
1160
|
+
setNotesIfChanged(fetchedNotes);
|
|
1161
|
+
setConsumableNotesIfChanged(fetchedConsumable);
|
|
1012
1162
|
} catch (err) {
|
|
1013
1163
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1014
1164
|
} finally {
|
|
@@ -1021,8 +1171,8 @@ function useNotes(options) {
|
|
|
1021
1171
|
options?.status,
|
|
1022
1172
|
options?.accountId,
|
|
1023
1173
|
setLoadingNotes,
|
|
1024
|
-
|
|
1025
|
-
|
|
1174
|
+
setNotesIfChanged,
|
|
1175
|
+
setConsumableNotesIfChanged
|
|
1026
1176
|
]);
|
|
1027
1177
|
(0, import_react6.useEffect)(() => {
|
|
1028
1178
|
if (isReady && notes.length === 0) {
|
|
@@ -1049,14 +1199,65 @@ function useNotes(options) {
|
|
|
1049
1199
|
(assetId) => assetMetadata.get(assetId),
|
|
1050
1200
|
[assetMetadata]
|
|
1051
1201
|
);
|
|
1052
|
-
const
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1202
|
+
const normalizedSender = (0, import_react6.useMemo)(() => {
|
|
1203
|
+
if (!options?.sender) return null;
|
|
1204
|
+
try {
|
|
1205
|
+
return normalizeAccountId(options.sender);
|
|
1206
|
+
} catch {
|
|
1207
|
+
return options.sender;
|
|
1208
|
+
}
|
|
1209
|
+
}, [options?.sender]);
|
|
1210
|
+
const excludeIdsKey = (0, import_react6.useMemo)(() => {
|
|
1211
|
+
if (!options?.excludeIds || options.excludeIds.length === 0) return "";
|
|
1212
|
+
return [...options.excludeIds].sort().join("\0");
|
|
1213
|
+
}, [options?.excludeIds]);
|
|
1214
|
+
const filterBySender = (0, import_react6.useCallback)(
|
|
1215
|
+
(summaries, target) => {
|
|
1216
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1217
|
+
return summaries.filter((s) => {
|
|
1218
|
+
if (!s.sender) return false;
|
|
1219
|
+
let normalized = cache.get(s.sender);
|
|
1220
|
+
if (normalized === void 0) {
|
|
1221
|
+
try {
|
|
1222
|
+
normalized = normalizeAccountId(s.sender);
|
|
1223
|
+
} catch {
|
|
1224
|
+
normalized = s.sender;
|
|
1225
|
+
}
|
|
1226
|
+
cache.set(s.sender, normalized);
|
|
1227
|
+
}
|
|
1228
|
+
return normalized === target;
|
|
1229
|
+
});
|
|
1230
|
+
},
|
|
1231
|
+
[]
|
|
1059
1232
|
);
|
|
1233
|
+
const noteSummaries = (0, import_react6.useMemo)(() => {
|
|
1234
|
+
let summaries = notes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1235
|
+
if (normalizedSender) {
|
|
1236
|
+
summaries = filterBySender(summaries, normalizedSender);
|
|
1237
|
+
}
|
|
1238
|
+
if (excludeIdsKey) {
|
|
1239
|
+
const excludeSet = new Set(excludeIdsKey.split("\0"));
|
|
1240
|
+
summaries = summaries.filter((s) => !excludeSet.has(s.id));
|
|
1241
|
+
}
|
|
1242
|
+
return summaries;
|
|
1243
|
+
}, [notes, getMetadata, normalizedSender, excludeIdsKey, filterBySender]);
|
|
1244
|
+
const consumableNoteSummaries = (0, import_react6.useMemo)(() => {
|
|
1245
|
+
let summaries = consumableNotes.map((note) => getNoteSummary(note, getMetadata)).filter(Boolean);
|
|
1246
|
+
if (normalizedSender) {
|
|
1247
|
+
summaries = filterBySender(summaries, normalizedSender);
|
|
1248
|
+
}
|
|
1249
|
+
if (excludeIdsKey) {
|
|
1250
|
+
const excludeSet = new Set(excludeIdsKey.split("\0"));
|
|
1251
|
+
summaries = summaries.filter((s) => !excludeSet.has(s.id));
|
|
1252
|
+
}
|
|
1253
|
+
return summaries;
|
|
1254
|
+
}, [
|
|
1255
|
+
consumableNotes,
|
|
1256
|
+
getMetadata,
|
|
1257
|
+
normalizedSender,
|
|
1258
|
+
excludeIdsKey,
|
|
1259
|
+
filterBySender
|
|
1260
|
+
]);
|
|
1060
1261
|
return {
|
|
1061
1262
|
notes,
|
|
1062
1263
|
consumableNotes,
|
|
@@ -1067,46 +1268,246 @@ function useNotes(options) {
|
|
|
1067
1268
|
refetch
|
|
1068
1269
|
};
|
|
1069
1270
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1271
|
+
|
|
1272
|
+
// src/hooks/useNoteStream.ts
|
|
1273
|
+
var import_react7 = require("react");
|
|
1274
|
+
var import_miden_sdk11 = require("@miden-sdk/miden-sdk");
|
|
1275
|
+
|
|
1276
|
+
// src/utils/noteAttachment.ts
|
|
1277
|
+
var import_miden_sdk10 = require("@miden-sdk/miden-sdk");
|
|
1278
|
+
function readNoteAttachment(note) {
|
|
1279
|
+
try {
|
|
1280
|
+
const metadata = note.metadata?.();
|
|
1281
|
+
if (!metadata) return null;
|
|
1282
|
+
const attachment = metadata.attachment?.();
|
|
1283
|
+
if (!attachment) return null;
|
|
1284
|
+
const kind = attachment.kind?.();
|
|
1285
|
+
if (!kind) return null;
|
|
1286
|
+
if (kind === import_miden_sdk10.NoteAttachmentKind.None) return null;
|
|
1287
|
+
if (kind === import_miden_sdk10.NoteAttachmentKind.Word) {
|
|
1288
|
+
const word = attachment.asWord?.();
|
|
1289
|
+
if (!word) return null;
|
|
1290
|
+
const u64s = word.toU64s();
|
|
1291
|
+
const values = Array.from(u64s).map(
|
|
1292
|
+
(v) => BigInt(v)
|
|
1293
|
+
);
|
|
1294
|
+
return { values, kind: "word" };
|
|
1295
|
+
}
|
|
1296
|
+
if (kind === import_miden_sdk10.NoteAttachmentKind.Array) {
|
|
1297
|
+
const arr = attachment.asArray?.();
|
|
1298
|
+
if (!arr) return null;
|
|
1299
|
+
const u64s = arr.toU64s();
|
|
1300
|
+
const values = Array.from(u64s).map(
|
|
1301
|
+
(v) => BigInt(v)
|
|
1302
|
+
);
|
|
1303
|
+
return { values, kind: "array" };
|
|
1304
|
+
}
|
|
1305
|
+
return null;
|
|
1306
|
+
} catch {
|
|
1307
|
+
return null;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
function createNoteAttachment(values) {
|
|
1311
|
+
const bigints = [];
|
|
1312
|
+
for (let i = 0; i < values.length; i++) {
|
|
1313
|
+
bigints.push(BigInt(values[i]));
|
|
1314
|
+
}
|
|
1315
|
+
if (bigints.length === 0) {
|
|
1316
|
+
return new import_miden_sdk10.NoteAttachment();
|
|
1317
|
+
}
|
|
1318
|
+
const scheme = import_miden_sdk10.NoteAttachmentScheme.none();
|
|
1319
|
+
if (bigints.length <= 4) {
|
|
1320
|
+
while (bigints.length < 4) {
|
|
1321
|
+
bigints.push(0n);
|
|
1322
|
+
}
|
|
1323
|
+
const word = new import_miden_sdk10.Word(BigUint64Array.from(bigints));
|
|
1324
|
+
return import_miden_sdk10.NoteAttachment.newWord(scheme, word);
|
|
1325
|
+
}
|
|
1326
|
+
while (bigints.length % 4 !== 0) {
|
|
1327
|
+
bigints.push(0n);
|
|
1328
|
+
}
|
|
1329
|
+
const words = [];
|
|
1330
|
+
for (let i = 0; i < bigints.length; i += 4) {
|
|
1331
|
+
words.push(new import_miden_sdk10.Word(BigUint64Array.from(bigints.slice(i, i + 4))));
|
|
1332
|
+
}
|
|
1333
|
+
const newArray = import_miden_sdk10.NoteAttachment["newArray"];
|
|
1334
|
+
if (typeof newArray !== "function") {
|
|
1335
|
+
throw new Error(
|
|
1336
|
+
"NoteAttachment.newArray is not available. Ensure @miden-sdk/miden-sdk >= 0.13.1."
|
|
1337
|
+
);
|
|
1083
1338
|
}
|
|
1339
|
+
return newArray.call(import_miden_sdk10.NoteAttachment, scheme, words);
|
|
1084
1340
|
}
|
|
1085
1341
|
|
|
1086
|
-
// src/hooks/
|
|
1087
|
-
|
|
1088
|
-
var import_miden_sdk8 = require("@miden-sdk/miden-sdk");
|
|
1089
|
-
function useTransactionHistory(options = {}) {
|
|
1342
|
+
// src/hooks/useNoteStream.ts
|
|
1343
|
+
function useNoteStream(options = {}) {
|
|
1090
1344
|
const { client, isReady, runExclusive } = useMiden();
|
|
1091
1345
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1346
|
+
const allNotes = useNotesStore();
|
|
1347
|
+
const noteFirstSeen = useNoteFirstSeenStore();
|
|
1092
1348
|
const { lastSyncTime } = useSyncStateStore();
|
|
1093
|
-
const
|
|
1349
|
+
const setNotesIfChanged = useMidenStore((state) => state.setNotesIfChanged);
|
|
1094
1350
|
const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
|
|
1095
1351
|
const [error, setError] = (0, import_react7.useState)(null);
|
|
1096
|
-
const
|
|
1352
|
+
const handledIdsRef = (0, import_react7.useRef)(/* @__PURE__ */ new Set());
|
|
1353
|
+
const [handledVersion, setHandledVersion] = (0, import_react7.useState)(0);
|
|
1354
|
+
const status = options.status ?? "committed";
|
|
1355
|
+
const sender = options.sender ?? null;
|
|
1356
|
+
const since = options.since;
|
|
1357
|
+
const amountFilterRef = (0, import_react7.useRef)(options.amountFilter);
|
|
1358
|
+
amountFilterRef.current = options.amountFilter;
|
|
1359
|
+
const excludeIdsKey = (0, import_react7.useMemo)(() => {
|
|
1360
|
+
if (!options.excludeIds) return "";
|
|
1361
|
+
if (options.excludeIds instanceof Set)
|
|
1362
|
+
return Array.from(options.excludeIds).sort().join("\0");
|
|
1363
|
+
return [...options.excludeIds].sort().join("\0");
|
|
1364
|
+
}, [options.excludeIds]);
|
|
1365
|
+
const excludeIdSet = (0, import_react7.useMemo)(() => {
|
|
1366
|
+
if (!excludeIdsKey) return null;
|
|
1367
|
+
return new Set(excludeIdsKey.split("\0"));
|
|
1368
|
+
}, [excludeIdsKey]);
|
|
1369
|
+
const refetch = (0, import_react7.useCallback)(async () => {
|
|
1370
|
+
if (!client || !isReady) return;
|
|
1371
|
+
setIsLoading(true);
|
|
1372
|
+
setError(null);
|
|
1373
|
+
try {
|
|
1374
|
+
const filterType = getNoteFilterType(status);
|
|
1375
|
+
const filter = new import_miden_sdk11.NoteFilter(filterType);
|
|
1376
|
+
const fetched = await runExclusiveSafe(
|
|
1377
|
+
() => client.getInputNotes(filter)
|
|
1378
|
+
);
|
|
1379
|
+
setNotesIfChanged(fetched);
|
|
1380
|
+
} catch (err) {
|
|
1381
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1382
|
+
} finally {
|
|
1383
|
+
setIsLoading(false);
|
|
1384
|
+
}
|
|
1385
|
+
}, [client, isReady, runExclusiveSafe, status, setNotesIfChanged]);
|
|
1386
|
+
(0, import_react7.useEffect)(() => {
|
|
1387
|
+
if (isReady) {
|
|
1388
|
+
refetch();
|
|
1389
|
+
}
|
|
1390
|
+
}, [isReady, lastSyncTime, refetch]);
|
|
1391
|
+
const streamedNotes = (0, import_react7.useMemo)(() => {
|
|
1392
|
+
void handledVersion;
|
|
1393
|
+
const result = [];
|
|
1394
|
+
let normalizedSender = null;
|
|
1395
|
+
if (sender) {
|
|
1396
|
+
try {
|
|
1397
|
+
normalizedSender = normalizeAccountId(sender);
|
|
1398
|
+
} catch {
|
|
1399
|
+
normalizedSender = sender;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
for (const record of allNotes) {
|
|
1403
|
+
const note = buildStreamedNote(record, noteFirstSeen);
|
|
1404
|
+
if (!note) continue;
|
|
1405
|
+
if (handledIdsRef.current.has(note.id)) continue;
|
|
1406
|
+
if (excludeIdSet && excludeIdSet.has(note.id)) continue;
|
|
1407
|
+
if (normalizedSender && note.sender !== normalizedSender) continue;
|
|
1408
|
+
if (since !== void 0 && note.firstSeenAt < since) continue;
|
|
1409
|
+
if (amountFilterRef.current && !amountFilterRef.current(note.amount))
|
|
1410
|
+
continue;
|
|
1411
|
+
result.push(note);
|
|
1412
|
+
}
|
|
1413
|
+
result.sort((a, b) => a.firstSeenAt - b.firstSeenAt);
|
|
1414
|
+
return result;
|
|
1415
|
+
}, [allNotes, noteFirstSeen, excludeIdSet, sender, since, handledVersion]);
|
|
1416
|
+
const latest = (0, import_react7.useMemo)(
|
|
1417
|
+
() => streamedNotes.length > 0 ? streamedNotes[streamedNotes.length - 1] : null,
|
|
1418
|
+
[streamedNotes]
|
|
1419
|
+
);
|
|
1420
|
+
const markHandled = (0, import_react7.useCallback)((noteId) => {
|
|
1421
|
+
handledIdsRef.current = new Set(handledIdsRef.current).add(noteId);
|
|
1422
|
+
setHandledVersion((v) => v + 1);
|
|
1423
|
+
}, []);
|
|
1424
|
+
const markAllHandled = (0, import_react7.useCallback)(() => {
|
|
1425
|
+
const newSet = new Set(handledIdsRef.current);
|
|
1426
|
+
for (const note of streamedNotes) {
|
|
1427
|
+
newSet.add(note.id);
|
|
1428
|
+
}
|
|
1429
|
+
handledIdsRef.current = newSet;
|
|
1430
|
+
setHandledVersion((v) => v + 1);
|
|
1431
|
+
}, [streamedNotes]);
|
|
1432
|
+
const snapshot = (0, import_react7.useCallback)(() => {
|
|
1433
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1434
|
+
for (const note of streamedNotes) {
|
|
1435
|
+
ids.add(note.id);
|
|
1436
|
+
}
|
|
1437
|
+
return { ids, timestamp: Date.now() };
|
|
1438
|
+
}, [streamedNotes]);
|
|
1439
|
+
return {
|
|
1440
|
+
notes: streamedNotes,
|
|
1441
|
+
latest,
|
|
1442
|
+
markHandled,
|
|
1443
|
+
markAllHandled,
|
|
1444
|
+
snapshot,
|
|
1445
|
+
isLoading,
|
|
1446
|
+
error
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
function buildStreamedNote(record, noteFirstSeen) {
|
|
1450
|
+
try {
|
|
1451
|
+
const id = record.id().toString();
|
|
1452
|
+
const metadata = record.metadata?.();
|
|
1453
|
+
const senderHex = metadata?.sender?.()?.toString?.();
|
|
1454
|
+
const sender = senderHex ? toBech32AccountId(senderHex) : "";
|
|
1455
|
+
const assets = [];
|
|
1456
|
+
let primaryAmount = 0n;
|
|
1457
|
+
try {
|
|
1458
|
+
const details = record.details();
|
|
1459
|
+
const assetsList = details?.assets?.().fungibleAssets?.() ?? [];
|
|
1460
|
+
for (const asset of assetsList) {
|
|
1461
|
+
const assetId = asset.faucetId().toString();
|
|
1462
|
+
const amount = BigInt(asset.amount());
|
|
1463
|
+
assets.push({ assetId, amount });
|
|
1464
|
+
if (primaryAmount === 0n) {
|
|
1465
|
+
primaryAmount = amount;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
} catch {
|
|
1469
|
+
}
|
|
1470
|
+
const attachmentData = readNoteAttachment(record);
|
|
1471
|
+
const attachment = attachmentData ? attachmentData.values : null;
|
|
1472
|
+
const firstSeenAt = noteFirstSeen.get(id) ?? Date.now();
|
|
1473
|
+
return {
|
|
1474
|
+
id,
|
|
1475
|
+
sender,
|
|
1476
|
+
amount: primaryAmount,
|
|
1477
|
+
assets,
|
|
1478
|
+
record,
|
|
1479
|
+
firstSeenAt,
|
|
1480
|
+
attachment
|
|
1481
|
+
};
|
|
1482
|
+
} catch {
|
|
1483
|
+
return null;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
// src/hooks/useTransactionHistory.ts
|
|
1488
|
+
var import_react8 = require("react");
|
|
1489
|
+
var import_miden_sdk12 = require("@miden-sdk/miden-sdk");
|
|
1490
|
+
function useTransactionHistory(options = {}) {
|
|
1491
|
+
const { client, isReady, runExclusive } = useMiden();
|
|
1492
|
+
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1493
|
+
const { lastSyncTime } = useSyncStateStore();
|
|
1494
|
+
const [records, setRecords] = (0, import_react8.useState)([]);
|
|
1495
|
+
const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
|
|
1496
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1497
|
+
const rawIds = (0, import_react8.useMemo)(() => {
|
|
1097
1498
|
if (options.id) return [options.id];
|
|
1098
1499
|
if (options.ids && options.ids.length > 0) return options.ids;
|
|
1099
1500
|
return null;
|
|
1100
1501
|
}, [options.id, options.ids]);
|
|
1101
|
-
const idsHex = (0,
|
|
1502
|
+
const idsHex = (0, import_react8.useMemo)(() => {
|
|
1102
1503
|
if (!rawIds) return null;
|
|
1103
1504
|
return rawIds.map(
|
|
1104
|
-
(id) =>
|
|
1505
|
+
(id) => normalizeHex2(typeof id === "string" ? id : id.toHex())
|
|
1105
1506
|
);
|
|
1106
1507
|
}, [rawIds]);
|
|
1107
1508
|
const filter = options.filter;
|
|
1108
1509
|
const refreshOnSync = options.refreshOnSync !== false;
|
|
1109
|
-
const refetch = (0,
|
|
1510
|
+
const refetch = (0, import_react8.useCallback)(async () => {
|
|
1110
1511
|
if (!client || !isReady) return;
|
|
1111
1512
|
setIsLoading(true);
|
|
1112
1513
|
setError(null);
|
|
@@ -1120,7 +1521,7 @@ function useTransactionHistory(options = {}) {
|
|
|
1120
1521
|
() => client.getTransactions(resolvedFilter)
|
|
1121
1522
|
);
|
|
1122
1523
|
const filtered = localFilterHexes ? fetched.filter(
|
|
1123
|
-
(record2) => localFilterHexes.includes(
|
|
1524
|
+
(record2) => localFilterHexes.includes(normalizeHex2(record2.id().toHex()))
|
|
1124
1525
|
) : fetched;
|
|
1125
1526
|
setRecords(filtered);
|
|
1126
1527
|
} catch (err) {
|
|
@@ -1129,19 +1530,19 @@ function useTransactionHistory(options = {}) {
|
|
|
1129
1530
|
setIsLoading(false);
|
|
1130
1531
|
}
|
|
1131
1532
|
}, [client, isReady, runExclusiveSafe, filter, rawIds, idsHex]);
|
|
1132
|
-
(0,
|
|
1533
|
+
(0, import_react8.useEffect)(() => {
|
|
1133
1534
|
if (!isReady) return;
|
|
1134
1535
|
refetch();
|
|
1135
1536
|
}, [isReady, refetch]);
|
|
1136
|
-
(0,
|
|
1537
|
+
(0, import_react8.useEffect)(() => {
|
|
1137
1538
|
if (!isReady || !refreshOnSync || !lastSyncTime) return;
|
|
1138
1539
|
refetch();
|
|
1139
1540
|
}, [isReady, lastSyncTime, refreshOnSync, refetch]);
|
|
1140
|
-
const record = (0,
|
|
1541
|
+
const record = (0, import_react8.useMemo)(() => {
|
|
1141
1542
|
if (!idsHex || idsHex.length !== 1) return null;
|
|
1142
|
-
return records.find((item) =>
|
|
1543
|
+
return records.find((item) => normalizeHex2(item.id().toHex()) === idsHex[0]) ?? null;
|
|
1143
1544
|
}, [records, idsHex]);
|
|
1144
|
-
const status = (0,
|
|
1545
|
+
const status = (0, import_react8.useMemo)(() => {
|
|
1145
1546
|
if (!record) return null;
|
|
1146
1547
|
const current = record.transactionStatus();
|
|
1147
1548
|
if (current.isCommitted()) return "committed";
|
|
@@ -1163,29 +1564,29 @@ function buildFilter(filter, ids, idsHex) {
|
|
|
1163
1564
|
return { filter };
|
|
1164
1565
|
}
|
|
1165
1566
|
if (!ids || ids.length === 0) {
|
|
1166
|
-
return { filter:
|
|
1567
|
+
return { filter: import_miden_sdk12.TransactionFilter.all() };
|
|
1167
1568
|
}
|
|
1168
1569
|
const allTransactionIds = ids.every((id) => typeof id !== "string");
|
|
1169
1570
|
if (allTransactionIds) {
|
|
1170
|
-
return { filter:
|
|
1571
|
+
return { filter: import_miden_sdk12.TransactionFilter.ids(ids) };
|
|
1171
1572
|
}
|
|
1172
1573
|
return {
|
|
1173
|
-
filter:
|
|
1574
|
+
filter: import_miden_sdk12.TransactionFilter.all(),
|
|
1174
1575
|
localFilterHexes: idsHex ?? []
|
|
1175
1576
|
};
|
|
1176
1577
|
}
|
|
1177
|
-
function
|
|
1578
|
+
function normalizeHex2(value) {
|
|
1178
1579
|
const trimmed = value.trim();
|
|
1179
1580
|
const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
|
|
1180
1581
|
return normalized.toLowerCase();
|
|
1181
1582
|
}
|
|
1182
1583
|
|
|
1183
1584
|
// src/hooks/useSyncState.ts
|
|
1184
|
-
var
|
|
1585
|
+
var import_react9 = require("react");
|
|
1185
1586
|
function useSyncState() {
|
|
1186
1587
|
const { sync: triggerSync } = useMiden();
|
|
1187
1588
|
const syncState = useSyncStateStore();
|
|
1188
|
-
const sync = (0,
|
|
1589
|
+
const sync = (0, import_react9.useCallback)(async () => {
|
|
1189
1590
|
await triggerSync();
|
|
1190
1591
|
}, [triggerSync]);
|
|
1191
1592
|
return {
|
|
@@ -1195,21 +1596,20 @@ function useSyncState() {
|
|
|
1195
1596
|
}
|
|
1196
1597
|
|
|
1197
1598
|
// src/hooks/useCreateWallet.ts
|
|
1198
|
-
var
|
|
1199
|
-
var
|
|
1599
|
+
var import_react10 = require("react");
|
|
1600
|
+
var import_miden_sdk13 = require("@miden-sdk/miden-sdk");
|
|
1200
1601
|
function useCreateWallet() {
|
|
1201
|
-
const { client, isReady,
|
|
1602
|
+
const { client, isReady, runExclusive } = useMiden();
|
|
1202
1603
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1203
1604
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1204
|
-
const [wallet, setWallet] = (0,
|
|
1205
|
-
const [isCreating, setIsCreating] = (0,
|
|
1206
|
-
const [error, setError] = (0,
|
|
1207
|
-
const createWallet = (0,
|
|
1605
|
+
const [wallet, setWallet] = (0, import_react10.useState)(null);
|
|
1606
|
+
const [isCreating, setIsCreating] = (0, import_react10.useState)(false);
|
|
1607
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
1608
|
+
const createWallet = (0, import_react10.useCallback)(
|
|
1208
1609
|
async (options = {}) => {
|
|
1209
1610
|
if (!client || !isReady) {
|
|
1210
1611
|
throw new Error("Miden client is not ready");
|
|
1211
1612
|
}
|
|
1212
|
-
await sync();
|
|
1213
1613
|
setIsCreating(true);
|
|
1214
1614
|
setError(null);
|
|
1215
1615
|
try {
|
|
@@ -1242,7 +1642,7 @@ function useCreateWallet() {
|
|
|
1242
1642
|
},
|
|
1243
1643
|
[client, isReady, runExclusive, setAccounts]
|
|
1244
1644
|
);
|
|
1245
|
-
const reset = (0,
|
|
1645
|
+
const reset = (0, import_react10.useCallback)(() => {
|
|
1246
1646
|
setWallet(null);
|
|
1247
1647
|
setIsCreating(false);
|
|
1248
1648
|
setError(null);
|
|
@@ -1258,27 +1658,27 @@ function useCreateWallet() {
|
|
|
1258
1658
|
function getStorageMode(mode) {
|
|
1259
1659
|
switch (mode) {
|
|
1260
1660
|
case "private":
|
|
1261
|
-
return
|
|
1661
|
+
return import_miden_sdk13.AccountStorageMode.private();
|
|
1262
1662
|
case "public":
|
|
1263
|
-
return
|
|
1663
|
+
return import_miden_sdk13.AccountStorageMode.public();
|
|
1264
1664
|
case "network":
|
|
1265
|
-
return
|
|
1665
|
+
return import_miden_sdk13.AccountStorageMode.network();
|
|
1266
1666
|
default:
|
|
1267
|
-
return
|
|
1667
|
+
return import_miden_sdk13.AccountStorageMode.private();
|
|
1268
1668
|
}
|
|
1269
1669
|
}
|
|
1270
1670
|
|
|
1271
1671
|
// src/hooks/useCreateFaucet.ts
|
|
1272
|
-
var
|
|
1273
|
-
var
|
|
1672
|
+
var import_react11 = require("react");
|
|
1673
|
+
var import_miden_sdk14 = require("@miden-sdk/miden-sdk");
|
|
1274
1674
|
function useCreateFaucet() {
|
|
1275
1675
|
const { client, isReady, runExclusive } = useMiden();
|
|
1276
1676
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1277
1677
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1278
|
-
const [faucet, setFaucet] = (0,
|
|
1279
|
-
const [isCreating, setIsCreating] = (0,
|
|
1280
|
-
const [error, setError] = (0,
|
|
1281
|
-
const createFaucet = (0,
|
|
1678
|
+
const [faucet, setFaucet] = (0, import_react11.useState)(null);
|
|
1679
|
+
const [isCreating, setIsCreating] = (0, import_react11.useState)(false);
|
|
1680
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
1681
|
+
const createFaucet = (0, import_react11.useCallback)(
|
|
1282
1682
|
async (options) => {
|
|
1283
1683
|
if (!client || !isReady) {
|
|
1284
1684
|
throw new Error("Miden client is not ready");
|
|
@@ -1317,7 +1717,7 @@ function useCreateFaucet() {
|
|
|
1317
1717
|
},
|
|
1318
1718
|
[client, isReady, runExclusive, setAccounts]
|
|
1319
1719
|
);
|
|
1320
|
-
const reset = (0,
|
|
1720
|
+
const reset = (0, import_react11.useCallback)(() => {
|
|
1321
1721
|
setFaucet(null);
|
|
1322
1722
|
setIsCreating(false);
|
|
1323
1723
|
setError(null);
|
|
@@ -1333,27 +1733,27 @@ function useCreateFaucet() {
|
|
|
1333
1733
|
function getStorageMode2(mode) {
|
|
1334
1734
|
switch (mode) {
|
|
1335
1735
|
case "private":
|
|
1336
|
-
return
|
|
1736
|
+
return import_miden_sdk14.AccountStorageMode.private();
|
|
1337
1737
|
case "public":
|
|
1338
|
-
return
|
|
1738
|
+
return import_miden_sdk14.AccountStorageMode.public();
|
|
1339
1739
|
case "network":
|
|
1340
|
-
return
|
|
1740
|
+
return import_miden_sdk14.AccountStorageMode.network();
|
|
1341
1741
|
default:
|
|
1342
|
-
return
|
|
1742
|
+
return import_miden_sdk14.AccountStorageMode.private();
|
|
1343
1743
|
}
|
|
1344
1744
|
}
|
|
1345
1745
|
|
|
1346
1746
|
// src/hooks/useImportAccount.ts
|
|
1347
|
-
var
|
|
1348
|
-
var
|
|
1349
|
-
function useImportAccount() {
|
|
1747
|
+
var import_react12 = require("react");
|
|
1748
|
+
var import_miden_sdk15 = require("@miden-sdk/miden-sdk");
|
|
1749
|
+
function useImportAccount() {
|
|
1350
1750
|
const { client, isReady, runExclusive } = useMiden();
|
|
1351
1751
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1352
1752
|
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
1353
|
-
const [account, setAccount] = (0,
|
|
1354
|
-
const [isImporting, setIsImporting] = (0,
|
|
1355
|
-
const [error, setError] = (0,
|
|
1356
|
-
const importAccount = (0,
|
|
1753
|
+
const [account, setAccount] = (0, import_react12.useState)(null);
|
|
1754
|
+
const [isImporting, setIsImporting] = (0, import_react12.useState)(false);
|
|
1755
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
1756
|
+
const importAccount = (0, import_react12.useCallback)(
|
|
1357
1757
|
async (options) => {
|
|
1358
1758
|
if (!client || !isReady) {
|
|
1359
1759
|
throw new Error("Miden client is not ready");
|
|
@@ -1448,7 +1848,7 @@ function useImportAccount() {
|
|
|
1448
1848
|
},
|
|
1449
1849
|
[client, isReady, runExclusive, setAccounts]
|
|
1450
1850
|
);
|
|
1451
|
-
const reset = (0,
|
|
1851
|
+
const reset = (0, import_react12.useCallback)(() => {
|
|
1452
1852
|
setAccount(null);
|
|
1453
1853
|
setIsImporting(false);
|
|
1454
1854
|
setError(null);
|
|
@@ -1466,10 +1866,10 @@ function resolveAccountId(accountId) {
|
|
|
1466
1866
|
}
|
|
1467
1867
|
async function resolveAccountFile(file) {
|
|
1468
1868
|
if (file instanceof Uint8Array) {
|
|
1469
|
-
return
|
|
1869
|
+
return import_miden_sdk15.AccountFile.deserialize(file);
|
|
1470
1870
|
}
|
|
1471
1871
|
if (file instanceof ArrayBuffer) {
|
|
1472
|
-
return
|
|
1872
|
+
return import_miden_sdk15.AccountFile.deserialize(new Uint8Array(file));
|
|
1473
1873
|
}
|
|
1474
1874
|
return file;
|
|
1475
1875
|
}
|
|
@@ -1498,43 +1898,146 @@ function bytesEqual(left, right) {
|
|
|
1498
1898
|
}
|
|
1499
1899
|
|
|
1500
1900
|
// src/hooks/useSend.ts
|
|
1501
|
-
var
|
|
1502
|
-
var
|
|
1901
|
+
var import_react13 = require("react");
|
|
1902
|
+
var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
|
|
1903
|
+
|
|
1904
|
+
// src/utils/errors.ts
|
|
1905
|
+
var MidenError = class extends Error {
|
|
1906
|
+
constructor(message, options) {
|
|
1907
|
+
super(message);
|
|
1908
|
+
this.name = "MidenError";
|
|
1909
|
+
this.code = options?.code ?? "UNKNOWN";
|
|
1910
|
+
if (options?.cause !== void 0) {
|
|
1911
|
+
this.cause = options.cause;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
var ERROR_PATTERNS = [
|
|
1916
|
+
{
|
|
1917
|
+
test: (msg) => msg.includes("_assertClass") || msg.includes("expected instance of"),
|
|
1918
|
+
code: "WASM_CLASS_MISMATCH",
|
|
1919
|
+
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."
|
|
1920
|
+
},
|
|
1921
|
+
{
|
|
1922
|
+
test: (msg) => msg.includes("null pointer") || msg.includes("already been freed") || msg.includes("dereferencing a null"),
|
|
1923
|
+
code: "WASM_POINTER_CONSUMED",
|
|
1924
|
+
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."
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
test: (msg) => msg.includes("not initialized") || msg.includes("Cannot read properties of null"),
|
|
1928
|
+
code: "WASM_NOT_INITIALIZED",
|
|
1929
|
+
message: "Miden client is not initialized. Ensure you are inside a <MidenProvider> and the client is ready before calling SDK methods."
|
|
1930
|
+
},
|
|
1931
|
+
{
|
|
1932
|
+
test: (msg) => msg.includes("state commitment mismatch") || msg.includes("stale state"),
|
|
1933
|
+
code: "WASM_SYNC_REQUIRED",
|
|
1934
|
+
message: "Account state is stale. Call sync() before executing transactions, or ensure no concurrent transactions are running against the same account."
|
|
1935
|
+
}
|
|
1936
|
+
];
|
|
1937
|
+
function wrapWasmError(e) {
|
|
1938
|
+
if (e instanceof MidenError) return e;
|
|
1939
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1940
|
+
for (const pattern of ERROR_PATTERNS) {
|
|
1941
|
+
if (pattern.test(msg)) {
|
|
1942
|
+
return new MidenError(pattern.message, { cause: e, code: pattern.code });
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
if (e instanceof Error) return e;
|
|
1946
|
+
return new Error(msg);
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
// src/hooks/useSend.ts
|
|
1503
1950
|
function useSend() {
|
|
1504
1951
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1505
1952
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1506
|
-
const
|
|
1507
|
-
const [
|
|
1508
|
-
const [
|
|
1509
|
-
const [
|
|
1510
|
-
const
|
|
1953
|
+
const isBusyRef = (0, import_react13.useRef)(false);
|
|
1954
|
+
const [result, setResult] = (0, import_react13.useState)(null);
|
|
1955
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
|
|
1956
|
+
const [stage, setStage] = (0, import_react13.useState)("idle");
|
|
1957
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1958
|
+
const send = (0, import_react13.useCallback)(
|
|
1511
1959
|
async (options) => {
|
|
1512
1960
|
if (!client || !isReady) {
|
|
1513
1961
|
throw new Error("Miden client is not ready");
|
|
1514
1962
|
}
|
|
1963
|
+
if (isBusyRef.current) {
|
|
1964
|
+
throw new MidenError(
|
|
1965
|
+
"A send is already in progress. Await the previous send before starting another.",
|
|
1966
|
+
{ code: "SEND_BUSY" }
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
isBusyRef.current = true;
|
|
1515
1970
|
setIsLoading(true);
|
|
1516
1971
|
setStage("executing");
|
|
1517
1972
|
setError(null);
|
|
1518
1973
|
try {
|
|
1974
|
+
if (!options.skipSync) {
|
|
1975
|
+
await sync();
|
|
1976
|
+
}
|
|
1519
1977
|
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
1520
|
-
|
|
1521
|
-
|
|
1978
|
+
let amount = options.amount;
|
|
1979
|
+
if (options.sendAll) {
|
|
1980
|
+
const resolvedAmount = await runExclusiveSafe(async () => {
|
|
1981
|
+
const fromId = parseAccountId(options.from);
|
|
1982
|
+
const account = await client.getAccount(fromId);
|
|
1983
|
+
if (!account) throw new Error("Account not found");
|
|
1984
|
+
const assetIdObj = parseAccountId(options.assetId);
|
|
1985
|
+
const balance = account.vault?.()?.getBalance?.(assetIdObj);
|
|
1986
|
+
if (balance === void 0 || balance === null) {
|
|
1987
|
+
throw new Error("Could not query account balance");
|
|
1988
|
+
}
|
|
1989
|
+
const bal = BigInt(balance);
|
|
1990
|
+
if (bal === 0n) {
|
|
1991
|
+
throw new Error("Account has zero balance for this asset");
|
|
1992
|
+
}
|
|
1993
|
+
return bal;
|
|
1994
|
+
});
|
|
1995
|
+
amount = resolvedAmount;
|
|
1996
|
+
}
|
|
1997
|
+
if (amount === void 0 || amount === null) {
|
|
1998
|
+
throw new Error("Amount is required (provide amount or sendAll)");
|
|
1999
|
+
}
|
|
1522
2000
|
const assetId = options.assetId ?? options.faucetId ?? null;
|
|
1523
2001
|
if (!assetId) {
|
|
1524
2002
|
throw new Error("Asset ID is required");
|
|
1525
2003
|
}
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
toAccountId,
|
|
1531
|
-
assetIdObj,
|
|
1532
|
-
noteType,
|
|
1533
|
-
options.amount,
|
|
1534
|
-
options.recallHeight ?? null,
|
|
1535
|
-
options.timelockHeight ?? null
|
|
2004
|
+
const hasAttachment = options.attachment !== void 0 && options.attachment !== null;
|
|
2005
|
+
if (hasAttachment && (options.recallHeight != null || options.timelockHeight != null)) {
|
|
2006
|
+
throw new Error(
|
|
2007
|
+
"recallHeight and timelockHeight are not supported when attachment is provided"
|
|
1536
2008
|
);
|
|
1537
|
-
|
|
2009
|
+
}
|
|
2010
|
+
const txResult = await runExclusiveSafe(async () => {
|
|
2011
|
+
const fromAccountId = parseAccountId(options.from);
|
|
2012
|
+
const toAccountId = parseAccountId(options.to);
|
|
2013
|
+
const assetIdObj = parseAccountId(assetId);
|
|
2014
|
+
let txRequest;
|
|
2015
|
+
if (hasAttachment) {
|
|
2016
|
+
const attachment = createNoteAttachment(options.attachment);
|
|
2017
|
+
const assets = new import_miden_sdk16.NoteAssets([
|
|
2018
|
+
new import_miden_sdk16.FungibleAsset(assetIdObj, amount)
|
|
2019
|
+
]);
|
|
2020
|
+
const note = import_miden_sdk16.Note.createP2IDNote(
|
|
2021
|
+
fromAccountId,
|
|
2022
|
+
toAccountId,
|
|
2023
|
+
assets,
|
|
2024
|
+
noteType,
|
|
2025
|
+
attachment
|
|
2026
|
+
);
|
|
2027
|
+
txRequest = new import_miden_sdk16.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk16.OutputNoteArray([import_miden_sdk16.OutputNote.full(note)])).build();
|
|
2028
|
+
} else {
|
|
2029
|
+
txRequest = client.newSendTransactionRequest(
|
|
2030
|
+
fromAccountId,
|
|
2031
|
+
toAccountId,
|
|
2032
|
+
assetIdObj,
|
|
2033
|
+
noteType,
|
|
2034
|
+
amount,
|
|
2035
|
+
options.recallHeight ?? null,
|
|
2036
|
+
options.timelockHeight ?? null
|
|
2037
|
+
);
|
|
2038
|
+
}
|
|
2039
|
+
const execAccountId = parseAccountId(options.from);
|
|
2040
|
+
return await client.executeTransaction(execAccountId, txRequest);
|
|
1538
2041
|
});
|
|
1539
2042
|
setStage("proving");
|
|
1540
2043
|
const provenTransaction = await runExclusiveSafe(
|
|
@@ -1544,22 +2047,31 @@ function useSend() {
|
|
|
1544
2047
|
const submissionHeight = await runExclusiveSafe(
|
|
1545
2048
|
() => client.submitProvenTransaction(provenTransaction, txResult)
|
|
1546
2049
|
);
|
|
2050
|
+
const txIdHex = txResult.id().toHex();
|
|
2051
|
+
const txIdString = txResult.id().toString();
|
|
2052
|
+
let fullNote = null;
|
|
2053
|
+
if (noteType === import_miden_sdk16.NoteType.Private) {
|
|
2054
|
+
fullNote = extractFullNote(txResult);
|
|
2055
|
+
}
|
|
1547
2056
|
await runExclusiveSafe(
|
|
1548
2057
|
() => client.applyTransaction(txResult, submissionHeight)
|
|
1549
2058
|
);
|
|
1550
|
-
|
|
1551
|
-
await waitForTransactionCommit(client, runExclusiveSafe, txId);
|
|
1552
|
-
if (noteType === import_miden_sdk12.NoteType.Private) {
|
|
1553
|
-
const fullNote = extractFullNote(txResult);
|
|
2059
|
+
if (noteType === import_miden_sdk16.NoteType.Private) {
|
|
1554
2060
|
if (!fullNote) {
|
|
1555
2061
|
throw new Error("Missing full note for private send");
|
|
1556
2062
|
}
|
|
1557
|
-
|
|
2063
|
+
await waitForTransactionCommit(
|
|
2064
|
+
client,
|
|
2065
|
+
runExclusiveSafe,
|
|
2066
|
+
txIdHex
|
|
2067
|
+
);
|
|
2068
|
+
const recipientAccountId = parseAccountId(options.to);
|
|
2069
|
+
const recipientAddress = parseAddress(options.to, recipientAccountId);
|
|
1558
2070
|
await runExclusiveSafe(
|
|
1559
2071
|
() => client.sendPrivateNote(fullNote, recipientAddress)
|
|
1560
2072
|
);
|
|
1561
2073
|
}
|
|
1562
|
-
const txSummary = { transactionId:
|
|
2074
|
+
const txSummary = { transactionId: txIdString };
|
|
1563
2075
|
setStage("complete");
|
|
1564
2076
|
setResult(txSummary);
|
|
1565
2077
|
await sync();
|
|
@@ -1571,11 +2083,12 @@ function useSend() {
|
|
|
1571
2083
|
throw error2;
|
|
1572
2084
|
} finally {
|
|
1573
2085
|
setIsLoading(false);
|
|
2086
|
+
isBusyRef.current = false;
|
|
1574
2087
|
}
|
|
1575
2088
|
},
|
|
1576
2089
|
[client, isReady, prover, runExclusive, sync]
|
|
1577
2090
|
);
|
|
1578
|
-
const reset = (0,
|
|
2091
|
+
const reset = (0, import_react13.useCallback)(() => {
|
|
1579
2092
|
setResult(null);
|
|
1580
2093
|
setIsLoading(false);
|
|
1581
2094
|
setStage("idle");
|
|
@@ -1590,39 +2103,6 @@ function useSend() {
|
|
|
1590
2103
|
reset
|
|
1591
2104
|
};
|
|
1592
2105
|
}
|
|
1593
|
-
function getNoteType(type) {
|
|
1594
|
-
switch (type) {
|
|
1595
|
-
case "private":
|
|
1596
|
-
return import_miden_sdk12.NoteType.Private;
|
|
1597
|
-
case "public":
|
|
1598
|
-
return import_miden_sdk12.NoteType.Public;
|
|
1599
|
-
case "encrypted":
|
|
1600
|
-
return import_miden_sdk12.NoteType.Encrypted;
|
|
1601
|
-
default:
|
|
1602
|
-
return import_miden_sdk12.NoteType.Private;
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
async function waitForTransactionCommit(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
|
|
1606
|
-
let waited = 0;
|
|
1607
|
-
while (waited < maxWaitMs) {
|
|
1608
|
-
await runExclusiveSafe(() => client.syncState());
|
|
1609
|
-
const [record] = await runExclusiveSafe(
|
|
1610
|
-
() => client.getTransactions(import_miden_sdk12.TransactionFilter.ids([txId]))
|
|
1611
|
-
);
|
|
1612
|
-
if (record) {
|
|
1613
|
-
const status = record.transactionStatus();
|
|
1614
|
-
if (status.isCommitted()) {
|
|
1615
|
-
return;
|
|
1616
|
-
}
|
|
1617
|
-
if (status.isDiscarded()) {
|
|
1618
|
-
throw new Error("Transaction was discarded before commit");
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1622
|
-
waited += delayMs;
|
|
1623
|
-
}
|
|
1624
|
-
throw new Error("Timeout waiting for transaction commit");
|
|
1625
|
-
}
|
|
1626
2106
|
function extractFullNote(txResult) {
|
|
1627
2107
|
try {
|
|
1628
2108
|
const executedTx = txResult.executedTransaction?.();
|
|
@@ -1635,16 +2115,17 @@ function extractFullNote(txResult) {
|
|
|
1635
2115
|
}
|
|
1636
2116
|
|
|
1637
2117
|
// src/hooks/useMultiSend.ts
|
|
1638
|
-
var
|
|
1639
|
-
var
|
|
2118
|
+
var import_react14 = require("react");
|
|
2119
|
+
var import_miden_sdk17 = require("@miden-sdk/miden-sdk");
|
|
1640
2120
|
function useMultiSend() {
|
|
1641
2121
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1642
2122
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1643
|
-
const
|
|
1644
|
-
const [
|
|
1645
|
-
const [
|
|
1646
|
-
const [
|
|
1647
|
-
const
|
|
2123
|
+
const isBusyRef = (0, import_react14.useRef)(false);
|
|
2124
|
+
const [result, setResult] = (0, import_react14.useState)(null);
|
|
2125
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
|
|
2126
|
+
const [stage, setStage] = (0, import_react14.useState)("idle");
|
|
2127
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
2128
|
+
const sendMany = (0, import_react14.useCallback)(
|
|
1648
2129
|
async (options) => {
|
|
1649
2130
|
if (!client || !isReady) {
|
|
1650
2131
|
throw new Error("Miden client is not ready");
|
|
@@ -1652,35 +2133,53 @@ function useMultiSend() {
|
|
|
1652
2133
|
if (options.recipients.length === 0) {
|
|
1653
2134
|
throw new Error("No recipients provided");
|
|
1654
2135
|
}
|
|
2136
|
+
if (isBusyRef.current) {
|
|
2137
|
+
throw new MidenError(
|
|
2138
|
+
"A send is already in progress. Await the previous send before starting another.",
|
|
2139
|
+
{ code: "SEND_BUSY" }
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
isBusyRef.current = true;
|
|
1655
2143
|
setIsLoading(true);
|
|
1656
2144
|
setStage("executing");
|
|
1657
2145
|
setError(null);
|
|
1658
2146
|
try {
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
receiverId
|
|
1668
|
-
assets
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
2147
|
+
if (!options.skipSync) {
|
|
2148
|
+
await sync();
|
|
2149
|
+
}
|
|
2150
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2151
|
+
const outputs = options.recipients.map(
|
|
2152
|
+
({ to, amount, attachment, noteType: recipientNoteType }) => {
|
|
2153
|
+
const iterSenderId = parseAccountId(options.from);
|
|
2154
|
+
const iterAssetId = parseAccountId(options.assetId);
|
|
2155
|
+
const receiverId = parseAccountId(to);
|
|
2156
|
+
const assets = new import_miden_sdk17.NoteAssets([
|
|
2157
|
+
new import_miden_sdk17.FungibleAsset(iterAssetId, amount)
|
|
2158
|
+
]);
|
|
2159
|
+
const resolvedNoteType = recipientNoteType ? getNoteType(recipientNoteType) : noteType;
|
|
2160
|
+
const noteAttachment = attachment !== void 0 && attachment !== null ? createNoteAttachment(attachment) : new import_miden_sdk17.NoteAttachment();
|
|
2161
|
+
const note = import_miden_sdk17.Note.createP2IDNote(
|
|
2162
|
+
iterSenderId,
|
|
2163
|
+
receiverId,
|
|
2164
|
+
assets,
|
|
2165
|
+
resolvedNoteType,
|
|
2166
|
+
noteAttachment
|
|
2167
|
+
);
|
|
2168
|
+
const recipientAddress = parseAddress(to, receiverId);
|
|
2169
|
+
return {
|
|
2170
|
+
outputNote: import_miden_sdk17.OutputNote.full(note),
|
|
2171
|
+
note,
|
|
2172
|
+
recipientAddress,
|
|
2173
|
+
noteType: resolvedNoteType
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
);
|
|
2177
|
+
const txRequest = new import_miden_sdk17.TransactionRequestBuilder().withOwnOutputNotes(
|
|
2178
|
+
new import_miden_sdk17.OutputNoteArray(outputs.map((o) => o.outputNote))
|
|
1681
2179
|
).build();
|
|
2180
|
+
const txSenderId = parseAccountId(options.from);
|
|
1682
2181
|
const txResult = await runExclusiveSafe(
|
|
1683
|
-
() => client.executeTransaction(
|
|
2182
|
+
() => client.executeTransaction(txSenderId, txRequest)
|
|
1684
2183
|
);
|
|
1685
2184
|
setStage("proving");
|
|
1686
2185
|
const provenTransaction = await runExclusiveSafe(
|
|
@@ -1690,23 +2189,27 @@ function useMultiSend() {
|
|
|
1690
2189
|
const submissionHeight = await runExclusiveSafe(
|
|
1691
2190
|
() => client.submitProvenTransaction(provenTransaction, txResult)
|
|
1692
2191
|
);
|
|
2192
|
+
const txIdHex = txResult.id().toHex();
|
|
2193
|
+
const txIdString = txResult.id().toString();
|
|
1693
2194
|
await runExclusiveSafe(
|
|
1694
2195
|
() => client.applyTransaction(txResult, submissionHeight)
|
|
1695
2196
|
);
|
|
1696
|
-
const
|
|
1697
|
-
if (
|
|
1698
|
-
await
|
|
2197
|
+
const hasPrivate = outputs.some((o) => o.noteType === import_miden_sdk17.NoteType.Private);
|
|
2198
|
+
if (hasPrivate) {
|
|
2199
|
+
await waitForTransactionCommit(
|
|
1699
2200
|
client,
|
|
1700
2201
|
runExclusiveSafe,
|
|
1701
|
-
|
|
2202
|
+
txIdHex
|
|
1702
2203
|
);
|
|
1703
2204
|
for (const output of outputs) {
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
2205
|
+
if (output.noteType === import_miden_sdk17.NoteType.Private) {
|
|
2206
|
+
await runExclusiveSafe(
|
|
2207
|
+
() => client.sendPrivateNote(output.note, output.recipientAddress)
|
|
2208
|
+
);
|
|
2209
|
+
}
|
|
1707
2210
|
}
|
|
1708
2211
|
}
|
|
1709
|
-
const txSummary = { transactionId:
|
|
2212
|
+
const txSummary = { transactionId: txIdString };
|
|
1710
2213
|
setStage("complete");
|
|
1711
2214
|
setResult(txSummary);
|
|
1712
2215
|
await sync();
|
|
@@ -1718,11 +2221,12 @@ function useMultiSend() {
|
|
|
1718
2221
|
throw error2;
|
|
1719
2222
|
} finally {
|
|
1720
2223
|
setIsLoading(false);
|
|
2224
|
+
isBusyRef.current = false;
|
|
1721
2225
|
}
|
|
1722
2226
|
},
|
|
1723
2227
|
[client, isReady, prover, runExclusive, sync]
|
|
1724
2228
|
);
|
|
1725
|
-
const reset = (0,
|
|
2229
|
+
const reset = (0, import_react14.useCallback)(() => {
|
|
1726
2230
|
setResult(null);
|
|
1727
2231
|
setIsLoading(false);
|
|
1728
2232
|
setStage("idle");
|
|
@@ -1737,71 +2241,38 @@ function useMultiSend() {
|
|
|
1737
2241
|
reset
|
|
1738
2242
|
};
|
|
1739
2243
|
}
|
|
1740
|
-
function getNoteType2(type) {
|
|
1741
|
-
switch (type) {
|
|
1742
|
-
case "private":
|
|
1743
|
-
return import_miden_sdk13.NoteType.Private;
|
|
1744
|
-
case "public":
|
|
1745
|
-
return import_miden_sdk13.NoteType.Public;
|
|
1746
|
-
case "encrypted":
|
|
1747
|
-
return import_miden_sdk13.NoteType.Encrypted;
|
|
1748
|
-
default:
|
|
1749
|
-
return import_miden_sdk13.NoteType.Private;
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
async function waitForTransactionCommit2(client, runExclusiveSafe, txId, maxWaitMs = 1e4, delayMs = 1e3) {
|
|
1753
|
-
let waited = 0;
|
|
1754
|
-
while (waited < maxWaitMs) {
|
|
1755
|
-
await runExclusiveSafe(() => client.syncState());
|
|
1756
|
-
const [record] = await runExclusiveSafe(
|
|
1757
|
-
() => client.getTransactions(import_miden_sdk13.TransactionFilter.ids([txId]))
|
|
1758
|
-
);
|
|
1759
|
-
if (record) {
|
|
1760
|
-
const status = record.transactionStatus();
|
|
1761
|
-
if (status.isCommitted()) {
|
|
1762
|
-
return;
|
|
1763
|
-
}
|
|
1764
|
-
if (status.isDiscarded()) {
|
|
1765
|
-
throw new Error("Transaction was discarded before commit");
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1769
|
-
waited += delayMs;
|
|
1770
|
-
}
|
|
1771
|
-
throw new Error("Timeout waiting for transaction commit");
|
|
1772
|
-
}
|
|
1773
2244
|
|
|
1774
2245
|
// src/hooks/useInternalTransfer.ts
|
|
1775
|
-
var
|
|
1776
|
-
var
|
|
2246
|
+
var import_react15 = require("react");
|
|
2247
|
+
var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
|
|
1777
2248
|
function useInternalTransfer() {
|
|
1778
2249
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
1779
2250
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1780
|
-
const [result, setResult] = (0,
|
|
1781
|
-
const [isLoading, setIsLoading] = (0,
|
|
1782
|
-
const [stage, setStage] = (0,
|
|
1783
|
-
const [error, setError] = (0,
|
|
1784
|
-
const transferOnce = (0,
|
|
2251
|
+
const [result, setResult] = (0, import_react15.useState)(null);
|
|
2252
|
+
const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
|
|
2253
|
+
const [stage, setStage] = (0, import_react15.useState)("idle");
|
|
2254
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
2255
|
+
const transferOnce = (0, import_react15.useCallback)(
|
|
1785
2256
|
async (options) => {
|
|
1786
2257
|
if (!client || !isReady) {
|
|
1787
2258
|
throw new Error("Miden client is not ready");
|
|
1788
2259
|
}
|
|
1789
|
-
const noteType =
|
|
2260
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
1790
2261
|
const senderId = parseAccountId(options.from);
|
|
1791
2262
|
const receiverId = parseAccountId(options.to);
|
|
1792
2263
|
const assetId = parseAccountId(options.assetId);
|
|
1793
|
-
const assets = new
|
|
1794
|
-
new
|
|
2264
|
+
const assets = new import_miden_sdk18.NoteAssets([
|
|
2265
|
+
new import_miden_sdk18.FungibleAsset(assetId, options.amount)
|
|
1795
2266
|
]);
|
|
1796
|
-
const note =
|
|
2267
|
+
const note = import_miden_sdk18.Note.createP2IDNote(
|
|
1797
2268
|
senderId,
|
|
1798
2269
|
receiverId,
|
|
1799
2270
|
assets,
|
|
1800
2271
|
noteType,
|
|
1801
|
-
new
|
|
2272
|
+
new import_miden_sdk18.NoteAttachment()
|
|
1802
2273
|
);
|
|
1803
2274
|
const noteId = note.id().toString();
|
|
1804
|
-
const createRequest = new
|
|
2275
|
+
const createRequest = new import_miden_sdk18.TransactionRequestBuilder().withOwnOutputNotes(new import_miden_sdk18.OutputNoteArray([import_miden_sdk18.OutputNote.full(note)])).build();
|
|
1805
2276
|
const createTxId = await runExclusiveSafe(
|
|
1806
2277
|
() => prover ? client.submitNewTransactionWithProver(
|
|
1807
2278
|
senderId,
|
|
@@ -1809,7 +2280,7 @@ function useInternalTransfer() {
|
|
|
1809
2280
|
prover
|
|
1810
2281
|
) : client.submitNewTransaction(senderId, createRequest)
|
|
1811
2282
|
);
|
|
1812
|
-
const consumeRequest = new
|
|
2283
|
+
const consumeRequest = new import_miden_sdk18.TransactionRequestBuilder().withInputNotes(new import_miden_sdk18.NoteAndArgsArray([new import_miden_sdk18.NoteAndArgs(note, null)])).build();
|
|
1813
2284
|
const consumeTxId = await runExclusiveSafe(
|
|
1814
2285
|
() => prover ? client.submitNewTransactionWithProver(
|
|
1815
2286
|
receiverId,
|
|
@@ -1825,7 +2296,7 @@ function useInternalTransfer() {
|
|
|
1825
2296
|
},
|
|
1826
2297
|
[client, isReady, prover, runExclusiveSafe]
|
|
1827
2298
|
);
|
|
1828
|
-
const transfer = (0,
|
|
2299
|
+
const transfer = (0, import_react15.useCallback)(
|
|
1829
2300
|
async (options) => {
|
|
1830
2301
|
if (!client || !isReady) {
|
|
1831
2302
|
throw new Error("Miden client is not ready");
|
|
@@ -1851,7 +2322,7 @@ function useInternalTransfer() {
|
|
|
1851
2322
|
},
|
|
1852
2323
|
[client, isReady, sync, transferOnce]
|
|
1853
2324
|
);
|
|
1854
|
-
const transferChain = (0,
|
|
2325
|
+
const transferChain = (0, import_react15.useCallback)(
|
|
1855
2326
|
async (options) => {
|
|
1856
2327
|
if (!client || !isReady) {
|
|
1857
2328
|
throw new Error("Miden client is not ready");
|
|
@@ -1892,7 +2363,7 @@ function useInternalTransfer() {
|
|
|
1892
2363
|
},
|
|
1893
2364
|
[client, isReady, sync, transferOnce]
|
|
1894
2365
|
);
|
|
1895
|
-
const reset = (0,
|
|
2366
|
+
const reset = (0, import_react15.useCallback)(() => {
|
|
1896
2367
|
setResult(null);
|
|
1897
2368
|
setIsLoading(false);
|
|
1898
2369
|
setStage("idle");
|
|
@@ -1908,47 +2379,35 @@ function useInternalTransfer() {
|
|
|
1908
2379
|
reset
|
|
1909
2380
|
};
|
|
1910
2381
|
}
|
|
1911
|
-
function getNoteType3(type) {
|
|
1912
|
-
switch (type) {
|
|
1913
|
-
case "private":
|
|
1914
|
-
return import_miden_sdk14.NoteType.Private;
|
|
1915
|
-
case "public":
|
|
1916
|
-
return import_miden_sdk14.NoteType.Public;
|
|
1917
|
-
case "encrypted":
|
|
1918
|
-
return import_miden_sdk14.NoteType.Encrypted;
|
|
1919
|
-
default:
|
|
1920
|
-
return import_miden_sdk14.NoteType.Private;
|
|
1921
|
-
}
|
|
1922
|
-
}
|
|
1923
2382
|
|
|
1924
2383
|
// src/hooks/useWaitForCommit.ts
|
|
1925
|
-
var
|
|
1926
|
-
var
|
|
2384
|
+
var import_react16 = require("react");
|
|
2385
|
+
var import_miden_sdk19 = require("@miden-sdk/miden-sdk");
|
|
1927
2386
|
function useWaitForCommit() {
|
|
1928
2387
|
const { client, isReady, runExclusive } = useMiden();
|
|
1929
2388
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1930
|
-
const waitForCommit = (0,
|
|
2389
|
+
const waitForCommit = (0, import_react16.useCallback)(
|
|
1931
2390
|
async (txId, options) => {
|
|
1932
2391
|
if (!client || !isReady) {
|
|
1933
2392
|
throw new Error("Miden client is not ready");
|
|
1934
2393
|
}
|
|
1935
2394
|
const timeoutMs = Math.max(0, options?.timeoutMs ?? 1e4);
|
|
1936
2395
|
const intervalMs = Math.max(1, options?.intervalMs ?? 1e3);
|
|
1937
|
-
const targetHex =
|
|
2396
|
+
const targetHex = normalizeHex3(
|
|
1938
2397
|
typeof txId === "string" ? txId : txId.toHex()
|
|
1939
2398
|
);
|
|
1940
|
-
|
|
1941
|
-
while (
|
|
2399
|
+
const deadline = Date.now() + timeoutMs;
|
|
2400
|
+
while (Date.now() < deadline) {
|
|
1942
2401
|
await runExclusiveSafe(
|
|
1943
2402
|
() => client.syncState()
|
|
1944
2403
|
);
|
|
1945
2404
|
const records = await runExclusiveSafe(
|
|
1946
2405
|
() => client.getTransactions(
|
|
1947
|
-
typeof txId === "string" ?
|
|
2406
|
+
typeof txId === "string" ? import_miden_sdk19.TransactionFilter.all() : import_miden_sdk19.TransactionFilter.ids([txId])
|
|
1948
2407
|
)
|
|
1949
2408
|
);
|
|
1950
2409
|
const record = records.find(
|
|
1951
|
-
(item) =>
|
|
2410
|
+
(item) => normalizeHex3(item.id().toHex()) === targetHex
|
|
1952
2411
|
);
|
|
1953
2412
|
if (record) {
|
|
1954
2413
|
const status = record.transactionStatus();
|
|
@@ -1960,7 +2419,6 @@ function useWaitForCommit() {
|
|
|
1960
2419
|
}
|
|
1961
2420
|
}
|
|
1962
2421
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
1963
|
-
waited += intervalMs;
|
|
1964
2422
|
}
|
|
1965
2423
|
throw new Error("Timeout waiting for transaction commit");
|
|
1966
2424
|
},
|
|
@@ -1968,18 +2426,18 @@ function useWaitForCommit() {
|
|
|
1968
2426
|
);
|
|
1969
2427
|
return { waitForCommit };
|
|
1970
2428
|
}
|
|
1971
|
-
function
|
|
2429
|
+
function normalizeHex3(value) {
|
|
1972
2430
|
const trimmed = value.trim();
|
|
1973
2431
|
const normalized = trimmed.startsWith("0x") || trimmed.startsWith("0X") ? trimmed : `0x${trimmed}`;
|
|
1974
2432
|
return normalized.toLowerCase();
|
|
1975
2433
|
}
|
|
1976
2434
|
|
|
1977
2435
|
// src/hooks/useWaitForNotes.ts
|
|
1978
|
-
var
|
|
2436
|
+
var import_react17 = require("react");
|
|
1979
2437
|
function useWaitForNotes() {
|
|
1980
2438
|
const { client, isReady, runExclusive } = useMiden();
|
|
1981
2439
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
1982
|
-
const waitForConsumableNotes = (0,
|
|
2440
|
+
const waitForConsumableNotes = (0, import_react17.useCallback)(
|
|
1983
2441
|
async (options) => {
|
|
1984
2442
|
if (!client || !isReady) {
|
|
1985
2443
|
throw new Error("Miden client is not ready");
|
|
@@ -1990,7 +2448,9 @@ function useWaitForNotes() {
|
|
|
1990
2448
|
const accountId = parseAccountId(options.accountId);
|
|
1991
2449
|
let waited = 0;
|
|
1992
2450
|
while (waited < timeoutMs) {
|
|
1993
|
-
await runExclusiveSafe(
|
|
2451
|
+
await runExclusiveSafe(
|
|
2452
|
+
() => client.syncState()
|
|
2453
|
+
);
|
|
1994
2454
|
const notes = await runExclusiveSafe(
|
|
1995
2455
|
() => client.getConsumableNotes(accountId)
|
|
1996
2456
|
);
|
|
@@ -2008,16 +2468,15 @@ function useWaitForNotes() {
|
|
|
2008
2468
|
}
|
|
2009
2469
|
|
|
2010
2470
|
// src/hooks/useMint.ts
|
|
2011
|
-
var
|
|
2012
|
-
var import_miden_sdk16 = require("@miden-sdk/miden-sdk");
|
|
2471
|
+
var import_react18 = require("react");
|
|
2013
2472
|
function useMint() {
|
|
2014
2473
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2015
2474
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2016
|
-
const [result, setResult] = (0,
|
|
2017
|
-
const [isLoading, setIsLoading] = (0,
|
|
2018
|
-
const [stage, setStage] = (0,
|
|
2019
|
-
const [error, setError] = (0,
|
|
2020
|
-
const mint = (0,
|
|
2475
|
+
const [result, setResult] = (0, import_react18.useState)(null);
|
|
2476
|
+
const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
|
|
2477
|
+
const [stage, setStage] = (0, import_react18.useState)("idle");
|
|
2478
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
2479
|
+
const mint = (0, import_react18.useCallback)(
|
|
2021
2480
|
async (options) => {
|
|
2022
2481
|
if (!client || !isReady) {
|
|
2023
2482
|
throw new Error("Miden client is not ready");
|
|
@@ -2026,7 +2485,7 @@ function useMint() {
|
|
|
2026
2485
|
setStage("executing");
|
|
2027
2486
|
setError(null);
|
|
2028
2487
|
try {
|
|
2029
|
-
const noteType =
|
|
2488
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2030
2489
|
const targetAccountIdObj = parseAccountId(options.targetAccountId);
|
|
2031
2490
|
const faucetIdObj = parseAccountId(options.faucetId);
|
|
2032
2491
|
setStage("proving");
|
|
@@ -2059,7 +2518,7 @@ function useMint() {
|
|
|
2059
2518
|
},
|
|
2060
2519
|
[client, isReady, prover, runExclusive, sync]
|
|
2061
2520
|
);
|
|
2062
|
-
const reset = (0,
|
|
2521
|
+
const reset = (0, import_react18.useCallback)(() => {
|
|
2063
2522
|
setResult(null);
|
|
2064
2523
|
setIsLoading(false);
|
|
2065
2524
|
setStage("idle");
|
|
@@ -2074,30 +2533,18 @@ function useMint() {
|
|
|
2074
2533
|
reset
|
|
2075
2534
|
};
|
|
2076
2535
|
}
|
|
2077
|
-
function getNoteType4(type) {
|
|
2078
|
-
switch (type) {
|
|
2079
|
-
case "private":
|
|
2080
|
-
return import_miden_sdk16.NoteType.Private;
|
|
2081
|
-
case "public":
|
|
2082
|
-
return import_miden_sdk16.NoteType.Public;
|
|
2083
|
-
case "encrypted":
|
|
2084
|
-
return import_miden_sdk16.NoteType.Encrypted;
|
|
2085
|
-
default:
|
|
2086
|
-
return import_miden_sdk16.NoteType.Private;
|
|
2087
|
-
}
|
|
2088
|
-
}
|
|
2089
2536
|
|
|
2090
2537
|
// src/hooks/useConsume.ts
|
|
2091
|
-
var
|
|
2092
|
-
var
|
|
2538
|
+
var import_react19 = require("react");
|
|
2539
|
+
var import_miden_sdk20 = require("@miden-sdk/miden-sdk");
|
|
2093
2540
|
function useConsume() {
|
|
2094
2541
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2095
2542
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2096
|
-
const [result, setResult] = (0,
|
|
2097
|
-
const [isLoading, setIsLoading] = (0,
|
|
2098
|
-
const [stage, setStage] = (0,
|
|
2099
|
-
const [error, setError] = (0,
|
|
2100
|
-
const consume = (0,
|
|
2543
|
+
const [result, setResult] = (0, import_react19.useState)(null);
|
|
2544
|
+
const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
|
|
2545
|
+
const [stage, setStage] = (0, import_react19.useState)("idle");
|
|
2546
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
2547
|
+
const consume = (0, import_react19.useCallback)(
|
|
2101
2548
|
async (options) => {
|
|
2102
2549
|
if (!client || !isReady) {
|
|
2103
2550
|
throw new Error("Miden client is not ready");
|
|
@@ -2113,9 +2560,9 @@ function useConsume() {
|
|
|
2113
2560
|
setStage("proving");
|
|
2114
2561
|
const txResult = await runExclusiveSafe(async () => {
|
|
2115
2562
|
const noteIds = options.noteIds.map(
|
|
2116
|
-
(noteId) =>
|
|
2563
|
+
(noteId) => import_miden_sdk20.NoteId.fromHex(noteId)
|
|
2117
2564
|
);
|
|
2118
|
-
const filter = new
|
|
2565
|
+
const filter = new import_miden_sdk20.NoteFilter(import_miden_sdk20.NoteFilterTypes.List, noteIds);
|
|
2119
2566
|
const noteRecords = await client.getInputNotes(filter);
|
|
2120
2567
|
const notes = noteRecords.map((record) => record.toNote());
|
|
2121
2568
|
if (notes.length === 0) {
|
|
@@ -2147,7 +2594,7 @@ function useConsume() {
|
|
|
2147
2594
|
},
|
|
2148
2595
|
[client, isReady, prover, runExclusive, sync]
|
|
2149
2596
|
);
|
|
2150
|
-
const reset = (0,
|
|
2597
|
+
const reset = (0, import_react19.useCallback)(() => {
|
|
2151
2598
|
setResult(null);
|
|
2152
2599
|
setIsLoading(false);
|
|
2153
2600
|
setStage("idle");
|
|
@@ -2164,16 +2611,15 @@ function useConsume() {
|
|
|
2164
2611
|
}
|
|
2165
2612
|
|
|
2166
2613
|
// src/hooks/useSwap.ts
|
|
2167
|
-
var
|
|
2168
|
-
var import_miden_sdk18 = require("@miden-sdk/miden-sdk");
|
|
2614
|
+
var import_react20 = require("react");
|
|
2169
2615
|
function useSwap() {
|
|
2170
2616
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2171
2617
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2172
|
-
const [result, setResult] = (0,
|
|
2173
|
-
const [isLoading, setIsLoading] = (0,
|
|
2174
|
-
const [stage, setStage] = (0,
|
|
2175
|
-
const [error, setError] = (0,
|
|
2176
|
-
const swap = (0,
|
|
2618
|
+
const [result, setResult] = (0, import_react20.useState)(null);
|
|
2619
|
+
const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
|
|
2620
|
+
const [stage, setStage] = (0, import_react20.useState)("idle");
|
|
2621
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
2622
|
+
const swap = (0, import_react20.useCallback)(
|
|
2177
2623
|
async (options) => {
|
|
2178
2624
|
if (!client || !isReady) {
|
|
2179
2625
|
throw new Error("Miden client is not ready");
|
|
@@ -2182,8 +2628,8 @@ function useSwap() {
|
|
|
2182
2628
|
setStage("executing");
|
|
2183
2629
|
setError(null);
|
|
2184
2630
|
try {
|
|
2185
|
-
const noteType =
|
|
2186
|
-
const paybackNoteType =
|
|
2631
|
+
const noteType = getNoteType(options.noteType ?? DEFAULTS.NOTE_TYPE);
|
|
2632
|
+
const paybackNoteType = getNoteType(
|
|
2187
2633
|
options.paybackNoteType ?? DEFAULTS.NOTE_TYPE
|
|
2188
2634
|
);
|
|
2189
2635
|
const accountIdObj = parseAccountId(options.accountId);
|
|
@@ -2222,7 +2668,7 @@ function useSwap() {
|
|
|
2222
2668
|
},
|
|
2223
2669
|
[client, isReady, prover, runExclusive, sync]
|
|
2224
2670
|
);
|
|
2225
|
-
const reset = (0,
|
|
2671
|
+
const reset = (0, import_react20.useCallback)(() => {
|
|
2226
2672
|
setResult(null);
|
|
2227
2673
|
setIsLoading(false);
|
|
2228
2674
|
setStage("idle");
|
|
@@ -2237,41 +2683,40 @@ function useSwap() {
|
|
|
2237
2683
|
reset
|
|
2238
2684
|
};
|
|
2239
2685
|
}
|
|
2240
|
-
function getNoteType5(type) {
|
|
2241
|
-
switch (type) {
|
|
2242
|
-
case "private":
|
|
2243
|
-
return import_miden_sdk18.NoteType.Private;
|
|
2244
|
-
case "public":
|
|
2245
|
-
return import_miden_sdk18.NoteType.Public;
|
|
2246
|
-
case "encrypted":
|
|
2247
|
-
return import_miden_sdk18.NoteType.Encrypted;
|
|
2248
|
-
default:
|
|
2249
|
-
return import_miden_sdk18.NoteType.Private;
|
|
2250
|
-
}
|
|
2251
|
-
}
|
|
2252
2686
|
|
|
2253
2687
|
// src/hooks/useTransaction.ts
|
|
2254
|
-
var
|
|
2688
|
+
var import_react21 = require("react");
|
|
2255
2689
|
function useTransaction() {
|
|
2256
2690
|
const { client, isReady, sync, runExclusive, prover } = useMiden();
|
|
2257
2691
|
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2258
|
-
const
|
|
2259
|
-
const [
|
|
2260
|
-
const [
|
|
2261
|
-
const [
|
|
2262
|
-
const
|
|
2692
|
+
const isBusyRef = (0, import_react21.useRef)(false);
|
|
2693
|
+
const [result, setResult] = (0, import_react21.useState)(null);
|
|
2694
|
+
const [isLoading, setIsLoading] = (0, import_react21.useState)(false);
|
|
2695
|
+
const [stage, setStage] = (0, import_react21.useState)("idle");
|
|
2696
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
2697
|
+
const execute = (0, import_react21.useCallback)(
|
|
2263
2698
|
async (options) => {
|
|
2264
2699
|
if (!client || !isReady) {
|
|
2265
2700
|
throw new Error("Miden client is not ready");
|
|
2266
2701
|
}
|
|
2702
|
+
if (isBusyRef.current) {
|
|
2703
|
+
throw new MidenError(
|
|
2704
|
+
"A transaction is already in progress. Await the previous transaction before starting another.",
|
|
2705
|
+
{ code: "SEND_BUSY" }
|
|
2706
|
+
);
|
|
2707
|
+
}
|
|
2708
|
+
isBusyRef.current = true;
|
|
2267
2709
|
setIsLoading(true);
|
|
2268
2710
|
setStage("executing");
|
|
2269
2711
|
setError(null);
|
|
2270
2712
|
try {
|
|
2713
|
+
if (!options.skipSync) {
|
|
2714
|
+
await sync();
|
|
2715
|
+
}
|
|
2716
|
+
const txRequest = await resolveRequest(options.request, client);
|
|
2271
2717
|
setStage("proving");
|
|
2272
2718
|
const txResult = await runExclusiveSafe(async () => {
|
|
2273
2719
|
const accountIdObj = resolveAccountId2(options.accountId);
|
|
2274
|
-
const txRequest = await resolveRequest(options.request, client);
|
|
2275
2720
|
const txId = prover ? await client.submitNewTransactionWithProver(
|
|
2276
2721
|
accountIdObj,
|
|
2277
2722
|
txRequest,
|
|
@@ -2290,11 +2735,12 @@ function useTransaction() {
|
|
|
2290
2735
|
throw error2;
|
|
2291
2736
|
} finally {
|
|
2292
2737
|
setIsLoading(false);
|
|
2738
|
+
isBusyRef.current = false;
|
|
2293
2739
|
}
|
|
2294
2740
|
},
|
|
2295
2741
|
[client, isReady, prover, runExclusive, sync]
|
|
2296
2742
|
);
|
|
2297
|
-
const reset = (0,
|
|
2743
|
+
const reset = (0, import_react21.useCallback)(() => {
|
|
2298
2744
|
setResult(null);
|
|
2299
2745
|
setIsLoading(false);
|
|
2300
2746
|
setStage("idle");
|
|
@@ -2319,17 +2765,339 @@ async function resolveRequest(request, client) {
|
|
|
2319
2765
|
return request;
|
|
2320
2766
|
}
|
|
2321
2767
|
|
|
2768
|
+
// src/hooks/useSessionAccount.ts
|
|
2769
|
+
var import_react22 = require("react");
|
|
2770
|
+
var import_miden_sdk21 = require("@miden-sdk/miden-sdk");
|
|
2771
|
+
function useSessionAccount(options) {
|
|
2772
|
+
const { client, isReady, sync, runExclusive } = useMiden();
|
|
2773
|
+
const runExclusiveSafe = runExclusive ?? runExclusiveDirect;
|
|
2774
|
+
const setAccounts = useMidenStore((state) => state.setAccounts);
|
|
2775
|
+
const [sessionAccountId, setSessionAccountId] = (0, import_react22.useState)(null);
|
|
2776
|
+
const [step, setStep] = (0, import_react22.useState)("idle");
|
|
2777
|
+
const [error, setError] = (0, import_react22.useState)(null);
|
|
2778
|
+
const cancelledRef = (0, import_react22.useRef)(false);
|
|
2779
|
+
const isBusyRef = (0, import_react22.useRef)(false);
|
|
2780
|
+
const storagePrefix = options.storagePrefix ?? "miden-session";
|
|
2781
|
+
const pollIntervalMs = options.pollIntervalMs ?? 3e3;
|
|
2782
|
+
const maxWaitMs = options.maxWaitMs ?? 6e4;
|
|
2783
|
+
const storageMode = options.walletOptions?.storageMode ?? "public";
|
|
2784
|
+
const mutable = options.walletOptions?.mutable ?? DEFAULTS.WALLET_MUTABLE;
|
|
2785
|
+
const authScheme = options.walletOptions?.authScheme ?? DEFAULTS.AUTH_SCHEME;
|
|
2786
|
+
const fundRef = (0, import_react22.useRef)(options.fund);
|
|
2787
|
+
fundRef.current = options.fund;
|
|
2788
|
+
(0, import_react22.useEffect)(() => {
|
|
2789
|
+
try {
|
|
2790
|
+
const stored = localStorage.getItem(`${storagePrefix}:accountId`);
|
|
2791
|
+
const storedReady = localStorage.getItem(`${storagePrefix}:ready`);
|
|
2792
|
+
if (stored && stored.length > 0) {
|
|
2793
|
+
const validationId = parseAccountId(stored);
|
|
2794
|
+
validationId?.free?.();
|
|
2795
|
+
setSessionAccountId(stored);
|
|
2796
|
+
if (storedReady === "true") {
|
|
2797
|
+
setStep("ready");
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
} catch {
|
|
2801
|
+
localStorage.removeItem(`${storagePrefix}:accountId`);
|
|
2802
|
+
localStorage.removeItem(`${storagePrefix}:ready`);
|
|
2803
|
+
}
|
|
2804
|
+
}, [storagePrefix]);
|
|
2805
|
+
const initialize = (0, import_react22.useCallback)(async () => {
|
|
2806
|
+
if (!client || !isReady) {
|
|
2807
|
+
throw new Error("Miden client is not ready");
|
|
2808
|
+
}
|
|
2809
|
+
if (isBusyRef.current) {
|
|
2810
|
+
throw new MidenError(
|
|
2811
|
+
"Session account initialization is already in progress.",
|
|
2812
|
+
{ code: "OPERATION_BUSY" }
|
|
2813
|
+
);
|
|
2814
|
+
}
|
|
2815
|
+
isBusyRef.current = true;
|
|
2816
|
+
cancelledRef.current = false;
|
|
2817
|
+
setError(null);
|
|
2818
|
+
try {
|
|
2819
|
+
let walletId = sessionAccountId;
|
|
2820
|
+
if (!walletId) {
|
|
2821
|
+
setStep("creating");
|
|
2822
|
+
const resolvedStorageMode = getStorageMode3(storageMode);
|
|
2823
|
+
const wallet = await runExclusiveSafe(async () => {
|
|
2824
|
+
const w = await client.newWallet(
|
|
2825
|
+
resolvedStorageMode,
|
|
2826
|
+
mutable,
|
|
2827
|
+
authScheme
|
|
2828
|
+
);
|
|
2829
|
+
ensureAccountBech32(w);
|
|
2830
|
+
const accounts = await client.getAccounts();
|
|
2831
|
+
setAccounts(accounts);
|
|
2832
|
+
return w;
|
|
2833
|
+
});
|
|
2834
|
+
if (cancelledRef.current) return;
|
|
2835
|
+
walletId = wallet.id().toString();
|
|
2836
|
+
setSessionAccountId(walletId);
|
|
2837
|
+
localStorage.setItem(`${storagePrefix}:accountId`, walletId);
|
|
2838
|
+
}
|
|
2839
|
+
setStep("funding");
|
|
2840
|
+
await fundRef.current(walletId);
|
|
2841
|
+
if (cancelledRef.current) return;
|
|
2842
|
+
setStep("consuming");
|
|
2843
|
+
await waitAndConsume(
|
|
2844
|
+
client,
|
|
2845
|
+
runExclusiveSafe,
|
|
2846
|
+
walletId,
|
|
2847
|
+
pollIntervalMs,
|
|
2848
|
+
maxWaitMs,
|
|
2849
|
+
cancelledRef
|
|
2850
|
+
);
|
|
2851
|
+
if (cancelledRef.current) return;
|
|
2852
|
+
setStep("ready");
|
|
2853
|
+
localStorage.setItem(`${storagePrefix}:ready`, "true");
|
|
2854
|
+
await sync();
|
|
2855
|
+
} catch (err) {
|
|
2856
|
+
if (!cancelledRef.current) {
|
|
2857
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2858
|
+
setError(error2);
|
|
2859
|
+
setStep("idle");
|
|
2860
|
+
throw error2;
|
|
2861
|
+
}
|
|
2862
|
+
} finally {
|
|
2863
|
+
isBusyRef.current = false;
|
|
2864
|
+
}
|
|
2865
|
+
}, [
|
|
2866
|
+
client,
|
|
2867
|
+
isReady,
|
|
2868
|
+
sync,
|
|
2869
|
+
runExclusiveSafe,
|
|
2870
|
+
sessionAccountId,
|
|
2871
|
+
storageMode,
|
|
2872
|
+
mutable,
|
|
2873
|
+
authScheme,
|
|
2874
|
+
storagePrefix,
|
|
2875
|
+
pollIntervalMs,
|
|
2876
|
+
maxWaitMs,
|
|
2877
|
+
setAccounts
|
|
2878
|
+
]);
|
|
2879
|
+
const reset = (0, import_react22.useCallback)(() => {
|
|
2880
|
+
cancelledRef.current = true;
|
|
2881
|
+
isBusyRef.current = false;
|
|
2882
|
+
setSessionAccountId(null);
|
|
2883
|
+
setStep("idle");
|
|
2884
|
+
setError(null);
|
|
2885
|
+
localStorage.removeItem(`${storagePrefix}:accountId`);
|
|
2886
|
+
localStorage.removeItem(`${storagePrefix}:ready`);
|
|
2887
|
+
}, [storagePrefix]);
|
|
2888
|
+
return {
|
|
2889
|
+
initialize,
|
|
2890
|
+
sessionAccountId,
|
|
2891
|
+
isReady: step === "ready",
|
|
2892
|
+
step,
|
|
2893
|
+
error,
|
|
2894
|
+
reset
|
|
2895
|
+
};
|
|
2896
|
+
}
|
|
2897
|
+
function getStorageMode3(mode) {
|
|
2898
|
+
switch (mode) {
|
|
2899
|
+
case "private":
|
|
2900
|
+
return import_miden_sdk21.AccountStorageMode.private();
|
|
2901
|
+
case "public":
|
|
2902
|
+
return import_miden_sdk21.AccountStorageMode.public();
|
|
2903
|
+
default:
|
|
2904
|
+
return import_miden_sdk21.AccountStorageMode.public();
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
async function waitAndConsume(client, runExclusiveSafe, walletId, pollIntervalMs, maxWaitMs, cancelledRef) {
|
|
2908
|
+
const deadline = Date.now() + maxWaitMs;
|
|
2909
|
+
while (Date.now() < deadline) {
|
|
2910
|
+
if (cancelledRef.current) return;
|
|
2911
|
+
await runExclusiveSafe(
|
|
2912
|
+
() => client.syncState()
|
|
2913
|
+
);
|
|
2914
|
+
if (cancelledRef.current) return;
|
|
2915
|
+
const consumed = await runExclusiveSafe(async () => {
|
|
2916
|
+
const accountIdObj = parseAccountId(walletId);
|
|
2917
|
+
const consumable = await client.getConsumableNotes(accountIdObj);
|
|
2918
|
+
if (consumable.length === 0) return false;
|
|
2919
|
+
const notes = consumable.map((c) => c.inputNoteRecord().toNote());
|
|
2920
|
+
const txRequest = client.newConsumeTransactionRequest(notes);
|
|
2921
|
+
const freshAccountId = parseAccountId(walletId);
|
|
2922
|
+
await client.submitNewTransaction(freshAccountId, txRequest);
|
|
2923
|
+
return true;
|
|
2924
|
+
});
|
|
2925
|
+
if (consumed) return;
|
|
2926
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2927
|
+
}
|
|
2928
|
+
throw new Error("Timeout waiting for session wallet funding");
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
// src/utils/bytes.ts
|
|
2932
|
+
function bytesToBigInt(bytes) {
|
|
2933
|
+
let result = 0n;
|
|
2934
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2935
|
+
result = result << 8n | BigInt(bytes[i]);
|
|
2936
|
+
}
|
|
2937
|
+
return result;
|
|
2938
|
+
}
|
|
2939
|
+
function bigIntToBytes(value, length) {
|
|
2940
|
+
if (value < 0n) {
|
|
2941
|
+
throw new RangeError("bigIntToBytes: value must be non-negative");
|
|
2942
|
+
}
|
|
2943
|
+
const maxValue = (1n << BigInt(length * 8)) - 1n;
|
|
2944
|
+
if (value > maxValue) {
|
|
2945
|
+
throw new RangeError(
|
|
2946
|
+
`bigIntToBytes: value ${value} does not fit in ${length} byte(s) (max ${maxValue})`
|
|
2947
|
+
);
|
|
2948
|
+
}
|
|
2949
|
+
const bytes = new Uint8Array(length);
|
|
2950
|
+
let remaining = value;
|
|
2951
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
2952
|
+
bytes[i] = Number(remaining & 0xffn);
|
|
2953
|
+
remaining >>= 8n;
|
|
2954
|
+
}
|
|
2955
|
+
return bytes;
|
|
2956
|
+
}
|
|
2957
|
+
function concatBytes(...arrays) {
|
|
2958
|
+
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
|
2959
|
+
const result = new Uint8Array(totalLength);
|
|
2960
|
+
let offset = 0;
|
|
2961
|
+
for (const arr of arrays) {
|
|
2962
|
+
result.set(arr, offset);
|
|
2963
|
+
offset += arr.length;
|
|
2964
|
+
}
|
|
2965
|
+
return result;
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
// src/utils/walletDetection.ts
|
|
2969
|
+
async function waitForWalletDetection(adapter, timeoutMs = 5e3) {
|
|
2970
|
+
if (adapter.readyState === "Installed") return;
|
|
2971
|
+
return new Promise((resolve, reject) => {
|
|
2972
|
+
let settled = false;
|
|
2973
|
+
const settle = () => {
|
|
2974
|
+
if (settled) return;
|
|
2975
|
+
settled = true;
|
|
2976
|
+
clearTimeout(timer);
|
|
2977
|
+
adapter.off("readyStateChange", onReady);
|
|
2978
|
+
resolve();
|
|
2979
|
+
};
|
|
2980
|
+
const timer = setTimeout(() => {
|
|
2981
|
+
if (settled) return;
|
|
2982
|
+
settled = true;
|
|
2983
|
+
adapter.off("readyStateChange", onReady);
|
|
2984
|
+
reject(
|
|
2985
|
+
new Error(
|
|
2986
|
+
`Wallet extension not detected within ${timeoutMs}ms. Is the browser extension installed and enabled?`
|
|
2987
|
+
)
|
|
2988
|
+
);
|
|
2989
|
+
}, timeoutMs);
|
|
2990
|
+
const onReady = (state) => {
|
|
2991
|
+
if (state === "Installed") settle();
|
|
2992
|
+
};
|
|
2993
|
+
adapter.on("readyStateChange", onReady);
|
|
2994
|
+
if (adapter.readyState === "Installed") settle();
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
// src/utils/storage.ts
|
|
2999
|
+
async function migrateStorage(options) {
|
|
3000
|
+
if (typeof window === "undefined") return false;
|
|
3001
|
+
const versionKey = options.versionKey ?? "miden:storageVersion";
|
|
3002
|
+
const stored = localStorage.getItem(versionKey);
|
|
3003
|
+
if (stored === options.version) return false;
|
|
3004
|
+
if (options.onBeforeClear) {
|
|
3005
|
+
await options.onBeforeClear();
|
|
3006
|
+
}
|
|
3007
|
+
await clearMidenStorage();
|
|
3008
|
+
localStorage.setItem(versionKey, options.version);
|
|
3009
|
+
if (options.reloadOnClear !== false) {
|
|
3010
|
+
window.location.reload();
|
|
3011
|
+
}
|
|
3012
|
+
return true;
|
|
3013
|
+
}
|
|
3014
|
+
async function clearMidenStorage() {
|
|
3015
|
+
if (typeof indexedDB === "undefined") return;
|
|
3016
|
+
try {
|
|
3017
|
+
const databases = await indexedDB.databases();
|
|
3018
|
+
const midenDbs = databases.filter(
|
|
3019
|
+
(db) => db.name?.toLowerCase().includes("miden")
|
|
3020
|
+
);
|
|
3021
|
+
await Promise.all(
|
|
3022
|
+
midenDbs.map(
|
|
3023
|
+
(db) => new Promise((resolve, reject) => {
|
|
3024
|
+
if (!db.name) {
|
|
3025
|
+
resolve();
|
|
3026
|
+
return;
|
|
3027
|
+
}
|
|
3028
|
+
const req = indexedDB.deleteDatabase(db.name);
|
|
3029
|
+
req.onsuccess = () => resolve();
|
|
3030
|
+
req.onerror = () => reject(req.error);
|
|
3031
|
+
req.onblocked = () => {
|
|
3032
|
+
console.warn(
|
|
3033
|
+
`IndexedDB "${db.name}" delete was blocked \u2014 close other tabs using this database.`
|
|
3034
|
+
);
|
|
3035
|
+
resolve();
|
|
3036
|
+
};
|
|
3037
|
+
})
|
|
3038
|
+
)
|
|
3039
|
+
);
|
|
3040
|
+
} catch {
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
function createMidenStorage(prefix) {
|
|
3044
|
+
const fullKey = (key) => `${prefix}:${key}`;
|
|
3045
|
+
return {
|
|
3046
|
+
get(key) {
|
|
3047
|
+
try {
|
|
3048
|
+
const raw = localStorage.getItem(fullKey(key));
|
|
3049
|
+
if (raw === null) return null;
|
|
3050
|
+
return JSON.parse(raw);
|
|
3051
|
+
} catch {
|
|
3052
|
+
return null;
|
|
3053
|
+
}
|
|
3054
|
+
},
|
|
3055
|
+
set(key, value) {
|
|
3056
|
+
try {
|
|
3057
|
+
localStorage.setItem(fullKey(key), JSON.stringify(value));
|
|
3058
|
+
} catch (e) {
|
|
3059
|
+
console.warn(`Failed to write localStorage key "${fullKey(key)}":`, e);
|
|
3060
|
+
}
|
|
3061
|
+
},
|
|
3062
|
+
remove(key) {
|
|
3063
|
+
localStorage.removeItem(fullKey(key));
|
|
3064
|
+
},
|
|
3065
|
+
clear() {
|
|
3066
|
+
const keysToRemove = [];
|
|
3067
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
3068
|
+
const k = localStorage.key(i);
|
|
3069
|
+
if (k?.startsWith(`${prefix}:`)) {
|
|
3070
|
+
keysToRemove.push(k);
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
keysToRemove.forEach((k) => localStorage.removeItem(k));
|
|
3074
|
+
}
|
|
3075
|
+
};
|
|
3076
|
+
}
|
|
3077
|
+
|
|
2322
3078
|
// src/index.ts
|
|
2323
3079
|
installAccountBech32();
|
|
2324
3080
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2325
3081
|
0 && (module.exports = {
|
|
3082
|
+
AuthScheme,
|
|
2326
3083
|
DEFAULTS,
|
|
3084
|
+
MidenError,
|
|
2327
3085
|
MidenProvider,
|
|
2328
3086
|
SignerContext,
|
|
3087
|
+
accountIdsEqual,
|
|
3088
|
+
bigIntToBytes,
|
|
3089
|
+
bytesToBigInt,
|
|
3090
|
+
clearMidenStorage,
|
|
3091
|
+
concatBytes,
|
|
3092
|
+
createMidenStorage,
|
|
3093
|
+
createNoteAttachment,
|
|
2329
3094
|
formatAssetAmount,
|
|
2330
3095
|
formatNoteSummary,
|
|
2331
3096
|
getNoteSummary,
|
|
3097
|
+
migrateStorage,
|
|
3098
|
+
normalizeAccountId,
|
|
2332
3099
|
parseAssetAmount,
|
|
3100
|
+
readNoteAttachment,
|
|
2333
3101
|
toBech32AccountId,
|
|
2334
3102
|
useAccount,
|
|
2335
3103
|
useAccounts,
|
|
@@ -2343,13 +3111,17 @@ installAccountBech32();
|
|
|
2343
3111
|
useMidenClient,
|
|
2344
3112
|
useMint,
|
|
2345
3113
|
useMultiSend,
|
|
3114
|
+
useNoteStream,
|
|
2346
3115
|
useNotes,
|
|
2347
3116
|
useSend,
|
|
3117
|
+
useSessionAccount,
|
|
2348
3118
|
useSigner,
|
|
2349
3119
|
useSwap,
|
|
2350
3120
|
useSyncState,
|
|
2351
3121
|
useTransaction,
|
|
2352
3122
|
useTransactionHistory,
|
|
2353
3123
|
useWaitForCommit,
|
|
2354
|
-
useWaitForNotes
|
|
3124
|
+
useWaitForNotes,
|
|
3125
|
+
waitForWalletDetection,
|
|
3126
|
+
wrapWasmError
|
|
2355
3127
|
});
|