@veilo/sdk-core 0.4.0 → 0.5.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 (296) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +286 -1298
  3. package/dist/cjs/accounts/admin.d.ts +84 -0
  4. package/dist/cjs/accounts/admin.js +208 -0
  5. package/dist/cjs/accounts/errors.d.ts +6 -0
  6. package/dist/cjs/accounts/errors.js +98 -0
  7. package/dist/cjs/accounts/index.d.ts +4 -0
  8. package/dist/cjs/accounts/index.js +20 -0
  9. package/dist/cjs/accounts/pdas.d.ts +23 -0
  10. package/dist/cjs/accounts/pdas.js +44 -0
  11. package/dist/cjs/accounts/queries.d.ts +41 -0
  12. package/dist/cjs/accounts/queries.js +95 -0
  13. package/dist/cjs/client.d.ts +2 -407
  14. package/dist/cjs/client.js +6 -938
  15. package/dist/cjs/cloak/client.d.ts +28 -0
  16. package/dist/cjs/cloak/client.js +68 -0
  17. package/dist/cjs/cloak/errors.d.ts +13 -0
  18. package/dist/cjs/cloak/errors.js +25 -0
  19. package/dist/cjs/cloak/helpers.d.ts +6 -0
  20. package/dist/cjs/cloak/helpers.js +35 -0
  21. package/dist/cjs/cloak/index.d.ts +6 -0
  22. package/dist/cjs/cloak/index.js +24 -0
  23. package/dist/cjs/cloak/polling.d.ts +7 -0
  24. package/dist/cjs/cloak/polling.js +66 -0
  25. package/dist/cjs/cloak/transport.d.ts +15 -0
  26. package/dist/cjs/cloak/transport.js +119 -0
  27. package/dist/cjs/cloak/types.d.ts +188 -0
  28. package/dist/cjs/cloak/types.js +5 -0
  29. package/dist/cjs/cloak.d.ts +1 -0
  30. package/dist/cjs/cloak.js +18 -0
  31. package/dist/cjs/compactNote.d.ts +21 -0
  32. package/dist/cjs/compactNote.js +31 -7
  33. package/dist/cjs/index.d.ts +2 -1
  34. package/dist/cjs/index.js +4 -1
  35. package/dist/cjs/notes/encryption.d.ts +41 -0
  36. package/dist/cjs/notes/encryption.js +75 -0
  37. package/dist/cjs/notes/index.d.ts +5 -0
  38. package/dist/cjs/notes/index.js +21 -0
  39. package/dist/cjs/notes/mailbox.d.ts +70 -0
  40. package/dist/cjs/notes/mailbox.js +164 -0
  41. package/dist/cjs/notes/model.d.ts +91 -0
  42. package/dist/cjs/notes/model.js +109 -0
  43. package/dist/cjs/notes/nullifier.d.ts +27 -0
  44. package/dist/cjs/notes/nullifier.js +45 -0
  45. package/dist/cjs/notes/recovery.d.ts +10 -0
  46. package/dist/cjs/notes/recovery.js +31 -0
  47. package/dist/cjs/proof.d.ts +1 -183
  48. package/dist/cjs/proof.js +16 -290
  49. package/dist/cjs/proofs/encoding.d.ts +17 -0
  50. package/dist/cjs/proofs/encoding.js +72 -0
  51. package/dist/cjs/proofs/formatting.d.ts +6 -0
  52. package/dist/cjs/proofs/formatting.js +34 -0
  53. package/dist/cjs/proofs/index.d.ts +5 -0
  54. package/dist/cjs/proofs/index.js +21 -0
  55. package/dist/cjs/proofs/swap.d.ts +87 -0
  56. package/dist/cjs/proofs/swap.js +144 -0
  57. package/dist/cjs/proofs/transaction.d.ts +28 -0
  58. package/dist/cjs/proofs/transaction.js +110 -0
  59. package/dist/cjs/proofs/types.d.ts +70 -0
  60. package/dist/cjs/prover.d.ts +4 -1
  61. package/dist/cjs/prover.js +12 -2
  62. package/dist/cjs/relayer/client.d.ts +61 -0
  63. package/dist/cjs/relayer/client.js +151 -0
  64. package/dist/cjs/relayer/crypto.d.ts +5 -0
  65. package/dist/cjs/relayer/crypto.js +26 -0
  66. package/dist/cjs/relayer/encoding.d.ts +2 -0
  67. package/dist/cjs/relayer/encoding.js +23 -0
  68. package/dist/cjs/relayer/errors.d.ts +7 -0
  69. package/dist/cjs/relayer/errors.js +17 -0
  70. package/dist/cjs/relayer/index.d.ts +3 -0
  71. package/dist/cjs/relayer/index.js +19 -0
  72. package/dist/cjs/relayer/transport.d.ts +17 -0
  73. package/dist/cjs/relayer/transport.js +63 -0
  74. package/dist/{src/relayer.d.ts → cjs/relayer/types.d.ts} +44 -86
  75. package/dist/cjs/relayer/types.js +5 -0
  76. package/dist/cjs/relayer.d.ts +1 -318
  77. package/dist/cjs/relayer.js +15 -254
  78. package/dist/cjs/shield/alt.js +8 -8
  79. package/dist/cjs/shield/errors.js +2 -2
  80. package/dist/cjs/shield/finalize.js +2 -2
  81. package/dist/cjs/shield/ix.d.ts +1 -1
  82. package/dist/cjs/shield/owner.js +9 -8
  83. package/dist/cjs/shield/ports.js +3 -3
  84. package/dist/cjs/shield/preflight.js +3 -3
  85. package/dist/cjs/shield/shield.js +20 -19
  86. package/dist/cjs/shield/types.d.ts +1 -1
  87. package/dist/cjs/transactions/deposit.d.ts +94 -0
  88. package/dist/cjs/transactions/deposit.js +234 -0
  89. package/dist/cjs/transactions/index.d.ts +7 -0
  90. package/dist/cjs/transactions/index.js +26 -0
  91. package/dist/cjs/transactions/swap.d.ts +71 -0
  92. package/dist/cjs/transactions/swap.js +184 -0
  93. package/dist/cjs/transactions/transact.d.ts +34 -0
  94. package/dist/cjs/transactions/transact.js +146 -0
  95. package/dist/cjs/transactions/transfer.d.ts +51 -0
  96. package/dist/cjs/transactions/transfer.js +106 -0
  97. package/dist/cjs/transactions/withdraw.d.ts +52 -0
  98. package/dist/cjs/transactions/withdraw.js +104 -0
  99. package/dist/cjs/utxo.d.ts +1 -235
  100. package/dist/cjs/utxo.js +15 -404
  101. package/dist/esm/accounts/admin.d.ts +84 -0
  102. package/dist/esm/accounts/admin.js +165 -0
  103. package/dist/esm/accounts/errors.d.ts +6 -0
  104. package/dist/esm/accounts/errors.js +95 -0
  105. package/dist/esm/accounts/index.d.ts +4 -0
  106. package/dist/esm/accounts/index.js +4 -0
  107. package/dist/esm/accounts/pdas.d.ts +23 -0
  108. package/dist/esm/accounts/pdas.js +38 -0
  109. package/dist/esm/accounts/queries.d.ts +41 -0
  110. package/dist/esm/accounts/queries.js +88 -0
  111. package/dist/esm/client.d.ts +2 -407
  112. package/dist/esm/client.js +3 -891
  113. package/dist/esm/cloak/client.d.ts +28 -0
  114. package/dist/esm/cloak/client.js +64 -0
  115. package/dist/esm/cloak/errors.d.ts +13 -0
  116. package/dist/esm/cloak/errors.js +21 -0
  117. package/dist/esm/cloak/helpers.d.ts +6 -0
  118. package/dist/esm/cloak/helpers.js +31 -0
  119. package/dist/esm/cloak/index.d.ts +6 -0
  120. package/dist/esm/cloak/index.js +6 -0
  121. package/dist/esm/cloak/polling.d.ts +7 -0
  122. package/dist/esm/cloak/polling.js +63 -0
  123. package/dist/esm/cloak/transport.d.ts +15 -0
  124. package/dist/esm/cloak/transport.js +115 -0
  125. package/dist/esm/cloak/types.d.ts +188 -0
  126. package/dist/esm/cloak/types.js +4 -0
  127. package/dist/esm/cloak.d.ts +1 -0
  128. package/dist/esm/cloak.js +2 -0
  129. package/dist/esm/compactNote.d.ts +21 -0
  130. package/dist/esm/compactNote.js +24 -1
  131. package/dist/esm/index.d.ts +2 -1
  132. package/dist/esm/index.js +3 -1
  133. package/dist/esm/notes/encryption.d.ts +41 -0
  134. package/dist/esm/notes/encryption.js +67 -0
  135. package/dist/esm/notes/index.d.ts +5 -0
  136. package/dist/esm/notes/index.js +5 -0
  137. package/dist/esm/notes/mailbox.d.ts +70 -0
  138. package/dist/esm/notes/mailbox.js +154 -0
  139. package/dist/esm/notes/model.d.ts +91 -0
  140. package/dist/esm/notes/model.js +99 -0
  141. package/dist/esm/notes/nullifier.d.ts +27 -0
  142. package/dist/esm/notes/nullifier.js +40 -0
  143. package/dist/esm/notes/recovery.d.ts +10 -0
  144. package/dist/esm/notes/recovery.js +28 -0
  145. package/dist/esm/proof.d.ts +1 -183
  146. package/dist/esm/proof.js +2 -281
  147. package/dist/esm/proofs/encoding.d.ts +17 -0
  148. package/dist/esm/proofs/encoding.js +68 -0
  149. package/dist/esm/proofs/formatting.d.ts +6 -0
  150. package/dist/esm/proofs/formatting.js +31 -0
  151. package/dist/esm/proofs/index.d.ts +5 -0
  152. package/dist/esm/proofs/index.js +5 -0
  153. package/dist/esm/proofs/swap.d.ts +87 -0
  154. package/dist/esm/proofs/swap.js +138 -0
  155. package/dist/esm/proofs/transaction.d.ts +28 -0
  156. package/dist/esm/proofs/transaction.js +105 -0
  157. package/dist/esm/proofs/types.d.ts +70 -0
  158. package/dist/esm/proofs/types.js +1 -0
  159. package/dist/esm/prover.d.ts +4 -1
  160. package/dist/esm/prover.js +10 -1
  161. package/dist/esm/relayer/client.d.ts +61 -0
  162. package/dist/esm/relayer/client.js +144 -0
  163. package/dist/esm/relayer/crypto.d.ts +5 -0
  164. package/dist/esm/relayer/crypto.js +20 -0
  165. package/dist/esm/relayer/encoding.d.ts +2 -0
  166. package/dist/esm/relayer/encoding.js +19 -0
  167. package/dist/esm/relayer/errors.d.ts +7 -0
  168. package/dist/esm/relayer/errors.js +13 -0
  169. package/dist/esm/relayer/index.d.ts +3 -0
  170. package/dist/esm/relayer/index.js +3 -0
  171. package/dist/esm/relayer/transport.d.ts +17 -0
  172. package/dist/esm/relayer/transport.js +59 -0
  173. package/dist/esm/relayer/types.d.ts +276 -0
  174. package/dist/esm/relayer/types.js +4 -0
  175. package/dist/esm/relayer.d.ts +1 -318
  176. package/dist/esm/relayer.js +2 -249
  177. package/dist/esm/shield/alt.js +1 -1
  178. package/dist/esm/shield/errors.js +1 -1
  179. package/dist/esm/shield/finalize.js +1 -1
  180. package/dist/esm/shield/ix.d.ts +1 -1
  181. package/dist/esm/shield/owner.js +2 -1
  182. package/dist/esm/shield/ports.js +1 -1
  183. package/dist/esm/shield/preflight.js +1 -1
  184. package/dist/esm/shield/shield.js +4 -3
  185. package/dist/esm/shield/types.d.ts +1 -1
  186. package/dist/esm/transactions/deposit.d.ts +94 -0
  187. package/dist/esm/transactions/deposit.js +198 -0
  188. package/dist/esm/transactions/index.d.ts +7 -0
  189. package/dist/esm/transactions/index.js +7 -0
  190. package/dist/esm/transactions/swap.d.ts +71 -0
  191. package/dist/esm/transactions/swap.js +144 -0
  192. package/dist/esm/transactions/transact.d.ts +34 -0
  193. package/dist/esm/transactions/transact.js +110 -0
  194. package/dist/esm/transactions/transfer.d.ts +51 -0
  195. package/dist/esm/transactions/transfer.js +103 -0
  196. package/dist/esm/transactions/withdraw.d.ts +52 -0
  197. package/dist/esm/transactions/withdraw.js +101 -0
  198. package/dist/esm/utxo.d.ts +1 -235
  199. package/dist/esm/utxo.js +2 -382
  200. package/package.json +54 -16
  201. package/SHIELD_INTEGRATION.md +0 -143
  202. package/config.d.ts +0 -2
  203. package/config.js +0 -4
  204. package/dist/src/client.d.ts +0 -407
  205. package/dist/src/client.js +0 -951
  206. package/dist/src/compactNote.d.ts +0 -107
  207. package/dist/src/compactNote.js +0 -167
  208. package/dist/src/config.d.ts +0 -82
  209. package/dist/src/config.js +0 -57
  210. package/dist/src/events.d.ts +0 -77
  211. package/dist/src/events.js +0 -167
  212. package/dist/src/idl/privacy_pool.d.ts +0 -5
  213. package/dist/src/idl/privacy_pool.js +0 -15218
  214. package/dist/src/index.d.ts +0 -16
  215. package/dist/src/index.js +0 -67
  216. package/dist/src/merkle.d.ts +0 -77
  217. package/dist/src/merkle.js +0 -156
  218. package/dist/src/poseidon.d.ts +0 -29
  219. package/dist/src/poseidon.js +0 -100
  220. package/dist/src/program.d.ts +0 -37
  221. package/dist/src/program.js +0 -61
  222. package/dist/src/proof.d.ts +0 -183
  223. package/dist/src/proof.js +0 -292
  224. package/dist/src/prover.d.ts +0 -54
  225. package/dist/src/prover.js +0 -112
  226. package/dist/src/random.d.ts +0 -16
  227. package/dist/src/random.js +0 -28
  228. package/dist/src/relayer.js +0 -257
  229. package/dist/src/retry.d.ts +0 -32
  230. package/dist/src/retry.js +0 -75
  231. package/dist/src/shield/alt.d.ts +0 -87
  232. package/dist/src/shield/alt.js +0 -194
  233. package/dist/src/shield/computeBudget.d.ts +0 -61
  234. package/dist/src/shield/computeBudget.js +0 -64
  235. package/dist/src/shield/errors.d.ts +0 -58
  236. package/dist/src/shield/errors.js +0 -121
  237. package/dist/src/shield/finalize.d.ts +0 -45
  238. package/dist/src/shield/finalize.js +0 -119
  239. package/dist/src/shield/index.d.ts +0 -35
  240. package/dist/src/shield/index.js +0 -68
  241. package/dist/src/shield/ix.d.ts +0 -54
  242. package/dist/src/shield/ix.js +0 -119
  243. package/dist/src/shield/owner.d.ts +0 -36
  244. package/dist/src/shield/owner.js +0 -126
  245. package/dist/src/shield/ports.d.ts +0 -43
  246. package/dist/src/shield/ports.js +0 -153
  247. package/dist/src/shield/preflight.d.ts +0 -30
  248. package/dist/src/shield/preflight.js +0 -154
  249. package/dist/src/shield/shield.d.ts +0 -68
  250. package/dist/src/shield/shield.js +0 -499
  251. package/dist/src/shield/types.d.ts +0 -202
  252. package/dist/src/utxo.d.ts +0 -235
  253. package/dist/src/utxo.js +0 -407
  254. package/dist/tests/compact-note.test.d.ts +0 -1
  255. package/dist/tests/compact-note.test.js +0 -173
  256. package/dist/tests/config.test.d.ts +0 -1
  257. package/dist/tests/config.test.js +0 -102
  258. package/dist/tests/edge-cases.test.d.ts +0 -1
  259. package/dist/tests/edge-cases.test.js +0 -220
  260. package/dist/tests/encryption.test.d.ts +0 -1
  261. package/dist/tests/encryption.test.js +0 -215
  262. package/dist/tests/events.test.d.ts +0 -1
  263. package/dist/tests/events.test.js +0 -78
  264. package/dist/tests/multi-tree.test.d.ts +0 -1
  265. package/dist/tests/multi-tree.test.js +0 -405
  266. package/dist/tests/pda.test.d.ts +0 -1
  267. package/dist/tests/pda.test.js +0 -229
  268. package/dist/tests/poseidon-builder-parity.test.d.ts +0 -1
  269. package/dist/tests/poseidon-builder-parity.test.js +0 -72
  270. package/dist/tests/poseidon.test.d.ts +0 -1
  271. package/dist/tests/poseidon.test.js +0 -142
  272. package/dist/tests/proof.test.d.ts +0 -1
  273. package/dist/tests/proof.test.js +0 -296
  274. package/dist/tests/relayer.test.d.ts +0 -1
  275. package/dist/tests/relayer.test.js +0 -271
  276. package/dist/tests/sdk.integration.test.d.ts +0 -1
  277. package/dist/tests/sdk.integration.test.js +0 -330
  278. package/dist/tests/shield-owner.test.d.ts +0 -1
  279. package/dist/tests/shield-owner.test.js +0 -89
  280. package/dist/tests/shield-preflight.test.d.ts +0 -1
  281. package/dist/tests/shield-preflight.test.js +0 -87
  282. package/dist/tests/shield-realproof.test.d.ts +0 -1
  283. package/dist/tests/shield-realproof.test.js +0 -272
  284. package/dist/tests/shield.test.d.ts +0 -1
  285. package/dist/tests/shield.test.js +0 -403
  286. package/dist/tests/utxo.test.d.ts +0 -1
  287. package/dist/tests/utxo.test.js +0 -140
  288. package/poseidon.d.ts +0 -2
  289. package/poseidon.js +0 -4
  290. package/proof.d.ts +0 -2
  291. package/proof.js +0 -4
  292. package/prover.d.ts +0 -2
  293. package/prover.js +0 -4
  294. package/shield.d.ts +0 -2
  295. package/shield.js +0 -4
  296. /package/dist/{src/shield → cjs/proofs}/types.js +0 -0
