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