@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,2 @@
1
+ export * from "./merkle/index.js";
2
+ export * from "./store/index.js";
@@ -0,0 +1,17 @@
1
+ import type { Storage } from "../types.js";
2
+ import type { LeafRecord } from "./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/leaf-store.ts"],"names":[],"mappings":"AACA,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;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,27 @@
1
+ export type LeafLoader = (chainId: number, index: number) => Promise<{
2
+ commitment: string;
3
+ } | null>;
4
+ export declare function rebuildTreeFromStore({ chainId, trees, loadLeaf, }: {
5
+ chainId: number;
6
+ trees: {
7
+ reset(chainId: number): void;
8
+ addLeaf(chainId: number, value: bigint): {
9
+ index: number;
10
+ };
11
+ getLeafCount?(chainId: number): number;
12
+ };
13
+ loadLeaf: LeafLoader;
14
+ }): Promise<number>;
15
+ export type HydrateChainParams = {
16
+ chainId: number;
17
+ trees: {
18
+ reset(chainId: number): void;
19
+ addLeaf(chainId: number, value: bigint): {
20
+ index: number;
21
+ };
22
+ };
23
+ loadLeaf: LeafLoader;
24
+ hydrated: Set<number>;
25
+ };
26
+ export declare function hydrateChain({ chainId, trees, loadLeaf, hydrated, }: HydrateChainParams): Promise<void>;
27
+ //# sourceMappingURL=hydrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrator.d.ts","sourceRoot":"","sources":["../../../state/merkle/hydrator.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,CACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,KACV,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AAE5C,wBAAsB,oBAAoB,CAAC,EACzC,OAAO,EACP,KAAK,EACL,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3D,YAAY,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;KACxC,CAAC;IACF,QAAQ,EAAE,UAAU,CAAC;CACtB,mBAeA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAC5D,CAAC;IACF,QAAQ,EAAE,UAAU,CAAC;IACrB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACvB,CAAC;AAKF,wBAAsB,YAAY,CAAC,EACjC,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,iBAcpB"}
@@ -0,0 +1,36 @@
1
+ import { parseHexToBigInt } from "../../utils/bigint.js";
2
+ export async function rebuildTreeFromStore({ chainId, trees, loadLeaf, }) {
3
+ trees.reset(chainId);
4
+ let idx = 0;
5
+ for (;;) {
6
+ const leaf = await loadLeaf(chainId, idx);
7
+ if (!leaf)
8
+ break;
9
+ const { index } = trees.addLeaf(chainId, parseHexToBigInt(leaf.commitment));
10
+ if (index !== idx) {
11
+ throw new Error(`stored leaves are inconsistent with local tree, expected ${idx}, got ${index}`);
12
+ }
13
+ idx += 1;
14
+ }
15
+ return idx;
16
+ }
17
+ // TODO: Will be used for inmemory merkle tree handling for caching.
18
+ // Atm everytime we need to access the tree we have to rebuild it from the store.
19
+ // This function will help to avoid multiple rebuilds for the same chain
20
+ export async function hydrateChain({ chainId, trees, loadLeaf, hydrated, }) {
21
+ if (hydrated.has(chainId))
22
+ return;
23
+ trees.reset(chainId);
24
+ let idx = 0;
25
+ for (;;) {
26
+ const leaf = await loadLeaf(chainId, idx);
27
+ if (!leaf)
28
+ break;
29
+ const { index } = trees.addLeaf(chainId, parseHexToBigInt(leaf.commitment));
30
+ if (index !== idx) {
31
+ throw new Error("stored leaves are inconsistent with local tree");
32
+ }
33
+ idx += 1;
34
+ }
35
+ hydrated.add(chainId);
36
+ }
@@ -0,0 +1,3 @@
1
+ export { createLocalMerkleTree, createMerkleTrees, type LocalMerkleTree, type LocalMerkleTrees, type MerkleProof, } from "./merkle-tree.js";
2
+ export { hydrateChain, rebuildTreeFromStore, type HydrateChainParams, } from "./hydrator.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../state/merkle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createLocalMerkleTree, createMerkleTrees, } from "./merkle-tree.js";
2
+ export { hydrateChain, rebuildTreeFromStore, } from "./hydrator.js";
@@ -0,0 +1,34 @@
1
+ import { IMTMerkleProof } from "@zk-kit/imt";
2
+ export type AddLeafResult = {
3
+ index: number;
4
+ root: string;
5
+ };
6
+ export type MerkleProof = {
7
+ root: string;
8
+ leaf: string;
9
+ pathElements: string[][];
10
+ pathIndices: number[];
11
+ leafIndex: number;
12
+ };
13
+ export declare function createLocalMerkleTree(): {
14
+ addLeaf: (value: bigint) => AddLeafResult;
15
+ getRoot: () => string;
16
+ getLeafCount: () => number;
17
+ getLeaf: (index: number) => string;
18
+ createMerkleProof: (index: number) => IMTMerkleProof;
19
+ getZero(level: number): string;
20
+ readonly depth: number;
21
+ readonly capacity: number;
22
+ };
23
+ export type LocalMerkleTree = ReturnType<typeof createLocalMerkleTree>;
24
+ export type LocalMerkleTrees = {
25
+ get(chainId: number): LocalMerkleTree | undefined;
26
+ getOrCreate(chainId: number): LocalMerkleTree;
27
+ addLeaf(chainId: number, value: bigint): AddLeafResult;
28
+ createMerkleProof(chainId: number, index: number): IMTMerkleProof;
29
+ getRoot(chainId: number): string;
30
+ getLeafCount(chainId: number): number;
31
+ reset(chainId: number): void;
32
+ };
33
+ export declare function createMerkleTrees(): LocalMerkleTrees;
34
+ //# sourceMappingURL=merkle-tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle-tree.d.ts","sourceRoot":"","sources":["../../../state/merkle/merkle-tree.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,cAAc,EAGf,MAAM,aAAa,CAAC;AAWrB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAaF,wBAAgB,qBAAqB;qBAUX,MAAM,KAAG,aAAa;;;qBAsBtB,MAAM;+BAQI,MAAM,KAAG,cAAc;mBAUxC,MAAM;;;EAiBxB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEvE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAClD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC;IAC9C,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC;IACvD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAAC;IAClE,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,gBAAgB,CAwCpD"}
@@ -0,0 +1,104 @@
1
+ import { poseidon } from "@railgun-community/circomlibjs";
2
+ import { IMT, } from "@zk-kit/imt";
3
+ import { ByteLength, ByteUtils } from "../../key-derivation/bytes.js";
4
+ import { ensureChainId } from "../../utils/validators.js";
5
+ const DEFAULT_DEPTH = 16;
6
+ const DEFAULT_ARITY = 2;
7
+ const ZERO_BYTE_LENGTH = ByteLength.UINT_256;
8
+ // Simple adapter: IMTNode[] -> poseidon(bigint[])
9
+ const hash = (values) => poseidon(values.map((v) => BigInt(v)));
10
+ const formatNode = (value) => ByteUtils.nToHex(value, ZERO_BYTE_LENGTH, true);
11
+ export function createLocalMerkleTree() {
12
+ const zeroLeaf = 0n;
13
+ const capacity = 2 ** DEFAULT_DEPTH;
14
+ const tree = new IMT(hash, DEFAULT_DEPTH, zeroLeaf, DEFAULT_ARITY);
15
+ function addLeaf(value) {
16
+ if (tree.leaves.length >= capacity) {
17
+ throw new Error("merkle tree is full");
18
+ }
19
+ const insertedIndex = tree.leaves.length;
20
+ tree.insert(value);
21
+ return {
22
+ index: insertedIndex,
23
+ root: formatNode(tree.root),
24
+ };
25
+ }
26
+ function getRoot() {
27
+ return formatNode(tree.root);
28
+ }
29
+ function getLeafCount() {
30
+ return tree.leaves.length;
31
+ }
32
+ function getLeaf(index) {
33
+ const leaf = tree.leaves[index];
34
+ if (leaf === undefined) {
35
+ throw new Error("leaf does not exist in this tree");
36
+ }
37
+ return formatNode(BigInt(leaf));
38
+ }
39
+ function createMerkleProof(index) {
40
+ return tree.createProof(index);
41
+ }
42
+ return {
43
+ addLeaf,
44
+ getRoot,
45
+ getLeafCount,
46
+ getLeaf,
47
+ createMerkleProof,
48
+ getZero(level) {
49
+ if (level === tree.depth) {
50
+ return getRoot();
51
+ }
52
+ const zero = tree.zeroes[level];
53
+ if (zero === undefined) {
54
+ throw new Error("invalid level");
55
+ }
56
+ return formatNode(zero);
57
+ },
58
+ get depth() {
59
+ return tree.depth;
60
+ },
61
+ get capacity() {
62
+ return capacity;
63
+ },
64
+ };
65
+ }
66
+ export function createMerkleTrees() {
67
+ const trees = new Map();
68
+ const resetTree = (chainId) => {
69
+ ensureChainId(chainId);
70
+ const tree = createLocalMerkleTree();
71
+ trees.set(chainId, tree);
72
+ return tree;
73
+ };
74
+ const getOrCreate = (chainId) => {
75
+ ensureChainId(chainId);
76
+ let tree = trees.get(chainId);
77
+ if (!tree) {
78
+ tree = resetTree(chainId);
79
+ }
80
+ return tree;
81
+ };
82
+ return {
83
+ get(chainId) {
84
+ ensureChainId(chainId);
85
+ return trees.get(chainId);
86
+ },
87
+ getOrCreate,
88
+ addLeaf(chainId, value) {
89
+ return getOrCreate(chainId).addLeaf(value);
90
+ },
91
+ createMerkleProof(chainId, index) {
92
+ return getOrCreate(chainId).createMerkleProof(index);
93
+ },
94
+ getRoot(chainId) {
95
+ return getOrCreate(chainId).getRoot();
96
+ },
97
+ getLeafCount(chainId) {
98
+ return getOrCreate(chainId).getLeafCount();
99
+ },
100
+ reset(chainId) {
101
+ resetTree(chainId);
102
+ },
103
+ };
104
+ }
@@ -0,0 +1,34 @@
1
+ import { IMTMerkleProof } from "@zk-kit/imt";
2
+ export type AddLeafResult = {
3
+ index: number;
4
+ root: string;
5
+ };
6
+ export type MerkleProof = {
7
+ root: string;
8
+ leaf: string;
9
+ pathElements: string[][];
10
+ pathIndices: number[];
11
+ leafIndex: number;
12
+ };
13
+ export declare function createLocalMerkleTree(): {
14
+ addLeaf: (value: bigint) => AddLeafResult;
15
+ getRoot: () => string;
16
+ getLeafCount: () => number;
17
+ getLeaf: (index: number) => string;
18
+ createMerkleProof: (index: number) => IMTMerkleProof;
19
+ getZero(level: number): string;
20
+ readonly depth: number;
21
+ readonly capacity: number;
22
+ };
23
+ export type LocalMerkleTree = ReturnType<typeof createLocalMerkleTree>;
24
+ export type LocalMerkleTrees = {
25
+ get(chainId: number): LocalMerkleTree | undefined;
26
+ getOrCreate(chainId: number): LocalMerkleTree;
27
+ addLeaf(chainId: number, value: bigint): AddLeafResult;
28
+ createMerkleProof(chainId: number, index: number): IMTMerkleProof;
29
+ getRoot(chainId: number): string;
30
+ getLeafCount(chainId: number): number;
31
+ reset(chainId: number): void;
32
+ };
33
+ export declare function createMerkleTrees(): LocalMerkleTrees;
34
+ //# sourceMappingURL=merkle-tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle-tree.d.ts","sourceRoot":"","sources":["../../state/merkle-tree.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,cAAc,EAGf,MAAM,aAAa,CAAC;AAWrB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAaF,wBAAgB,qBAAqB;qBAUX,MAAM,KAAG,aAAa;;;qBAsBtB,MAAM;+BAQI,MAAM,KAAG,cAAc;mBAUxC,MAAM;;;EAiBxB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEvE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAClD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC;IAC9C,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC;IACvD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAAC;IAClE,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,gBAAgB,CAwCpD"}
@@ -0,0 +1,104 @@
1
+ import { poseidon } from "@railgun-community/circomlibjs";
2
+ import { IMT, } from "@zk-kit/imt";
3
+ import { ByteLength, ByteUtils } from "../key-derivation/bytes.js";
4
+ import { ensureChainId } from "../utils/validators.js";
5
+ const DEFAULT_DEPTH = 16;
6
+ const DEFAULT_ARITY = 2;
7
+ const ZERO_BYTE_LENGTH = ByteLength.UINT_256;
8
+ // Simple adapter: IMTNode[] -> poseidon(bigint[])
9
+ const hash = (values) => poseidon(values.map((v) => BigInt(v)));
10
+ const formatNode = (value) => ByteUtils.nToHex(value, ZERO_BYTE_LENGTH, true);
11
+ export function createLocalMerkleTree() {
12
+ const zeroLeaf = 0n;
13
+ const capacity = 2 ** DEFAULT_DEPTH;
14
+ const tree = new IMT(hash, DEFAULT_DEPTH, zeroLeaf, DEFAULT_ARITY);
15
+ function addLeaf(value) {
16
+ if (tree.leaves.length >= capacity) {
17
+ throw new Error("merkle tree is full");
18
+ }
19
+ const insertedIndex = tree.leaves.length;
20
+ tree.insert(value);
21
+ return {
22
+ index: insertedIndex,
23
+ root: formatNode(tree.root),
24
+ };
25
+ }
26
+ function getRoot() {
27
+ return formatNode(tree.root);
28
+ }
29
+ function getLeafCount() {
30
+ return tree.leaves.length;
31
+ }
32
+ function getLeaf(index) {
33
+ const leaf = tree.leaves[index];
34
+ if (leaf === undefined) {
35
+ throw new Error("leaf does not exist in this tree");
36
+ }
37
+ return formatNode(BigInt(leaf));
38
+ }
39
+ function createMerkleProof(index) {
40
+ return tree.createProof(index);
41
+ }
42
+ return {
43
+ addLeaf,
44
+ getRoot,
45
+ getLeafCount,
46
+ getLeaf,
47
+ createMerkleProof,
48
+ getZero(level) {
49
+ if (level === tree.depth) {
50
+ return getRoot();
51
+ }
52
+ const zero = tree.zeroes[level];
53
+ if (zero === undefined) {
54
+ throw new Error("invalid level");
55
+ }
56
+ return formatNode(zero);
57
+ },
58
+ get depth() {
59
+ return tree.depth;
60
+ },
61
+ get capacity() {
62
+ return capacity;
63
+ },
64
+ };
65
+ }
66
+ export function createMerkleTrees() {
67
+ const trees = new Map();
68
+ const resetTree = (chainId) => {
69
+ ensureChainId(chainId);
70
+ const tree = createLocalMerkleTree();
71
+ trees.set(chainId, tree);
72
+ return tree;
73
+ };
74
+ const getOrCreate = (chainId) => {
75
+ ensureChainId(chainId);
76
+ let tree = trees.get(chainId);
77
+ if (!tree) {
78
+ tree = resetTree(chainId);
79
+ }
80
+ return tree;
81
+ };
82
+ return {
83
+ get(chainId) {
84
+ ensureChainId(chainId);
85
+ return trees.get(chainId);
86
+ },
87
+ getOrCreate,
88
+ addLeaf(chainId, value) {
89
+ return getOrCreate(chainId).addLeaf(value);
90
+ },
91
+ createMerkleProof(chainId, index) {
92
+ return getOrCreate(chainId).createMerkleProof(index);
93
+ },
94
+ getRoot(chainId) {
95
+ return getOrCreate(chainId).getRoot();
96
+ },
97
+ getLeafCount(chainId) {
98
+ return getOrCreate(chainId).getLeafCount();
99
+ },
100
+ reset(chainId) {
101
+ resetTree(chainId);
102
+ },
103
+ };
104
+ }
@@ -0,0 +1,37 @@
1
+ import type { Storage } from "../types.js";
2
+ import type { NoteInsert, NoteRecord } from "./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
+ */
8
+ putNote(note: NoteInsert): Promise<void>;
9
+ /**
10
+ * Fetch a note by (chainId, index) if it exists in local storage.
11
+ */
12
+ getNote(chainId: number, index: number): Promise<NoteRecord | null>;
13
+ /**
14
+ * List notes matching optional filters (by chainId, mpk) and spent state.
15
+ */
16
+ listNotes(options?: {
17
+ chainId?: number;
18
+ mpk?: string;
19
+ token?: string;
20
+ includeSpent?: boolean;
21
+ }): Promise<NoteRecord[]>;
22
+ /**
23
+ * Mark a cached note as spent by setting its timestamp and re-indexing metadata.
24
+ */
25
+ markNoteSpent(chainId: number, index: number, spentAt?: number): Promise<NoteRecord>;
26
+ /**
27
+ * Drop the spent marker from a cached note, returning it to the unspent index.
28
+ */
29
+ markNoteUnspent(chainId: number, index: number): Promise<NoteRecord>;
30
+ /**
31
+ * Aggregate unspent note balances per token for a given master public key.
32
+ */
33
+ getZkBalances(mpk: string, options?: {
34
+ chainId?: number;
35
+ }): Promise<Record<string, bigint>>;
36
+ };
37
+ //# sourceMappingURL=note-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-store.d.ts","sourceRoot":"","sources":["../../state/note-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,OAAO,EAAE,MAAM,aAAa,CAAC;AAapD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE3D,eAAO,MAAM,UAAU,+BAA0B,CAAC;AAElD,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO;IAyC5C;;OAEG;kBACiB,UAAU;IAI9B;;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,133 @@
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
+ */
45
+ async putNote(note) {
46
+ await persistNote({ ...note });
47
+ },
48
+ /**
49
+ * Fetch a note by (chainId, index) if it exists in local storage.
50
+ */
51
+ async getNote(chainId, index) {
52
+ ensureChainId(chainId);
53
+ ensurePositiveInt("note index", index);
54
+ return getJson(storage, keys.note(chainId, index));
55
+ },
56
+ /**
57
+ * List notes matching optional filters (by chainId, mpk) and spent state.
58
+ */
59
+ async listNotes(options = {}) {
60
+ const { chainId, mpk, token, includeSpent = true } = options;
61
+ if (chainId !== undefined) {
62
+ ensureChainId(chainId);
63
+ }
64
+ if (mpk !== undefined) {
65
+ ensureMpk(mpk);
66
+ }
67
+ const prefix = chainId !== undefined ? `notes:${chainId}:` : "notes:";
68
+ const entries = await storage.iter({ prefix });
69
+ const filtered = entries
70
+ .map(({ value }) => decodeJson(value))
71
+ .filter((note) => (chainId === undefined || note.chainId === chainId) &&
72
+ (mpk === undefined || note.mpk === mpk) &&
73
+ (token === undefined || note.token === token) &&
74
+ (includeSpent || note.spentAt === undefined));
75
+ filtered.sort((a, b) => a.index - b.index);
76
+ return filtered;
77
+ },
78
+ /**
79
+ * Mark a cached note as spent by setting its timestamp and re-indexing metadata.
80
+ */
81
+ async markNoteSpent(chainId, index, spentAt = Date.now()) {
82
+ ensureChainId(chainId);
83
+ ensurePositiveInt("note index", index);
84
+ ensurePositiveInt("note spentAt", spentAt);
85
+ const existing = await store.getNote(chainId, index);
86
+ if (!existing) {
87
+ throw new CoreError("note not found");
88
+ }
89
+ if (existing.spentAt === spentAt) {
90
+ return existing;
91
+ }
92
+ const updated = { ...existing, spentAt };
93
+ await persistNote(updated);
94
+ return updated;
95
+ },
96
+ /**
97
+ * Drop the spent marker from a cached note, returning it to the unspent index.
98
+ */
99
+ async markNoteUnspent(chainId, index) {
100
+ ensureChainId(chainId);
101
+ ensurePositiveInt("note index", index);
102
+ const existing = await store.getNote(chainId, index);
103
+ if (!existing) {
104
+ throw new CoreError("note not found");
105
+ }
106
+ if (existing.spentAt === undefined) {
107
+ return existing;
108
+ }
109
+ const updated = { ...existing };
110
+ delete updated.spentAt;
111
+ await persistNote(updated);
112
+ return updated;
113
+ },
114
+ /**
115
+ * Aggregate unspent note balances per token for a given master public key.
116
+ */
117
+ async getZkBalances(mpk, options = {}) {
118
+ ensureMpk(mpk);
119
+ const notes = await store.listNotes({
120
+ chainId: options.chainId,
121
+ mpk,
122
+ includeSpent: false,
123
+ });
124
+ const totals = {};
125
+ for (const note of notes) {
126
+ const amount = BigInt(note.value);
127
+ totals[note.token] = (totals[note.token] ?? 0n) + amount;
128
+ }
129
+ return totals;
130
+ },
131
+ };
132
+ return store;
133
+ }
@@ -0,0 +1,13 @@
1
+ import type { Storage } from "../types.js";
2
+ import type { NullifierRecord } from "./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
+ //# sourceMappingURL=nullifier-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nullifier-store.d.ts","sourceRoot":"","sources":["../../state/nullifier-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO;IAEjD;;OAEG;4BAC2B,eAAe;IAS7C;;OAEG;0BACyB,MAAM,SAAS,MAAM;EAKpD"}
@@ -0,0 +1,21 @@
1
+ import { keys } from "../keys.js";
2
+ import { getJson, putJson } from "../utils/json-codec.js";
3
+ import { ensureChainId } from "../utils/validators.js";
4
+ export function createNullifierStore(storage) {
5
+ return {
6
+ /**
7
+ * Record a nullifier observation so later syncs can de-duplicate work.
8
+ */
9
+ async putNullifier(nullifier) {
10
+ ensureChainId(nullifier.chainId);
11
+ await putJson(storage, keys.nullifier(nullifier.chainId, nullifier.nullifier), nullifier);
12
+ },
13
+ /**
14
+ * Lookup a previously observed nullifier by value.
15
+ */
16
+ async getNullifier(chainId, value) {
17
+ ensureChainId(chainId);
18
+ return getJson(storage, keys.nullifier(chainId, value));
19
+ },
20
+ };
21
+ }