@unlink-xyz/core 0.1.2 → 0.1.3-canary.0877bfe

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 (350) hide show
  1. package/dist/account/{zkAccount.d.ts → account.d.ts} +7 -5
  2. package/dist/account/account.d.ts.map +1 -0
  3. package/dist/account/{zkAccount.js → account.js} +57 -43
  4. package/dist/browser/index.js +108202 -0
  5. package/dist/browser/index.js.map +1 -0
  6. package/dist/circuits.json +74 -0
  7. package/dist/clients/broadcaster.d.ts +7 -2
  8. package/dist/clients/broadcaster.d.ts.map +1 -1
  9. package/dist/clients/broadcaster.js +9 -1
  10. package/dist/clients/http.d.ts +6 -0
  11. package/dist/clients/http.d.ts.map +1 -1
  12. package/dist/clients/http.js +24 -9
  13. package/dist/clients/indexer.d.ts +11 -0
  14. package/dist/clients/indexer.d.ts.map +1 -1
  15. package/dist/clients/indexer.js +40 -11
  16. package/dist/config.d.ts +28 -9
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +33 -26
  19. package/dist/constants.d.ts +6 -0
  20. package/dist/constants.d.ts.map +1 -0
  21. package/dist/constants.js +5 -0
  22. package/dist/core.d.ts.map +1 -1
  23. package/dist/core.js +5 -2
  24. package/dist/crypto-adapters/auto-init.d.ts +2 -0
  25. package/dist/crypto-adapters/auto-init.d.ts.map +1 -0
  26. package/dist/crypto-adapters/auto-init.js +7 -0
  27. package/dist/crypto-adapters/index.d.ts +22 -0
  28. package/dist/crypto-adapters/index.d.ts.map +1 -0
  29. package/dist/crypto-adapters/index.js +47 -0
  30. package/dist/crypto-adapters/polyfills.d.ts +5 -0
  31. package/dist/crypto-adapters/polyfills.d.ts.map +1 -0
  32. package/dist/crypto-adapters/polyfills.js +8 -0
  33. package/dist/errors.d.ts +9 -0
  34. package/dist/errors.d.ts.map +1 -1
  35. package/dist/errors.js +18 -0
  36. package/dist/history/index.d.ts +3 -0
  37. package/dist/history/index.d.ts.map +1 -0
  38. package/dist/history/index.js +2 -0
  39. package/dist/history/service.d.ts +46 -0
  40. package/dist/history/service.d.ts.map +1 -0
  41. package/dist/history/service.js +354 -0
  42. package/dist/history/types.d.ts +21 -0
  43. package/dist/history/types.d.ts.map +1 -0
  44. package/dist/index.d.ts +12 -5
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +11 -4
  47. package/dist/keys/address.d.ts +13 -0
  48. package/dist/keys/address.d.ts.map +1 -0
  49. package/dist/keys/address.js +55 -0
  50. package/dist/keys/derive.d.ts +37 -0
  51. package/dist/keys/derive.d.ts.map +1 -0
  52. package/dist/keys/derive.js +112 -0
  53. package/dist/keys/hex.d.ts +17 -0
  54. package/dist/keys/hex.d.ts.map +1 -0
  55. package/dist/keys/hex.js +66 -0
  56. package/dist/keys/index.d.ts +5 -0
  57. package/dist/keys/index.d.ts.map +1 -0
  58. package/dist/keys/index.js +4 -0
  59. package/dist/keys/mnemonic.d.ts +8 -0
  60. package/dist/keys/mnemonic.d.ts.map +1 -0
  61. package/dist/keys/mnemonic.js +23 -0
  62. package/dist/keys.d.ts +4 -1
  63. package/dist/keys.d.ts.map +1 -1
  64. package/dist/keys.js +4 -0
  65. package/dist/prover/config.d.ts +1 -15
  66. package/dist/prover/config.d.ts.map +1 -1
  67. package/dist/prover/config.js +1 -11
  68. package/dist/prover/prover.d.ts +15 -4
  69. package/dist/prover/prover.d.ts.map +1 -1
  70. package/dist/prover/prover.js +115 -98
  71. package/dist/prover/registry.d.ts +3 -30
  72. package/dist/prover/registry.d.ts.map +1 -1
  73. package/dist/prover/registry.js +12 -51
  74. package/dist/state/merkle/hydrator.d.ts.map +1 -1
  75. package/dist/state/merkle/hydrator.js +3 -2
  76. package/dist/state/merkle/index.d.ts +1 -1
  77. package/dist/state/merkle/index.d.ts.map +1 -1
  78. package/dist/state/merkle/index.js +1 -1
  79. package/dist/state/merkle/merkle-tree.d.ts +8 -0
  80. package/dist/state/merkle/merkle-tree.d.ts.map +1 -1
  81. package/dist/state/merkle/merkle-tree.js +16 -7
  82. package/dist/state/store/ciphertext-store.d.ts +4 -0
  83. package/dist/state/store/ciphertext-store.d.ts.map +1 -1
  84. package/dist/state/store/ciphertext-store.js +12 -0
  85. package/dist/state/store/history-store.d.ts +24 -0
  86. package/dist/state/store/history-store.d.ts.map +1 -0
  87. package/dist/state/store/history-store.js +53 -0
  88. package/dist/state/store/index.d.ts +3 -2
  89. package/dist/state/store/index.d.ts.map +1 -1
  90. package/dist/state/store/index.js +1 -0
  91. package/dist/state/store/job-store.d.ts +7 -7
  92. package/dist/state/store/job-store.d.ts.map +1 -1
  93. package/dist/state/store/job-store.js +65 -39
  94. package/dist/state/store/jobs.d.ts +65 -18
  95. package/dist/state/store/jobs.d.ts.map +1 -1
  96. package/dist/state/store/leaf-store.d.ts.map +1 -1
  97. package/dist/state/store/leaf-store.js +0 -3
  98. package/dist/state/store/note-store.d.ts +7 -7
  99. package/dist/state/store/note-store.d.ts.map +1 -1
  100. package/dist/state/store/note-store.js +38 -34
  101. package/dist/state/store/nullifier-store.d.ts +9 -0
  102. package/dist/state/store/nullifier-store.d.ts.map +1 -1
  103. package/dist/state/store/nullifier-store.js +32 -2
  104. package/dist/state/store/records.d.ts +31 -2
  105. package/dist/state/store/records.d.ts.map +1 -1
  106. package/dist/state/store/root-store.d.ts.map +1 -1
  107. package/dist/state/store/root-store.js +0 -4
  108. package/dist/state/store/store.d.ts +61 -27
  109. package/dist/state/store/store.d.ts.map +1 -1
  110. package/dist/state/store/store.js +92 -1
  111. package/dist/storage/indexeddb.js +1 -1
  112. package/dist/storage/memory.d.ts.map +1 -1
  113. package/dist/storage/memory.js +5 -1
  114. package/dist/transactions/deposit.d.ts +12 -15
  115. package/dist/transactions/deposit.d.ts.map +1 -1
  116. package/dist/transactions/deposit.js +203 -152
  117. package/dist/transactions/index.d.ts +7 -4
  118. package/dist/transactions/index.d.ts.map +1 -1
  119. package/dist/transactions/index.js +7 -2
  120. package/dist/transactions/note-selection.d.ts +17 -0
  121. package/dist/transactions/note-selection.d.ts.map +1 -0
  122. package/dist/transactions/note-selection.js +201 -0
  123. package/dist/transactions/note-sync.d.ts +5 -33
  124. package/dist/transactions/note-sync.d.ts.map +1 -1
  125. package/dist/transactions/note-sync.js +320 -155
  126. package/dist/transactions/reconcile.d.ts +10 -12
  127. package/dist/transactions/reconcile.d.ts.map +1 -1
  128. package/dist/transactions/reconcile.js +53 -7
  129. package/dist/transactions/transact.d.ts +13 -24
  130. package/dist/transactions/transact.d.ts.map +1 -1
  131. package/dist/transactions/transact.js +393 -507
  132. package/dist/transactions/transaction-planner.d.ts +34 -0
  133. package/dist/transactions/transaction-planner.d.ts.map +1 -0
  134. package/dist/transactions/transaction-planner.js +116 -0
  135. package/dist/transactions/transfer-planner.d.ts +36 -0
  136. package/dist/transactions/transfer-planner.d.ts.map +1 -0
  137. package/dist/transactions/transfer-planner.js +85 -0
  138. package/dist/transactions/types/deposit.d.ts +67 -0
  139. package/dist/transactions/types/deposit.d.ts.map +1 -0
  140. package/dist/transactions/types/domain.d.ts +67 -0
  141. package/dist/transactions/types/domain.d.ts.map +1 -0
  142. package/dist/transactions/types/domain.js +4 -0
  143. package/dist/transactions/types/index.d.ts +18 -0
  144. package/dist/transactions/types/index.d.ts.map +1 -0
  145. package/dist/transactions/types/index.js +17 -0
  146. package/dist/transactions/types/options.d.ts +45 -0
  147. package/dist/transactions/types/options.d.ts.map +1 -0
  148. package/dist/transactions/types/options.js +1 -0
  149. package/dist/transactions/types/planning.d.ts +80 -0
  150. package/dist/transactions/types/planning.d.ts.map +1 -0
  151. package/dist/transactions/types/planning.js +1 -0
  152. package/dist/transactions/types/state-stores.d.ts +103 -0
  153. package/dist/transactions/types/state-stores.d.ts.map +1 -0
  154. package/dist/transactions/types/state-stores.js +1 -0
  155. package/dist/transactions/types/transact.d.ts +76 -0
  156. package/dist/transactions/types/transact.d.ts.map +1 -0
  157. package/dist/transactions/types/transact.js +1 -0
  158. package/dist/transactions/withdrawal-planner.d.ts +58 -0
  159. package/dist/transactions/withdrawal-planner.d.ts.map +1 -0
  160. package/dist/transactions/withdrawal-planner.js +128 -0
  161. package/dist/tsconfig.tsbuildinfo +1 -1
  162. package/dist/tsup.browser.config.d.ts +7 -0
  163. package/dist/tsup.browser.config.d.ts.map +1 -0
  164. package/dist/tsup.browser.config.js +34 -0
  165. package/dist/utils/amounts.d.ts +39 -0
  166. package/dist/utils/amounts.d.ts.map +1 -0
  167. package/dist/utils/amounts.js +89 -0
  168. package/dist/utils/async.d.ts +9 -0
  169. package/dist/utils/async.d.ts.map +1 -1
  170. package/dist/utils/async.js +24 -0
  171. package/dist/utils/bigint.js +7 -7
  172. package/dist/utils/crypto.d.ts +11 -5
  173. package/dist/utils/crypto.d.ts.map +1 -1
  174. package/dist/utils/crypto.js +12 -6
  175. package/dist/utils/format.d.ts +25 -0
  176. package/dist/utils/format.d.ts.map +1 -0
  177. package/dist/utils/format.js +33 -0
  178. package/dist/utils/json-codec.js +1 -1
  179. package/dist/utils/notes.d.ts +15 -0
  180. package/dist/utils/notes.d.ts.map +1 -0
  181. package/dist/utils/notes.js +14 -0
  182. package/dist/utils/polling.d.ts +5 -0
  183. package/dist/utils/polling.d.ts.map +1 -1
  184. package/dist/utils/polling.js +5 -0
  185. package/dist/utils/random.d.ts +13 -0
  186. package/dist/utils/random.d.ts.map +1 -0
  187. package/dist/utils/random.js +27 -0
  188. package/dist/utils/secure-memory.d.ts +25 -0
  189. package/dist/utils/secure-memory.d.ts.map +1 -0
  190. package/dist/utils/secure-memory.js +28 -0
  191. package/dist/utils/signature.d.ts +6 -0
  192. package/dist/utils/signature.d.ts.map +1 -1
  193. package/dist/utils/signature.js +8 -6
  194. package/dist/utils/validators.d.ts +21 -10
  195. package/dist/utils/validators.d.ts.map +1 -1
  196. package/dist/utils/validators.js +37 -11
  197. package/dist/vitest.config.d.ts +3 -0
  198. package/dist/vitest.config.d.ts.map +1 -0
  199. package/dist/vitest.config.js +13 -0
  200. package/package.json +28 -11
  201. package/.eslintrc.json +0 -4
  202. package/account/zkAccount.test.ts +0 -316
  203. package/account/zkAccount.ts +0 -222
  204. package/clients/broadcaster.ts +0 -67
  205. package/clients/http.ts +0 -94
  206. package/clients/indexer.ts +0 -150
  207. package/config.ts +0 -39
  208. package/core.ts +0 -17
  209. package/dist/account/railgun-imports-prototype.d.ts +0 -12
  210. package/dist/account/railgun-imports-prototype.d.ts.map +0 -1
  211. package/dist/account/railgun-imports-prototype.js +0 -30
  212. package/dist/account/zkAccount.d.ts.map +0 -1
  213. package/dist/key-derivation/babyjubjub.d.ts +0 -9
  214. package/dist/key-derivation/babyjubjub.d.ts.map +0 -1
  215. package/dist/key-derivation/babyjubjub.js +0 -9
  216. package/dist/key-derivation/bech32.d.ts +0 -22
  217. package/dist/key-derivation/bech32.d.ts.map +0 -1
  218. package/dist/key-derivation/bech32.js +0 -86
  219. package/dist/key-derivation/bip32.d.ts +0 -17
  220. package/dist/key-derivation/bip32.d.ts.map +0 -1
  221. package/dist/key-derivation/bip32.js +0 -41
  222. package/dist/key-derivation/bip39.d.ts +0 -22
  223. package/dist/key-derivation/bip39.d.ts.map +0 -1
  224. package/dist/key-derivation/bip39.js +0 -56
  225. package/dist/key-derivation/bytes.d.ts +0 -19
  226. package/dist/key-derivation/bytes.d.ts.map +0 -1
  227. package/dist/key-derivation/bytes.js +0 -92
  228. package/dist/key-derivation/hash.d.ts +0 -3
  229. package/dist/key-derivation/hash.d.ts.map +0 -1
  230. package/dist/key-derivation/hash.js +0 -10
  231. package/dist/key-derivation/index.d.ts +0 -8
  232. package/dist/key-derivation/index.d.ts.map +0 -1
  233. package/dist/key-derivation/index.js +0 -7
  234. package/dist/key-derivation/wallet-node.d.ts +0 -45
  235. package/dist/key-derivation/wallet-node.d.ts.map +0 -1
  236. package/dist/key-derivation/wallet-node.js +0 -109
  237. package/dist/state/ciphertext-store.d.ts +0 -12
  238. package/dist/state/ciphertext-store.d.ts.map +0 -1
  239. package/dist/state/ciphertext-store.js +0 -25
  240. package/dist/state/hydrator.d.ts +0 -16
  241. package/dist/state/hydrator.d.ts.map +0 -1
  242. package/dist/state/hydrator.js +0 -18
  243. package/dist/state/job-store.d.ts +0 -12
  244. package/dist/state/job-store.d.ts.map +0 -1
  245. package/dist/state/job-store.js +0 -118
  246. package/dist/state/jobs.d.ts +0 -50
  247. package/dist/state/jobs.d.ts.map +0 -1
  248. package/dist/state/jobs.js +0 -1
  249. package/dist/state/leaf-store.d.ts +0 -17
  250. package/dist/state/leaf-store.d.ts.map +0 -1
  251. package/dist/state/leaf-store.js +0 -35
  252. package/dist/state/merkle-tree.d.ts +0 -34
  253. package/dist/state/merkle-tree.d.ts.map +0 -1
  254. package/dist/state/merkle-tree.js +0 -104
  255. package/dist/state/note-store.d.ts +0 -37
  256. package/dist/state/note-store.d.ts.map +0 -1
  257. package/dist/state/note-store.js +0 -133
  258. package/dist/state/nullifier-store.d.ts +0 -13
  259. package/dist/state/nullifier-store.d.ts.map +0 -1
  260. package/dist/state/nullifier-store.js +0 -21
  261. package/dist/state/records.d.ts +0 -57
  262. package/dist/state/records.d.ts.map +0 -1
  263. package/dist/state/root-store.d.ts +0 -13
  264. package/dist/state/root-store.d.ts.map +0 -1
  265. package/dist/state/root-store.js +0 -30
  266. package/dist/state/store.d.ts +0 -26
  267. package/dist/state/store.d.ts.map +0 -1
  268. package/dist/state/store.js +0 -19
  269. package/dist/state.d.ts +0 -83
  270. package/dist/state.d.ts.map +0 -1
  271. package/dist/state.js +0 -171
  272. package/dist/transactions/shield.d.ts +0 -5
  273. package/dist/transactions/shield.d.ts.map +0 -1
  274. package/dist/transactions/shield.js +0 -93
  275. package/dist/transactions/types.d.ts +0 -114
  276. package/dist/transactions/types.d.ts.map +0 -1
  277. package/dist/transactions/utils.d.ts +0 -10
  278. package/dist/transactions/utils.d.ts.map +0 -1
  279. package/dist/transactions/utils.js +0 -17
  280. package/dist/utils/time.d.ts +0 -2
  281. package/dist/utils/time.d.ts.map +0 -1
  282. package/dist/utils/time.js +0 -3
  283. package/dist/utils/witness.d.ts +0 -11
  284. package/dist/utils/witness.d.ts.map +0 -1
  285. package/dist/utils/witness.js +0 -19
  286. package/errors.ts +0 -20
  287. package/index.ts +0 -17
  288. package/key-derivation/babyjubjub.ts +0 -11
  289. package/key-derivation/bech32.test.ts +0 -90
  290. package/key-derivation/bech32.ts +0 -124
  291. package/key-derivation/bip32.ts +0 -56
  292. package/key-derivation/bip39.ts +0 -76
  293. package/key-derivation/bytes.ts +0 -118
  294. package/key-derivation/hash.ts +0 -13
  295. package/key-derivation/index.ts +0 -7
  296. package/key-derivation/wallet-node.ts +0 -155
  297. package/keys.ts +0 -47
  298. package/prover/config.ts +0 -104
  299. package/prover/index.ts +0 -1
  300. package/prover/prover.integration.test.ts +0 -162
  301. package/prover/prover.test.ts +0 -309
  302. package/prover/prover.ts +0 -405
  303. package/prover/registry.test.ts +0 -90
  304. package/prover/registry.ts +0 -82
  305. package/schema.ts +0 -17
  306. package/setup-artifacts.sh +0 -57
  307. package/state/index.ts +0 -2
  308. package/state/merkle/hydrator.ts +0 -69
  309. package/state/merkle/index.ts +0 -12
  310. package/state/merkle/merkle-tree.test.ts +0 -50
  311. package/state/merkle/merkle-tree.ts +0 -163
  312. package/state/store/ciphertext-store.ts +0 -28
  313. package/state/store/index.ts +0 -24
  314. package/state/store/job-store.ts +0 -162
  315. package/state/store/jobs.ts +0 -64
  316. package/state/store/leaf-store.ts +0 -39
  317. package/state/store/note-store.ts +0 -177
  318. package/state/store/nullifier-store.ts +0 -39
  319. package/state/store/records.ts +0 -61
  320. package/state/store/root-store.ts +0 -34
  321. package/state/store/store.ts +0 -25
  322. package/state.test.ts +0 -235
  323. package/storage/index.ts +0 -3
  324. package/storage/indexeddb.test.ts +0 -99
  325. package/storage/indexeddb.ts +0 -235
  326. package/storage/memory.test.ts +0 -59
  327. package/storage/memory.ts +0 -93
  328. package/transactions/deposit.test.ts +0 -160
  329. package/transactions/deposit.ts +0 -227
  330. package/transactions/index.ts +0 -20
  331. package/transactions/note-sync.test.ts +0 -155
  332. package/transactions/note-sync.ts +0 -452
  333. package/transactions/reconcile.ts +0 -73
  334. package/transactions/transact.test.ts +0 -451
  335. package/transactions/transact.ts +0 -811
  336. package/transactions/types.ts +0 -141
  337. package/tsconfig.json +0 -14
  338. package/types/global.d.ts +0 -15
  339. package/types.ts +0 -24
  340. package/utils/async.ts +0 -15
  341. package/utils/bigint.ts +0 -34
  342. package/utils/crypto.test.ts +0 -69
  343. package/utils/crypto.ts +0 -58
  344. package/utils/json-codec.ts +0 -38
  345. package/utils/polling.ts +0 -6
  346. package/utils/signature.ts +0 -16
  347. package/utils/validators.test.ts +0 -64
  348. package/utils/validators.ts +0 -86
  349. /package/dist/{transactions → history}/types.js +0 -0
  350. /package/dist/{state/records.js → transactions/types/deposit.js} +0 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * State store interfaces for transaction operations.
