@unlink-xyz/core 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 (185) hide show
  1. package/dist/account/zkAccount.d.ts +38 -0
  2. package/dist/account/zkAccount.d.ts.map +1 -0
  3. package/dist/account/zkAccount.js +128 -0
  4. package/dist/clients/broadcaster.d.ts +33 -0
  5. package/dist/clients/broadcaster.d.ts.map +1 -0
  6. package/dist/clients/broadcaster.js +23 -0
  7. package/dist/clients/http.d.ts +23 -0
  8. package/dist/clients/http.d.ts.map +1 -0
  9. package/dist/clients/http.js +57 -0
  10. package/dist/clients/indexer.d.ts +44 -0
  11. package/dist/clients/indexer.d.ts.map +1 -0
  12. package/dist/clients/indexer.js +67 -0
  13. package/dist/config.d.ts +12 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +29 -0
  16. package/dist/core.d.ts +10 -0
  17. package/dist/core.d.ts.map +1 -0
  18. package/dist/core.js +12 -0
  19. package/dist/errors.d.ts +10 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +18 -0
  22. package/dist/index.d.ts +18 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +16 -0
  25. package/dist/key-derivation/babyjubjub.d.ts +9 -0
  26. package/dist/key-derivation/babyjubjub.d.ts.map +1 -0
  27. package/dist/key-derivation/babyjubjub.js +9 -0
  28. package/dist/key-derivation/bech32.d.ts +22 -0
  29. package/dist/key-derivation/bech32.d.ts.map +1 -0
  30. package/dist/key-derivation/bech32.js +86 -0
  31. package/dist/key-derivation/bip32.d.ts +17 -0
  32. package/dist/key-derivation/bip32.d.ts.map +1 -0
  33. package/dist/key-derivation/bip32.js +41 -0
  34. package/dist/key-derivation/bip39.d.ts +22 -0
  35. package/dist/key-derivation/bip39.d.ts.map +1 -0
  36. package/dist/key-derivation/bip39.js +56 -0
  37. package/dist/key-derivation/bytes.d.ts +19 -0
  38. package/dist/key-derivation/bytes.d.ts.map +1 -0
  39. package/dist/key-derivation/bytes.js +92 -0
  40. package/dist/key-derivation/hash.d.ts +3 -0
  41. package/dist/key-derivation/hash.d.ts.map +1 -0
  42. package/dist/key-derivation/hash.js +10 -0
  43. package/dist/key-derivation/index.d.ts +8 -0
  44. package/dist/key-derivation/index.d.ts.map +1 -0
  45. package/dist/key-derivation/index.js +7 -0
  46. package/dist/key-derivation/wallet-node.d.ts +45 -0
  47. package/dist/key-derivation/wallet-node.d.ts.map +1 -0
  48. package/dist/key-derivation/wallet-node.js +109 -0
  49. package/dist/keys.d.ts +22 -0
  50. package/dist/keys.d.ts.map +1 -0
  51. package/dist/keys.js +41 -0
  52. package/dist/prover/config.d.ts +60 -0
  53. package/dist/prover/config.d.ts.map +1 -0
  54. package/dist/prover/config.js +80 -0
  55. package/dist/prover/index.d.ts +2 -0
  56. package/dist/prover/index.d.ts.map +1 -0
  57. package/dist/prover/index.js +1 -0
  58. package/dist/prover/prover.d.ts +59 -0
  59. package/dist/prover/prover.d.ts.map +1 -0
  60. package/dist/prover/prover.js +274 -0
  61. package/dist/prover/registry.d.ts +39 -0
  62. package/dist/prover/registry.d.ts.map +1 -0
  63. package/dist/prover/registry.js +57 -0
  64. package/dist/schema.d.ts +4 -0
  65. package/dist/schema.d.ts.map +1 -0
  66. package/dist/schema.js +14 -0
  67. package/dist/state/ciphertext-store.d.ts +12 -0
  68. package/dist/state/ciphertext-store.d.ts.map +1 -0
  69. package/dist/state/ciphertext-store.js +25 -0
  70. package/dist/state/index.d.ts +3 -0
  71. package/dist/state/index.d.ts.map +1 -0
  72. package/dist/state/index.js +2 -0
  73. package/dist/state/leaf-store.d.ts +17 -0
  74. package/dist/state/leaf-store.d.ts.map +1 -0
  75. package/dist/state/leaf-store.js +35 -0
  76. package/dist/state/merkle/hydrator.d.ts +27 -0
  77. package/dist/state/merkle/hydrator.d.ts.map +1 -0
  78. package/dist/state/merkle/hydrator.js +36 -0
  79. package/dist/state/merkle/index.d.ts +3 -0
  80. package/dist/state/merkle/index.d.ts.map +1 -0
  81. package/dist/state/merkle/index.js +2 -0
  82. package/dist/state/merkle/merkle-tree.d.ts +34 -0
  83. package/dist/state/merkle/merkle-tree.d.ts.map +1 -0
  84. package/dist/state/merkle/merkle-tree.js +104 -0
  85. package/dist/state/merkle-tree.d.ts +34 -0
  86. package/dist/state/merkle-tree.d.ts.map +1 -0
  87. package/dist/state/merkle-tree.js +104 -0
  88. package/dist/state/note-store.d.ts +37 -0
  89. package/dist/state/note-store.d.ts.map +1 -0
  90. package/dist/state/note-store.js +133 -0
  91. package/dist/state/nullifier-store.d.ts +13 -0
  92. package/dist/state/nullifier-store.d.ts.map +1 -0
  93. package/dist/state/nullifier-store.js +21 -0
  94. package/dist/state/records.d.ts +57 -0
  95. package/dist/state/records.d.ts.map +1 -0
  96. package/dist/state/records.js +1 -0
  97. package/dist/state/root-store.d.ts +13 -0
  98. package/dist/state/root-store.d.ts.map +1 -0
  99. package/dist/state/root-store.js +30 -0
  100. package/dist/state/store/ciphertext-store.d.ts +12 -0
  101. package/dist/state/store/ciphertext-store.d.ts.map +1 -0
  102. package/dist/state/store/ciphertext-store.js +25 -0
  103. package/dist/state/store/index.d.ts +10 -0
  104. package/dist/state/store/index.d.ts.map +1 -0
  105. package/dist/state/store/index.js +8 -0
  106. package/dist/state/store/job-store.d.ts +12 -0
  107. package/dist/state/store/job-store.d.ts.map +1 -0
  108. package/dist/state/store/job-store.js +118 -0
  109. package/dist/state/store/jobs.d.ts +50 -0
  110. package/dist/state/store/jobs.d.ts.map +1 -0
  111. package/dist/state/store/jobs.js +1 -0
  112. package/dist/state/store/leaf-store.d.ts +17 -0
  113. package/dist/state/store/leaf-store.d.ts.map +1 -0
  114. package/dist/state/store/leaf-store.js +35 -0
  115. package/dist/state/store/note-store.d.ts +38 -0
  116. package/dist/state/store/note-store.d.ts.map +1 -0
  117. package/dist/state/store/note-store.js +142 -0
  118. package/dist/state/store/nullifier-store.d.ts +17 -0
  119. package/dist/state/store/nullifier-store.d.ts.map +1 -0
  120. package/dist/state/store/nullifier-store.js +30 -0
  121. package/dist/state/store/records.d.ts +57 -0
  122. package/dist/state/store/records.d.ts.map +1 -0
  123. package/dist/state/store/records.js +1 -0
  124. package/dist/state/store/root-store.d.ts +13 -0
  125. package/dist/state/store/root-store.d.ts.map +1 -0
  126. package/dist/state/store/root-store.js +30 -0
  127. package/dist/state/store/store.d.ts +34 -0
  128. package/dist/state/store/store.d.ts.map +1 -0
  129. package/dist/state/store/store.js +22 -0
  130. package/dist/state/store.d.ts +26 -0
  131. package/dist/state/store.d.ts.map +1 -0
  132. package/dist/state/store.js +19 -0
  133. package/dist/storage/index.d.ts +4 -0
  134. package/dist/storage/index.d.ts.map +1 -0
  135. package/dist/storage/index.js +2 -0
  136. package/dist/storage/indexeddb.d.ts +27 -0
  137. package/dist/storage/indexeddb.d.ts.map +1 -0
  138. package/dist/storage/indexeddb.js +205 -0
  139. package/dist/storage/memory.d.ts +25 -0
  140. package/dist/storage/memory.d.ts.map +1 -0
  141. package/dist/storage/memory.js +87 -0
  142. package/dist/transactions/deposit.d.ts +18 -0
  143. package/dist/transactions/deposit.d.ts.map +1 -0
  144. package/dist/transactions/deposit.js +173 -0
  145. package/dist/transactions/index.d.ts +7 -0
  146. package/dist/transactions/index.d.ts.map +1 -0
  147. package/dist/transactions/index.js +4 -0
  148. package/dist/transactions/note-sync.d.ts +46 -0
  149. package/dist/transactions/note-sync.d.ts.map +1 -0
  150. package/dist/transactions/note-sync.js +320 -0
  151. package/dist/transactions/reconcile.d.ts +22 -0
  152. package/dist/transactions/reconcile.d.ts.map +1 -0
  153. package/dist/transactions/reconcile.js +39 -0
  154. package/dist/transactions/transact.d.ts +34 -0
  155. package/dist/transactions/transact.d.ts.map +1 -0
  156. package/dist/transactions/transact.js +561 -0
  157. package/dist/transactions/types.d.ts +114 -0
  158. package/dist/transactions/types.d.ts.map +1 -0
  159. package/dist/transactions/types.js +1 -0
  160. package/dist/tsconfig.tsbuildinfo +1 -0
  161. package/dist/types.d.ts +27 -0
  162. package/dist/types.d.ts.map +1 -0
  163. package/dist/types.js +1 -0
  164. package/dist/utils/async.d.ts +10 -0
  165. package/dist/utils/async.d.ts.map +1 -0
  166. package/dist/utils/async.js +13 -0
  167. package/dist/utils/bigint.d.ts +9 -0
  168. package/dist/utils/bigint.d.ts.map +1 -0
  169. package/dist/utils/bigint.js +29 -0
  170. package/dist/utils/crypto.d.ts +12 -0
  171. package/dist/utils/crypto.d.ts.map +1 -0
  172. package/dist/utils/crypto.js +39 -0
  173. package/dist/utils/json-codec.d.ts +9 -0
  174. package/dist/utils/json-codec.d.ts.map +1 -0
  175. package/dist/utils/json-codec.js +25 -0
  176. package/dist/utils/polling.d.ts +7 -0
  177. package/dist/utils/polling.d.ts.map +1 -0
  178. package/dist/utils/polling.js +6 -0
  179. package/dist/utils/signature.d.ts +9 -0
  180. package/dist/utils/signature.d.ts.map +1 -0
  181. package/dist/utils/signature.js +12 -0
  182. package/dist/utils/validators.d.ts +30 -0
  183. package/dist/utils/validators.d.ts.map +1 -0
  184. package/dist/utils/validators.js +70 -0
  185. package/package.json +52 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Locally cached metadata for a deposit note we consider owned.
