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