3
+ */
4
+ import type { JobKind, JobRecord, JobStatus, LeafRecord, NoteRecord, NullifierRecord, RootRecord } from "../../state/index.js";
5
+ /**
6
+ * Base state store interface with common methods shared across services.
7
+ */
8
+ export type BaseStateStore = {
9
+ putLeaf(record: LeafRecord): Promise<void>;
10
+ getLeaf(chainId: number, index: number): Promise<LeafRecord | null>;
11
+ clearLeaves(chainId: number): Promise<void>;
12
+ putRoot(record: RootRecord): Promise<void>;
13
+ putJob(job: JobRecord): Promise<void>;
14
+ getJob(relayId: string): Promise<JobRecord | null>;
15
+ listJobs(filter?: {
16
+ kind?: JobKind;
17
+ statuses?: JobStatus[];
18
+ }): Promise<JobRecord[]>;
19
+ deleteJob(relayId: string): Promise<void>;
20
+ };
21
+ /**
22
+ * State store interface for transaction operations.
23
+ */
24
+ export type TransactStateStore = BaseStateStore & {
25
+ getNote(chainId: number, index: number): Promise<NoteRecord | null>;
26
+ markNoteSpent(chainId: number, index: number, spentAt?: number, spentTxHash?: string): Promise<NoteRecord>;
27
+ putNullifier(record: NullifierRecord): Promise<void>;
28
+ listNotes(options?: {
29
+ chainId?: number;
30
+ mpk?: string;
31
+ token?: string;
32
+ includeSpent?: boolean;
33
+ }): Promise<NoteRecord[]>;
34
+ };
35
+ /**
36
+ * State store interface for note synchronization operations.
37
+ * Extends BaseStateStore with note-specific methods.
38
+ */
39
+ export type NoteSyncStateStore = BaseStateStore & {
40
+ putNote(record: NoteRecord): Promise<void>;
41
+ getNote(chainId: number, index: number): Promise<NoteRecord | null>;
42
+ clearNotes(chainId: number): Promise<void>;
43
+ listNotes(options?: {
44
+ chainId?: number;
45
+ mpk?: string;
46
+ token?: string;
47
+ includeSpent?: boolean;
48
+ }): Promise<NoteRecord[]>;
49
+ markNoteSpent(chainId: number, index: number, spentAt?: number, spentTxHash?: string): Promise<NoteRecord>;
50
+ putCiphertext(chainId: number, index: number, payload: Uint8Array): Promise<void>;
51
+ getCiphertext(chainId: number, index: number): Promise<Uint8Array | null>;
52
+ clearCiphertexts(chainId: number): Promise<void>;
53
+ countNullifiers(chainId: number): Promise<number>;
54
+ clearNullifiers(chainId: number): Promise<void>;
55
+ clearNullifiersFromIndex(chainId: number, fromIndex: number): Promise<void>;
56
+ putNullifier(record: {
57
+ chainId: number;
58
+ nullifier: string;
59
+ noteIndex?: number;
60
+ }): Promise<void>;
61
+ /**
62
+ * Atomically store a commitment's leaf, ciphertext, root, and optionally note.
63
+ * Uses storage.batch() for all-or-nothing semantics.
64
+ */
65
+ syncCommitment(params: {
66
+ leaf: {
67
+ chainId: number;
68
+ index: number;
69
+ commitment: string;
70
+ txHash?: string;
71
+ eventType?: string;
72
+ insertedAt?: number;
73
+ };
74
+ ciphertext: {
75
+ chainId: number;
76
+ index: number;
77
+ payload: Uint8Array;
78
+ };
79
+ root: {
80
+ chainId: number;
81
+ root: string;
82
+ };
83
+ note?: {
84
+ chainId: number;
85
+ index: number;
86
+ token: string;
87
+ value: string;
88
+ commitment: string;
89
+ npk: string;
90
+ mpk: string;
91
+ random: string;
92
+ nullifier: string;
93
+ createdTxHash?: string;
94
+ createdEventType?: string;
95
+ createdAt?: number;
96
+ spentAt?: number;
97
+ spentTxHash?: string;
98
+ };
99
+ }): Promise<void>;
100
+ /** Clear notes, leaves, ciphertexts, and unspent indices for indices >= fromIndex. */
101
+ clearChainDataFromIndex(chainId: number, fromIndex: number): Promise<void>;
102
+ };
103
+ //# sourceMappingURL=state-stores.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-stores.d.ts","sourceRoot":"","sources":["../../../transactions/types/state-stores.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Types for transaction operations.
3
+ */
4
+ import type { IMTMerkleProof } from "@zk-kit/imt";
5
+ import type { Account } from "../../account/account.js";
6
+ import type { CommitmentRecord } from "../../clients/indexer.js";
7
+ import type { NoteInput, Proof, SpendNoteReference, WithdrawalNoteInput } from "./domain.js";
8
+ /**
9
+ * A single transaction item (used in the transactions array).
10
+ */
11
+ export type TransactItem = {
12
+ /** Token address */
13
+ token: string;
14
+ /** Input notes to spend */
15
+ inputs: SpendNoteReference[];
16
+ /** Output notes to create */
17
+ outputs: NoteInput[];
18
+ /** Optional withdrawal output */
19
+ withdrawal?: WithdrawalNoteInput;
20
+ };
21
+ /**
22
+ * Parameters required to execute private transaction(s).
23
+ * Always accepts an array of transactions - single tx just passes [item].
24
+ */
25
+ export type TransactParams = {
26
+ /** Account with keys for signing and viewing */
27
+ account: Account;
28
+ /** Chain ID for the target blockchain */
29
+ chainId: number;
30
+ /** Pool contract address */
31
+ poolAddress: string;
32
+ /** Transactions to execute (proofs generated in parallel, bundled into one call) */
33
+ transactions: TransactItem[];
34
+ };
35
+ /**
36
+ * Result of a single transaction within the batch.
37
+ */
38
+ export type TransactItemResult = {
39
+ /** Generated proof */
40
+ proof: Proof;
41
+ /** Merkle witnesses for inputs */
42
+ witnesses: IMTMerkleProof[];
43
+ /** Nullifiers of spent notes */
44
+ nullifiers: string[];
45
+ /** Predicted commitment hex strings */
46
+ predictedCommitments: string[];
47
+ };
48
+ /**
49
+ * Result of the transact flow, including calldata and state deltas.
50
+ */
51
+ export type TransactRelayResult = {
52
+ /** Relay ID for tracking */
53
+ relayId: string;
54
+ /** Calldata to submit on-chain */
55
+ calldata: string;
56
+ /** Individual transaction results */
57
+ transactions: TransactItemResult[];
58
+ };
59
+ /**
60
+ * Result of syncing a pending transaction.
61
+ */
62
+ export type TransactSyncResult = {
63
+ /** Chain ID */
64
+ chainId: number;
65
+ /** Merkle root after transaction */
66
+ root: string;
67
+ /** Nullifiers of spent notes (all transactions combined) */
68
+ nullifiers: string[];
69
+ /** New commitment hex strings (all transactions combined) */
70
+ newCommitments: string[];
71
+ /** Transaction hash (if available) */
72
+ txHash?: string;
73
+ /** Indexed commitments */
74
+ indexedCommitments?: CommitmentRecord[];
75
+ };
76
+ //# sourceMappingURL=transact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transact.d.ts","sourceRoot":"","sources":["../../../transactions/types/transact.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EACV,SAAS,EACT,KAAK,EACL,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,6BAA6B;IAC7B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,iCAAiC;IACjC,UAAU,CAAC,EAAE,mBAAmB,CAAC;CAClC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,YAAY,EAAE,YAAY,EAAE,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB;IACtB,KAAK,EAAE,KAAK,CAAC;IACb,kCAAkC;IAClC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,gCAAgC;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,uCAAuC;IACvC,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,YAAY,EAAE,kBAAkB,EAAE,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACzC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,58 @@
1
+ import { type CircuitConfig } from "../prover/registry.js";
2
+ import type { NoteInput, SelectableNote, WithdrawalNoteInput } from "./types/index.js";
3
+ /**
4
+ * Result of planning a withdrawal transaction.
5
+ */
6
+ export type WithdrawalPlan<T> = {
7
+ /** Selected input notes to spend */
8
+ inputs: SelectableNote<T>[];
9
+ /** Output notes (change only, if any) */
10
+ outputNotes: NoteInput[];
11
+ /** Withdrawal specification */
12
+ withdrawal: WithdrawalNoteInput;
13
+ /** Selected circuit configuration */
14
+ circuit: CircuitConfig;
15
+ /** Total input amount from selected notes */
16
+ totalInput: bigint;
17
+ /** Amount being withdrawn */
18
+ withdrawAmount: bigint;
19
+ /** Change amount returned to sender */
20
+ change: bigint;
21
+ /** Token address */
22
+ token: string;
23
+ };
24
+ /**
25
+ * Input for a single withdrawal in a batch.
26
+ */
27
+ export type WithdrawalInput = {
28
+ token: string;
29
+ amount: bigint;
30
+ recipient: string;
31
+ };
32
+ /**
33
+ * Plan withdrawal transaction(s).
34
+ * Accepts 1 or more withdrawals. When multiple withdrawals use the same token,
35
+ * notes are tracked across withdrawals to avoid double-spending.
36
+ *
37
+ * @param notes - Available unspent notes (all tokens)
38
+ * @param withdrawals - Withdrawals to plan (each with token, amount, recipient)
39
+ * @param senderMpk - Sender's master public key (for change outputs)
40
+ * @returns Array of withdrawal plans, one per withdrawal input
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Single withdrawal
45
+ * const [plan] = planWithdrawals(notes, [{ token, amount: 100n, recipient: "0x..." }], mpk);
46
+ *
47
+ * // Multiple withdrawals (possibly same token)
48
+ * const plans = planWithdrawals(notes, [
49
+ * { token: ETH, amount: 100n, recipient: "0x..." },
50
+ * { token: USDC, amount: 50n, recipient: "0x..." },
51
+ * ], mpk);
52
+ * ```
53
+ */
54
+ export declare function planWithdrawals<T extends {
55
+ index: number;
56
+ value: bigint | string;
57
+ }>(notes: SelectableNote<T>[], withdrawals: WithdrawalInput[], senderMpk: bigint): WithdrawalPlan<T>[];
58
+ //# sourceMappingURL=withdrawal-planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withdrawal-planner.d.ts","sourceRoot":"","sources":["../../transactions/withdrawal-planner.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG7E,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAE1B;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,oCAAoC;IACpC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5B,yCAAyC;IACzC,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,+BAA+B;IAC/B,UAAU,EAAE,mBAAmB,CAAC;IAChC,qCAAqC;IACrC,OAAO,EAAE,aAAa,CAAC;IACvB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAmFF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAC7B,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,EAEnD,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,EAC1B,WAAW,EAAE,eAAe,EAAE,EAC9B,SAAS,EAAE,MAAM,GAChB,cAAc,CAAC,CAAC,CAAC,EAAE,CA0ErB"}
@@ -0,0 +1,128 @@
1
+ import { ProofError, ValidationError } from "../errors.js";
2
+ import { CIRCUIT_REGISTRY } from "../prover/registry.js";
3
+ import { randomBigint } from "../utils/random.js";
4
+ import { selectNotesForAmount } from "./note-selection.js";
5
+ /**
6
+ * Select the smallest circuit that fits the given input/output counts.
7
+ * For withdrawals, outputs = change only (0 or 1).
8
+ */
9
+ function selectCircuitForWithdrawal(inputCount, outputCount) {
10
+ // Sort circuits by total size (inputs + outputs) ascending
11
+ const circuits = Object.values(CIRCUIT_REGISTRY).sort((a, b) => a.inputs + a.outputs - (b.inputs + b.outputs));
12
+ const circuit = circuits.find((c) => c.inputs >= inputCount && c.outputs >= outputCount);
13
+ if (!circuit) {
14
+ throw new ProofError(`No circuit supports ${inputCount} inputs and ${outputCount} outputs. ` +
15
+ `Available: ${circuits.map((c) => `${c.inputs}x${c.outputs}`).join(", ")}`);
16
+ }
17
+ return circuit;
18
+ }
19
+ /**
20
+ * Plan a single withdrawal transaction. Used internally by `planWithdrawals`.
21
+ */
22
+ function planSingleWithdrawal(notes, withdrawAmount, recipientAddress, senderMpk, token) {
23
+ if (withdrawAmount <= 0n) {
24
+ throw new ValidationError("Withdrawal amount must be positive");
25
+ }
26
+ const selection = selectNotesForAmount(notes, withdrawAmount, {
27
+ recipientCount: 0,
28
+ });
29
+ const { selected: inputs, totalInput, change } = selection;
30
+ const changeOutputCount = change > 0n ? 1 : 0;
31
+ const outputCount = changeOutputCount + 1;
32
+ const circuit = selectCircuitForWithdrawal(inputs.length, outputCount);
33
+ const outputNotes = [];
34
+ if (change > 0n) {
35
+ const random = randomBigint();
36
+ outputNotes.push({
37
+ mpk: senderMpk,
38
+ random,
39
+ token,
40
+ amount: change,
41
+ });
42
+ }
43
+ const withdrawal = {
44
+ npk: BigInt(recipientAddress),
45
+ amount: withdrawAmount,
46
+ token,
47
+ };
48
+ return {
49
+ inputs,
50
+ outputNotes,
51
+ withdrawal,
52
+ circuit,
53
+ totalInput,
54
+ withdrawAmount,
55
+ change,
56
+ token,
57
+ };
58
+ }
59
+ /**
60
+ * Plan withdrawal transaction(s).
61
+ * Accepts 1 or more withdrawals. When multiple withdrawals use the same token,
62
+ * notes are tracked across withdrawals to avoid double-spending.
63
+ *
64
+ * @param notes - Available unspent notes (all tokens)
65
+ * @param withdrawals - Withdrawals to plan (each with token, amount, recipient)
66
+ * @param senderMpk - Sender's master public key (for change outputs)
67
+ * @returns Array of withdrawal plans, one per withdrawal input
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * // Single withdrawal
72
+ * const [plan] = planWithdrawals(notes, [{ token, amount: 100n, recipient: "0x..." }], mpk);
73
+ *
74
+ * // Multiple withdrawals (possibly same token)
75
+ * const plans = planWithdrawals(notes, [
76
+ * { token: ETH, amount: 100n, recipient: "0x..." },
77
+ * { token: USDC, amount: 50n, recipient: "0x..." },
78
+ * ], mpk);
79
+ * ```
80
+ */
81
+ export function planWithdrawals(notes, withdrawals, senderMpk) {
82
+ if (!withdrawals.length) {
83
+ throw new ValidationError("At least one withdrawal is required");
84
+ }
85
+ // Validate all withdrawals upfront
86
+ for (const w of withdrawals) {
87
+ if (w.amount <= 0n) {
88
+ throw new ValidationError(`Invalid withdrawal amount for ${w.token}: ${w.amount}`);
89
+ }
90
+ }
91
+ // Pre-validate total balances per token (use normalized tokens for comparison)
92
+ const requiredByToken = new Map();
93
+ for (const w of withdrawals) {
94
+ const tokenLower = w.token.toLowerCase();
95
+ const existing = requiredByToken.get(tokenLower) ?? 0n;
96
+ requiredByToken.set(tokenLower, existing + w.amount);
97
+ }
98
+ for (const [tokenLower, required] of requiredByToken) {
99
+ const available = notes
100
+ .filter((n) => n.token.toLowerCase() ===
101
+ tokenLower)
102
+ .reduce((sum, n) => sum + BigInt(n.value), 0n);
103
+ if (available < required) {
104
+ throw new ValidationError(`Insufficient balance for ${tokenLower}: need ${required}, have ${available}`);
105
+ }
106
+ }
107
+ // Track used note indices per token to avoid double-spending
108
+ const usedNotesByToken = new Map();
109
+ const plans = [];
110
+ for (const w of withdrawals) {
111
+ const tokenLower = w.token.toLowerCase();
112
+ // Get available notes for this token, excluding already-used ones
113
+ const usedIndices = usedNotesByToken.get(tokenLower) ?? new Set();
114
+ const availableNotes = notes.filter((n) => n.token.toLowerCase() ===
115
+ tokenLower && !usedIndices.has(n.index));
116
+ // Plan this withdrawal (pass original token for output)
117
+ const plan = planSingleWithdrawal(availableNotes, w.amount, w.recipient, senderMpk, w.token);
118
+ // Mark selected notes as used
119
+ if (!usedNotesByToken.has(tokenLower)) {
120
+ usedNotesByToken.set(tokenLower, new Set());
121
+ }
122
+ for (const input of plan.inputs) {
123
+ usedNotesByToken.get(tokenLower).add(input.index);
124
+ }
125
+ plans.push(plan);
126
+ }
127
+ return plans;
128
+ }