3
+ */
4
+ export type NoteRecord = {
5
+ chainId: number;
6
+ /** Leaf index within the on-chain tree (zero-based, monotonic). */
7
+ index: number;
8
+ /** Canonical asset identifier, typically the ERC-20 address lowercased. */
9
+ token: string;
10
+ /** Amount expressed as an unsigned BigInt serialized to a base-10 string. */
11
+ value: string;
12
+ /** Commitment stored on-chain (Poseidon(note)). */
13
+ commitment: string;
14
+ /** Note public key derived from the master public key. */
15
+ npk: string;
16
+ /**
17
+ * Master public key for the account (Poseidon(spendingPk.public, nullifyingKey)).
18
+ * Acts as the stable account identifier when grouping notes locally.
19
+ */
20
+ mpk: string;
21
+ /** Randomizer used when committing the note. */
22
+ random: string;
23
+ /** Nullifier that will be revealed when the note is spent. */
24
+ nullifier: string;
25
+ /** Optional timestamp when the note was marked as spent. */
26
+ spentAt?: number;
27
+ };
28
+ export type NoteInsert = Omit<NoteRecord, 'spentAt'>;
29
+ /**
30
+ * Details about a nullifier observed on-chain, whether or not we own the note.
31
+ */
32
+ export type NullifierRecord = {
33
+ chainId: number;
34
+ /** Nullifier value (expected to match NoteRecord.nullifier). */
35
+ nullifier: string;
36
+ /** Leaf index of the corresponding note when known. */
37
+ noteIndex?: number;
38
+ };
39
+ /**
40
+ * Public information about a leaf commitment inserted into the pool's tree.
41
+ */
42
+ export type LeafRecord = {
43
+ chainId: number;
44
+ /** Leaf index inside the tree (zero-based). */
45
+ index: number;
46
+ /** Commitment value stored in the tree. */
47
+ commitment: string;
48
+ };
49
+ /**
50
+ * Historical merkle root snapshot used for proof construction.
51
+ */
52
+ export type RootRecord = {
53
+ chainId: number;
54
+ /** Merkle root value committed on-chain. */
55
+ root: string;
56
+ };
57
+ //# sourceMappingURL=records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../state/records.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { Storage } from "../types.js";
2
+ import type { RootRecord } from "./records.js";
3
+ export declare function createRootStore(storage: Storage): {
4
+ /**
5
+ * Persist a historical root snapshot for proof generation.
6
+ */
7
+ putRoot(root: RootRecord): Promise<void>;
8
+ /**
9
+ * Retrieve a root snapshot by Merkle root value.
10
+ */
11
+ getRoot(chainId: number, value: string): Promise<RootRecord | null>;
12
+ };
13
+ //# sourceMappingURL=root-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-store.d.ts","sourceRoot":"","sources":["../../state/root-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO;IAE5C;;OAEG;kBACiB,UAAU;IAU9B;;OAEG;qBACoB,MAAM,SAAS,MAAM;EAQ/C"}
@@ -0,0 +1,30 @@
1
+ import { CoreError } from "../errors.js";
2
+ import { keys, validateKey } from "../keys.js";
3
+ import { getJson, putJson } from "../utils/json-codec.js";
4
+ import { ensureChainId } from "../utils/validators.js";
5
+ export function createRootStore(storage) {
6
+ return {
7
+ /**
8
+ * Persist a historical root snapshot for proof generation.
9
+ */
10
+ async putRoot(root) {
11
+ ensureChainId(root.chainId);
12
+ if (typeof root.root !== "string" || root.root.length === 0) {
13
+ throw new CoreError("root value must be a non-empty string");
14
+ }
15
+ const key = keys.root(root.chainId, root.root);
16
+ validateKey(key);
17
+ await putJson(storage, key, root);
18
+ },
19
+ /**
20
+ * Retrieve a root snapshot by Merkle root value.
21
+ */
22
+ async getRoot(chainId, value) {
23
+ ensureChainId(chainId);
24
+ if (typeof value !== "string" || value.length === 0) {
25
+ throw new CoreError("root value must be a non-empty string");
26
+ }
27
+ return getJson(storage, keys.root(chainId, value));
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,12 @@
1
+ import type { Storage } from "../../types.js";
2
+ export declare function createCiphertextStore(storage: Storage): {
3
+ /**
4
+ * Store encrypted note payloads alongside their on-chain commitments.
5
+ */
6
+ putCiphertext(chainId: number, index: number, payload: Uint8Array): Promise<void>;
7
+ /**
8
+ * Retrieve encrypted note payloads; returns null when the ciphertext is missing.
9
+ */
10
+ getCiphertext(chainId: number, index: number): Promise<Uint8Array<ArrayBuffer> | null>;
11
+ };
12
+ //# sourceMappingURL=ciphertext-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ciphertext-store.d.ts","sourceRoot":"","sources":["../../../state/store/ciphertext-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO;IAElD;;OAEG;2BAC0B,MAAM,SAAS,MAAM,WAAW,UAAU;IAQvE;;OAEG;2BAC0B,MAAM,SAAS,MAAM;EAOrD"}
@@ -0,0 +1,25 @@
1
+ import { keys, validateKey } from "../../keys.js";
2
+ import { ensureChainId, ensurePositiveInt } from "../../utils/validators.js";
3
+ export function createCiphertextStore(storage) {
4
+ return {
5
+ /**
6
+ * Store encrypted note payloads alongside their on-chain commitments.
7
+ */
8
+ async putCiphertext(chainId, index, payload) {
9
+ ensureChainId(chainId);
10
+ ensurePositiveInt("ciphertext index", index);
11
+ const key = keys.ciphertext(chainId, index);
12
+ validateKey(key);
13
+ await storage.put(key, new Uint8Array(payload));
14
+ },
15
+ /**
16
+ * Retrieve encrypted note payloads; returns null when the ciphertext is missing.
17
+ */
18
+ async getCiphertext(chainId, index) {
19
+ ensureChainId(chainId);
20
+ ensurePositiveInt("ciphertext index", index);
21
+ const data = await storage.get(keys.ciphertext(chainId, index));
22
+ return data ? new Uint8Array(data) : null;
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,10 @@
1
+ export { createStateStore } from "./store.js";
2
+ export { createLeafStore } from "./leaf-store.js";
3
+ export { createNoteStore } from "./note-store.js";
4
+ export { createNullifierStore } from "./nullifier-store.js";
5
+ export { createRootStore } from "./root-store.js";
6
+ export { createCiphertextStore } from "./ciphertext-store.js";
7
+ export { createJobStore } from "./job-store.js";
8
+ export { DEFAULT_JOB_TIMEOUT_MS, type JobStatus, type PendingJobKind, type PendingJobRecord, type PendingDepositJob, type PendingTransactJob, type PendingTransactContext, type PendingTransactOutput, } from "./jobs.js";
9
+ export type { LeafRecord, NoteInsert, NoteRecord, NullifierRecord, RootRecord, } from "./records.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../state/store/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EACL,sBAAsB,EACtB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,eAAe,EACf,UAAU,GACX,MAAM,cAAc,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { createStateStore } from "./store.js";
2
+ export { createLeafStore } from "./leaf-store.js";
3
+ export { createNoteStore } from "./note-store.js";
4
+ export { createNullifierStore } from "./nullifier-store.js";
5
+ export { createRootStore } from "./root-store.js";
6
+ export { createCiphertextStore } from "./ciphertext-store.js";
7
+ export { createJobStore } from "./job-store.js";
8
+ export { DEFAULT_JOB_TIMEOUT_MS, } from "./jobs.js";
@@ -0,0 +1,12 @@
1
+ import type { Storage } from "../../types.js";
2
+ import type { JobStatus, PendingJobKind, PendingJobRecord } from "../store/jobs.js";
3
+ export declare function createJobStore(storage: Storage): {
4
+ putPendingJob(job: PendingJobRecord): Promise<void>;
5
+ getPendingJob(relayId: string): Promise<PendingJobRecord | null>;
6
+ listPendingJobs(filter?: {
7
+ kind?: PendingJobKind;
8
+ statuses?: JobStatus[];
9
+ }): Promise<PendingJobRecord[]>;
10
+ deletePendingJob(relayId: string): Promise<void>;
11
+ };
12
+ //# sourceMappingURL=job-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-store.d.ts","sourceRoot":"","sources":["../../../state/store/job-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAO9C,OAAO,KAAK,EACV,SAAS,EAET,cAAc,EACd,gBAAgB,EAGjB,MAAM,kBAAkB,CAAC;AA4G1B,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO;uBAElB,gBAAgB;2BASZ,MAAM;6BAKzB;QACN,IAAI,CAAC,EAAE,cAAc,CAAC;QACtB,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;KACxB;8BAe6B,MAAM;EAIzC"}
@@ -0,0 +1,118 @@
1
+ import { keys } from "../../keys.js";
2
+ import { decodeJson, encodeJson, getJson } from "../../utils/json-codec.js";
3
+ import { ensureAddress, ensureChainId, ensurePositiveInt, } from "../../utils/validators.js";
4
+ import { DEFAULT_JOB_TIMEOUT_MS } from "../store/jobs.js";
5
+ const VALID_STATUSES = [
6
+ "pending",
7
+ "submitted",
8
+ "broadcasting",
9
+ "succeeded",
10
+ "failed",
11
+ "dead",
12
+ ];
13
+ function assertStatus(status) {
14
+ if (!VALID_STATUSES.includes(status)) {
15
+ throw new Error(`invalid job status: ${status}`);
16
+ }
17
+ }
18
+ function assertKind(kind) {
19
+ if (kind !== "deposit" && kind !== "transact") {
20
+ throw new Error(`invalid job kind: ${kind}`);
21
+ }
22
+ }
23
+ function normalizeTimestamps(job) {
24
+ const createdAt = typeof job.createdAt === "number" && Number.isFinite(job.createdAt)
25
+ ? job.createdAt
26
+ : Date.now();
27
+ const timeoutMs = typeof job.timeoutMs === "number" && job.timeoutMs > 0
28
+ ? job.timeoutMs
29
+ : DEFAULT_JOB_TIMEOUT_MS;
30
+ return {
31
+ ...job,
32
+ createdAt,
33
+ timeoutMs,
34
+ };
35
+ }
36
+ function validateTransactContext(context) {
37
+ ensurePositiveInt("context index", context.index);
38
+ if (!context.nullifier) {
39
+ throw new Error("context nullifier is required");
40
+ }
41
+ const { witness } = context;
42
+ if (!witness) {
43
+ throw new Error("context witness is required");
44
+ }
45
+ ensurePositiveInt("witness leafIndex", witness.leafIndex);
46
+ if (!Array.isArray(witness.pathElements) ||
47
+ !Array.isArray(witness.pathIndices)) {
48
+ throw new Error("witness pathElements and pathIndices are required");
49
+ }
50
+ }
51
+ function validateTransactJob(job) {
52
+ ensureAddress("pool address", job.poolAddress);
53
+ if (!job.calldata) {
54
+ throw new Error("calldata is required for transact job");
55
+ }
56
+ job.contexts.forEach(validateTransactContext);
57
+ job.predictedOutputs.forEach((output) => {
58
+ if (!output.hex) {
59
+ throw new Error("predicted output hex is required");
60
+ }
61
+ ensurePositiveInt("predicted output index", output.index);
62
+ });
63
+ }
64
+ function validateDepositJob(job) {
65
+ if (!job.predictedCommitment?.hex) {
66
+ throw new Error("predicted commitment hex is required");
67
+ }
68
+ if (job.predictedCommitment.index !== undefined) {
69
+ ensurePositiveInt("predicted commitment index", job.predictedCommitment.index);
70
+ }
71
+ }
72
+ function validateJob(job) {
73
+ if (!job.relayId) {
74
+ throw new Error("relayId is required");
75
+ }
76
+ ensureChainId(job.chainId);
77
+ assertStatus(job.status);
78
+ assertKind(job.kind);
79
+ ensurePositiveInt("job createdAt", job.createdAt);
80
+ ensurePositiveInt("job timeoutMs", job.timeoutMs);
81
+ if (job.lastCheckedAt !== undefined) {
82
+ ensurePositiveInt("job lastCheckedAt", job.lastCheckedAt);
83
+ }
84
+ if (job.kind === "deposit") {
85
+ validateDepositJob(job);
86
+ }
87
+ else {
88
+ validateTransactJob(job);
89
+ }
90
+ }
91
+ function buildJobKey(relayId) {
92
+ return keys.job(relayId);
93
+ }
94
+ export function createJobStore(storage) {
95
+ return {
96
+ async putPendingJob(job) {
97
+ const normalized = normalizeTimestamps(job);
98
+ validateJob(normalized);
99
+ await storage.put(buildJobKey(normalized.relayId), encodeJson(normalized));
100
+ },
101
+ async getPendingJob(relayId) {
102
+ return getJson(storage, buildJobKey(relayId));
103
+ },
104
+ async listPendingJobs(filter = {}) {
105
+ const entries = await storage.iter({ prefix: "jobs:" });
106
+ const statuses = filter.statuses ?? VALID_STATUSES;
107
+ const filtered = entries
108
+ .map(({ value }) => decodeJson(value))
109
+ .filter((job) => (filter.kind === undefined || job.kind === filter.kind) &&
110
+ statuses.includes(job.status));
111
+ filtered.sort((a, b) => a.createdAt - b.createdAt);
112
+ return filtered;
113
+ },
114
+ async deletePendingJob(relayId) {
115
+ await storage.delete(buildJobKey(relayId));
116
+ },
117
+ };
118
+ }
@@ -0,0 +1,50 @@
1
+ export type JobStatus = "pending" | "submitted" | "broadcasting" | "succeeded" | "failed" | "dead";
2
+ export type PendingJobKind = "deposit" | "transact";
3
+ export type PendingJobBase = {
4
+ relayId: string;
5
+ kind: PendingJobKind;
6
+ chainId: number;
7
+ status: JobStatus;
8
+ broadcasterRelayId?: string | null;
9
+ txHash?: string | null;
10
+ createdAt: number;
11
+ lastCheckedAt?: number;
12
+ timeoutMs: number;
13
+ error?: string | null;
14
+ };
15
+ export type PendingDepositJob = PendingJobBase & {
16
+ kind: "deposit";
17
+ predictedCommitment: {
18
+ hex: string;
19
+ index?: number;
20
+ root?: string;
21
+ };
22
+ };
23
+ export type PendingTransactContext = {
24
+ index: number;
25
+ nullifier: string;
26
+ witness: {
27
+ root: string;
28
+ leaf: string;
29
+ pathElements: string[][];
30
+ pathIndices: number[];
31
+ leafIndex: number;
32
+ };
33
+ root: string;
34
+ };
35
+ export type PendingTransactOutput = {
36
+ hex: string;
37
+ index: number;
38
+ root?: string;
39
+ };
40
+ export type PendingTransactJob = PendingJobBase & {
41
+ kind: "transact";
42
+ poolAddress: string;
43
+ calldata: string;
44
+ contexts: PendingTransactContext[];
45
+ predictedOutputs: PendingTransactOutput[];
46
+ expectedRoot?: string;
47
+ };
48
+ export type PendingJobRecord = PendingDepositJob | PendingTransactJob;
49
+ export declare const DEFAULT_JOB_TIMEOUT_MS: number;
50
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../../../state/store/jobs.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,WAAW,GACX,cAAc,GACd,WAAW,GACX,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,CAAC;AAEpD,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG;IAC/C,IAAI,EAAE,SAAS,CAAC;IAChB,mBAAmB,EAAE;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAElB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC;QACzB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG;IAChD,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,gBAAgB,EAAE,qBAAqB,EAAE,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAEtE,eAAO,MAAM,sBAAsB,QAAgB,CAAC"}
@@ -0,0 +1 @@
1
+ export const DEFAULT_JOB_TIMEOUT_MS = 5 * 60 * 1000;
@@ -0,0 +1,17 @@
1
+ import type { Storage } from "../../types.js";
2
+ import type { LeafRecord } from "../store/records.js";
3
+ export declare function createLeafStore(storage: Storage): {
4
+ /**
5
+ * Cache public leaf data pulled from the on-chain Merkle tree.
6
+ */
7
+ putLeaf(leaf: LeafRecord): Promise<void>;
8
+ /**
9
+ * Load a leaf commitment by tree index.
10
+ */
11
+ getLeaf(chainId: number, index: number): Promise<LeafRecord | null>;
12
+ /**
13
+ * Remove all cached leaves for a chain.
14
+ */
15
+ clearLeaves(chainId: number): Promise<void>;
16
+ };
17
+ //# sourceMappingURL=leaf-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaf-store.d.ts","sourceRoot":"","sources":["../../../state/store/leaf-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO;IAE5C;;OAEG;kBACiB,UAAU;IAM9B;;OAEG;qBACoB,MAAM,SAAS,MAAM;IAM5C;;OAEG;yBACwB,MAAM;EASpC"}
@@ -0,0 +1,35 @@
1
+ import { keys } from "../../keys.js";
2
+ import { getJson, putJson } from "../../utils/json-codec.js";
3
+ import { ensureChainId, ensurePositiveInt } from "../../utils/validators.js";
4
+ export function createLeafStore(storage) {
5
+ return {
6
+ /**
7
+ * Cache public leaf data pulled from the on-chain Merkle tree.
8
+ */
9
+ async putLeaf(leaf) {
10
+ ensureChainId(leaf.chainId);
11
+ ensurePositiveInt("leaf index", leaf.index);
12
+ await putJson(storage, keys.leaf(leaf.chainId, leaf.index), leaf);
13
+ },
14
+ /**
15
+ * Load a leaf commitment by tree index.
16
+ */
17
+ async getLeaf(chainId, index) {
18
+ ensureChainId(chainId);
19
+ ensurePositiveInt("leaf index", index);
20
+ return getJson(storage, keys.leaf(chainId, index));
21
+ },
22
+ /**
23
+ * Remove all cached leaves for a chain.
24
+ */
25
+ async clearLeaves(chainId) {
26
+ ensureChainId(chainId);
27
+ const prefix = `leaves:${chainId}:`;
28
+ const entries = await storage.iter({ prefix });
29
+ if (entries.length === 0)
30
+ return;
31
+ const deletions = entries.map(({ key }) => ({ del: key }));
32
+ await storage.batch(deletions);
33
+ },
34
+ };
35
+ }
@@ -0,0 +1,38 @@
1
+ import type { Storage } from "../../types.js";
2
+ import type { NoteInsert, NoteRecord } from "../store/records.js";
3
+ export declare const emptyBytes: () => Uint8Array<ArrayBuffer>;
4
+ export declare function createNoteStore(storage: Storage): {
5
+ /**
6
+ * Upsert a note record and maintain the unspent-note index for fast balance queries.
7
+ * If the note already exists and is marked as spent, preserve the spentAt field.
8
+ */
9
+ putNote(note: NoteInsert): Promise<void>;
10
+ /**
11
+ * Fetch a note by (chainId, index) if it exists in local storage.
12
+ */
13
+ getNote(chainId: number, index: number): Promise<NoteRecord | null>;
14
+ /**
15
+ * List notes matching optional filters (by chainId, mpk) and spent state.
16
+ */
17
+ listNotes(options?: {
18
+ chainId?: number;
19
+ mpk?: string;
20
+ token?: string;
21
+ includeSpent?: boolean;
22
+ }): Promise<NoteRecord[]>;
23
+ /**
24
+ * Mark a cached note as spent by setting its timestamp and re-indexing metadata.
25
+ */
26
+ markNoteSpent(chainId: number, index: number, spentAt?: number): Promise<NoteRecord>;
27
+ /**
28
+ * Drop the spent marker from a cached note, returning it to the unspent index.
29
+ */
30
+ markNoteUnspent(chainId: number, index: number): Promise<NoteRecord>;
31
+ /**
32
+ * Aggregate unspent note balances per token for a given master public key.
33
+ */
34
+ getZkBalances(mpk: string, options?: {
35
+ chainId?: number;
36
+ }): Promise<Record<string, bigint>>;
37
+ };
38
+ //# sourceMappingURL=note-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-store.d.ts","sourceRoot":"","sources":["../../../state/store/note-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAavD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAElE,eAAO,MAAM,UAAU,+BAA0B,CAAC;AAElD,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO;IAyC5C;;;OAGG;kBACiB,UAAU;IAW9B;;OAEG;qBACoB,MAAM,SAAS,MAAM;IAM5C;;OAEG;wBAEQ;QACP,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB;IAyBH;;OAEG;2BAC0B,MAAM,SAAS,MAAM;IAgBlD;;OAEG;6BAC4B,MAAM,SAAS,MAAM;IAgBpD;;OAEG;uBACsB,MAAM,YAAW;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;EAiBjE"}
@@ -0,0 +1,142 @@
1
+ import { CoreError } from "../../errors.js";
2
+ import { keys } from "../../keys.js";
3
+ import { decodeJson, encodeJson, getJson, } from "../../utils/json-codec.js";
4
+ import { ensureBigIntString, ensureChainId, ensureMpk, ensurePositiveInt, } from "../../utils/validators.js";
5
+ export const emptyBytes = () => new Uint8Array(0);
6
+ export function createNoteStore(storage) {
7
+ const persistNote = async (record) => {
8
+ ensureChainId(record.chainId);
9
+ ensurePositiveInt("note index", record.index);
10
+ ensureMpk(record.mpk);
11
+ ensureBigIntString("note value", record.value);
12
+ if (record.spentAt !== undefined) {
13
+ ensurePositiveInt("note spentAt", record.spentAt);
14
+ }
15
+ const noteKey = keys.note(record.chainId, record.index);
16
+ const previous = await getJson(storage, noteKey);
17
+ const ops = [
18
+ { put: [noteKey, encodeJson(record)] },
19
+ ];
20
+ if (previous && previous.spentAt === undefined) {
21
+ ops.push({
22
+ del: keys.unspent(previous.chainId, previous.mpk, previous.index),
23
+ });
24
+ }
25
+ if (record.spentAt === undefined) {
26
+ // idx:notes:unspent functions as a set, so we only persist the sentinel bytes.
27
+ ops.push({
28
+ put: [
29
+ keys.unspent(record.chainId, record.mpk, record.index),
30
+ emptyBytes(),
31
+ ],
32
+ });
33
+ }
34
+ else {
35
+ ops.push({
36
+ del: keys.unspent(record.chainId, record.mpk, record.index),
37
+ });
38
+ }
39
+ await storage.batch(ops);
40
+ };
41
+ const store = {
42
+ /**
43
+ * Upsert a note record and maintain the unspent-note index for fast balance queries.
44
+ * If the note already exists and is marked as spent, preserve the spentAt field.
45
+ */
46
+ async putNote(note) {
47
+ const noteKey = keys.note(note.chainId, note.index);
48
+ const existing = await getJson(storage, noteKey);
49
+ if (existing?.spentAt !== undefined) {
50
+ // Preserve spentAt if note was already marked as spent
51
+ await persistNote({ ...note, spentAt: existing.spentAt });
52
+ }
53
+ else {
54
+ await persistNote({ ...note });
55
+ }
56
+ },
57
+ /**
58
+ * Fetch a note by (chainId, index) if it exists in local storage.
59
+ */
60
+ async getNote(chainId, index) {
61
+ ensureChainId(chainId);
62
+ ensurePositiveInt("note index", index);
63
+ return getJson(storage, keys.note(chainId, index));
64
+ },
65
+ /**
66
+ * List notes matching optional filters (by chainId, mpk) and spent state.
67
+ */
68
+ async listNotes(options = {}) {
69
+ const { chainId, mpk, token, includeSpent = true } = options;
70
+ if (chainId !== undefined) {
71
+ ensureChainId(chainId);
72
+ }
73
+ if (mpk !== undefined) {
74
+ ensureMpk(mpk);
75
+ }
76
+ const prefix = chainId !== undefined ? `notes:${chainId}:` : "notes:";
77
+ const entries = await storage.iter({ prefix });
78
+ const filtered = entries
79
+ .map(({ value }) => decodeJson(value))
80
+ .filter((note) => (chainId === undefined || note.chainId === chainId) &&
81
+ (mpk === undefined || note.mpk === mpk) &&
82
+ (token === undefined || note.token === token) &&
83
+ (includeSpent || note.spentAt === undefined));
84
+ filtered.sort((a, b) => a.index - b.index);
85
+ return filtered;
86
+ },
87
+ /**
88
+ * Mark a cached note as spent by setting its timestamp and re-indexing metadata.
89
+ */
90
+ async markNoteSpent(chainId, index, spentAt = Date.now()) {
91
+ ensureChainId(chainId);
92
+ ensurePositiveInt("note index", index);
93
+ ensurePositiveInt("note spentAt", spentAt);
94
+ const existing = await store.getNote(chainId, index);
95
+ if (!existing) {
96
+ throw new CoreError("note not found");
97
+ }
98
+ if (existing.spentAt === spentAt) {
99
+ return existing;
100
+ }
101
+ const updated = { ...existing, spentAt };
102
+ await persistNote(updated);
103
+ return updated;
104
+ },
105
+ /**
106
+ * Drop the spent marker from a cached note, returning it to the unspent index.
107
+ */
108
+ async markNoteUnspent(chainId, index) {
109
+ ensureChainId(chainId);
110
+ ensurePositiveInt("note index", index);
111
+ const existing = await store.getNote(chainId, index);
112
+ if (!existing) {
113
+ throw new CoreError("note not found");
114
+ }
115
+ if (existing.spentAt === undefined) {
116
+ return existing;
117
+ }
118
+ const updated = { ...existing };
119
+ delete updated.spentAt;
120
+ await persistNote(updated);
121
+ return updated;
122
+ },
123
+ /**
124
+ * Aggregate unspent note balances per token for a given master public key.
125
+ */
126
+ async getZkBalances(mpk, options = {}) {
127
+ ensureMpk(mpk);
128
+ const notes = await store.listNotes({
129
+ chainId: options.chainId,
130
+ mpk,
131
+ includeSpent: false,
132
+ });
133
+ const totals = {};
134
+ for (const note of notes) {
135
+ const amount = BigInt(note.value);
136
+ totals[note.token] = (totals[note.token] ?? 0n) + amount;
137
+ }
138
+ return totals;
139
+ },
140
+ };
141
+ return store;
142
+ }
@@ -0,0 +1,17 @@
1
+ import type { Storage } from "../../types.js";
2
+ import type { NullifierRecord } from "../store/records.js";
3
+ export declare function createNullifierStore(storage: Storage): {
4
+ /**
5
+ * Record a nullifier observation so later syncs can de-duplicate work.
6
+ */
7
+ putNullifier(nullifier: NullifierRecord): Promise<void>;
8
+ /**
9
+ * Lookup a previously observed nullifier by value.
10
+ */
11
+ getNullifier(chainId: number, value: string): Promise<NullifierRecord | null>;
12
+ /**
13
+ * Count all nullifiers stored locally for a given chain.
14
+ */
15
+ countNullifiers(chainId: number): Promise<number>;
16
+ };
17
+ //# sourceMappingURL=nullifier-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nullifier-store.d.ts","sourceRoot":"","sources":["../../../state/store/nullifier-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO;IAEjD;;OAEG;4BAC2B,eAAe;IAS7C;;OAEG;0BACyB,MAAM,SAAS,MAAM;IAKjD;;OAEG;6BAC4B,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;EAO1D"}