@@ -1,107 +0,0 @@
1
- /**
2
- * Compact note ciphers — the 80-byte payload carried inside the on-chain
3
- * `transact` instruction (`note_ciphers: Option<NoteCiphers>`) and re-emitted in
4
- * `CommitmentEvent`.
5
- *
6
- * This is what makes a note recoverable from chain data alone: a recipient who
7
- * was never told about a deposit can still find it by scanning `view_tag` and
8
- * decrypting the blob. Without it, note delivery depends on someone calling the
9
- * relayer, which a third-party integrator cannot be trusted to do.
10
- *
11
- * ## Byte-compatibility is load-bearing
12
- *
13
- * Four sibling implementations already exist (relayer-server, extension ×2,
14
- * wallet-app). This is the canonical one, and it MUST agree with them byte for
15
- * byte in both directions:
16
- *
17
- * - disagree on encrypt → new notes are invisible to every existing client
18
- * - disagree on decrypt → the entire historical note corpus becomes unreadable
19
- *
20
- * Three details are easy to get wrong and are individually fatal:
21
- *
22
- * 1. The KDF is `nacl.hash(x).slice(0, 32)` — **truncated SHA-512**, despite the
23
- * sibling helper being named `sha256ForNotes`. See `kdfSHA512_256` in utxo.ts.
24
- * 2. The ephemeral key published on-chain is **Ed25519**; it is converted to
25
- * X25519 only for the Diffie-Hellman. Scanners convert it back.
26
- * 3. `viewTag` is the first byte of the hash of the **raw shared secret**, not of
27
- * the derived key. A wrong view tag makes every note invisible to the scan
28
- * loop, which rejects ~255/256 candidates on this byte alone.
29
- *
30
- * The ECDH primitives are imported from `utxo.ts` rather than reimplemented — a
31
- * fifth independent Edwards→Montgomery implementation is exactly how the current
32
- * drift risk between the four siblings arose.
33
- *
34
- * Verified against the siblings by `tests/compact-note.test.ts` (golden vectors)
35
- * and `scripts/verify-compact-cipher-parity.mjs` (differential).
36
- */
37
- /** Size of the on-chain compact blob: nonce[24] || secretbox(40-byte plaintext)[56]. */
38
- export declare const COMPACT_BLOB_LENGTH = 80;
39
- export type CompactNoteCipher = {
40
- /** Ed25519 ephemeral public key, published on-chain. */
41
- ephemeralPublicKey: Uint8Array;
42
- /** 80 bytes: nonce[24] || ciphertext[56]. */
43
- compactBlob: Uint8Array;
44
- /** 1-byte scan filter. */
45
- viewTag: number;
46
- };
47
- /**
48
- * Test-only determinism hook. NOT part of the public contract — it exists so
49
- * golden vectors can pin exact bytes against the sibling implementations, which
50
- * is the only way to prove byte-compatibility rather than assume it.
51
- *
52
- * @internal
53
- */
54
- export type CompactNoteDeterminism = {
55
- ephemeralSeed: Uint8Array;
56
- nonce: Uint8Array;
57
- };
58
- /**
59
- * Encrypt a note's secret material to a recipient's Solana wallet key.
60
- *
61
- * The recipient does not need to be the signer of the transaction, or to have
62
- * any prior relationship with the sender — this is what makes shielding to an
63
- * arbitrary owner possible.
64
- *
65
- * @param recipientWalletPubkey 32-byte Ed25519 Solana wallet public key
66
- * @param blinding 32-byte big-endian blinding factor
67
- * @param amount note amount in base units
68
- */
69
- export declare function createCompactNoteCipher(recipientWalletPubkey: Uint8Array, blinding: Uint8Array, amount: bigint,
70
- /** @internal */ __det?: CompactNoteDeterminism): CompactNoteCipher;
71
- /**
72
- * Recover a note's blinding and amount from an on-chain compact cipher.
73
- *
74
- * Returns `null` when the blob was not encrypted to this key — the expected
75
- * outcome for the overwhelming majority of candidates during a scan, so callers
76
- * should filter on `viewTag` first (see {@link matchesViewTag}) and only attempt
77
- * decryption on the ~1/256 that survive.
78
- *
79
- * @param walletSecretKey 32-byte Ed25519 seed or 64-byte secret key
80
- */
81
- export declare function decryptCompactNoteCipher(walletSecretKey: Uint8Array, ephemeralPublicKey: Uint8Array, compactBlob: Uint8Array, precomputed?: {
82
- sharedSecret?: Uint8Array;
83
- x25519Private?: Uint8Array;
84
- }): {
85
- blinding: Uint8Array;
86
- amount: bigint;
87
- } | null;
88
- /**
89
- * Cheap scan filter: does this on-chain cipher plausibly belong to us?
90
- *
91
- * Rejects ~255/256 candidates for the cost of one scalar multiplication and one
92
- * hash, versus a full secretbox open. Hoist `x25519Private` across a scan loop
93
- * with {@link toX25519Private}.
94
- */
95
- export declare function matchesViewTag(walletSecretKey: Uint8Array, ephemeralPublicKey: Uint8Array, viewTag: number, precomputed?: {
96
- x25519Private?: Uint8Array;
97
- }): {
98
- matches: boolean;
99
- sharedSecret: Uint8Array;
100
- };
101
- /**
102
- * Convert an Ed25519 wallet secret key to its X25519 scalar once, for reuse
103
- * across a scan loop.
104
- */
105
- export declare function toX25519Private(walletSecretKey: Uint8Array): Uint8Array;
106
- /** The all-zero cipher the program treats as "no note here". */
107
- export declare function emptyNoteCipher(): CompactNoteCipher;
@@ -1,167 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.COMPACT_BLOB_LENGTH = void 0;
7
- exports.createCompactNoteCipher = createCompactNoteCipher;
8
- exports.decryptCompactNoteCipher = decryptCompactNoteCipher;
9
- exports.matchesViewTag = matchesViewTag;
10
- exports.toX25519Private = toX25519Private;
11
- exports.emptyNoteCipher = emptyNoteCipher;
12
- const tweetnacl_1 = __importDefault(require("tweetnacl"));
13
- const utxo_js_1 = require("./utxo.js");
14
- const random_js_1 = require("./random.js");
15
- /**
16
- * Compact note ciphers — the 80-byte payload carried inside the on-chain
17
- * `transact` instruction (`note_ciphers: Option<NoteCiphers>`) and re-emitted in
18
- * `CommitmentEvent`.
19
- *
20
- * This is what makes a note recoverable from chain data alone: a recipient who
21
- * was never told about a deposit can still find it by scanning `view_tag` and
22
- * decrypting the blob. Without it, note delivery depends on someone calling the
23
- * relayer, which a third-party integrator cannot be trusted to do.
24
- *
25
- * ## Byte-compatibility is load-bearing
26
- *
27
- * Four sibling implementations already exist (relayer-server, extension ×2,
28
- * wallet-app). This is the canonical one, and it MUST agree with them byte for
29
- * byte in both directions:
30
- *
31
- * - disagree on encrypt → new notes are invisible to every existing client
32
- * - disagree on decrypt → the entire historical note corpus becomes unreadable
33
- *
34
- * Three details are easy to get wrong and are individually fatal:
35
- *
36
- * 1. The KDF is `nacl.hash(x).slice(0, 32)` — **truncated SHA-512**, despite the
37
- * sibling helper being named `sha256ForNotes`. See `kdfSHA512_256` in utxo.ts.
38
- * 2. The ephemeral key published on-chain is **Ed25519**; it is converted to
39
- * X25519 only for the Diffie-Hellman. Scanners convert it back.
40
- * 3. `viewTag` is the first byte of the hash of the **raw shared secret**, not of
41
- * the derived key. A wrong view tag makes every note invisible to the scan
42
- * loop, which rejects ~255/256 candidates on this byte alone.
43
- *
44
- * The ECDH primitives are imported from `utxo.ts` rather than reimplemented — a
45
- * fifth independent Edwards→Montgomery implementation is exactly how the current
46
- * drift risk between the four siblings arose.
47
- *
48
- * Verified against the siblings by `tests/compact-note.test.ts` (golden vectors)
49
- * and `scripts/verify-compact-cipher-parity.mjs` (differential).
50
- */
51
- /** Size of the on-chain compact blob: nonce[24] || secretbox(40-byte plaintext)[56]. */
52
- exports.COMPACT_BLOB_LENGTH = 80;
53
- /** Plaintext layout: blinding[32] || amount as little-endian u64[8]. */
54
- const COMPACT_PLAINTEXT_LENGTH = 40;
55
- const NONCE_LENGTH = 24;
56
- /**
57
- * Encrypt a note's secret material to a recipient's Solana wallet key.
58
- *
59
- * The recipient does not need to be the signer of the transaction, or to have
60
- * any prior relationship with the sender — this is what makes shielding to an
61
- * arbitrary owner possible.
62
- *
63
- * @param recipientWalletPubkey 32-byte Ed25519 Solana wallet public key
64
- * @param blinding 32-byte big-endian blinding factor
65
- * @param amount note amount in base units
66
- */
67
- function createCompactNoteCipher(recipientWalletPubkey, blinding, amount,
68
- /** @internal */ __det) {
69
- if (recipientWalletPubkey.length !== 32) {
70
- throw new Error(`recipientWalletPubkey must be 32 bytes, got ${recipientWalletPubkey.length}`);
71
- }
72
- if (blinding.length < 32) {
73
- throw new Error(`blinding must be at least 32 bytes, got ${blinding.length}`);
74
- }
75
- if (amount < 0n || amount > 0xffffffffffffffffn) {
76
- throw new Error(`amount ${amount} does not fit in a u64`);
77
- }
78
- // Ed25519 ephemeral keypair. `nacl.sign.keyPair.fromSeed(seed)` produces the
79
- // same public key as web3.js `Keypair.generate()` for the same seed, which is
80
- // what the sibling implementations use — but without pulling @solana/web3.js
81
- // into the crypto path.
82
- const ephemeralSeed = __det?.ephemeralSeed ?? (0, random_js_1.randomBytes)(32);
83
- const ephemeralPublicKey = tweetnacl_1.default.sign.keyPair.fromSeed(ephemeralSeed).publicKey;
84
- const sharedSecret = deriveSharedSecret(ephemeralSeed, recipientWalletPubkey);
85
- const key = (0, utxo_js_1.kdfSHA512_256)(sharedSecret);
86
- const plaintext = new Uint8Array(COMPACT_PLAINTEXT_LENGTH);
87
- plaintext.set(blinding.slice(0, 32), 0);
88
- let amt = amount;
89
- for (let i = 0; i < 8; i++) {
90
- plaintext[32 + i] = Number(amt & 0xffn);
91
- amt >>= 8n;
92
- }
93
- const nonce = __det?.nonce ?? tweetnacl_1.default.randomBytes(NONCE_LENGTH);
94
- const encrypted = tweetnacl_1.default.secretbox(plaintext, nonce, key);
95
- const compactBlob = new Uint8Array(exports.COMPACT_BLOB_LENGTH);
96
- compactBlob.set(nonce, 0);
97
- compactBlob.set(encrypted, NONCE_LENGTH);
98
- // First byte of the hash of the RAW shared secret — not of `key`.
99
- const viewTag = tweetnacl_1.default.hash(sharedSecret)[0];
100
- return { ephemeralPublicKey, compactBlob, viewTag };
101
- }
102
- /**
103
- * Recover a note's blinding and amount from an on-chain compact cipher.
104
- *
105
- * Returns `null` when the blob was not encrypted to this key — the expected
106
- * outcome for the overwhelming majority of candidates during a scan, so callers
107
- * should filter on `viewTag` first (see {@link matchesViewTag}) and only attempt
108
- * decryption on the ~1/256 that survive.
109
- *
110
- * @param walletSecretKey 32-byte Ed25519 seed or 64-byte secret key
111
- */
112
- function decryptCompactNoteCipher(walletSecretKey, ephemeralPublicKey, compactBlob, precomputed) {
113
- if (compactBlob.length !== exports.COMPACT_BLOB_LENGTH)
114
- return null;
115
- const sharedSecret = precomputed?.sharedSecret ??
116
- (precomputed?.x25519Private
117
- ? tweetnacl_1.default.scalarMult(precomputed.x25519Private, (0, utxo_js_1.ed25519PublicKeyToX25519)(ephemeralPublicKey))
118
- : deriveSharedSecret(walletSecretKey, ephemeralPublicKey));
119
- const key = (0, utxo_js_1.kdfSHA512_256)(sharedSecret);
120
- const nonce = compactBlob.slice(0, NONCE_LENGTH);
121
- const encrypted = compactBlob.slice(NONCE_LENGTH);
122
- const plaintext = tweetnacl_1.default.secretbox.open(encrypted, nonce, key);
123
- if (!plaintext)
124
- return null;
125
- const blinding = new Uint8Array(plaintext.slice(0, 32));
126
- let amount = 0n;
127
- for (let i = 7; i >= 0; i--) {
128
- amount = (amount << 8n) | BigInt(plaintext[32 + i]);
129
- }
130
- return { blinding, amount };
131
- }
132
- /**
133
- * Cheap scan filter: does this on-chain cipher plausibly belong to us?
134
- *
135
- * Rejects ~255/256 candidates for the cost of one scalar multiplication and one
136
- * hash, versus a full secretbox open. Hoist `x25519Private` across a scan loop
137
- * with {@link toX25519Private}.
138
- */
139
- function matchesViewTag(walletSecretKey, ephemeralPublicKey, viewTag, precomputed) {
140
- const sharedSecret = precomputed?.x25519Private
141
- ? tweetnacl_1.default.scalarMult(precomputed.x25519Private, (0, utxo_js_1.ed25519PublicKeyToX25519)(ephemeralPublicKey))
142
- : deriveSharedSecret(walletSecretKey, ephemeralPublicKey);
143
- return { matches: tweetnacl_1.default.hash(sharedSecret)[0] === viewTag, sharedSecret };
144
- }
145
- /**
146
- * Convert an Ed25519 wallet secret key to its X25519 scalar once, for reuse
147
- * across a scan loop.
148
- */
149
- function toX25519Private(walletSecretKey) {
150
- return (0, utxo_js_1.ed25519SeedToX25519Private)(seedOf(walletSecretKey));
151
- }
152
- /** The all-zero cipher the program treats as "no note here". */
153
- function emptyNoteCipher() {
154
- return {
155
- ephemeralPublicKey: new Uint8Array(32),
156
- compactBlob: new Uint8Array(exports.COMPACT_BLOB_LENGTH),
157
- viewTag: 0,
158
- };
159
- }
160
- // -- internal -----------------------------------------------------------------
161
- /** Accept either a 32-byte Ed25519 seed or a 64-byte secret key, as the siblings do. */
162
- function seedOf(secretKey) {
163
- return secretKey.length === 64 ? secretKey.slice(0, 32) : secretKey;
164
- }
165
- function deriveSharedSecret(mySecretKey, theirEd25519PublicKey) {
166
- return tweetnacl_1.default.scalarMult((0, utxo_js_1.ed25519SeedToX25519Private)(seedOf(mySecretKey)), (0, utxo_js_1.ed25519PublicKeyToX25519)(theirEd25519PublicKey));
167
- }
@@ -1,82 +0,0 @@
1
- import { PublicKey } from "@solana/web3.js";
2
- /** Default relayer fee in basis points (50 = 0.5%). */
3
- export declare const DEFAULT_FEE_BPS = 50;
4
- /** Merkle tree depth - matches on-chain MerkleTreeAccount subtrees array size */
5
- export declare const MERKLE_TREE_DEPTH = 22;
6
- /** Root history size - matches on-chain MerkleTreeAccount root_history array size */
7
- export declare const ROOT_HISTORY_SIZE = 256;
8
- /** Native SOL mint address (Pubkey::default() = all zeros) */
9
- export declare const NATIVE_SOL_MINT: PublicKey;
10
- /** Convert SOL to lamports (e.g. `sol(1.5)` → `1_500_000_000n`). */
11
- export declare function sol(n: number): bigint;
12
- /** Configuration for initializing a privacy pool */
13
- export type PoolInitConfig = {
14
- /** Fee in basis points (0-10000, where 10000 = 100%) */
15
- feeBps?: number;
16
- /** Token mint address (use NATIVE_SOL_MINT for SOL pools) */
17
- mintAddress: PublicKey;
18
- /** Minimum deposit amount in lamports/token units */
19
- minDepositAmount?: bigint;
20
- /** Maximum deposit amount in lamports/token units */
21
- maxDepositAmount?: bigint;
22
- /** Minimum withdrawal amount in lamports/token units */
23
- minWithdrawAmount?: bigint;
24
- /** Maximum withdrawal amount in lamports/token units */
25
- maxWithdrawAmount?: bigint;
26
- };
27
- /** On-chain PrivacyConfig account structure */
28
- export type PrivacyConfigAccount = {
29
- bump: number;
30
- vaultBump: number;
31
- admin: PublicKey;
32
- feeBps: number;
33
- feeErrorMarginBps: number;
34
- minWithdrawalFee: bigint;
35
- /** Minimum fee kept by relayer on swaps (in destination token base units) */
36
- minSwapFee: bigint;
37
- /** Fee rate applied to swap output in basis points */
38
- swapFeeBps: number;
39
- totalTvl: bigint;
40
- mintAddress: PublicKey;
41
- minDepositAmount: bigint;
42
- maxDepositAmount: bigint;
43
- minWithdrawAmount: bigint;
44
- maxWithdrawAmount: bigint;
45
- numRelayers: number;
46
- relayers: PublicKey[];
47
- numTrees: number;
48
- nextTreeIndex: number;
49
- };
50
- /** On-chain GlobalConfig account structure */
51
- export type GlobalConfigAccount = {
52
- bump: number;
53
- admin: PublicKey;
54
- relayerEnabled: boolean;
55
- };
56
- /**
57
- * Compute the relayer fee for a withdrawal.
58
- * Mirrors the formula in the relayer-server:
59
- * fee = max(amount * feeBps / 10_000, minWithdrawalFee)
60
- *
61
- * @returns fee in base token units, and the amount that reaches the recipient
62
- */
63
- export declare function computeWithdrawalFee(amount: bigint, feeBps: number, minWithdrawalFee: bigint): {
64
- fee: bigint;
65
- toRecipient: bigint;
66
- };
67
- /**
68
- * Compute the relayer fee for a cross-pool swap.
69
- * Mirrors the formula in the relayer-server:
70
- * relayerFee = max(estimatedOutput * swapFeeBps / 10_000, minSwapFee)
71
- * destAmount = minAmountOut - relayerFee
72
- *
73
- * @param estimatedOutput Jupiter quote output amount
74
- * @param swapFeeBps From the destination pool's PrivacyConfigAccount
75
- * @param minSwapFee From the destination pool's PrivacyConfigAccount
76
- * @param minAmountOut User-agreed minimum swap output (after slippage)
77
- * @returns relayerFee and the amount committed into the destination UTXO
78
- */
79
- export declare function computeSwapFee(estimatedOutput: bigint, swapFeeBps: number, minSwapFee: bigint, minAmountOut: bigint): {
80
- relayerFee: bigint;
81
- destAmount: bigint;
82
- };
@@ -1,57 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NATIVE_SOL_MINT = exports.ROOT_HISTORY_SIZE = exports.MERKLE_TREE_DEPTH = exports.DEFAULT_FEE_BPS = void 0;
4
- exports.sol = sol;
5
- exports.computeWithdrawalFee = computeWithdrawalFee;
6
- exports.computeSwapFee = computeSwapFee;
7
- const web3_js_1 = require("@solana/web3.js");
8
- // -----------------------------------------------------------------------------
9
- // Constants
10
- // -----------------------------------------------------------------------------
11
- /** Default relayer fee in basis points (50 = 0.5%). */
12
- exports.DEFAULT_FEE_BPS = 50;
13
- /** Merkle tree depth - matches on-chain MerkleTreeAccount subtrees array size */
14
- exports.MERKLE_TREE_DEPTH = 22;
15
- /** Root history size - matches on-chain MerkleTreeAccount root_history array size */
16
- exports.ROOT_HISTORY_SIZE = 256;
17
- /** Native SOL mint address (Pubkey::default() = all zeros) */
18
- exports.NATIVE_SOL_MINT = web3_js_1.PublicKey.default;
19
- // -----------------------------------------------------------------------------
20
- // Helpers
21
- // -----------------------------------------------------------------------------
22
- /** Convert SOL to lamports (e.g. `sol(1.5)` → `1_500_000_000n`). */
23
- function sol(n) {
24
- return BigInt(n * web3_js_1.LAMPORTS_PER_SOL);
25
- }
26
- // -----------------------------------------------------------------------------
27
- // Fee Calculation Helpers
28
- // -----------------------------------------------------------------------------
29
- /**
30
- * Compute the relayer fee for a withdrawal.
31
- * Mirrors the formula in the relayer-server:
32
- * fee = max(amount * feeBps / 10_000, minWithdrawalFee)
33
- *
34
- * @returns fee in base token units, and the amount that reaches the recipient
35
- */
36
- function computeWithdrawalFee(amount, feeBps, minWithdrawalFee) {
37
- const computed = (amount * BigInt(feeBps)) / 10000n;
38
- const fee = computed > minWithdrawalFee ? computed : minWithdrawalFee;
39
- return { fee, toRecipient: amount - fee };
40
- }
41
- /**
42
- * Compute the relayer fee for a cross-pool swap.
43
- * Mirrors the formula in the relayer-server:
44
- * relayerFee = max(estimatedOutput * swapFeeBps / 10_000, minSwapFee)
45
- * destAmount = minAmountOut - relayerFee
46
- *
47
- * @param estimatedOutput Jupiter quote output amount
48
- * @param swapFeeBps From the destination pool's PrivacyConfigAccount
49
- * @param minSwapFee From the destination pool's PrivacyConfigAccount
50
- * @param minAmountOut User-agreed minimum swap output (after slippage)
51
- * @returns relayerFee and the amount committed into the destination UTXO
52
- */
53
- function computeSwapFee(estimatedOutput, swapFeeBps, minSwapFee, minAmountOut) {
54
- const computed = (estimatedOutput * BigInt(swapFeeBps)) / 10000n;
55
- const relayerFee = computed > minSwapFee ? computed : minSwapFee;
56
- return { relayerFee, destAmount: minAmountOut - relayerFee };
57
- }
@@ -1,77 +0,0 @@
1
- import { PublicKey } from "@solana/web3.js";
2
- import { Program, Idl } from "@coral-xyz/anchor";
3
- import { MerkleTree } from "./merkle.js";
4
- /**
5
- * On-chain CommitmentEvent emitted by `transact` and `transact_swap`.
6
- * Mirrors the IDL CommitmentEvent struct.
7
- */
8
- export type CommitmentEvent = {
9
- commitment: Uint8Array;
10
- leafIndex: number;
11
- newRoot: Uint8Array;
12
- timestamp: number;
13
- mintAddress: PublicKey;
14
- treeId: number;
15
- txSignature: string;
16
- slot: number;
17
- };
18
- /**
19
- * On-chain NullifierSpent event emitted when a UTXO is consumed.
20
- * Mirrors the IDL NullifierSpent struct.
21
- */
22
- export type NullifierSpentEvent = {
23
- nullifier: Uint8Array;
24
- timestamp: number;
25
- mintAddress: PublicKey;
26
- treeId: number;
27
- txSignature: string;
28
- slot: number;
29
- };
30
- /**
31
- * Fetch and parse CommitmentEvents for a program, optionally filtered by mint.
32
- *
33
- * @param program - Anchor program instance
34
- * @param mintAddress - Filter to a specific pool; omit to get all pools
35
- * @param before - Start paging before this signature (exclusive)
36
- * @param until - Stop paging at this signature (exclusive)
37
- * @param limit - Max signatures to fetch per page (default 1000)
38
- */
39
- export declare function scanCommitmentEvents<T extends Idl>(params: {
40
- program: Program<T>;
41
- mintAddress?: PublicKey;
42
- before?: string;
43
- until?: string;
44
- limit?: number;
45
- }): Promise<CommitmentEvent[]>;
46
- /**
47
- * Fetch and parse NullifierSpent events for a program, optionally filtered by mint.
48
- */
49
- export declare function scanNullifierEvents<T extends Idl>(params: {
50
- program: Program<T>;
51
- mintAddress?: PublicKey;
52
- before?: string;
53
- until?: string;
54
- limit?: number;
55
- }): Promise<NullifierSpentEvent[]>;
56
- /**
57
- * Rebuild a local MerkleTree from on-chain CommitmentEvents.
58
- * Use this to get a valid inclusion proof for spending any UTXO.
59
- *
60
- * CommitmentEvents are sorted by (treeId, leafIndex) so the local tree
61
- * matches the on-chain state exactly.
62
- *
63
- * @param program - Anchor program instance
64
- * @param mintAddress - Pool to reconstruct
65
- * @param treeId - Which tree to reconstruct (default 0)
66
- * @param depth - Merkle tree depth (default 22, must match on-chain)
67
- */
68
- export declare function buildTreeFromEvents<T extends Idl>(params: {
69
- program: Program<T>;
70
- mintAddress: PublicKey;
71
- treeId?: number;
72
- depth?: number;
73
- }): Promise<{
74
- tree: MerkleTree;
75
- events: CommitmentEvent[];
76
- latestSignature?: string;
77
- }>;
@@ -1,167 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.scanCommitmentEvents = scanCommitmentEvents;
37
- exports.scanNullifierEvents = scanNullifierEvents;
38
- exports.buildTreeFromEvents = buildTreeFromEvents;
39
- const anchor = __importStar(require("@coral-xyz/anchor"));
40
- const merkle_js_1 = require("./merkle.js");
41
- // -----------------------------------------------------------------------------
42
- // Event Scanning
43
- // -----------------------------------------------------------------------------
44
- /**
45
- * Fetch and parse CommitmentEvents for a program, optionally filtered by mint.
46
- *
47
- * @param program - Anchor program instance
48
- * @param mintAddress - Filter to a specific pool; omit to get all pools
49
- * @param before - Start paging before this signature (exclusive)
50
- * @param until - Stop paging at this signature (exclusive)
51
- * @param limit - Max signatures to fetch per page (default 1000)
52
- */
53
- async function scanCommitmentEvents(params) {
54
- const { program, mintAddress, before, until, limit = 1000 } = params;
55
- const out = [];
56
- const eventParser = new anchor.EventParser(program.programId, new anchor.BorshCoder(program.idl));
57
- const sigs = await program.provider.connection.getSignaturesForAddress(program.programId, { before, until, limit });
58
- for (const sigInfo of sigs) {
59
- if (sigInfo.err)
60
- continue;
61
- const tx = await program.provider.connection.getTransaction(sigInfo.signature, { commitment: "confirmed", maxSupportedTransactionVersion: 0 });
62
- if (!tx)
63
- continue;
64
- const events = Array.from(eventParser.parseLogs(tx.meta?.logMessages ?? []));
65
- for (const ev of events) {
66
- if (ev.name !== "commitmentEvent")
67
- continue;
68
- const d = ev.data;
69
- const evMint = d.mintAddress;
70
- if (mintAddress && !evMint.equals(mintAddress))
71
- continue;
72
- out.push({
73
- commitment: new Uint8Array(d.commitment),
74
- leafIndex: Number(d.leafIndex),
75
- newRoot: new Uint8Array(d.newRoot),
76
- timestamp: Number(d.timestamp),
77
- mintAddress: evMint,
78
- treeId: Number(d.treeId),
79
- txSignature: sigInfo.signature,
80
- slot: sigInfo.slot,
81
- });
82
- }
83
- }
84
- return out;
85
- }
86
- /**
87
- * Fetch and parse NullifierSpent events for a program, optionally filtered by mint.
88
- */
89
- async function scanNullifierEvents(params) {
90
- const { program, mintAddress, before, until, limit = 1000 } = params;
91
- const out = [];
92
- const eventParser = new anchor.EventParser(program.programId, new anchor.BorshCoder(program.idl));
93
- const sigs = await program.provider.connection.getSignaturesForAddress(program.programId, { before, until, limit });
94
- for (const sigInfo of sigs) {
95
- if (sigInfo.err)
96
- continue;
97
- const tx = await program.provider.connection.getTransaction(sigInfo.signature, { commitment: "confirmed", maxSupportedTransactionVersion: 0 });
98
- if (!tx)
99
- continue;
100
- const events = Array.from(eventParser.parseLogs(tx.meta?.logMessages ?? []));
101
- for (const ev of events) {
102
- if (ev.name !== "nullifierSpent")
103
- continue;
104
- const d = ev.data;
105
- const evMint = d.mintAddress;
106
- if (mintAddress && !evMint.equals(mintAddress))
107
- continue;
108
- out.push({
109
- nullifier: new Uint8Array(d.nullifier),
110
- timestamp: Number(d.timestamp),
111
- mintAddress: evMint,
112
- treeId: Number(d.treeId),
113
- txSignature: sigInfo.signature,
114
- slot: sigInfo.slot,
115
- });
116
- }
117
- }
118
- return out;
119
- }
120
- // -----------------------------------------------------------------------------
121
- // Tree Reconstruction
122
- // -----------------------------------------------------------------------------
123
- /**
124
- * Rebuild a local MerkleTree from on-chain CommitmentEvents.
125
- * Use this to get a valid inclusion proof for spending any UTXO.
126
- *
127
- * CommitmentEvents are sorted by (treeId, leafIndex) so the local tree
128
- * matches the on-chain state exactly.
129
- *
130
- * @param program - Anchor program instance
131
- * @param mintAddress - Pool to reconstruct
132
- * @param treeId - Which tree to reconstruct (default 0)
133
- * @param depth - Merkle tree depth (default 22, must match on-chain)
134
- */
135
- async function buildTreeFromEvents(params) {
136
- const { program, mintAddress, treeId = 0, depth = 22 } = params;
137
- // Fetch all commitment events for this pool (page until no more results).
138
- // Oldest-first so we insert leaves in the correct order.
139
- const allEvents = [];
140
- let before;
141
- while (true) {
142
- const page = await scanCommitmentEvents({
143
- program,
144
- mintAddress,
145
- before,
146
- limit: 1000,
147
- });
148
- if (page.length === 0)
149
- break;
150
- allEvents.push(...page);
151
- before = page[page.length - 1].txSignature;
152
- if (page.length < 1000)
153
- break;
154
- }
155
- // Keep only events for this treeId, sort by leafIndex ascending
156
- const treeEvents = allEvents
157
- .filter((e) => e.treeId === treeId)
158
- .sort((a, b) => a.leafIndex - b.leafIndex);
159
- const tree = new merkle_js_1.MerkleTree(depth);
160
- for (const ev of treeEvents) {
161
- tree.insert(ev.commitment);
162
- }
163
- const latestSignature = treeEvents.length > 0
164
- ? treeEvents[treeEvents.length - 1].txSignature
165
- : undefined;
166
- return { tree, events: treeEvents, latestSignature };
167
- }
@@ -1,5 +0,0 @@
1
- import type { Idl } from "@coral-xyz/anchor";
2
- declare const IDL_JSON: Idl & {
3
- address: string;
4
- };
5
- export default IDL_JSON;