@permissionless-technologies/upp-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +194 -0
  3. package/dist/asp-TXSAFFD3.cjs +53 -0
  4. package/dist/asp-TXSAFFD3.cjs.map +1 -0
  5. package/dist/asp-ZA3RGN7G.js +4 -0
  6. package/dist/asp-ZA3RGN7G.js.map +1 -0
  7. package/dist/babyjubjub-2MGQVCKB.js +5 -0
  8. package/dist/babyjubjub-2MGQVCKB.js.map +1 -0
  9. package/dist/babyjubjub-MWZLJOVZ.cjs +66 -0
  10. package/dist/babyjubjub-MWZLJOVZ.cjs.map +1 -0
  11. package/dist/chunk-2JQISXBD.js +150 -0
  12. package/dist/chunk-2JQISXBD.js.map +1 -0
  13. package/dist/chunk-3HQ7A6ZM.cjs +61 -0
  14. package/dist/chunk-3HQ7A6ZM.cjs.map +1 -0
  15. package/dist/chunk-5AKBSMEQ.cjs +1008 -0
  16. package/dist/chunk-5AKBSMEQ.cjs.map +1 -0
  17. package/dist/chunk-5V5HSN6Y.js +81 -0
  18. package/dist/chunk-5V5HSN6Y.js.map +1 -0
  19. package/dist/chunk-BH24DZ5S.cjs +91 -0
  20. package/dist/chunk-BH24DZ5S.cjs.map +1 -0
  21. package/dist/chunk-C7QQOJ7T.cjs +67 -0
  22. package/dist/chunk-C7QQOJ7T.cjs.map +1 -0
  23. package/dist/chunk-ERQE57IA.cjs +404 -0
  24. package/dist/chunk-ERQE57IA.cjs.map +1 -0
  25. package/dist/chunk-EUP7MBAH.cjs +165 -0
  26. package/dist/chunk-EUP7MBAH.cjs.map +1 -0
  27. package/dist/chunk-G7VZBCD6.cjs +35 -0
  28. package/dist/chunk-G7VZBCD6.cjs.map +1 -0
  29. package/dist/chunk-GQV47S3N.cjs +10 -0
  30. package/dist/chunk-GQV47S3N.cjs.map +1 -0
  31. package/dist/chunk-GXZ3MTCQ.cjs +527 -0
  32. package/dist/chunk-GXZ3MTCQ.cjs.map +1 -0
  33. package/dist/chunk-JWNXBALH.cjs +57 -0
  34. package/dist/chunk-JWNXBALH.cjs.map +1 -0
  35. package/dist/chunk-KIKBPJXJ.cjs +348 -0
  36. package/dist/chunk-KIKBPJXJ.cjs.map +1 -0
  37. package/dist/chunk-NCW4AE7L.js +8 -0
  38. package/dist/chunk-NCW4AE7L.js.map +1 -0
  39. package/dist/chunk-NDM5EJEV.cjs +70 -0
  40. package/dist/chunk-NDM5EJEV.cjs.map +1 -0
  41. package/dist/chunk-NUIQHTSA.js +489 -0
  42. package/dist/chunk-NUIQHTSA.js.map +1 -0
  43. package/dist/chunk-OQDSHMXU.js +1002 -0
  44. package/dist/chunk-OQDSHMXU.js.map +1 -0
  45. package/dist/chunk-P37MRZ73.js +58 -0
  46. package/dist/chunk-P37MRZ73.js.map +1 -0
  47. package/dist/chunk-PWHOUQOZ.js +335 -0
  48. package/dist/chunk-PWHOUQOZ.js.map +1 -0
  49. package/dist/chunk-S4B7GYLN.js +112 -0
  50. package/dist/chunk-S4B7GYLN.js.map +1 -0
  51. package/dist/chunk-SGZZL5AC.js +59 -0
  52. package/dist/chunk-SGZZL5AC.js.map +1 -0
  53. package/dist/chunk-SQKBT2SH.cjs +122 -0
  54. package/dist/chunk-SQKBT2SH.cjs.map +1 -0
  55. package/dist/chunk-TSF6HEVS.cjs +201 -0
  56. package/dist/chunk-TSF6HEVS.cjs.map +1 -0
  57. package/dist/chunk-V23OSL25.js +48 -0
  58. package/dist/chunk-V23OSL25.js.map +1 -0
  59. package/dist/chunk-W77GRBO4.js +53 -0
  60. package/dist/chunk-W77GRBO4.js.map +1 -0
  61. package/dist/chunk-XV72HNHN.js +399 -0
  62. package/dist/chunk-XV72HNHN.js.map +1 -0
  63. package/dist/chunk-YOWDERVC.js +186 -0
  64. package/dist/chunk-YOWDERVC.js.map +1 -0
  65. package/dist/chunk-Z6ZWNWWR.js +30 -0
  66. package/dist/chunk-Z6ZWNWWR.js.map +1 -0
  67. package/dist/chunk-ZKZV6OI3.cjs +165 -0
  68. package/dist/chunk-ZKZV6OI3.cjs.map +1 -0
  69. package/dist/chunk-ZU6J7KMY.js +159 -0
  70. package/dist/chunk-ZU6J7KMY.js.map +1 -0
  71. package/dist/core/index.cjs +300 -0
  72. package/dist/core/index.cjs.map +1 -0
  73. package/dist/core/index.d.cts +9 -0
  74. package/dist/core/index.d.ts +9 -0
  75. package/dist/core/index.js +11 -0
  76. package/dist/core/index.js.map +1 -0
  77. package/dist/index-BBzvvrhG.d.ts +757 -0
  78. package/dist/index-BGvapsJy.d.cts +2811 -0
  79. package/dist/index-C-jSNw6j.d.cts +757 -0
  80. package/dist/index-ChGaGPzP.d.ts +2811 -0
  81. package/dist/index.cjs +3652 -0
  82. package/dist/index.cjs.map +1 -0
  83. package/dist/index.d.cts +12 -0
  84. package/dist/index.d.ts +12 -0
  85. package/dist/index.js +3112 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/indexer/index.cjs +58 -0
  88. package/dist/indexer/index.cjs.map +1 -0
  89. package/dist/indexer/index.d.cts +206 -0
  90. package/dist/indexer/index.d.ts +206 -0
  91. package/dist/indexer/index.js +5 -0
  92. package/dist/indexer/index.js.map +1 -0
  93. package/dist/keccak-m31-B_AqBbRF.d.cts +70 -0
  94. package/dist/keccak-m31-B_AqBbRF.d.ts +70 -0
  95. package/dist/keys/index.cjs +68 -0
  96. package/dist/keys/index.cjs.map +1 -0
  97. package/dist/keys/index.d.cts +158 -0
  98. package/dist/keys/index.d.ts +158 -0
  99. package/dist/keys/index.js +7 -0
  100. package/dist/keys/index.js.map +1 -0
  101. package/dist/merkle-7KS2EHRF.js +5 -0
  102. package/dist/merkle-7KS2EHRF.js.map +1 -0
  103. package/dist/merkle-HGDC6OB4.cjs +30 -0
  104. package/dist/merkle-HGDC6OB4.cjs.map +1 -0
  105. package/dist/merkle-mteVOlDf.d.cts +188 -0
  106. package/dist/merkle-mteVOlDf.d.ts +188 -0
  107. package/dist/poseidon-UHTJLWQM.js +7 -0
  108. package/dist/poseidon-UHTJLWQM.js.map +1 -0
  109. package/dist/poseidon-WHJSZSNP.cjs +45 -0
  110. package/dist/poseidon-WHJSZSNP.cjs.map +1 -0
  111. package/dist/proof-5OECB3RQ.cjs +45 -0
  112. package/dist/proof-5OECB3RQ.cjs.map +1 -0
  113. package/dist/proof-C4YBP6RY.js +4 -0
  114. package/dist/proof-C4YBP6RY.js.map +1 -0
  115. package/dist/react/index.cjs +2641 -0
  116. package/dist/react/index.cjs.map +1 -0
  117. package/dist/react/index.d.cts +757 -0
  118. package/dist/react/index.d.ts +757 -0
  119. package/dist/react/index.js +2598 -0
  120. package/dist/react/index.js.map +1 -0
  121. package/dist/transfer-2UDHDS7Q.cjs +37 -0
  122. package/dist/transfer-2UDHDS7Q.cjs.map +1 -0
  123. package/dist/transfer-BlmbO-Rd.d.ts +1270 -0
  124. package/dist/transfer-DKZuJnRM.d.cts +1270 -0
  125. package/dist/transfer-KTCXKHS4.js +8 -0
  126. package/dist/transfer-KTCXKHS4.js.map +1 -0
  127. package/dist/types-CJSbxv4q.d.cts +143 -0
  128. package/dist/types-mLybMxNR.d.ts +143 -0
  129. package/dist/utils/index.cjs +178 -0
  130. package/dist/utils/index.cjs.map +1 -0
  131. package/dist/utils/index.d.cts +88 -0
  132. package/dist/utils/index.d.ts +88 -0
  133. package/dist/utils/index.js +9 -0
  134. package/dist/utils/index.js.map +1 -0
  135. package/package.json +119 -0
  136. package/src/contracts/interfaces/IASPRegistry.sol +36 -0
  137. package/src/contracts/interfaces/IUniversalPrivatePool.sol +260 -0
  138. package/src/contracts/interfaces/IVerifiers.sol +68 -0
  139. package/src/deployments/11155111.json +19 -0
  140. package/src/deployments/31337.json +19 -0
@@ -0,0 +1,2598 @@
1
+ import { NoteStore, init_stealth, stealth_exports, SWAP_ORDER_PLACED_EVENT, filterOrdersByTokenPair, filterOrdersByASP, generateCancelSecret, computeCancelKeyHash, computeGiveAmount } from '../chunk-NUIQHTSA.js';
2
+ import { computeSingleOriginASPRoot } from '../chunk-P37MRZ73.js';
3
+ export { ASP_TREE_DEPTH, buildASPTree, computeMultiOriginASPRoot, computeSingleOriginASPRoot, generateASPProof, generateMultiOriginASPProof, generateSingleOriginASPProof } from '../chunk-P37MRZ73.js';
4
+ import { createAutoAdapter } from '../chunk-XV72HNHN.js';
5
+ import '../chunk-W77GRBO4.js';
6
+ import { init_poseidon, BABYJUBJUB_SUBORDER } from '../chunk-V23OSL25.js';
7
+ import { __toCommonJS } from '../chunk-Z6ZWNWWR.js';
8
+ import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
9
+ import { toHex, keccak256, toBytes, getAddress, encodePacked } from 'viem';
10
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
+ import { createPortal } from 'react-dom';
12
+ import { ASP_REGISTRY_HUB_ABI } from '@permissionless-technologies/upc-sdk';
13
+
14
+ var UPP_EIP712_DOMAIN = {
15
+ name: "UPP Stealth Account",
16
+ version: "2"
17
+ };
18
+ var UPP_EIP712_TYPES = {
19
+ Connect: [
20
+ { name: "info", type: "string" },
21
+ { name: "warning", type: "string" },
22
+ { name: "passwordHash", type: "bytes32" }
23
+ ]
24
+ };
25
+ var UPPAccountContext = createContext(null);
26
+ var sdkPromise = null;
27
+ async function loadSDK() {
28
+ if (!sdkPromise) {
29
+ sdkPromise = import('../index.js');
30
+ }
31
+ return sdkPromise;
32
+ }
33
+ function getStorageKey(ethAddress) {
34
+ return `upp_pq_account_${ethAddress.toLowerCase()}`;
35
+ }
36
+ function getNotesStorageKey(chainId, ownerHashPrefix) {
37
+ return `upp_pq_notes_${chainId}_${ownerHashPrefix}`;
38
+ }
39
+ function getChainFingerprintKey(chainId) {
40
+ return `upp_chain_fp_${chainId}`;
41
+ }
42
+ async function checkChainFingerprint(chainId, publicClient) {
43
+ if (typeof window === "undefined" || !publicClient) return true;
44
+ const fpKey = getChainFingerprintKey(chainId);
45
+ const stored = localStorage.getItem(fpKey);
46
+ try {
47
+ const [currentBlock, genesisBlock] = await Promise.all([
48
+ publicClient.getBlockNumber(),
49
+ publicClient.getBlock({ blockNumber: 0n })
50
+ ]);
51
+ const currentGenesisHash = genesisBlock.hash;
52
+ const currentBlockNum = Number(currentBlock);
53
+ if (stored) {
54
+ const fp = JSON.parse(stored);
55
+ if (fp.genesisHash !== currentGenesisHash || currentBlockNum < fp.blockNumber) {
56
+ localStorage.removeItem(fpKey);
57
+ return false;
58
+ }
59
+ }
60
+ const newFp = {
61
+ genesisHash: currentGenesisHash,
62
+ blockNumber: currentBlockNum
63
+ };
64
+ localStorage.setItem(fpKey, JSON.stringify(newFp));
65
+ return true;
66
+ } catch (e) {
67
+ console.warn("[UPPAccount] Chain fingerprint check failed:", e);
68
+ return true;
69
+ }
70
+ }
71
+ function UPPAccountProvider({
72
+ children,
73
+ ethAddress,
74
+ chainId = 1,
75
+ indexerConfig,
76
+ signTypedData,
77
+ publicClient: publicClientProp,
78
+ activeProofSystem
79
+ }) {
80
+ const [masterKeys, setMasterKeys] = useState(null);
81
+ const [starkMasterKeys, setStarkMasterKeys] = useState(null);
82
+ const [notes, setNotes] = useState([]);
83
+ const [isLoading, setIsLoading] = useState(false);
84
+ const [isConnecting, setIsConnecting] = useState(false);
85
+ const [cryptoReady, setCryptoReady] = useState(false);
86
+ const [isSyncing, setIsSyncing] = useState(false);
87
+ const [lastSyncedBlock, _setLastSyncedBlock] = useState(0);
88
+ const [liveSyncInterval, setLiveSyncInterval] = useState(null);
89
+ const unwatchRef = useRef(null);
90
+ const syncPromiseRef = useRef(null);
91
+ const noteStoreRef = useRef(null);
92
+ useEffect(() => {
93
+ loadSDK().then(() => setCryptoReady(true));
94
+ }, []);
95
+ useEffect(() => {
96
+ let noteStoreUnsub = null;
97
+ if (typeof window === "undefined") return;
98
+ if (!ethAddress || !cryptoReady) {
99
+ setMasterKeys(null);
100
+ setStarkMasterKeys(null);
101
+ setNotes([]);
102
+ noteStoreRef.current = null;
103
+ return;
104
+ }
105
+ const saved = localStorage.getItem(getStorageKey(ethAddress));
106
+ if (saved) {
107
+ try {
108
+ const parsed = JSON.parse(saved);
109
+ if (!parsed.starkSecret || !parsed.spendingSecret) {
110
+ console.log("[UPPAccount] Invalid account data, clearing...");
111
+ localStorage.removeItem(getStorageKey(ethAddress));
112
+ setMasterKeys(null);
113
+ setStarkMasterKeys(null);
114
+ setNotes([]);
115
+ return;
116
+ }
117
+ const keys = {
118
+ spendingSecret: BigInt(parsed.spendingSecret),
119
+ ownerHash: BigInt(parsed.ownerHash),
120
+ viewingSecret: BigInt(parsed.viewingSecret),
121
+ viewingHash: BigInt(parsed.viewingHash)
122
+ };
123
+ setMasterKeys(keys);
124
+ if (parsed.starkSecret) {
125
+ const starkKeys = {
126
+ starkSecret: parsed.starkSecret.map((s) => BigInt(s)),
127
+ starkOwnerHash: parsed.starkOwnerHash.map((s) => BigInt(s)),
128
+ starkViewingSecret: parsed.starkViewingSecret.map((s) => BigInt(s)),
129
+ starkViewingHash: parsed.starkViewingHash.map((s) => BigInt(s))
130
+ };
131
+ setStarkMasterKeys(starkKeys);
132
+ }
133
+ const ownerHashHex2 = toHex(keys.ownerHash, { size: 32 });
134
+ const storagePrefix = `upp_${chainId}_${ownerHashHex2.slice(0, 12)}`;
135
+ const storage = createAutoAdapter(storagePrefix);
136
+ const store = new NoteStore(storage, "notes");
137
+ noteStoreRef.current = store;
138
+ noteStoreUnsub = store.onChange(() => {
139
+ setNotes([...store.getNotes()]);
140
+ });
141
+ store.load().then(() => {
142
+ if (store.getNotes().length === 0) {
143
+ const legacyKey = getNotesStorageKey(chainId, ownerHashHex2.slice(0, 12));
144
+ const legacyNotes = localStorage.getItem(legacyKey);
145
+ if (legacyNotes) {
146
+ try {
147
+ const parsed2 = JSON.parse(legacyNotes);
148
+ const migrated = parsed2.map((n) => ({
149
+ ...n,
150
+ amount: BigInt(n.amount),
151
+ blinding: BigInt(n.blinding),
152
+ origin: n.origin ?? "0x0000000000000000000000000000000000000000",
153
+ token: n.token ?? "0x0000000000000000000000000000000000000000",
154
+ proofSystem: n.proofSystem ?? "snark"
155
+ }));
156
+ store.addNotes(migrated);
157
+ store.persist();
158
+ console.log(`[NoteStore] Migrated ${migrated.length} legacy notes`);
159
+ } catch {
160
+ }
161
+ }
162
+ }
163
+ setNotes([...store.getNotes()]);
164
+ });
165
+ if (publicClientProp) {
166
+ checkChainFingerprint(chainId, publicClientProp).then((valid) => {
167
+ if (!valid) {
168
+ console.log(`[UPPAccount] Chain ${chainId} was reset \u2014 clearing stale notes`);
169
+ store.clear();
170
+ const legacyKey = getNotesStorageKey(chainId, ownerHashHex2.slice(0, 12));
171
+ localStorage.removeItem(legacyKey);
172
+ }
173
+ });
174
+ }
175
+ } catch (e) {
176
+ console.error("Failed to load saved account:", e);
177
+ }
178
+ } else {
179
+ setMasterKeys(null);
180
+ setStarkMasterKeys(null);
181
+ setNotes([]);
182
+ }
183
+ return () => {
184
+ if (noteStoreUnsub) noteStoreUnsub();
185
+ };
186
+ }, [ethAddress, cryptoReady, chainId, publicClientProp]);
187
+ const persistNotes = useCallback(
188
+ (_notesToSave) => {
189
+ noteStoreRef.current?.persist().catch(console.error);
190
+ },
191
+ []
192
+ );
193
+ const setupAccount = useCallback(
194
+ async (signature) => {
195
+ if (!ethAddress || !cryptoReady) {
196
+ throw new Error("Not ready to setup account");
197
+ }
198
+ setIsLoading(true);
199
+ try {
200
+ const sdk = await loadSDK();
201
+ const keys = await sdk.deriveKeysFromSignature(signature);
202
+ const starkKeys = sdk.deriveStarkKeysFromSignature(signature);
203
+ setMasterKeys(keys);
204
+ setStarkMasterKeys(starkKeys);
205
+ setNotes([]);
206
+ const serialized = {
207
+ version: 3,
208
+ spendingSecret: toHex(keys.spendingSecret, { size: 32 }),
209
+ ownerHash: toHex(keys.ownerHash, { size: 32 }),
210
+ viewingSecret: toHex(keys.viewingSecret, { size: 32 }),
211
+ viewingHash: toHex(keys.viewingHash, { size: 32 }),
212
+ starkSecret: starkKeys.starkSecret.map((v) => v.toString()),
213
+ starkOwnerHash: starkKeys.starkOwnerHash.map((v) => v.toString()),
214
+ starkViewingSecret: starkKeys.starkViewingSecret.map((v) => v.toString()),
215
+ starkViewingHash: starkKeys.starkViewingHash.map((v) => v.toString())
216
+ };
217
+ localStorage.setItem(getStorageKey(ethAddress), JSON.stringify(serialized));
218
+ } finally {
219
+ setIsLoading(false);
220
+ }
221
+ },
222
+ [ethAddress, cryptoReady]
223
+ );
224
+ const connect = useCallback(
225
+ async (password) => {
226
+ if (!signTypedData) {
227
+ throw new Error("signTypedData not provided to UPPAccountProvider. Pass signTypedDataAsync from wagmi.");
228
+ }
229
+ if (!ethAddress) {
230
+ throw new Error("Wallet not connected");
231
+ }
232
+ setIsConnecting(true);
233
+ try {
234
+ const passwordHash = password ? keccak256(toBytes(password)) : keccak256(toBytes(""));
235
+ const signature = await signTypedData({
236
+ domain: { ...UPP_EIP712_DOMAIN, chainId },
237
+ types: UPP_EIP712_TYPES,
238
+ primaryType: "Connect",
239
+ message: {
240
+ info: "Setup UPP Private Account (SNARK + STARK)",
241
+ warning: "This signature derives your private keys. Never share it.",
242
+ passwordHash
243
+ }
244
+ });
245
+ await setupAccount(signature);
246
+ } finally {
247
+ setIsConnecting(false);
248
+ }
249
+ },
250
+ [signTypedData, ethAddress, chainId, setupAccount]
251
+ );
252
+ const logout = useCallback(() => {
253
+ noteStoreRef.current?.clear().catch(console.error);
254
+ noteStoreRef.current = null;
255
+ if (masterKeys) {
256
+ const ownerHashHex2 = toHex(masterKeys.ownerHash, { size: 32 });
257
+ const notesKey = getNotesStorageKey(chainId, ownerHashHex2.slice(0, 12));
258
+ localStorage.removeItem(notesKey);
259
+ }
260
+ if (ethAddress) {
261
+ localStorage.removeItem(getStorageKey(ethAddress));
262
+ }
263
+ setMasterKeys(null);
264
+ setStarkMasterKeys(null);
265
+ setNotes([]);
266
+ }, [masterKeys, ethAddress, chainId]);
267
+ const addNote = useCallback(
268
+ (note) => {
269
+ const store = noteStoreRef.current;
270
+ if (store) {
271
+ store.addNote(note);
272
+ store.persist().catch(console.error);
273
+ } else {
274
+ setNotes((prev) => [...prev, note]);
275
+ }
276
+ },
277
+ []
278
+ );
279
+ const markNoteSpent = useCallback(
280
+ (commitment) => {
281
+ const store = noteStoreRef.current;
282
+ if (store) {
283
+ store.markSpent(commitment);
284
+ store.persist().catch(console.error);
285
+ } else {
286
+ setNotes(
287
+ (prev) => prev.map(
288
+ (n) => n.commitment.toLowerCase() === commitment.toLowerCase() ? { ...n, status: "spent" } : n
289
+ )
290
+ );
291
+ }
292
+ },
293
+ []
294
+ );
295
+ const createNoteForSelf = useCallback(
296
+ async (amount, origin, token) => {
297
+ if (!masterKeys || !cryptoReady) throw new Error("Account not ready");
298
+ const sdk = await loadSDK();
299
+ return createHashBasedNote(sdk, amount, masterKeys.spendingSecret, masterKeys.ownerHash, masterKeys.viewingSecret, origin, token);
300
+ },
301
+ [masterKeys, cryptoReady]
302
+ );
303
+ const getOwnerHash = useCallback(() => {
304
+ return masterKeys?.ownerHash ?? null;
305
+ }, [masterKeys]);
306
+ const unspentNotes = useMemo(() => {
307
+ const unspent = notes.filter((n) => n.status !== "spent");
308
+ if (!activeProofSystem) return unspent;
309
+ return unspent.filter((n) => (n.proofSystem ?? "snark") === activeProofSystem);
310
+ }, [notes, activeProofSystem]);
311
+ const balance = useMemo(
312
+ () => unspentNotes.reduce((acc, n) => acc + n.amount, 0n),
313
+ [unspentNotes]
314
+ );
315
+ const selectOptimalCircuit = useCallback(
316
+ (requiredAmount, tokenAddress) => {
317
+ let candidates = unspentNotes;
318
+ if (tokenAddress) {
319
+ candidates = candidates.filter(
320
+ (n) => n.token?.toLowerCase() === tokenAddress.toLowerCase()
321
+ );
322
+ }
323
+ const sortedNotes = [...candidates].sort((a, b) => a.amount > b.amount ? 1 : -1);
324
+ const singleNote = sortedNotes.find((n) => n.amount >= requiredAmount);
325
+ if (singleNote) {
326
+ return { circuit: "1x2", selectedNotes: [singleNote] };
327
+ }
328
+ for (let i = 0; i < sortedNotes.length; i++) {
329
+ for (let j = i + 1; j < sortedNotes.length; j++) {
330
+ const combined = sortedNotes[i].amount + sortedNotes[j].amount;
331
+ if (combined >= requiredAmount) {
332
+ return { circuit: "2x2", selectedNotes: [sortedNotes[i], sortedNotes[j]] };
333
+ }
334
+ }
335
+ }
336
+ const candidateBalance = candidates.reduce((acc, n) => acc + n.amount, 0n);
337
+ if (candidateBalance >= requiredAmount) {
338
+ return {
339
+ circuit: null,
340
+ selectedNotes: [],
341
+ error: "Requires more than 2 notes. Please consolidate first."
342
+ };
343
+ }
344
+ return { circuit: null, selectedNotes: [], error: "Insufficient balance" };
345
+ },
346
+ [unspentNotes, balance]
347
+ );
348
+ const syncNotes = useCallback(
349
+ async (contractAddress, client) => {
350
+ if (!masterKeys || !cryptoReady) return 0;
351
+ if (syncPromiseRef.current) {
352
+ return syncPromiseRef.current;
353
+ }
354
+ const syncPromise = (async () => {
355
+ setIsSyncing(true);
356
+ try {
357
+ const sdk = await loadSDK();
358
+ const viewingSecret = masterKeys.viewingSecret;
359
+ const spendingSecret = masterKeys.spendingSecret;
360
+ const aesKeyHex = keccak256(toHex(viewingSecret, { size: 32 }));
361
+ const aesKeyBytes = hexToBytes(aesKeyHex);
362
+ const cryptoKey = await crypto.subtle.importKey(
363
+ "raw",
364
+ aesKeyBytes.buffer.slice(aesKeyBytes.byteOffset, aesKeyBytes.byteOffset + aesKeyBytes.byteLength),
365
+ { name: "AES-GCM", length: 256 },
366
+ false,
367
+ ["decrypt"]
368
+ );
369
+ const existingCommitments = new Set(
370
+ notes.map((n) => n.commitment.toLowerCase())
371
+ );
372
+ const candidates = [];
373
+ console.log("[syncNotes] Scanning contract:", contractAddress, "\u2014 existing:", existingCommitments.size, "notes");
374
+ try {
375
+ const shieldedLogs = await client.getLogs({
376
+ address: contractAddress,
377
+ event: {
378
+ type: "event",
379
+ name: "Shielded",
380
+ inputs: [
381
+ { name: "token", type: "address", indexed: true },
382
+ { name: "depositor", type: "address", indexed: true },
383
+ { name: "commitment", type: "bytes32", indexed: true },
384
+ { name: "leafIndex", type: "uint256", indexed: false },
385
+ { name: "encryptedNote", type: "bytes", indexed: false }
386
+ ]
387
+ },
388
+ fromBlock: 0n,
389
+ toBlock: "latest"
390
+ });
391
+ for (const log of shieldedLogs) {
392
+ const commitment = log.args.commitment;
393
+ if (existingCommitments.has(commitment.toLowerCase())) continue;
394
+ candidates.push({
395
+ commitment,
396
+ leafIndex: Number(log.args.leafIndex),
397
+ packedData: log.args.encryptedNote,
398
+ txHash: log.transactionHash
399
+ });
400
+ }
401
+ } catch (e) {
402
+ console.warn("[syncNotes] Failed to scan Shielded events:", e?.message ?? e);
403
+ }
404
+ const commitmentLeafMap = /* @__PURE__ */ new Map();
405
+ try {
406
+ const transferredLogs = await client.getLogs({
407
+ address: contractAddress,
408
+ event: {
409
+ type: "event",
410
+ name: "Transferred",
411
+ inputs: [
412
+ { name: "nullifier", type: "bytes32", indexed: true },
413
+ { name: "outputCommitment1", type: "bytes32", indexed: true },
414
+ { name: "outputCommitment2", type: "bytes32", indexed: true },
415
+ { name: "encryptedNote1", type: "bytes", indexed: false },
416
+ { name: "encryptedNote2", type: "bytes", indexed: false }
417
+ ]
418
+ },
419
+ fromBlock: 0n,
420
+ toBlock: "latest"
421
+ });
422
+ try {
423
+ const ciLogs = await client.getLogs({
424
+ address: contractAddress,
425
+ event: {
426
+ type: "event",
427
+ name: "CommitmentInserted",
428
+ inputs: [
429
+ { name: "commitment", type: "bytes32", indexed: true },
430
+ { name: "leafIndex", type: "uint256", indexed: false },
431
+ { name: "timestamp", type: "uint256", indexed: false }
432
+ ]
433
+ },
434
+ fromBlock: 0n,
435
+ toBlock: "latest"
436
+ });
437
+ for (const log of ciLogs) {
438
+ commitmentLeafMap.set(
439
+ log.args.commitment.toLowerCase(),
440
+ Number(log.args.leafIndex)
441
+ );
442
+ }
443
+ } catch (e) {
444
+ console.warn("[syncNotes] Failed to scan CommitmentInserted events:", e);
445
+ }
446
+ for (const log of transferredLogs) {
447
+ const c1 = log.args.outputCommitment1;
448
+ const c2 = log.args.outputCommitment2;
449
+ const txHash = log.transactionHash;
450
+ if (!existingCommitments.has(c1.toLowerCase())) {
451
+ candidates.push({
452
+ commitment: c1,
453
+ leafIndex: commitmentLeafMap.get(c1.toLowerCase()) ?? -1,
454
+ packedData: log.args.encryptedNote1,
455
+ txHash
456
+ });
457
+ }
458
+ if (!existingCommitments.has(c2.toLowerCase())) {
459
+ candidates.push({
460
+ commitment: c2,
461
+ leafIndex: commitmentLeafMap.get(c2.toLowerCase()) ?? -1,
462
+ packedData: log.args.encryptedNote2,
463
+ txHash
464
+ });
465
+ }
466
+ }
467
+ } catch (e) {
468
+ console.warn("[syncNotes] Failed to scan Transferred events:", e);
469
+ }
470
+ let discovered = 0;
471
+ let skippedEmpty = 0, skippedOwner = 0;
472
+ for (const candidate of candidates) {
473
+ try {
474
+ const packed = candidate.packedData;
475
+ if (!packed || packed === "0x" || packed.length < 82) {
476
+ skippedEmpty++;
477
+ continue;
478
+ }
479
+ const raw = packed.startsWith("0x") ? packed.slice(2) : packed;
480
+ const noteOwnerHash = BigInt("0x" + raw.slice(16, 80));
481
+ const encryptedPayload = raw.slice(80);
482
+ if (noteOwnerHash !== masterKeys.ownerHash) {
483
+ skippedOwner++;
484
+ continue;
485
+ }
486
+ const encBytes = hexToBytes("0x" + encryptedPayload);
487
+ if (encBytes.length < 12) continue;
488
+ const nonce = encBytes.slice(0, 12);
489
+ const ciphertext = encBytes.slice(12);
490
+ let plaintext;
491
+ try {
492
+ plaintext = await crypto.subtle.decrypt(
493
+ { name: "AES-GCM", iv: nonce },
494
+ cryptoKey,
495
+ ciphertext
496
+ );
497
+ } catch {
498
+ continue;
499
+ }
500
+ const ptBytes = new Uint8Array(plaintext);
501
+ if (ptBytes.length !== 104) continue;
502
+ const amount = bytesToBigint(ptBytes.slice(0, 32));
503
+ const blinding = bytesToBigint(ptBytes.slice(32, 64));
504
+ const originRaw = "0x" + Array.from(ptBytes.slice(64, 84)).map((b) => b.toString(16).padStart(2, "0")).join("");
505
+ const tokenRaw = "0x" + Array.from(ptBytes.slice(84, 104)).map((b) => b.toString(16).padStart(2, "0")).join("");
506
+ const origin = getAddress(originRaw);
507
+ const token = getAddress(tokenRaw);
508
+ const pubkey = await sdk.privateToPublic(spendingSecret);
509
+ const expectedCommitment = await sdk.poseidon([
510
+ amount,
511
+ pubkey.x,
512
+ pubkey.y,
513
+ blinding,
514
+ BigInt(origin),
515
+ BigInt(token)
516
+ ]);
517
+ const expectedHex = toHex(expectedCommitment, { size: 32 });
518
+ if (expectedHex.toLowerCase() !== candidate.commitment.toLowerCase()) {
519
+ console.warn("[syncNotes] Commitment mismatch, skipping");
520
+ continue;
521
+ }
522
+ const newNote = {
523
+ commitment: candidate.commitment,
524
+ amount,
525
+ blinding,
526
+ ownerSecret: toHex(spendingSecret, { size: 32 }),
527
+ ownerHash: toHex(masterKeys.ownerHash, { size: 32 }),
528
+ origin,
529
+ token,
530
+ leafIndex: candidate.leafIndex,
531
+ status: "confirmed",
532
+ timestamp: Math.floor(Date.now() / 1e3),
533
+ txHash: candidate.txHash,
534
+ proofSystem: "snark"
535
+ };
536
+ const store2 = noteStoreRef.current;
537
+ if (store2) {
538
+ if (store2.addNote(newNote)) discovered++;
539
+ } else {
540
+ setNotes((prev) => {
541
+ if (prev.some((n) => n.commitment.toLowerCase() === newNote.commitment.toLowerCase())) return prev;
542
+ return [...prev, newNote];
543
+ });
544
+ discovered++;
545
+ }
546
+ } catch (e) {
547
+ console.warn("[syncNotes] Failed to process candidate:", e);
548
+ }
549
+ }
550
+ if (discovered > 0 || candidates.length > 0) {
551
+ console.log(`[syncNotes] Discovered ${discovered} new notes from ${candidates.length} candidates`);
552
+ }
553
+ if (commitmentLeafMap.size === 0) {
554
+ try {
555
+ const ciLogs = await client.getLogs({
556
+ address: contractAddress,
557
+ event: {
558
+ type: "event",
559
+ name: "CommitmentInserted",
560
+ inputs: [
561
+ { name: "commitment", type: "bytes32", indexed: true },
562
+ { name: "leafIndex", type: "uint256", indexed: false },
563
+ { name: "timestamp", type: "uint256", indexed: false }
564
+ ]
565
+ },
566
+ fromBlock: 0n,
567
+ toBlock: "latest"
568
+ });
569
+ for (const log of ciLogs) {
570
+ commitmentLeafMap.set(
571
+ log.args.commitment.toLowerCase(),
572
+ Number(log.args.leafIndex)
573
+ );
574
+ }
575
+ } catch {
576
+ }
577
+ }
578
+ let repaired = 0;
579
+ const store = noteStoreRef.current;
580
+ if (store) {
581
+ for (const note of store.getNotes()) {
582
+ const correctLeafIndex = commitmentLeafMap.get(note.commitment.toLowerCase());
583
+ if (correctLeafIndex !== void 0 && note.leafIndex !== correctLeafIndex) {
584
+ store.updateLeafIndex(note.commitment, correctLeafIndex);
585
+ repaired++;
586
+ }
587
+ }
588
+ }
589
+ try {
590
+ const currentNotes = store ? store.getNotes() : notes;
591
+ const spentSnarkNotes = currentNotes.filter((n) => n.status === "spent" && n.proofSystem !== "stark");
592
+ if (spentSnarkNotes.length > 0) {
593
+ const sdk2 = await loadSDK();
594
+ for (const note of spentSnarkNotes) {
595
+ const correctLeaf = commitmentLeafMap.get(note.commitment.toLowerCase());
596
+ if (correctLeaf === void 0) continue;
597
+ const ownerSecret = BigInt(note.ownerSecret);
598
+ const commitment = BigInt(note.commitment);
599
+ const nullifier = await sdk2.poseidon([
600
+ ownerSecret % 2736030358979909402780800718157159386076813972158567259200215660948447373041n,
601
+ BigInt(correctLeaf),
602
+ commitment
603
+ ]);
604
+ const nullifierHex = toHex(nullifier, { size: 32 });
605
+ const isUsed = await client.readContract({
606
+ address: contractAddress,
607
+ abi: [{
608
+ type: "function",
609
+ name: "nullifierUsed",
610
+ inputs: [{ name: "", type: "bytes32" }],
611
+ outputs: [{ name: "", type: "bool" }],
612
+ stateMutability: "view"
613
+ }],
614
+ functionName: "nullifierUsed",
615
+ args: [nullifierHex]
616
+ });
617
+ if (!isUsed) {
618
+ console.log(`[syncNotes] Un-spending note ${note.commitment.slice(0, 12)} \u2014 nullifier not used on-chain`);
619
+ if (store) {
620
+ store.unmarkSpent(note.commitment);
621
+ store.updateLeafIndex(note.commitment, correctLeaf);
622
+ }
623
+ repaired++;
624
+ }
625
+ }
626
+ }
627
+ } catch (e) {
628
+ console.warn("[syncNotes] Nullifier verification failed:", e);
629
+ }
630
+ if (repaired > 0) {
631
+ console.log(`[syncNotes] Repaired ${repaired} existing notes`);
632
+ }
633
+ if (store && (discovered > 0 || repaired > 0)) {
634
+ await store.persist();
635
+ }
636
+ return discovered + repaired;
637
+ } finally {
638
+ setIsSyncing(false);
639
+ syncPromiseRef.current = null;
640
+ }
641
+ })();
642
+ syncPromiseRef.current = syncPromise;
643
+ return syncPromise;
644
+ },
645
+ [masterKeys, cryptoReady, notes, persistNotes]
646
+ );
647
+ const startLiveSync = useCallback(
648
+ (contractAddress, client) => {
649
+ if (liveSyncInterval) clearInterval(liveSyncInterval);
650
+ if (unwatchRef.current) {
651
+ unwatchRef.current();
652
+ unwatchRef.current = null;
653
+ }
654
+ syncNotes(contractAddress, client).catch(console.error);
655
+ try {
656
+ const unwatch = client.watchContractEvent({
657
+ address: contractAddress,
658
+ eventName: "CommitmentInserted",
659
+ onLogs: () => {
660
+ syncNotes(contractAddress, client).catch(console.error);
661
+ }
662
+ });
663
+ unwatchRef.current = unwatch;
664
+ } catch (e) {
665
+ console.warn("[liveSync] watchContractEvent not available, using polling only:", e);
666
+ }
667
+ const fallbackMs = indexerConfig?.liveSyncIntervalMs ?? 6e4;
668
+ const interval = setInterval(() => {
669
+ syncNotes(contractAddress, client).catch(console.error);
670
+ }, fallbackMs);
671
+ setLiveSyncInterval(interval);
672
+ },
673
+ [syncNotes, liveSyncInterval, indexerConfig?.liveSyncIntervalMs]
674
+ );
675
+ const stopLiveSync = useCallback(() => {
676
+ if (liveSyncInterval) {
677
+ clearInterval(liveSyncInterval);
678
+ setLiveSyncInterval(null);
679
+ }
680
+ if (unwatchRef.current) {
681
+ unwatchRef.current();
682
+ unwatchRef.current = null;
683
+ }
684
+ }, [liveSyncInterval]);
685
+ useEffect(() => {
686
+ return () => {
687
+ if (liveSyncInterval) clearInterval(liveSyncInterval);
688
+ if (unwatchRef.current) {
689
+ unwatchRef.current();
690
+ unwatchRef.current = null;
691
+ }
692
+ };
693
+ }, [liveSyncInterval]);
694
+ const ownerHashHex = masterKeys ? toHex(masterKeys.ownerHash, { size: 32 }) : null;
695
+ const stealthAddress = useMemo(() => {
696
+ if (!masterKeys) return null;
697
+ try {
698
+ const { encodeStealthAddress } = (init_stealth(), __toCommonJS(stealth_exports));
699
+ return encodeStealthAddress(masterKeys.ownerHash, masterKeys.viewingHash);
700
+ } catch {
701
+ return null;
702
+ }
703
+ }, [masterKeys]);
704
+ const starkStealthAddress = useMemo(() => {
705
+ if (!starkMasterKeys) return null;
706
+ try {
707
+ const { encodeStarkStealthAddress } = (init_stealth(), __toCommonJS(stealth_exports));
708
+ return encodeStarkStealthAddress(starkMasterKeys.starkOwnerHash, starkMasterKeys.starkViewingHash);
709
+ } catch {
710
+ return null;
711
+ }
712
+ }, [starkMasterKeys]);
713
+ return /* @__PURE__ */ jsx(
714
+ UPPAccountContext.Provider,
715
+ {
716
+ value: {
717
+ masterKeys,
718
+ starkMasterKeys,
719
+ ethAddress: ethAddress ?? null,
720
+ ownerHash: ownerHashHex,
721
+ stealthAddress,
722
+ starkStealthAddress,
723
+ notes,
724
+ unspentNotes,
725
+ balance,
726
+ isSetup: !!masterKeys,
727
+ isLoading,
728
+ isConnecting,
729
+ cryptoReady,
730
+ isSyncing,
731
+ lastSyncedBlock,
732
+ setupAccount,
733
+ connect,
734
+ logout,
735
+ disconnect: logout,
736
+ addNote,
737
+ markNoteSpent,
738
+ createNoteForSelf,
739
+ getOwnerHash,
740
+ selectOptimalCircuit,
741
+ syncNotes,
742
+ startLiveSync,
743
+ stopLiveSync,
744
+ isLiveSyncing: liveSyncInterval !== null
745
+ },
746
+ children
747
+ }
748
+ );
749
+ }
750
+ function useUPPAccount() {
751
+ const context = useContext(UPPAccountContext);
752
+ if (!context) {
753
+ throw new Error("useUPPAccount must be used within a UPPAccountProvider");
754
+ }
755
+ return context;
756
+ }
757
+ async function createHashBasedNote(sdk, amount, spendingSecret, ownerHash, viewingSecret, origin, token) {
758
+ const blinding = await sdk.randomFieldElement();
759
+ const pubkey = await sdk.privateToPublic(spendingSecret);
760
+ const commitment = await sdk.poseidon([
761
+ amount,
762
+ pubkey.x,
763
+ pubkey.y,
764
+ blinding,
765
+ origin,
766
+ token
767
+ ]);
768
+ const searchTagHash = await sdk.poseidon([viewingSecret, commitment]);
769
+ const searchTag = searchTagHash & (1n << 64n) - 1n;
770
+ const encryptedNote = await encryptNoteData(amount, blinding, origin, token, viewingSecret);
771
+ return {
772
+ commitment,
773
+ ownerSecret: spendingSecret,
774
+ ownerHash,
775
+ pubkeyX: pubkey.x,
776
+ pubkeyY: pubkey.y,
777
+ blinding,
778
+ encryptedNote,
779
+ searchTag,
780
+ amount,
781
+ origin,
782
+ token
783
+ };
784
+ }
785
+ async function encryptNoteData(amount, blinding, origin, token, viewingSecret) {
786
+ const keyMaterial = keccak256(toHex(viewingSecret, { size: 32 }));
787
+ const keyBytes = hexToBytes(keyMaterial);
788
+ const cryptoKey = await crypto.subtle.importKey(
789
+ "raw",
790
+ keyBytes.buffer.slice(keyBytes.byteOffset, keyBytes.byteOffset + keyBytes.byteLength),
791
+ { name: "AES-GCM", length: 256 },
792
+ false,
793
+ ["encrypt"]
794
+ );
795
+ const plaintext = new Uint8Array(104);
796
+ plaintext.set(bigintToBytes(amount, 32), 0);
797
+ plaintext.set(bigintToBytes(blinding, 32), 32);
798
+ plaintext.set(bigintToBytes(origin, 20), 64);
799
+ plaintext.set(bigintToBytes(token, 20), 84);
800
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
801
+ const ciphertext = await crypto.subtle.encrypt(
802
+ { name: "AES-GCM", iv: nonce },
803
+ cryptoKey,
804
+ plaintext
805
+ );
806
+ const result = new Uint8Array(12 + ciphertext.byteLength);
807
+ result.set(nonce, 0);
808
+ result.set(new Uint8Array(ciphertext), 12);
809
+ return toHex(result);
810
+ }
811
+ function hexToBytes(hex) {
812
+ const h = hex.startsWith("0x") ? hex.slice(2) : hex;
813
+ const bytes = new Uint8Array(h.length / 2);
814
+ for (let i = 0; i < bytes.length; i++) {
815
+ bytes[i] = parseInt(h.substr(i * 2, 2), 16);
816
+ }
817
+ return bytes;
818
+ }
819
+ function bigintToBytes(n, length) {
820
+ const bytes = new Uint8Array(length);
821
+ let temp = n;
822
+ for (let i = length - 1; i >= 0; i--) {
823
+ bytes[i] = Number(temp & 0xffn);
824
+ temp >>= 8n;
825
+ }
826
+ return bytes;
827
+ }
828
+ function bytesToBigint(bytes) {
829
+ let result = 0n;
830
+ for (const b of bytes) {
831
+ result = result << 8n | BigInt(b);
832
+ }
833
+ return result;
834
+ }
835
+
836
+ // src/react/utils/avatar.ts
837
+ function hashBytes(input) {
838
+ const bytes = new Array(32).fill(0);
839
+ for (let i = 0; i < input.length; i++) {
840
+ const c = input.charCodeAt(i);
841
+ bytes[i % 32] = bytes[i % 32] * 31 + c & 255;
842
+ }
843
+ for (let round = 0; round < 3; round++) {
844
+ for (let i = 0; i < 32; i++) {
845
+ bytes[i] = bytes[i] + bytes[(i + 7) % 32] * 17 + round * 53 & 255;
846
+ }
847
+ }
848
+ return bytes;
849
+ }
850
+ function byteToHex(r, g, b) {
851
+ return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
852
+ }
853
+ function adjustBrightness(r, g, b, minBrightness, maxBrightness) {
854
+ const brightness = (r * 299 + g * 587 + b * 114) / 1e3;
855
+ if (brightness < minBrightness) {
856
+ const factor = minBrightness / Math.max(brightness, 1);
857
+ return [
858
+ Math.min(255, Math.round(r * factor)),
859
+ Math.min(255, Math.round(g * factor)),
860
+ Math.min(255, Math.round(b * factor))
861
+ ];
862
+ }
863
+ if (brightness > maxBrightness) {
864
+ const factor = maxBrightness / brightness;
865
+ return [
866
+ Math.round(r * factor),
867
+ Math.round(g * factor),
868
+ Math.round(b * factor)
869
+ ];
870
+ }
871
+ return [r, g, b];
872
+ }
873
+ var SHAPE_TYPES = ["circle", "rect", "triangle"];
874
+ function generateAvatarData(address) {
875
+ const bytes = hashBytes(address);
876
+ const [bgR, bgG, bgB] = adjustBrightness(bytes[0], bytes[1], bytes[2], 30, 80);
877
+ const background = byteToHex(bgR, bgG, bgB);
878
+ const shapeCount = 3 + bytes[3] % 2;
879
+ const shapes = [];
880
+ for (let i = 0; i < shapeCount; i++) {
881
+ const offset = 4 + i * 6;
882
+ const [sr, sg, sb] = adjustBrightness(
883
+ bytes[offset % 32],
884
+ bytes[(offset + 1) % 32],
885
+ bytes[(offset + 2) % 32],
886
+ 100,
887
+ 240
888
+ );
889
+ shapes.push({
890
+ type: SHAPE_TYPES[bytes[(offset + 3) % 32] % 3],
891
+ x: 10 + bytes[(offset + 4) % 32] % 80,
892
+ y: 10 + bytes[(offset + 5) % 32] % 80,
893
+ size: 20 + bytes[(offset + 3) % 32] % 40,
894
+ color: byteToHex(sr, sg, sb),
895
+ opacity: 0.5 + bytes[(offset + 2) % 32] % 50 / 100,
896
+ rotation: bytes[(offset + 1) % 32] * 360 / 256
897
+ });
898
+ }
899
+ return { background, shapes };
900
+ }
901
+ function renderAvatarSVG(data, size = 32) {
902
+ const shapes = data.shapes.map((s) => {
903
+ const transform = `transform="rotate(${s.rotation} ${s.x} ${s.y})"`;
904
+ const style = `fill="${s.color}" opacity="${s.opacity}"`;
905
+ switch (s.type) {
906
+ case "circle":
907
+ return `<circle cx="${s.x}" cy="${s.y}" r="${s.size / 2}" ${style} />`;
908
+ case "rect":
909
+ return `<rect x="${s.x - s.size / 2}" y="${s.y - s.size / 2}" width="${s.size}" height="${s.size * 0.7}" rx="4" ${style} ${transform} />`;
910
+ case "triangle": {
911
+ const h = s.size * 0.866;
912
+ const points = `${s.x},${s.y - h / 2} ${s.x - s.size / 2},${s.y + h / 2} ${s.x + s.size / 2},${s.y + h / 2}`;
913
+ return `<polygon points="${points}" ${style} ${transform} />`;
914
+ }
915
+ }
916
+ }).join("\n ");
917
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="${size}" height="${size}">
918
+ <rect width="100" height="100" rx="20" fill="${data.background}" />
919
+ ${shapes}
920
+ </svg>`;
921
+ }
922
+ function ShapeSVG({ shape }) {
923
+ const transform = `rotate(${shape.rotation} ${shape.x} ${shape.y})`;
924
+ const fill = shape.color;
925
+ const opacity = shape.opacity;
926
+ switch (shape.type) {
927
+ case "circle":
928
+ return /* @__PURE__ */ jsx("circle", { cx: shape.x, cy: shape.y, r: shape.size / 2, fill, opacity });
929
+ case "rect":
930
+ return /* @__PURE__ */ jsx(
931
+ "rect",
932
+ {
933
+ x: shape.x - shape.size / 2,
934
+ y: shape.y - shape.size / 2,
935
+ width: shape.size,
936
+ height: shape.size * 0.7,
937
+ rx: 4,
938
+ fill,
939
+ opacity,
940
+ transform
941
+ }
942
+ );
943
+ case "triangle": {
944
+ const h = shape.size * 0.866;
945
+ const points = `${shape.x},${shape.y - h / 2} ${shape.x - shape.size / 2},${shape.y + h / 2} ${shape.x + shape.size / 2},${shape.y + h / 2}`;
946
+ return /* @__PURE__ */ jsx("polygon", { points, fill, opacity, transform });
947
+ }
948
+ }
949
+ }
950
+ function UPPAvatar({ address, size = 32, className, style }) {
951
+ const data = useMemo(() => generateAvatarData(address), [address]);
952
+ return /* @__PURE__ */ jsxs(
953
+ "svg",
954
+ {
955
+ xmlns: "http://www.w3.org/2000/svg",
956
+ viewBox: "0 0 100 100",
957
+ width: size,
958
+ height: size,
959
+ className,
960
+ style,
961
+ children: [
962
+ /* @__PURE__ */ jsx("rect", { width: "100", height: "100", rx: "20", fill: data.background }),
963
+ data.shapes.map((shape, i) => /* @__PURE__ */ jsx(ShapeSVG, { shape }, i))
964
+ ]
965
+ }
966
+ );
967
+ }
968
+
969
+ // src/react/components/styles.ts
970
+ var colors = {
971
+ backdrop: "rgba(0, 0, 0, 0.5)",
972
+ modalBg: "var(--upp-modal-bg, rgba(0, 0, 0, 0.85))",
973
+ border: "var(--upp-border, rgba(255, 255, 255, 0.1))",
974
+ textPrimary: "var(--upp-text-primary, #ffffff)",
975
+ textSecondary: "var(--upp-text-secondary, rgba(255, 255, 255, 0.6))",
976
+ textTertiary: "var(--upp-text-tertiary, rgba(255, 255, 255, 0.4))",
977
+ textMuted: "var(--upp-text-muted, rgba(255, 255, 255, 0.25))",
978
+ hoverBg: "var(--upp-hover-bg, rgba(255, 255, 255, 0.05))",
979
+ pillBg: "var(--upp-pill-bg, rgba(255, 255, 255, 0.05))",
980
+ pillBorder: "var(--upp-pill-border, rgba(255, 255, 255, 0.1))",
981
+ pillBorderDashed: "var(--upp-pill-border-dashed, rgba(255, 255, 255, 0.15))",
982
+ emeraldBg: "rgba(16, 185, 129, 0.1)",
983
+ emeraldBorder: "rgba(16, 185, 129, 0.2)",
984
+ emeraldBorderHover: "rgba(16, 185, 129, 0.3)",
985
+ indigo: "#6366f1",
986
+ indigoBg: "rgba(99, 102, 241, 0.15)",
987
+ indigoBorder: "rgba(99, 102, 241, 0.3)",
988
+ indigoRing: "rgba(99, 102, 241, 0.5)",
989
+ indigoHoverBg: "rgba(99, 102, 241, 0.15)",
990
+ indigoHoverBorder: "rgba(99, 102, 241, 0.3)",
991
+ redBg: "rgba(239, 68, 68, 0.2)",
992
+ redBorder: "rgba(239, 68, 68, 0.3)",
993
+ redText: "#fca5a5",
994
+ inputBg: "var(--upp-input-bg, rgba(0, 0, 0, 0.3))"
995
+ };
996
+ var backdrop = {
997
+ position: "fixed",
998
+ inset: 0,
999
+ zIndex: 50,
1000
+ display: "flex",
1001
+ alignItems: "center",
1002
+ justifyContent: "center",
1003
+ background: colors.backdrop,
1004
+ backdropFilter: "blur(4px)",
1005
+ WebkitBackdropFilter: "blur(4px)"
1006
+ };
1007
+ var modalContainer = {
1008
+ width: "100%",
1009
+ maxWidth: "28rem",
1010
+ margin: "0 1rem",
1011
+ background: colors.modalBg,
1012
+ backdropFilter: "blur(24px)",
1013
+ WebkitBackdropFilter: "blur(24px)",
1014
+ border: `1px solid ${colors.border}`,
1015
+ borderRadius: "1rem",
1016
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)"
1017
+ };
1018
+ var pillBase = {
1019
+ display: "flex",
1020
+ alignItems: "center",
1021
+ gap: "8px",
1022
+ height: "40px",
1023
+ padding: "0 14px",
1024
+ borderRadius: "12px",
1025
+ border: `1px solid ${colors.pillBorder}`,
1026
+ background: colors.pillBg,
1027
+ cursor: "pointer",
1028
+ transition: "all 150ms ease",
1029
+ outline: "none",
1030
+ boxSizing: "border-box"
1031
+ };
1032
+ var pillDisconnected = {
1033
+ ...pillBase,
1034
+ border: `1px dashed ${colors.pillBorderDashed}`
1035
+ };
1036
+ var pillConnected = {
1037
+ ...pillBase,
1038
+ background: colors.emeraldBg,
1039
+ border: `1px solid ${colors.emeraldBorder}`
1040
+ };
1041
+ var primaryButton = {
1042
+ width: "100%",
1043
+ height: "40px",
1044
+ background: colors.indigo,
1045
+ color: colors.textPrimary,
1046
+ borderRadius: "0.75rem",
1047
+ fontSize: "14px",
1048
+ fontWeight: 500,
1049
+ border: "none",
1050
+ cursor: "pointer",
1051
+ transition: "all 150ms ease",
1052
+ display: "flex",
1053
+ alignItems: "center",
1054
+ justifyContent: "center",
1055
+ gap: "8px"
1056
+ };
1057
+ var secondaryButton = {
1058
+ width: "100%",
1059
+ height: "40px",
1060
+ background: colors.hoverBg,
1061
+ color: colors.textSecondary,
1062
+ borderRadius: "0.75rem",
1063
+ fontSize: "14px",
1064
+ fontWeight: 500,
1065
+ border: `1px solid ${colors.border}`,
1066
+ cursor: "pointer",
1067
+ transition: "all 150ms ease"
1068
+ };
1069
+ var textInput = {
1070
+ width: "100%",
1071
+ height: "40px",
1072
+ background: colors.inputBg,
1073
+ border: `1px solid ${colors.border}`,
1074
+ borderRadius: "0.75rem",
1075
+ padding: "0 12px",
1076
+ fontSize: "14px",
1077
+ color: colors.textPrimary,
1078
+ fontFamily: "monospace",
1079
+ outline: "none",
1080
+ transition: "all 150ms ease",
1081
+ boxSizing: "border-box"
1082
+ };
1083
+ var UPP_KEYFRAMES = `
1084
+ @keyframes upp-spin {
1085
+ to { transform: rotate(360deg); }
1086
+ }
1087
+ @keyframes upp-fade-in {
1088
+ from { opacity: 0; }
1089
+ to { opacity: 1; }
1090
+ }
1091
+ @keyframes upp-zoom-in {
1092
+ from { opacity: 0; transform: scale(0.95); }
1093
+ to { opacity: 1; transform: scale(1); }
1094
+ }
1095
+ `;
1096
+ function UPPModal({ isOpen, onClose, settingsSlot }) {
1097
+ const { isSetup, connect, disconnect, isConnecting } = useUPPAccount();
1098
+ const [password, setPassword] = useState("");
1099
+ const [error, setError] = useState(null);
1100
+ const backdropRef = useRef(null);
1101
+ const [closeHover, setCloseHover] = useState(false);
1102
+ const [primaryHover, setPrimaryHover] = useState(false);
1103
+ const [disconnectHover, setDisconnectHover] = useState(false);
1104
+ const [inputFocused, setInputFocused] = useState(false);
1105
+ useEffect(() => {
1106
+ if (isOpen) {
1107
+ setPassword("");
1108
+ setError(null);
1109
+ }
1110
+ }, [isOpen]);
1111
+ useEffect(() => {
1112
+ if (!isOpen) return;
1113
+ const handler = (e) => {
1114
+ if (e.key === "Escape") onClose();
1115
+ };
1116
+ window.addEventListener("keydown", handler);
1117
+ return () => window.removeEventListener("keydown", handler);
1118
+ }, [isOpen, onClose]);
1119
+ const handleActivate = useCallback(async () => {
1120
+ setError(null);
1121
+ try {
1122
+ await connect(password || void 0);
1123
+ onClose();
1124
+ } catch (e) {
1125
+ if (e?.message?.includes("User rejected")) {
1126
+ setError("Signature rejected");
1127
+ } else {
1128
+ setError(e?.message || "Setup failed");
1129
+ }
1130
+ }
1131
+ }, [connect, password, onClose]);
1132
+ const handleDisconnect = useCallback(() => {
1133
+ disconnect();
1134
+ onClose();
1135
+ }, [disconnect, onClose]);
1136
+ const handleBackdropClick = useCallback(
1137
+ (e) => {
1138
+ if (e.target === backdropRef.current) onClose();
1139
+ },
1140
+ [onClose]
1141
+ );
1142
+ if (!isOpen) return null;
1143
+ if (typeof document === "undefined") return null;
1144
+ const closeButtonStyle = {
1145
+ padding: "6px",
1146
+ color: closeHover ? "rgba(255,255,255,0.6)" : "rgba(255,255,255,0.3)",
1147
+ background: closeHover ? "rgba(255,255,255,0.05)" : "transparent",
1148
+ border: "none",
1149
+ borderRadius: "8px",
1150
+ cursor: "pointer",
1151
+ transition: "all 150ms ease",
1152
+ display: "flex",
1153
+ alignItems: "center",
1154
+ justifyContent: "center"
1155
+ };
1156
+ const inputStyle = {
1157
+ ...textInput,
1158
+ ...inputFocused && {
1159
+ boxShadow: `0 0 0 1px ${colors.indigoRing}`,
1160
+ border: `1px solid ${colors.indigoRing}`
1161
+ }
1162
+ };
1163
+ const activateStyle = {
1164
+ ...primaryButton,
1165
+ ...primaryHover && !isConnecting && {
1166
+ background: "#4f46e5"
1167
+ },
1168
+ ...isConnecting && {
1169
+ background: "rgba(99, 102, 241, 0.5)",
1170
+ cursor: "not-allowed"
1171
+ }
1172
+ };
1173
+ const disconnectStyle = {
1174
+ ...secondaryButton,
1175
+ ...disconnectHover && {
1176
+ background: colors.redBg,
1177
+ color: colors.redText,
1178
+ border: `1px solid ${colors.redBorder}`
1179
+ }
1180
+ };
1181
+ return createPortal(
1182
+ /* @__PURE__ */ jsxs(Fragment, { children: [
1183
+ /* @__PURE__ */ jsx("style", { children: UPP_KEYFRAMES }),
1184
+ /* @__PURE__ */ jsx(
1185
+ "div",
1186
+ {
1187
+ ref: backdropRef,
1188
+ onClick: handleBackdropClick,
1189
+ style: { ...backdrop, animation: "upp-fade-in 150ms ease" },
1190
+ children: /* @__PURE__ */ jsxs("div", { style: { ...modalContainer, animation: "upp-zoom-in 200ms ease" }, children: [
1191
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "flex-end", padding: "12px 12px 0" }, children: /* @__PURE__ */ jsx(
1192
+ "button",
1193
+ {
1194
+ onClick: onClose,
1195
+ onMouseEnter: () => setCloseHover(true),
1196
+ onMouseLeave: () => setCloseHover(false),
1197
+ style: closeButtonStyle,
1198
+ children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) })
1199
+ }
1200
+ ) }),
1201
+ isSetup ? (
1202
+ /* ============ Account Mode ============ */
1203
+ /* @__PURE__ */ jsxs("div", { style: { padding: "0 24px 24px", display: "flex", flexDirection: "column", gap: "16px" }, children: [
1204
+ /* @__PURE__ */ jsx("h3", { style: { fontSize: "14px", fontWeight: 600, color: colors.textPrimary, margin: 0, textAlign: "center" }, children: "Private Account" }),
1205
+ settingsSlot,
1206
+ /* @__PURE__ */ jsx(
1207
+ "button",
1208
+ {
1209
+ onClick: handleDisconnect,
1210
+ onMouseEnter: () => setDisconnectHover(true),
1211
+ onMouseLeave: () => setDisconnectHover(false),
1212
+ style: disconnectStyle,
1213
+ children: "Disconnect"
1214
+ }
1215
+ )
1216
+ ] })
1217
+ ) : (
1218
+ /* ============ Setup Mode ============ */
1219
+ /* @__PURE__ */ jsxs("div", { style: { padding: "0 24px 24px", display: "flex", flexDirection: "column", gap: "16px" }, children: [
1220
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: "12px" }, children: [
1221
+ /* @__PURE__ */ jsx("div", { style: {
1222
+ padding: "12px",
1223
+ background: colors.indigoBg,
1224
+ borderRadius: "1rem",
1225
+ border: `1px solid ${colors.indigoBorder}`
1226
+ }, children: /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", style: { color: "#818cf8" }, children: /* @__PURE__ */ jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }) }),
1227
+ /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
1228
+ /* @__PURE__ */ jsx("h3", { style: { fontSize: "16px", fontWeight: 600, color: colors.textPrimary, margin: "0 0 4px" }, children: "Activate Private Account" }),
1229
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: colors.textTertiary, maxWidth: "20rem", margin: 0 }, children: "Sign once with your wallet to derive your private keys. The optional password creates a unique account." })
1230
+ ] })
1231
+ ] }),
1232
+ /* @__PURE__ */ jsx(
1233
+ "input",
1234
+ {
1235
+ type: "password",
1236
+ placeholder: "Password (optional)",
1237
+ value: password,
1238
+ onChange: (e) => setPassword(e.target.value),
1239
+ onKeyDown: (e) => {
1240
+ if (e.key === "Enter" && !isConnecting) handleActivate();
1241
+ },
1242
+ onFocus: () => setInputFocused(true),
1243
+ onBlur: () => setInputFocused(false),
1244
+ style: inputStyle
1245
+ }
1246
+ ),
1247
+ error && /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "#f87171", textAlign: "center", margin: 0 }, children: error }),
1248
+ /* @__PURE__ */ jsx(
1249
+ "button",
1250
+ {
1251
+ onClick: handleActivate,
1252
+ disabled: isConnecting,
1253
+ onMouseEnter: () => setPrimaryHover(true),
1254
+ onMouseLeave: () => setPrimaryHover(false),
1255
+ style: activateStyle,
1256
+ children: isConnecting ? /* @__PURE__ */ jsxs(Fragment, { children: [
1257
+ /* @__PURE__ */ jsx(
1258
+ "svg",
1259
+ {
1260
+ width: "16",
1261
+ height: "16",
1262
+ viewBox: "0 0 24 24",
1263
+ fill: "none",
1264
+ stroke: "currentColor",
1265
+ strokeWidth: "2",
1266
+ style: { animation: "upp-spin 1s linear infinite" },
1267
+ children: /* @__PURE__ */ jsx("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" })
1268
+ }
1269
+ ),
1270
+ "Signing..."
1271
+ ] }) : "Activate"
1272
+ }
1273
+ ),
1274
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "9px", color: colors.textMuted, textAlign: "center", margin: 0 }, children: "Your private key is derived from a wallet signature. No seed phrase needed." })
1275
+ ] })
1276
+ )
1277
+ ] })
1278
+ }
1279
+ )
1280
+ ] }),
1281
+ document.body
1282
+ );
1283
+ }
1284
+ function UPPPrivateButton({
1285
+ style: externalStyle,
1286
+ label = "Private Account",
1287
+ settingsSlot
1288
+ }) {
1289
+ const { isSetup, stealthAddress } = useUPPAccount();
1290
+ const [isModalOpen, setIsModalOpen] = useState(false);
1291
+ const [isHovered, setIsHovered] = useState(false);
1292
+ const openModal = useCallback(() => setIsModalOpen(true), []);
1293
+ const closeModal = useCallback(() => setIsModalOpen(false), []);
1294
+ if (isSetup && stealthAddress) {
1295
+ const connectedStyle = {
1296
+ ...pillConnected,
1297
+ ...isHovered && {
1298
+ background: "rgba(16, 185, 129, 0.2)",
1299
+ border: `1px solid ${colors.emeraldBorderHover}`
1300
+ },
1301
+ ...externalStyle
1302
+ };
1303
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1304
+ /* @__PURE__ */ jsxs(
1305
+ "button",
1306
+ {
1307
+ onClick: openModal,
1308
+ onMouseEnter: () => setIsHovered(true),
1309
+ onMouseLeave: () => setIsHovered(false),
1310
+ style: connectedStyle,
1311
+ title: "Private Account",
1312
+ children: [
1313
+ /* @__PURE__ */ jsx(UPPAvatar, { address: stealthAddress, size: 22, style: { borderRadius: "5px", flexShrink: 0 } }),
1314
+ /* @__PURE__ */ jsx("svg", { width: "10", height: "6", viewBox: "0 0 10 6", fill: "none", style: { color: "rgba(110, 231, 183, 0.4)" }, children: /* @__PURE__ */ jsx("path", { d: "M1 1l4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
1315
+ ]
1316
+ }
1317
+ ),
1318
+ /* @__PURE__ */ jsx(UPPModal, { isOpen: isModalOpen, onClose: closeModal, settingsSlot })
1319
+ ] });
1320
+ }
1321
+ const disconnectedStyle = {
1322
+ ...pillDisconnected,
1323
+ ...isHovered && {
1324
+ background: colors.indigoHoverBg,
1325
+ border: `1px dashed ${colors.indigoHoverBorder}`
1326
+ },
1327
+ ...externalStyle
1328
+ };
1329
+ const iconColor = isHovered ? colors.indigo : "rgba(255, 255, 255, 0.25)";
1330
+ const textColor = isHovered ? "rgba(255, 255, 255, 0.7)" : colors.textTertiary;
1331
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1332
+ /* @__PURE__ */ jsxs(
1333
+ "button",
1334
+ {
1335
+ onClick: openModal,
1336
+ onMouseEnter: () => setIsHovered(true),
1337
+ onMouseLeave: () => setIsHovered(false),
1338
+ style: disconnectedStyle,
1339
+ title: "Activate Private Account",
1340
+ children: [
1341
+ /* @__PURE__ */ jsx(
1342
+ "svg",
1343
+ {
1344
+ width: "18",
1345
+ height: "18",
1346
+ viewBox: "0 0 24 24",
1347
+ fill: "none",
1348
+ stroke: "currentColor",
1349
+ strokeWidth: "1.5",
1350
+ strokeLinecap: "round",
1351
+ strokeLinejoin: "round",
1352
+ style: { color: iconColor, transition: "color 150ms ease", flexShrink: 0 },
1353
+ children: /* @__PURE__ */ jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" })
1354
+ }
1355
+ ),
1356
+ /* @__PURE__ */ jsx("span", { style: {
1357
+ fontSize: "13px",
1358
+ fontWeight: 500,
1359
+ color: textColor,
1360
+ transition: "color 150ms ease"
1361
+ }, children: label })
1362
+ ]
1363
+ }
1364
+ ),
1365
+ /* @__PURE__ */ jsx(UPPModal, { isOpen: isModalOpen, onClose: closeModal, settingsSlot })
1366
+ ] });
1367
+ }
1368
+ var sdkPromise2 = null;
1369
+ function useUPPCrypto() {
1370
+ const [isReady, setIsReady] = useState(false);
1371
+ const loadSDK2 = useCallback(async () => {
1372
+ if (!sdkPromise2) {
1373
+ sdkPromise2 = import('../index.js');
1374
+ }
1375
+ return sdkPromise2;
1376
+ }, []);
1377
+ useEffect(() => {
1378
+ loadSDK2().then(() => setIsReady(true));
1379
+ }, [loadSDK2]);
1380
+ const poseidon = useCallback(
1381
+ async (inputs) => {
1382
+ const sdk = await loadSDK2();
1383
+ return sdk.poseidon(inputs);
1384
+ },
1385
+ [loadSDK2]
1386
+ );
1387
+ const randomFieldElement = useCallback(async () => {
1388
+ const sdk = await loadSDK2();
1389
+ return sdk.randomFieldElement();
1390
+ }, [loadSDK2]);
1391
+ const computeSharedSecret = useCallback(
1392
+ async (privateKey, publicKey) => {
1393
+ const sdk = await loadSDK2();
1394
+ return sdk.computeSharedSecret(privateKey, publicKey);
1395
+ },
1396
+ [loadSDK2]
1397
+ );
1398
+ const privateToPublic = useCallback(
1399
+ async (privateKey) => {
1400
+ const sdk = await loadSDK2();
1401
+ return sdk.privateToPublic(privateKey);
1402
+ },
1403
+ [loadSDK2]
1404
+ );
1405
+ const addPoints = useCallback(
1406
+ async (p1, p2) => {
1407
+ const sdk = await loadSDK2();
1408
+ return sdk.addPoints(p1, p2);
1409
+ },
1410
+ [loadSDK2]
1411
+ );
1412
+ const mulPointScalar = useCallback(
1413
+ async (point, scalar) => {
1414
+ const sdk = await loadSDK2();
1415
+ return sdk.mulPointScalar(point, scalar);
1416
+ },
1417
+ [loadSDK2]
1418
+ );
1419
+ const getSubOrder = useCallback(async () => {
1420
+ const sdk = await loadSDK2();
1421
+ return sdk.getSubOrder();
1422
+ }, [loadSDK2]);
1423
+ const init = useCallback(async () => {
1424
+ await loadSDK2();
1425
+ setIsReady(true);
1426
+ }, [loadSDK2]);
1427
+ return {
1428
+ isReady,
1429
+ init,
1430
+ poseidon,
1431
+ randomFieldElement,
1432
+ computeSharedSecret,
1433
+ privateToPublic,
1434
+ addPoints,
1435
+ mulPointScalar,
1436
+ getSubOrder
1437
+ };
1438
+ }
1439
+ function packNoteData(note) {
1440
+ return encodePacked(
1441
+ ["uint64", "uint256", "bytes"],
1442
+ [note.searchTag, note.ownerHash, note.encryptedNote]
1443
+ );
1444
+ }
1445
+ function useShield(config) {
1446
+ const { createNoteForSelf, isSetup, masterKeys } = useUPPAccount();
1447
+ const [isPending, setIsPending] = useState(false);
1448
+ const [stage, setStage] = useState(null);
1449
+ const [error, setError] = useState(null);
1450
+ const configRef = useRef(config);
1451
+ configRef.current = config;
1452
+ const reset = useCallback(() => {
1453
+ setError(null);
1454
+ setStage(null);
1455
+ }, []);
1456
+ const build = useCallback(
1457
+ async (params) => {
1458
+ if (!isSetup || !masterKeys) {
1459
+ throw new Error("Account not set up. Call setupAccount() first.");
1460
+ }
1461
+ setIsPending(true);
1462
+ setError(null);
1463
+ try {
1464
+ const { amount, originAddress } = params;
1465
+ const cfg = configRef.current;
1466
+ if (amount <= 0n) {
1467
+ throw new Error("Amount must be positive");
1468
+ }
1469
+ const origin = BigInt(originAddress);
1470
+ const token = BigInt(cfg.tokenAddress);
1471
+ setStage("creating_note");
1472
+ const noteData = await createNoteForSelf(amount, origin, token);
1473
+ const commitment = toHex(noteData.commitment, { size: 32 });
1474
+ const encryptedNote = packNoteData(noteData);
1475
+ return {
1476
+ amount,
1477
+ token: cfg.tokenAddress,
1478
+ commitment,
1479
+ encryptedNote,
1480
+ noteData
1481
+ };
1482
+ } catch (err) {
1483
+ const error2 = err instanceof Error ? err : new Error(String(err));
1484
+ setError(error2);
1485
+ throw error2;
1486
+ } finally {
1487
+ setIsPending(false);
1488
+ setStage(null);
1489
+ }
1490
+ },
1491
+ [isSetup, masterKeys, createNoteForSelf]
1492
+ );
1493
+ return {
1494
+ build,
1495
+ isPending,
1496
+ stage,
1497
+ error,
1498
+ reset
1499
+ };
1500
+ }
1501
+ function packNoteData2(note) {
1502
+ return encodePacked(
1503
+ ["uint64", "uint256", "bytes"],
1504
+ [note.searchTag, note.ownerHash, note.encryptedNote]
1505
+ );
1506
+ }
1507
+ function usePoolTransfer(config) {
1508
+ const {
1509
+ unspentNotes,
1510
+ createNoteForSelf,
1511
+ isSetup,
1512
+ masterKeys
1513
+ } = useUPPAccount();
1514
+ const [isPending, setIsPending] = useState(false);
1515
+ const [stage, setStage] = useState(null);
1516
+ const [error, setError] = useState(null);
1517
+ const configRef = useRef(config);
1518
+ configRef.current = config;
1519
+ const reset = useCallback(() => {
1520
+ setError(null);
1521
+ setStage(null);
1522
+ }, []);
1523
+ const build = useCallback(
1524
+ async (params) => {
1525
+ if (!isSetup || !masterKeys) {
1526
+ throw new Error("Account not set up. Call setupAccount() first.");
1527
+ }
1528
+ setIsPending(true);
1529
+ setError(null);
1530
+ try {
1531
+ const { amount, recipient: _recipient } = params;
1532
+ const cfg = configRef.current;
1533
+ setStage("selecting_notes");
1534
+ const confirmedNotes = unspentNotes.filter(
1535
+ (n) => n.status === "confirmed" && n.token?.toLowerCase() === cfg.tokenAddress.toLowerCase()
1536
+ );
1537
+ const sortedNotes = [...confirmedNotes].sort((a, b) => {
1538
+ const diff = b.amount - a.amount;
1539
+ return diff > 0n ? 1 : diff < 0n ? -1 : 0;
1540
+ });
1541
+ const selectedNote = sortedNotes.find((n) => n.amount >= amount);
1542
+ if (!selectedNote) {
1543
+ const totalBalance = confirmedNotes.reduce((sum, n) => sum + n.amount, 0n);
1544
+ if (totalBalance >= amount) {
1545
+ throw new Error(
1546
+ "No single note is large enough. Please merge notes first, or shield a larger amount."
1547
+ );
1548
+ }
1549
+ throw new Error("Insufficient shielded balance");
1550
+ }
1551
+ const changeAmount = selectedNote.amount - amount;
1552
+ const origin = BigInt(selectedNote.origin);
1553
+ const token = BigInt(selectedNote.token);
1554
+ setStage("creating_outputs");
1555
+ const recipientNote = await createNoteForSelf(amount, origin, token);
1556
+ const changeNote = await createNoteForSelf(changeAmount, origin, token);
1557
+ const [transferModule, proofModule, aspModule] = await Promise.all([
1558
+ import('../transfer-KTCXKHS4.js'),
1559
+ import('../proof-C4YBP6RY.js'),
1560
+ import('../asp-ZA3RGN7G.js')
1561
+ ]);
1562
+ const {
1563
+ syncMerkleTree,
1564
+ getMerkleProofsForNotes,
1565
+ buildUPPTransferCircuitInputs
1566
+ } = transferModule;
1567
+ const { generateUPPProof, formatProofForContract } = proofModule;
1568
+ const { generateASPProof: generateASPProof2, DEMO_ASP_ID } = aspModule;
1569
+ setStage("syncing_merkle");
1570
+ const { tree, leaves } = await syncMerkleTree(cfg.publicClient, cfg.poolAddress);
1571
+ const spendableNote = {
1572
+ amount: selectedNote.amount,
1573
+ blinding: selectedNote.blinding,
1574
+ commitment: selectedNote.commitment,
1575
+ ownerSecret: selectedNote.ownerSecret,
1576
+ ownerHash: selectedNote.ownerHash,
1577
+ leafIndex: selectedNote.leafIndex,
1578
+ origin,
1579
+ token
1580
+ };
1581
+ const [noteProof] = await getMerkleProofsForNotes([spendableNote], leaves, tree);
1582
+ const aspProof = await generateASPProof2(
1583
+ cfg.aspId ?? DEMO_ASP_ID,
1584
+ origin,
1585
+ cfg.aspApprovedOrigins
1586
+ );
1587
+ setStage("generating_proof");
1588
+ const recipientNoteWithAmount = { ...recipientNote, amount };
1589
+ const changeNoteWithAmount = { ...changeNote, amount: changeAmount };
1590
+ const circuitInputs = await buildUPPTransferCircuitInputs(
1591
+ noteProof,
1592
+ aspProof,
1593
+ recipientNoteWithAmount,
1594
+ changeNoteWithAmount
1595
+ );
1596
+ const { proof } = await generateUPPProof(
1597
+ "transfer",
1598
+ circuitInputs,
1599
+ cfg.circuitBaseUrl ?? "/circuits/"
1600
+ );
1601
+ const formattedProof = formatProofForContract(proof);
1602
+ const proofArray = [
1603
+ formattedProof.a[0],
1604
+ formattedProof.a[1],
1605
+ formattedProof.b[0][0],
1606
+ formattedProof.b[0][1],
1607
+ formattedProof.b[1][0],
1608
+ formattedProof.b[1][1],
1609
+ formattedProof.c[0],
1610
+ formattedProof.c[1]
1611
+ ];
1612
+ return {
1613
+ circuit: "transfer",
1614
+ proof: proofArray,
1615
+ nullifier: toHex(BigInt(circuitInputs.nullifier), { size: 32 }),
1616
+ stateRoot: BigInt(circuitInputs.stateRoot),
1617
+ aspRoot: BigInt(circuitInputs.aspRoot),
1618
+ token: cfg.tokenAddress,
1619
+ outputCommitment1: toHex(recipientNote.commitment, { size: 32 }),
1620
+ outputCommitment2: toHex(changeNote.commitment, { size: 32 }),
1621
+ encryptedNote1: packNoteData2(recipientNote),
1622
+ encryptedNote2: packNoteData2(changeNote),
1623
+ spentNote: selectedNote,
1624
+ recipientNoteData: recipientNote,
1625
+ changeNoteData: changeNote
1626
+ };
1627
+ } catch (err) {
1628
+ const error2 = err instanceof Error ? err : new Error(String(err));
1629
+ setError(error2);
1630
+ throw error2;
1631
+ } finally {
1632
+ setIsPending(false);
1633
+ setStage(null);
1634
+ }
1635
+ },
1636
+ [isSetup, masterKeys, unspentNotes, createNoteForSelf]
1637
+ );
1638
+ return {
1639
+ build,
1640
+ isPending,
1641
+ stage,
1642
+ error,
1643
+ reset
1644
+ };
1645
+ }
1646
+ init_poseidon();
1647
+ var STATE_TREE_DEPTH = 32;
1648
+ var ASP_TREE_DEPTH2 = 20;
1649
+ function padToDepth(arr, padValue, depth) {
1650
+ if (arr.length >= depth) {
1651
+ return arr.slice(0, depth);
1652
+ }
1653
+ return [...arr, ...Array(depth - arr.length).fill(padValue)];
1654
+ }
1655
+ function useWithdraw(config) {
1656
+ const {
1657
+ isSetup,
1658
+ masterKeys,
1659
+ unspentNotes
1660
+ } = useUPPAccount();
1661
+ const [isPending, setIsPending] = useState(false);
1662
+ const [stage, setStage] = useState(null);
1663
+ const [error, setError] = useState(null);
1664
+ const configRef = useRef(config);
1665
+ configRef.current = config;
1666
+ const reset = useCallback(() => {
1667
+ setError(null);
1668
+ setStage(null);
1669
+ }, []);
1670
+ const build = useCallback(
1671
+ async (params) => {
1672
+ if (!isSetup || !masterKeys) {
1673
+ throw new Error("Account not set up. Call setupAccount() first.");
1674
+ }
1675
+ setIsPending(true);
1676
+ setError(null);
1677
+ try {
1678
+ const {
1679
+ amount,
1680
+ recipient,
1681
+ aspId = 0n,
1682
+ aspRoot = 0n,
1683
+ isRagequit = false
1684
+ } = params;
1685
+ const cfg = configRef.current;
1686
+ setStage("selecting_notes");
1687
+ console.log(`[useWithdraw] === NOTE SELECTION DEBUG ===`);
1688
+ console.log(` Requested amount: ${amount}`);
1689
+ console.log(` Available unspent notes (${unspentNotes.length}):`);
1690
+ unspentNotes.forEach((n, i) => {
1691
+ console.log(` [${i}] amount=${n.amount}, status=${n.status}, leafIndex=${n.leafIndex}, commitment=${n.commitment.slice(0, 18)}...`);
1692
+ });
1693
+ const tokenFilteredNotes = unspentNotes.filter(
1694
+ (n) => n.token?.toLowerCase() === cfg.tokenAddress.toLowerCase() && n.proofSystem !== "stark"
1695
+ );
1696
+ const sortedNotes = [...tokenFilteredNotes].sort(
1697
+ (a, b) => a.amount > b.amount ? 1 : -1
1698
+ );
1699
+ console.log(` Sorted notes (ascending by amount):`);
1700
+ sortedNotes.forEach((n, i) => {
1701
+ console.log(` [${i}] amount=${n.amount}, commitment=${n.commitment.slice(0, 18)}...`);
1702
+ });
1703
+ const selectedNote = sortedNotes.find((n) => n.amount >= amount);
1704
+ console.log(` Selected note: ${selectedNote ? `amount=${selectedNote.amount}, commitment=${selectedNote.commitment.slice(0, 18)}...` : "NONE"}`);
1705
+ if (!selectedNote) {
1706
+ throw new Error(`Insufficient balance. Need ${amount}, have ${tokenFilteredNotes.reduce((s, n) => s + n.amount, 0n)}`);
1707
+ }
1708
+ if (selectedNote.amount !== amount) {
1709
+ throw new Error(
1710
+ `Withdraw circuit requires exact note amount. Note has ${selectedNote.amount}, requested ${amount}. Use private transfer to split the note first.`
1711
+ );
1712
+ }
1713
+ const origin = BigInt(selectedNote.origin);
1714
+ const token = BigInt(selectedNote.token);
1715
+ setStage("creating_outputs");
1716
+ const [transferModule, proofModule, sdk] = await Promise.all([
1717
+ import('../transfer-KTCXKHS4.js'),
1718
+ import('../proof-C4YBP6RY.js'),
1719
+ import('../index.js')
1720
+ ]);
1721
+ const { syncMerkleTree, getMerkleProofsForNotes } = transferModule;
1722
+ const { generateUPPProof, formatProofForContract } = proofModule;
1723
+ setStage("syncing_merkle");
1724
+ const { tree, leaves } = await syncMerkleTree(cfg.publicClient, cfg.poolAddress);
1725
+ const spendableNote = {
1726
+ amount: selectedNote.amount,
1727
+ blinding: selectedNote.blinding,
1728
+ commitment: selectedNote.commitment,
1729
+ ownerSecret: selectedNote.ownerSecret,
1730
+ ownerHash: selectedNote.ownerHash,
1731
+ leafIndex: selectedNote.leafIndex,
1732
+ origin,
1733
+ token
1734
+ };
1735
+ const [noteProof] = await getMerkleProofsForNotes([spendableNote], leaves, tree);
1736
+ setStage("generating_proof");
1737
+ const merkleProof = noteProof.proof;
1738
+ const stateRootBI = merkleProof.root;
1739
+ const actualLeafIndex = merkleProof.leafIndex;
1740
+ const inputPubkey = await sdk.privateToPublic(BigInt(selectedNote.ownerSecret));
1741
+ const localCommitment = await sdk.poseidon([
1742
+ selectedNote.amount,
1743
+ inputPubkey.x,
1744
+ inputPubkey.y,
1745
+ selectedNote.blinding,
1746
+ BigInt(selectedNote.origin),
1747
+ BigInt(selectedNote.token)
1748
+ ]);
1749
+ const storedCommitment = BigInt(selectedNote.commitment);
1750
+ if (localCommitment !== storedCommitment) {
1751
+ throw new Error(
1752
+ `Note commitment mismatch \u2014 this note was created with an outdated commitment formula. Clear your shielded account (localStorage) and re-shield tokens.`
1753
+ );
1754
+ }
1755
+ const nullifier = await sdk.poseidon([
1756
+ BigInt(selectedNote.ownerSecret) % BABYJUBJUB_SUBORDER,
1757
+ BigInt(actualLeafIndex),
1758
+ storedCommitment
1759
+ ]);
1760
+ const circuitInputs = {
1761
+ // Public inputs
1762
+ stateRoot: stateRootBI.toString(),
1763
+ aspRoot: aspRoot.toString(),
1764
+ nullifier: nullifier.toString(),
1765
+ amount: selectedNote.amount.toString(),
1766
+ recipient: BigInt(recipient).toString(),
1767
+ token: BigInt(cfg.tokenAddress).toString(),
1768
+ isRagequit: isRagequit ? "1" : "0",
1769
+ // Private inputs - Input Note
1770
+ // IMPORTANT: Use actualLeafIndex from Merkle proof, not stored leafIndex
1771
+ inputAmount: selectedNote.amount.toString(),
1772
+ inputOneTimeSecret: (BigInt(selectedNote.ownerSecret) % BABYJUBJUB_SUBORDER).toString(),
1773
+ inputBlinding: selectedNote.blinding.toString(),
1774
+ inputOrigin: origin.toString(),
1775
+ inputLeafIndex: actualLeafIndex.toString(),
1776
+ inputPathElements: padToDepth(merkleProof.pathElements.map(String), "0", STATE_TREE_DEPTH),
1777
+ inputPathIndices: padToDepth(merkleProof.pathIndices.map(String), "0", STATE_TREE_DEPTH),
1778
+ // ASP membership proof (zeros for ragequit)
1779
+ aspPathElements: Array(ASP_TREE_DEPTH2).fill("0"),
1780
+ aspPathIndices: Array(ASP_TREE_DEPTH2).fill("0")
1781
+ };
1782
+ const { proof } = await generateUPPProof(
1783
+ "withdraw",
1784
+ circuitInputs,
1785
+ cfg.circuitBaseUrl ?? "/circuits/"
1786
+ );
1787
+ const formattedProof = formatProofForContract(proof);
1788
+ const stateRoot = stateRootBI;
1789
+ const proofArray = [
1790
+ formattedProof.a[0],
1791
+ formattedProof.a[1],
1792
+ formattedProof.b[0][0],
1793
+ formattedProof.b[0][1],
1794
+ formattedProof.b[1][0],
1795
+ formattedProof.b[1][1],
1796
+ formattedProof.c[0],
1797
+ formattedProof.c[1]
1798
+ ];
1799
+ return {
1800
+ proof: proofArray,
1801
+ nullifier: toHex(nullifier, { size: 32 }),
1802
+ stateRoot,
1803
+ aspRoot,
1804
+ aspId,
1805
+ token: cfg.tokenAddress,
1806
+ amount,
1807
+ recipient,
1808
+ isRagequit,
1809
+ spentNote: selectedNote,
1810
+ changeNoteData: null,
1811
+ changeCommitment: null,
1812
+ changeEncryptedNote: null
1813
+ };
1814
+ } catch (err) {
1815
+ const error2 = err instanceof Error ? err : new Error(String(err));
1816
+ setError(error2);
1817
+ throw error2;
1818
+ } finally {
1819
+ setIsPending(false);
1820
+ setStage(null);
1821
+ }
1822
+ },
1823
+ [isSetup, masterKeys, unspentNotes]
1824
+ );
1825
+ return {
1826
+ build,
1827
+ isPending,
1828
+ stage,
1829
+ error,
1830
+ reset
1831
+ };
1832
+ }
1833
+ var STORAGE_KEY_PREFIX = "upp_personal_asp_";
1834
+ function getStorageKey2(chainId, address) {
1835
+ return `${STORAGE_KEY_PREFIX}${chainId}_${address.toLowerCase()}`;
1836
+ }
1837
+ function loadStoredASPId(chainId, address) {
1838
+ if (typeof window === "undefined") return null;
1839
+ try {
1840
+ const key = getStorageKey2(chainId, address);
1841
+ const stored = localStorage.getItem(key);
1842
+ return stored ? BigInt(stored) : null;
1843
+ } catch {
1844
+ return null;
1845
+ }
1846
+ }
1847
+ function storeASPId(chainId, address, aspId) {
1848
+ if (typeof window === "undefined") return;
1849
+ try {
1850
+ const key = getStorageKey2(chainId, address);
1851
+ localStorage.setItem(key, aspId.toString());
1852
+ } catch {
1853
+ }
1854
+ }
1855
+ function usePersonalASP(config) {
1856
+ const { aspHubAddress, publicClient, userAddress } = config;
1857
+ const [aspInfo, setAspInfo] = useState(null);
1858
+ const [isLoading, setIsLoading] = useState(true);
1859
+ const [error, setError] = useState(null);
1860
+ const refresh = useCallback(async () => {
1861
+ if (!userAddress || !publicClient) {
1862
+ setAspInfo(null);
1863
+ setIsLoading(false);
1864
+ return;
1865
+ }
1866
+ try {
1867
+ setIsLoading(true);
1868
+ setError(null);
1869
+ const chainId = await publicClient.getChainId();
1870
+ const storedAspId = loadStoredASPId(chainId, userAddress);
1871
+ if (storedAspId) {
1872
+ const aspData = await publicClient.readContract({
1873
+ address: aspHubAddress,
1874
+ abi: ASP_REGISTRY_HUB_ABI,
1875
+ functionName: "getASP",
1876
+ args: [storedAspId]
1877
+ });
1878
+ if (aspData.operator.toLowerCase() === userAddress.toLowerCase()) {
1879
+ const userOrigin = BigInt(userAddress);
1880
+ const expectedRoot = await computeSingleOriginASPRoot(userOrigin);
1881
+ const isApproved = aspData.currentRoot === expectedRoot;
1882
+ setAspInfo({
1883
+ aspId: storedAspId,
1884
+ currentRoot: aspData.currentRoot,
1885
+ isRegistered: true,
1886
+ isApproved
1887
+ });
1888
+ setIsLoading(false);
1889
+ return;
1890
+ }
1891
+ }
1892
+ setAspInfo({
1893
+ aspId: 0n,
1894
+ currentRoot: 0n,
1895
+ isRegistered: false,
1896
+ isApproved: false
1897
+ });
1898
+ } catch (err) {
1899
+ const error2 = err instanceof Error ? err : new Error(String(err));
1900
+ setError(error2);
1901
+ setAspInfo(null);
1902
+ } finally {
1903
+ setIsLoading(false);
1904
+ }
1905
+ }, [aspHubAddress, publicClient, userAddress]);
1906
+ useEffect(() => {
1907
+ refresh();
1908
+ }, [refresh]);
1909
+ const isOriginApproved = useCallback(async (origin) => {
1910
+ if (!aspInfo?.isRegistered || !publicClient) return false;
1911
+ try {
1912
+ const expectedRoot = await computeSingleOriginASPRoot(origin);
1913
+ const isValid = await publicClient.readContract({
1914
+ address: aspHubAddress,
1915
+ abi: ASP_REGISTRY_HUB_ABI,
1916
+ functionName: "isValidASPRoot",
1917
+ args: [aspInfo.aspId, expectedRoot]
1918
+ });
1919
+ return isValid;
1920
+ } catch {
1921
+ return false;
1922
+ }
1923
+ }, [aspInfo, aspHubAddress, publicClient]);
1924
+ const getASPId = useCallback(() => {
1925
+ return aspInfo?.isRegistered ? aspInfo.aspId : null;
1926
+ }, [aspInfo]);
1927
+ const getASPRootForOrigin = useCallback(async (origin) => {
1928
+ return computeSingleOriginASPRoot(origin);
1929
+ }, []);
1930
+ return {
1931
+ aspInfo,
1932
+ isLoading,
1933
+ error,
1934
+ isOriginApproved,
1935
+ getASPId,
1936
+ getASPRootForOrigin,
1937
+ refresh
1938
+ };
1939
+ }
1940
+ function storePersonalASPId(chainId, address, aspId) {
1941
+ storeASPId(chainId, address, aspId);
1942
+ }
1943
+ init_poseidon();
1944
+ var STATE_TREE_DEPTH2 = 32;
1945
+ function padToDepth2(arr, padValue, depth) {
1946
+ if (arr.length >= depth) return arr.slice(0, depth);
1947
+ return [...arr, ...Array(depth - arr.length).fill(padValue)];
1948
+ }
1949
+ var SWAP_ORDERS_ABI = [{
1950
+ type: "function",
1951
+ name: "swapOrders",
1952
+ inputs: [{ name: "", type: "bytes32" }],
1953
+ outputs: [
1954
+ { name: "sellToken", type: "address" },
1955
+ { name: "sellAmount", type: "uint256" },
1956
+ { name: "remainingSellAmount", type: "uint256" },
1957
+ { name: "buyToken", type: "address" },
1958
+ { name: "rate", type: "uint256" },
1959
+ { name: "accumulatedBuyAmount", type: "uint256" },
1960
+ { name: "makerAspId", type: "uint256" },
1961
+ { name: "requiredFillerAspId", type: "uint256" },
1962
+ { name: "cancelKeyHash", type: "bytes32" },
1963
+ { name: "expiry", type: "uint256" },
1964
+ { name: "claimed", type: "bool" },
1965
+ { name: "cancelled", type: "bool" }
1966
+ ],
1967
+ stateMutability: "view"
1968
+ }];
1969
+ function useSwapOrderBook(config) {
1970
+ const [orders, setOrders] = useState([]);
1971
+ const [isLoading, setIsLoading] = useState(false);
1972
+ const [error, setError] = useState(null);
1973
+ const intervalRef = useRef(null);
1974
+ const refresh = useCallback(async () => {
1975
+ setIsLoading(true);
1976
+ setError(null);
1977
+ try {
1978
+ const logs = await config.publicClient.getLogs({
1979
+ address: config.poolAddress,
1980
+ event: SWAP_ORDER_PLACED_EVENT,
1981
+ fromBlock: config.fromBlock ?? 0n,
1982
+ toBlock: "latest"
1983
+ });
1984
+ let parsedOrders = logs.map((log) => ({
1985
+ orderId: log.args.orderId,
1986
+ sellToken: log.args.sellToken,
1987
+ buyToken: log.args.buyToken,
1988
+ sellAmount: log.args.sellAmount,
1989
+ rate: log.args.rate,
1990
+ makerAspId: log.args.makerAspId,
1991
+ requiredFillerAspId: log.args.requiredFillerAspId,
1992
+ expiry: log.args.expiry,
1993
+ blockNumber: log.blockNumber ?? 0n
1994
+ }));
1995
+ if (config.sellToken && config.buyToken) {
1996
+ parsedOrders = filterOrdersByTokenPair(parsedOrders, config.sellToken, config.buyToken);
1997
+ }
1998
+ if (config.acceptableAspIds && config.acceptableAspIds.length > 0) {
1999
+ parsedOrders = filterOrdersByASP(parsedOrders, config.acceptableAspIds);
2000
+ }
2001
+ const enriched = [];
2002
+ for (const order of parsedOrders) {
2003
+ try {
2004
+ const result = await config.publicClient.readContract({
2005
+ address: config.poolAddress,
2006
+ abi: SWAP_ORDERS_ABI,
2007
+ functionName: "swapOrders",
2008
+ args: [order.orderId]
2009
+ });
2010
+ const claimed = result[10];
2011
+ const cancelled = result[11];
2012
+ const remainingSellAmount = result[2];
2013
+ enriched.push({
2014
+ ...order,
2015
+ remainingSellAmount,
2016
+ claimed,
2017
+ cancelled
2018
+ });
2019
+ } catch {
2020
+ enriched.push(order);
2021
+ }
2022
+ }
2023
+ setOrders(enriched);
2024
+ } catch (err) {
2025
+ setError(err instanceof Error ? err.message : "Failed to fetch order book");
2026
+ } finally {
2027
+ setIsLoading(false);
2028
+ }
2029
+ }, [config.publicClient, config.poolAddress, config.sellToken, config.buyToken, config.acceptableAspIds, config.fromBlock]);
2030
+ useEffect(() => {
2031
+ refresh();
2032
+ const interval = config.pollInterval ?? 15e3;
2033
+ intervalRef.current = setInterval(refresh, interval);
2034
+ return () => {
2035
+ if (intervalRef.current) clearInterval(intervalRef.current);
2036
+ };
2037
+ }, [refresh, config.pollInterval]);
2038
+ return { orders, isLoading, error, refresh };
2039
+ }
2040
+ function useSwap(config) {
2041
+ const {
2042
+ isSetup,
2043
+ masterKeys,
2044
+ unspentNotes,
2045
+ createNoteForSelf,
2046
+ ethAddress
2047
+ } = useUPPAccount();
2048
+ const [isPending, setIsPending] = useState(false);
2049
+ const [stage, setStage] = useState(null);
2050
+ const [error, setError] = useState(null);
2051
+ const configRef = useRef(config);
2052
+ configRef.current = config;
2053
+ const reset = useCallback(() => {
2054
+ setError(null);
2055
+ setStage(null);
2056
+ }, []);
2057
+ const buildPlaceOrder = useCallback(
2058
+ async (params) => {
2059
+ if (!isSetup || !masterKeys) {
2060
+ throw new Error("Account not set up. Call setupAccount() first.");
2061
+ }
2062
+ setIsPending(true);
2063
+ setError(null);
2064
+ try {
2065
+ const {
2066
+ sellToken,
2067
+ sellAmount,
2068
+ buyToken,
2069
+ rate,
2070
+ requiredFillerAspId = 0n,
2071
+ expiryBlocks,
2072
+ aspId,
2073
+ noteOverride
2074
+ } = params;
2075
+ const cfg = configRef.current;
2076
+ setStage("selecting_notes");
2077
+ let selectedNote;
2078
+ if (noteOverride) {
2079
+ selectedNote = noteOverride;
2080
+ } else {
2081
+ const sortedNotes = [...unspentNotes].filter((n) => n.token?.toLowerCase() === sellToken.toLowerCase() && n.proofSystem !== "stark").sort((a, b) => a.amount > b.amount ? 1 : -1);
2082
+ const exactNote = sortedNotes.find((n) => n.amount === sellAmount);
2083
+ if (!exactNote) {
2084
+ const largerNote = sortedNotes.find((n) => n.amount > sellAmount);
2085
+ if (largerNote) {
2086
+ throw new Error(`SPLIT_REQUIRED:${largerNote.commitment}`);
2087
+ }
2088
+ throw new Error(
2089
+ `Insufficient ${sellToken} balance for swap. Need ${sellAmount}, have ${sortedNotes.reduce((s, n) => s + n.amount, 0n)}`
2090
+ );
2091
+ }
2092
+ selectedNote = exactNote;
2093
+ }
2094
+ setStage("creating_outputs");
2095
+ const [transferModule, proofModule, sdk, aspModule] = await Promise.all([
2096
+ import('../transfer-KTCXKHS4.js'),
2097
+ import('../proof-C4YBP6RY.js'),
2098
+ import('../index.js'),
2099
+ import('../asp-ZA3RGN7G.js')
2100
+ ]);
2101
+ const { syncMerkleTree, getMerkleProofsForNotes } = transferModule;
2102
+ const { generateUPPProof, formatProofForContract } = proofModule;
2103
+ const { generateASPProof: generateASPProof2 } = aspModule;
2104
+ setStage("syncing_merkle");
2105
+ const { tree, leaves } = await syncMerkleTree(cfg.publicClient, cfg.poolAddress);
2106
+ const origin = BigInt(selectedNote.origin);
2107
+ const token = BigInt(selectedNote.token);
2108
+ const spendableNote = {
2109
+ amount: selectedNote.amount,
2110
+ blinding: selectedNote.blinding,
2111
+ commitment: selectedNote.commitment,
2112
+ ownerSecret: selectedNote.ownerSecret,
2113
+ ownerHash: selectedNote.ownerHash,
2114
+ leafIndex: selectedNote.leafIndex,
2115
+ origin,
2116
+ token
2117
+ };
2118
+ const [noteProof] = await getMerkleProofsForNotes([spendableNote], leaves, tree);
2119
+ const merkleProof = noteProof.proof;
2120
+ const stateRootBI = merkleProof.root;
2121
+ const actualLeafIndex = merkleProof.leafIndex;
2122
+ setStage("generating_proof");
2123
+ const inputPubkey = await sdk.privateToPublic(BigInt(selectedNote.ownerSecret));
2124
+ const localCommitment = await sdk.poseidon([
2125
+ selectedNote.amount,
2126
+ inputPubkey.x,
2127
+ inputPubkey.y,
2128
+ selectedNote.blinding,
2129
+ origin,
2130
+ token
2131
+ ]);
2132
+ const storedCommitment = BigInt(selectedNote.commitment);
2133
+ if (localCommitment !== storedCommitment) {
2134
+ throw new Error(
2135
+ `Note commitment mismatch \u2014 this note was created with an outdated commitment formula. Clear your shielded account (localStorage) and re-shield tokens.`
2136
+ );
2137
+ }
2138
+ const nullifier = await sdk.poseidon([
2139
+ BigInt(selectedNote.ownerSecret) % BABYJUBJUB_SUBORDER,
2140
+ BigInt(actualLeafIndex),
2141
+ storedCommitment
2142
+ ]);
2143
+ const aspProofData = await generateASPProof2(aspId, origin, cfg.aspApprovedOrigins);
2144
+ const circuitInputs = {
2145
+ stateRoot: stateRootBI.toString(),
2146
+ aspRoot: aspProofData.aspRoot.toString(),
2147
+ nullifier: nullifier.toString(),
2148
+ amount: selectedNote.amount.toString(),
2149
+ recipient: BigInt(cfg.poolAddress).toString(),
2150
+ token: token.toString(),
2151
+ isRagequit: "0",
2152
+ inputAmount: selectedNote.amount.toString(),
2153
+ inputOneTimeSecret: (BigInt(selectedNote.ownerSecret) % BABYJUBJUB_SUBORDER).toString(),
2154
+ inputBlinding: selectedNote.blinding.toString(),
2155
+ inputOrigin: origin.toString(),
2156
+ inputLeafIndex: actualLeafIndex.toString(),
2157
+ inputPathElements: padToDepth2(merkleProof.pathElements.map(String), "0", STATE_TREE_DEPTH2),
2158
+ inputPathIndices: padToDepth2(merkleProof.pathIndices.map(String), "0", STATE_TREE_DEPTH2),
2159
+ aspPathElements: aspProofData.aspPathElements.map(String),
2160
+ aspPathIndices: aspProofData.aspPathIndices.map(String)
2161
+ };
2162
+ const { proof } = await generateUPPProof(
2163
+ "withdraw",
2164
+ circuitInputs,
2165
+ cfg.circuitBaseUrl ?? "/circuits/"
2166
+ );
2167
+ const formattedProof = formatProofForContract(proof);
2168
+ const proofArray = [
2169
+ formattedProof.a[0],
2170
+ formattedProof.a[1],
2171
+ formattedProof.b[0][0],
2172
+ formattedProof.b[0][1],
2173
+ formattedProof.b[1][0],
2174
+ formattedProof.b[1][1],
2175
+ formattedProof.c[0],
2176
+ formattedProof.c[1]
2177
+ ];
2178
+ const cancelSecret = generateCancelSecret();
2179
+ const cancelKeyHash = computeCancelKeyHash(cancelSecret);
2180
+ const currentBlock = await cfg.publicClient.getBlockNumber();
2181
+ const expiry = currentBlock + expiryBlocks;
2182
+ return {
2183
+ proof: proofArray,
2184
+ nullifier: toHex(nullifier, { size: 32 }),
2185
+ stateRoot: stateRootBI,
2186
+ aspRoot: aspProofData.aspRoot,
2187
+ aspId,
2188
+ sellToken,
2189
+ sellAmount,
2190
+ buyToken,
2191
+ rate,
2192
+ cancelKeyHash,
2193
+ cancelSecret,
2194
+ requiredFillerAspId,
2195
+ expiry,
2196
+ spentNote: selectedNote
2197
+ };
2198
+ } catch (err) {
2199
+ const error2 = err instanceof Error ? err : new Error(String(err));
2200
+ setError(error2);
2201
+ throw error2;
2202
+ } finally {
2203
+ setIsPending(false);
2204
+ setStage(null);
2205
+ }
2206
+ },
2207
+ [isSetup, masterKeys, unspentNotes]
2208
+ );
2209
+ const buildFillOrder = useCallback(
2210
+ async (params) => {
2211
+ if (!isSetup || !masterKeys) {
2212
+ throw new Error("Account not set up. Call setupAccount() first.");
2213
+ }
2214
+ setIsPending(true);
2215
+ setError(null);
2216
+ try {
2217
+ const {
2218
+ orderId,
2219
+ takeAmount,
2220
+ rate,
2221
+ sellToken,
2222
+ buyToken,
2223
+ aspId,
2224
+ noteOverride
2225
+ } = params;
2226
+ const cfg = configRef.current;
2227
+ const giveAmount = computeGiveAmount(takeAmount, rate);
2228
+ setStage("selecting_notes");
2229
+ let selectedNote;
2230
+ if (noteOverride) {
2231
+ selectedNote = noteOverride;
2232
+ } else {
2233
+ const sortedNotes = [...unspentNotes].filter((n) => n.token?.toLowerCase() === buyToken.toLowerCase() && n.proofSystem !== "stark").sort((a, b) => a.amount > b.amount ? 1 : -1);
2234
+ const exactNote = sortedNotes.find((n) => n.amount === giveAmount);
2235
+ if (!exactNote) {
2236
+ const largerNote = sortedNotes.find((n) => n.amount > giveAmount);
2237
+ if (largerNote) {
2238
+ throw new Error(`SPLIT_REQUIRED:${largerNote.commitment}`);
2239
+ }
2240
+ throw new Error(
2241
+ `Insufficient ${buyToken} balance. Need ${giveAmount} to fill order, have ${sortedNotes.reduce((s, n) => s + n.amount, 0n)}`
2242
+ );
2243
+ }
2244
+ selectedNote = exactNote;
2245
+ }
2246
+ setStage("creating_outputs");
2247
+ const [transferModule, proofModule, sdk, aspModule] = await Promise.all([
2248
+ import('../transfer-KTCXKHS4.js'),
2249
+ import('../proof-C4YBP6RY.js'),
2250
+ import('../index.js'),
2251
+ import('../asp-ZA3RGN7G.js')
2252
+ ]);
2253
+ const { syncMerkleTree, getMerkleProofsForNotes } = transferModule;
2254
+ const { generateUPPProof, formatProofForContract } = proofModule;
2255
+ const { generateASPProof: generateASPProof2 } = aspModule;
2256
+ const fillerOrigin = ethAddress ? BigInt(ethAddress) : BigInt(masterKeys.ownerHash);
2257
+ const fillerNoteData = await createNoteForSelf(
2258
+ takeAmount,
2259
+ fillerOrigin,
2260
+ BigInt(sellToken)
2261
+ );
2262
+ setStage("syncing_merkle");
2263
+ const { tree, leaves } = await syncMerkleTree(cfg.publicClient, cfg.poolAddress);
2264
+ const origin = BigInt(selectedNote.origin);
2265
+ const token = BigInt(selectedNote.token);
2266
+ const spendableNote = {
2267
+ amount: selectedNote.amount,
2268
+ blinding: selectedNote.blinding,
2269
+ commitment: selectedNote.commitment,
2270
+ ownerSecret: selectedNote.ownerSecret,
2271
+ ownerHash: selectedNote.ownerHash,
2272
+ leafIndex: selectedNote.leafIndex,
2273
+ origin,
2274
+ token
2275
+ };
2276
+ const [noteProof] = await getMerkleProofsForNotes([spendableNote], leaves, tree);
2277
+ const merkleProof = noteProof.proof;
2278
+ const stateRootBI = merkleProof.root;
2279
+ const actualLeafIndex = merkleProof.leafIndex;
2280
+ setStage("generating_proof");
2281
+ const inputPubkeyF = await sdk.privateToPublic(BigInt(selectedNote.ownerSecret));
2282
+ const localCommitmentF = await sdk.poseidon([
2283
+ selectedNote.amount,
2284
+ inputPubkeyF.x,
2285
+ inputPubkeyF.y,
2286
+ selectedNote.blinding,
2287
+ origin,
2288
+ token
2289
+ ]);
2290
+ const storedCommitmentF = BigInt(selectedNote.commitment);
2291
+ if (localCommitmentF !== storedCommitmentF) {
2292
+ throw new Error(
2293
+ `Note commitment mismatch \u2014 this note was created with an outdated commitment formula. Clear your shielded account (localStorage) and re-shield tokens.`
2294
+ );
2295
+ }
2296
+ const nullifier = await sdk.poseidon([
2297
+ BigInt(selectedNote.ownerSecret) % BABYJUBJUB_SUBORDER,
2298
+ BigInt(actualLeafIndex),
2299
+ storedCommitmentF
2300
+ ]);
2301
+ const aspProofData = await generateASPProof2(aspId, origin, cfg.aspApprovedOrigins);
2302
+ const circuitInputs = {
2303
+ stateRoot: stateRootBI.toString(),
2304
+ aspRoot: aspProofData.aspRoot.toString(),
2305
+ nullifier: nullifier.toString(),
2306
+ amount: selectedNote.amount.toString(),
2307
+ recipient: BigInt(cfg.poolAddress).toString(),
2308
+ token: token.toString(),
2309
+ isRagequit: "0",
2310
+ inputAmount: selectedNote.amount.toString(),
2311
+ inputOneTimeSecret: (BigInt(selectedNote.ownerSecret) % BABYJUBJUB_SUBORDER).toString(),
2312
+ inputBlinding: selectedNote.blinding.toString(),
2313
+ inputOrigin: origin.toString(),
2314
+ inputLeafIndex: actualLeafIndex.toString(),
2315
+ inputPathElements: padToDepth2(merkleProof.pathElements.map(String), "0", STATE_TREE_DEPTH2),
2316
+ inputPathIndices: padToDepth2(merkleProof.pathIndices.map(String), "0", STATE_TREE_DEPTH2),
2317
+ aspPathElements: aspProofData.aspPathElements.map(String),
2318
+ aspPathIndices: aspProofData.aspPathIndices.map(String)
2319
+ };
2320
+ const { proof } = await generateUPPProof(
2321
+ "withdraw",
2322
+ circuitInputs,
2323
+ cfg.circuitBaseUrl ?? "/circuits/"
2324
+ );
2325
+ const formattedProof = formatProofForContract(proof);
2326
+ const proofArray = [
2327
+ formattedProof.a[0],
2328
+ formattedProof.a[1],
2329
+ formattedProof.b[0][0],
2330
+ formattedProof.b[0][1],
2331
+ formattedProof.b[1][0],
2332
+ formattedProof.b[1][1],
2333
+ formattedProof.c[0],
2334
+ formattedProof.c[1]
2335
+ ];
2336
+ const { encodePacked: encodePacked3 } = await import('viem');
2337
+ const packedFillerNote = encodePacked3(
2338
+ ["uint64", "uint256", "bytes"],
2339
+ [fillerNoteData.searchTag, fillerNoteData.ownerHash, fillerNoteData.encryptedNote]
2340
+ );
2341
+ return {
2342
+ proof: proofArray,
2343
+ nullifier: toHex(nullifier, { size: 32 }),
2344
+ stateRoot: stateRootBI,
2345
+ aspRoot: aspProofData.aspRoot,
2346
+ aspId,
2347
+ orderId,
2348
+ takeAmount,
2349
+ fillerOutputCommitment: toHex(fillerNoteData.commitment, { size: 32 }),
2350
+ fillerEncryptedNote: packedFillerNote,
2351
+ spentNote: selectedNote,
2352
+ fillerNoteData
2353
+ };
2354
+ } catch (err) {
2355
+ const error2 = err instanceof Error ? err : new Error(String(err));
2356
+ setError(error2);
2357
+ throw error2;
2358
+ } finally {
2359
+ setIsPending(false);
2360
+ setStage(null);
2361
+ }
2362
+ },
2363
+ [isSetup, masterKeys, unspentNotes, createNoteForSelf]
2364
+ );
2365
+ const buildClaimOrder = useCallback(
2366
+ async (params) => {
2367
+ if (!isSetup || !masterKeys) {
2368
+ throw new Error("Account not set up. Call setupAccount() first.");
2369
+ }
2370
+ setIsPending(true);
2371
+ setError(null);
2372
+ try {
2373
+ const {
2374
+ orderId,
2375
+ cancelSecret,
2376
+ remainingSellAmount,
2377
+ accumulatedBuyAmount,
2378
+ sellToken,
2379
+ buyToken
2380
+ } = params;
2381
+ let buyNoteData = null;
2382
+ let refundNoteData = null;
2383
+ const originAddr = ethAddress ? BigInt(ethAddress) : BigInt(masterKeys.ownerHash);
2384
+ if (accumulatedBuyAmount > 0n) {
2385
+ buyNoteData = await createNoteForSelf(
2386
+ accumulatedBuyAmount,
2387
+ originAddr,
2388
+ BigInt(buyToken)
2389
+ );
2390
+ }
2391
+ if (remainingSellAmount > 0n) {
2392
+ refundNoteData = await createNoteForSelf(
2393
+ remainingSellAmount,
2394
+ originAddr,
2395
+ BigInt(sellToken)
2396
+ );
2397
+ }
2398
+ const zeroHex = "0x0000000000000000000000000000000000000000000000000000000000000000";
2399
+ return {
2400
+ orderId,
2401
+ cancelSecret,
2402
+ buyOutputCommitment: buyNoteData ? toHex(buyNoteData.commitment, { size: 32 }) : zeroHex,
2403
+ refundCommitment: refundNoteData ? toHex(refundNoteData.commitment, { size: 32 }) : zeroHex,
2404
+ buyEncryptedNote: buyNoteData ? buyNoteData.encryptedNote : "0x",
2405
+ refundEncryptedNote: refundNoteData ? refundNoteData.encryptedNote : "0x",
2406
+ buyNoteData,
2407
+ refundNoteData
2408
+ };
2409
+ } catch (err) {
2410
+ const error2 = err instanceof Error ? err : new Error(String(err));
2411
+ setError(error2);
2412
+ throw error2;
2413
+ } finally {
2414
+ setIsPending(false);
2415
+ setStage(null);
2416
+ }
2417
+ },
2418
+ [isSetup, masterKeys, createNoteForSelf]
2419
+ );
2420
+ const buildCancelOrder = useCallback(
2421
+ async (params) => {
2422
+ if (!isSetup || !masterKeys) {
2423
+ throw new Error("Account not set up. Call setupAccount() first.");
2424
+ }
2425
+ setIsPending(true);
2426
+ setError(null);
2427
+ try {
2428
+ const { orderId, cancelSecret, sellAmount, sellToken } = params;
2429
+ const cancelOrigin = ethAddress ? BigInt(ethAddress) : BigInt(masterKeys.ownerHash);
2430
+ const refundNoteData = await createNoteForSelf(
2431
+ sellAmount,
2432
+ cancelOrigin,
2433
+ BigInt(sellToken)
2434
+ );
2435
+ return {
2436
+ orderId,
2437
+ cancelSecret,
2438
+ refundCommitment: toHex(refundNoteData.commitment, { size: 32 }),
2439
+ refundEncryptedNote: refundNoteData.encryptedNote,
2440
+ refundNoteData
2441
+ };
2442
+ } catch (err) {
2443
+ const error2 = err instanceof Error ? err : new Error(String(err));
2444
+ setError(error2);
2445
+ throw error2;
2446
+ } finally {
2447
+ setIsPending(false);
2448
+ setStage(null);
2449
+ }
2450
+ },
2451
+ [isSetup, masterKeys, createNoteForSelf]
2452
+ );
2453
+ const buildNoteSplit = useCallback(
2454
+ async (params) => {
2455
+ if (!isSetup || !masterKeys) {
2456
+ throw new Error("Account not set up. Call setupAccount() first.");
2457
+ }
2458
+ setIsPending(true);
2459
+ setError(null);
2460
+ try {
2461
+ const { note, targetAmount, aspId: splitAspId } = params;
2462
+ const cfg = configRef.current;
2463
+ if (targetAmount >= note.amount) {
2464
+ throw new Error("Target amount must be less than note amount");
2465
+ }
2466
+ if (targetAmount <= 0n) {
2467
+ throw new Error("Target amount must be positive");
2468
+ }
2469
+ const changeAmount = note.amount - targetAmount;
2470
+ const origin = BigInt(note.origin);
2471
+ const token = BigInt(note.token);
2472
+ setStage("creating_outputs");
2473
+ const [exactNoteData, changeNoteData] = await Promise.all([
2474
+ createNoteForSelf(targetAmount, origin, token),
2475
+ createNoteForSelf(changeAmount, origin, token)
2476
+ ]);
2477
+ const [transferModule, proofModule, aspModule] = await Promise.all([
2478
+ import('../transfer-KTCXKHS4.js'),
2479
+ import('../proof-C4YBP6RY.js'),
2480
+ import('../asp-ZA3RGN7G.js')
2481
+ ]);
2482
+ const { syncMerkleTree, getMerkleProofsForNotes, buildUPPTransferCircuitInputs } = transferModule;
2483
+ const { generateUPPProof, formatProofForContract } = proofModule;
2484
+ const { generateASPProof: generateASPProof2, DEMO_ASP_ID } = aspModule;
2485
+ setStage("syncing_merkle");
2486
+ const { tree, leaves } = await syncMerkleTree(cfg.publicClient, cfg.poolAddress);
2487
+ const spendableNote = {
2488
+ amount: note.amount,
2489
+ blinding: note.blinding,
2490
+ commitment: note.commitment,
2491
+ ownerSecret: note.ownerSecret,
2492
+ ownerHash: note.ownerHash,
2493
+ leafIndex: note.leafIndex,
2494
+ origin,
2495
+ token
2496
+ };
2497
+ const [noteProof] = await getMerkleProofsForNotes([spendableNote], leaves, tree);
2498
+ const aspProof = await generateASPProof2(splitAspId ?? DEMO_ASP_ID, origin, cfg.aspApprovedOrigins);
2499
+ setStage("generating_proof");
2500
+ const exactNoteWithAmount = { ...exactNoteData, amount: targetAmount };
2501
+ const changeNoteWithAmount = { ...changeNoteData, amount: changeAmount };
2502
+ const circuitInputs = await buildUPPTransferCircuitInputs(
2503
+ noteProof,
2504
+ aspProof,
2505
+ exactNoteWithAmount,
2506
+ changeNoteWithAmount
2507
+ );
2508
+ const { proof } = await generateUPPProof(
2509
+ "transfer",
2510
+ circuitInputs,
2511
+ cfg.circuitBaseUrl ?? "/circuits/"
2512
+ );
2513
+ const formattedProof = formatProofForContract(proof);
2514
+ const proofArray = [
2515
+ formattedProof.a[0],
2516
+ formattedProof.a[1],
2517
+ formattedProof.b[0][0],
2518
+ formattedProof.b[0][1],
2519
+ formattedProof.b[1][0],
2520
+ formattedProof.b[1][1],
2521
+ formattedProof.c[0],
2522
+ formattedProof.c[1]
2523
+ ];
2524
+ const { encodePacked: encodePacked3 } = await import('viem');
2525
+ const packNote = (n) => encodePacked3(
2526
+ ["uint64", "uint256", "bytes"],
2527
+ [n.searchTag, n.ownerHash, n.encryptedNote]
2528
+ );
2529
+ const proofSystem = note.proofSystem ?? "snark";
2530
+ const exactShieldedNote = {
2531
+ amount: targetAmount,
2532
+ blinding: exactNoteData.blinding,
2533
+ commitment: toHex(exactNoteData.commitment, { size: 32 }),
2534
+ ownerSecret: toHex(exactNoteData.ownerSecret, { size: 32 }),
2535
+ ownerHash: toHex(exactNoteData.ownerHash, { size: 32 }),
2536
+ leafIndex: 0,
2537
+ origin: note.origin,
2538
+ token: note.token,
2539
+ status: "confirmed",
2540
+ proofSystem,
2541
+ timestamp: Date.now()
2542
+ };
2543
+ const changeShieldedNote = {
2544
+ amount: changeAmount,
2545
+ blinding: changeNoteData.blinding,
2546
+ commitment: toHex(changeNoteData.commitment, { size: 32 }),
2547
+ ownerSecret: toHex(changeNoteData.ownerSecret, { size: 32 }),
2548
+ ownerHash: toHex(changeNoteData.ownerHash, { size: 32 }),
2549
+ leafIndex: 0,
2550
+ origin: note.origin,
2551
+ token: note.token,
2552
+ status: "confirmed",
2553
+ proofSystem,
2554
+ timestamp: Date.now()
2555
+ };
2556
+ return {
2557
+ proof: proofArray,
2558
+ nullifier: toHex(BigInt(circuitInputs.nullifier), { size: 32 }),
2559
+ stateRoot: BigInt(circuitInputs.stateRoot),
2560
+ aspRoot: BigInt(circuitInputs.aspRoot),
2561
+ token: note.token,
2562
+ outputCommitment1: toHex(exactNoteData.commitment, { size: 32 }),
2563
+ outputCommitment2: toHex(changeNoteData.commitment, { size: 32 }),
2564
+ encryptedNote1: packNote(exactNoteData),
2565
+ encryptedNote2: packNote(changeNoteData),
2566
+ exactNote: exactShieldedNote,
2567
+ changeNote: changeShieldedNote,
2568
+ spentNote: note,
2569
+ exactNoteData,
2570
+ changeNoteData
2571
+ };
2572
+ } catch (err) {
2573
+ const error2 = err instanceof Error ? err : new Error(String(err));
2574
+ setError(error2);
2575
+ throw error2;
2576
+ } finally {
2577
+ setIsPending(false);
2578
+ setStage(null);
2579
+ }
2580
+ },
2581
+ [isSetup, masterKeys, createNoteForSelf]
2582
+ );
2583
+ return {
2584
+ stage,
2585
+ isPending,
2586
+ error,
2587
+ buildNoteSplit,
2588
+ buildPlaceOrder,
2589
+ buildFillOrder,
2590
+ buildClaimOrder,
2591
+ buildCancelOrder,
2592
+ reset
2593
+ };
2594
+ }
2595
+
2596
+ export { UPPAccountProvider, UPPAvatar, UPPModal, UPPPrivateButton, generateAvatarData, renderAvatarSVG, storePersonalASPId, usePersonalASP, usePoolTransfer, useShield, useSwap, useSwapOrderBook, useUPPAccount, useUPPCrypto, useWithdraw };
2597
+ //# sourceMappingURL=index.js.map
2598
+ //# sourceMappingURL=index.js.map