@interest-protocol/vortex-sdk 2.0.0 → 3.0.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.
@@ -1,81 +1,3 @@
1
- /**
2
- * Sparse Merkle tree using Tornado Cash Nova's paired insertion strategy.
3
- * Inserts two leaves at once for better efficiency and privacy.
4
- */
5
- export declare class MerkleTree {
6
- levels: number;
7
- capacity: number;
8
- zeroElement: bigint;
9
- private zeros;
10
- private subtrees;
11
- private _nextIndex;
12
- private leaves;
13
- private _root;
14
- constructor(levels: number);
15
- /**
16
- * Returns the current Merkle root
17
- */
18
- root(): bigint;
19
- /**
20
- * Insert elements in bulk (must be even number for pairing)
21
- */
22
- bulkInsert(elements: bigint[]): void;
23
- /**
24
- * Insert a pair of leaves (Nova style)
25
- * This is the primary insertion method
26
- */
27
- insertPair(leaf1: bigint, leaf2: bigint): void;
28
- /**
29
- * Insert a single leaf (for backward compatibility)
30
- * Pairs it with a zero leaf
31
- */
32
- insert(leaf: bigint): void;
33
- /**
34
- * Generate Merkle path for a leaf at given index
35
- * Returns sibling hashes and indices for verification
36
- */
37
- path(index: number): {
38
- pathElements: bigint[];
39
- pathIndices: number[];
40
- };
41
- /**
42
- * Get all leaves in the tree
43
- */
44
- elements(): bigint[];
45
- /**
46
- * Find the index of a specific leaf
47
- */
48
- indexOf(element: bigint, comparator?: Function | null): number;
49
- /**
50
- * Serialize tree state
51
- */
52
- serialize(): {
53
- levels: number;
54
- zeros: bigint[];
55
- subtrees: bigint[];
56
- nextIndex: number;
57
- leaves: bigint[];
58
- root: bigint;
59
- };
60
- /**
61
- * Verify a Merkle path is valid for a given leaf and root
62
- */
63
- verify(leaf: bigint, pathElements: bigint[], pathIndices: number[], root: bigint): boolean;
64
- /**
65
- * Get the current number of leaves in the tree
66
- */
67
- get nextIndex(): number;
68
- /**
69
- * Check if the tree is full
70
- */
71
- isFull(): boolean;
72
- /**
73
- * Get the maximum capacity of the tree
74
- */
75
- getCapacity(): number;
76
- /**
77
- * Get the current fill percentage
78
- */
79
- getFillPercentage(): number;
80
- }
1
+ import { MerkleTree as FixedMerkleTree } from 'fixed-merkle-tree';
2
+ export declare const buildMerkleTree: () => FixedMerkleTree;
81
3
  //# sourceMappingURL=merkle-tree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"merkle-tree.d.ts","sourceRoot":"","sources":["../../src/entities/merkle-tree.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,qBAAa,UAAU;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,MAAM;IAyB1B;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE;IAU7B;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAuCvC;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM;IAInB;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,YAAY,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;IAyCtE;;OAEG;IACH,QAAQ,IAAI,MAAM,EAAE;IAIpB;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,QAAQ,GAAG,IAAW,GAAG,MAAM;IAOpE;;OAEG;IACH,SAAS;;;;;;;;IAWT;;OAEG;IACH,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EAAE,EACtB,WAAW,EAAE,MAAM,EAAE,EACrB,IAAI,EAAE,MAAM,GACX,OAAO;IAwBV;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,iBAAiB,IAAI,MAAM;CAG5B"}
1
+ {"version":3,"file":"merkle-tree.d.ts","sourceRoot":"","sources":["../../src/entities/merkle-tree.ts"],"names":[],"mappings":"AAIA,OAAO,EAAW,UAAU,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE3E,eAAO,MAAM,eAAe,uBAKxB,CAAC"}
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  var suitcaseCore = require('@polymedia/suitcase-core');
4
4
  var invariant = require('tiny-invariant');
5
5
  var ramda = require('ramda');
6
+ var fixedMerkleTree = require('fixed-merkle-tree');
6
7
  var require$$0 = require('fs');
7
8
  var bn_js = require('bn.js');
8
9
 
@@ -38843,201 +38844,10 @@ _VortexKeypair_instances = new WeakSet(), _VortexKeypair_decrypt = function _Vor
38843
38844
  };
38844
38845
 
38845
38846
  // packages/vortex/src/entities/merkle-tree.ts
38846
- /**
38847
- * Sparse Merkle tree using Tornado Cash Nova's paired insertion strategy.
38848
- * Inserts two leaves at once for better efficiency and privacy.
38849
- */
38850
- class MerkleTree {
38851
- constructor(levels) {
38852
- this.levels = levels;
38853
- this.capacity = 2 ** levels;
38854
- this.zeroElement = ZERO_VALUE;
38855
- this.zeros = [];
38856
- this.subtrees = [];
38857
- this._nextIndex = 0;
38858
- this.leaves = [];
38859
- // Initialize zero hashes (0 to levels, inclusive)
38860
- // We need levels+1 elements: zeros[0] through zeros[levels]
38861
- for (let i = 0; i <= levels; i++) {
38862
- this.zeros[i] = EMPTY_SUBTREE_HASHES[i];
38863
- }
38864
- // Initialize subtrees[0..levels-1] (matching Nova's filledSubtrees)
38865
- // subtrees[0] is initialized but never used (Nova quirk)
38866
- for (let i = 0; i < levels; i++) {
38867
- this.subtrees[i] = this.zeros[i];
38868
- }
38869
- // Empty root is zeros[levels]
38870
- this._root = this.zeros[levels];
38871
- }
38872
- /**
38873
- * Returns the current Merkle root
38874
- */
38875
- root() {
38876
- return this._root;
38877
- }
38878
- /**
38879
- * Insert elements in bulk (must be even number for pairing)
38880
- */
38881
- bulkInsert(elements) {
38882
- if (elements.length % 2 !== 0) {
38883
- throw new Error('Must insert even number of elements (pairs)');
38884
- }
38885
- for (let i = 0; i < elements.length; i += 2) {
38886
- this.insertPair(elements[i], elements[i + 1]);
38887
- }
38888
- }
38889
- /**
38890
- * Insert a pair of leaves (Nova style)
38891
- * This is the primary insertion method
38892
- */
38893
- insertPair(leaf1, leaf2) {
38894
- if (this._nextIndex >= this.capacity) {
38895
- throw new Error('Merkle tree is full. No more leaves can be added');
38896
- }
38897
- // Store both leaves
38898
- this.leaves.push(leaf1, leaf2);
38899
- // Start by hashing the pair (level 0)
38900
- let currentIndex = Math.floor(this._nextIndex / 2);
38901
- let currentLevelHash = poseidon2(leaf1, leaf2);
38902
- // Increment by 2 since we're inserting a pair
38903
- this._nextIndex += 2;
38904
- // Process levels 1 to levels-1 (matching Nova: for i = 1; i < levels)
38905
- for (let i = 1; i < this.levels; i++) {
38906
- let left;
38907
- let right;
38908
- if (currentIndex % 2 === 0) {
38909
- // Current is left child
38910
- left = currentLevelHash;
38911
- right = this.zeros[i];
38912
- this.subtrees[i] = currentLevelHash; // Cache left subtree
38913
- }
38914
- else {
38915
- // Current is right child
38916
- left = this.subtrees[i]; // Get cached left subtree
38917
- right = currentLevelHash;
38918
- }
38919
- currentLevelHash = poseidon2(left, right);
38920
- currentIndex = Math.floor(currentIndex / 2);
38921
- }
38922
- // Update root
38923
- this._root = currentLevelHash;
38924
- }
38925
- /**
38926
- * Insert a single leaf (for backward compatibility)
38927
- * Pairs it with a zero leaf
38928
- */
38929
- insert(leaf) {
38930
- this.insertPair(leaf, this.zeros[0]);
38931
- }
38932
- /**
38933
- * Generate Merkle path for a leaf at given index
38934
- * Returns sibling hashes and indices for verification
38935
- */
38936
- path(index) {
38937
- if (index < 0 || index >= this._nextIndex) {
38938
- throw new Error(`Index out of bounds: ${index} (tree has ${this._nextIndex} leaves)`);
38939
- }
38940
- const pathElements = [];
38941
- const pathIndices = [];
38942
- // Level 0: Get sibling leaf
38943
- const isLeftAtLevel0 = index % 2 === 0;
38944
- pathIndices.push(isLeftAtLevel0 ? 0 : 1);
38945
- const siblingIndex = isLeftAtLevel0 ? index + 1 : index - 1;
38946
- const sibling = siblingIndex < this._nextIndex
38947
- ? this.leaves[siblingIndex]
38948
- : this.zeros[0];
38949
- pathElements.push(sibling);
38950
- // Levels 1 to levels-1 (matching Nova's loop structure)
38951
- let currentIndex = Math.floor(index / 2);
38952
- for (let i = 1; i < this.levels; i++) {
38953
- const isLeft = currentIndex % 2 === 0;
38954
- pathIndices.push(isLeft ? 0 : 1);
38955
- if (isLeft) {
38956
- // We're left child, sibling is right (zero hash)
38957
- pathElements.push(this.zeros[i]);
38958
- }
38959
- else {
38960
- // We're right child, sibling is the cached left subtree
38961
- pathElements.push(this.subtrees[i]);
38962
- }
38963
- currentIndex = Math.floor(currentIndex / 2);
38964
- }
38965
- return { pathElements, pathIndices };
38966
- }
38967
- /**
38968
- * Get all leaves in the tree
38969
- */
38970
- elements() {
38971
- return this.leaves;
38972
- }
38973
- /**
38974
- * Find the index of a specific leaf
38975
- */
38976
- indexOf(element, comparator = null) {
38977
- if (comparator) {
38978
- return this.leaves.findIndex((leaf) => comparator(element, leaf));
38979
- }
38980
- return this.leaves.findIndex((leaf) => leaf === element);
38981
- }
38982
- /**
38983
- * Serialize tree state
38984
- */
38985
- serialize() {
38986
- return {
38987
- levels: this.levels,
38988
- zeros: this.zeros,
38989
- subtrees: this.subtrees,
38990
- nextIndex: this._nextIndex,
38991
- leaves: this.leaves,
38992
- root: this._root,
38993
- };
38994
- }
38995
- /**
38996
- * Verify a Merkle path is valid for a given leaf and root
38997
- */
38998
- verify(leaf, pathElements, pathIndices, root) {
38999
- if (pathElements.length !== this.levels ||
39000
- pathIndices.length !== this.levels) {
39001
- return false;
39002
- }
39003
- let currentHash = leaf;
39004
- for (let i = 0; i < this.levels; i++) {
39005
- const sibling = pathElements[i];
39006
- const isLeft = pathIndices[i] === 0;
39007
- if (isLeft) {
39008
- currentHash = poseidon2(currentHash, sibling);
39009
- }
39010
- else {
39011
- currentHash = poseidon2(sibling, currentHash);
39012
- }
39013
- }
39014
- return currentHash === root;
39015
- }
39016
- /**
39017
- * Get the current number of leaves in the tree
39018
- */
39019
- get nextIndex() {
39020
- return this._nextIndex;
39021
- }
39022
- /**
39023
- * Check if the tree is full
39024
- */
39025
- isFull() {
39026
- return this._nextIndex >= this.capacity;
39027
- }
39028
- /**
39029
- * Get the maximum capacity of the tree
39030
- */
39031
- getCapacity() {
39032
- return this.capacity;
39033
- }
39034
- /**
39035
- * Get the current fill percentage
39036
- */
39037
- getFillPercentage() {
39038
- return (this._nextIndex / this.capacity) * 100;
39039
- }
39040
- }
38847
+ const buildMerkleTree = () => new fixedMerkleTree.MerkleTree(MERKLE_TREE_HEIGHT, [], {
38848
+ hashFunction: (left, right) => poseidon2(BigInt(left), BigInt(right)).toString(),
38849
+ zeroElement: ZERO_VALUE.toString(),
38850
+ });
39041
38851
 
39042
38852
  class Utxo {
39043
38853
  constructor({ amount, blinding, keypair, index }) {
@@ -39612,7 +39422,7 @@ function getMerklePath(merkleTree, utxo) {
39612
39422
  .map(() => [ZERO_VALUE.toString(), ZERO_VALUE.toString()]);
39613
39423
  }
39614
39424
  const utxoIndex = Number(utxo.index);
39615
- const treeSize = merkleTree.elements().length;
39425
+ const treeSize = merkleTree.elements.length;
39616
39426
  // For deposits, input UTXOs don't exist yet
39617
39427
  if (utxoIndex < 0 || utxoIndex >= treeSize) {
39618
39428
  return Array(MERKLE_TREE_HEIGHT)
@@ -39623,13 +39433,13 @@ function getMerklePath(merkleTree, utxo) {
39623
39433
  const { pathElements, pathIndices } = merkleTree.path(utxoIndex);
39624
39434
  const commitment = utxo.commitment();
39625
39435
  // Verify commitment matches what's in the tree
39626
- const storedCommitment = merkleTree.elements()[utxoIndex];
39436
+ const storedCommitment = BigInt(merkleTree.elements[utxoIndex]);
39627
39437
  invariant(storedCommitment === commitment, `Commitment mismatch at index ${utxoIndex}: expected ${commitment}, got ${storedCommitment}`);
39628
39438
  // Build WASM-compatible path (always [left, right] format)
39629
39439
  const wasmPath = [];
39630
39440
  let currentHash = commitment;
39631
39441
  for (let i = 0; i < MERKLE_TREE_HEIGHT; i++) {
39632
- const sibling = pathElements[i];
39442
+ const sibling = BigInt(pathElements[i]);
39633
39443
  const isLeft = pathIndices[i] === 0;
39634
39444
  invariant(sibling !== undefined, `Sibling undefined at level ${i}`);
39635
39445
  const leftHash = isLeft ? currentHash : sibling;
@@ -39643,13 +39453,13 @@ function getMerklePath(merkleTree, utxo) {
39643
39453
  currentHash = nextHash;
39644
39454
  }
39645
39455
  const calculatedRoot = currentHash;
39646
- const expectedRoot = merkleTree.root();
39456
+ const expectedRoot = BigInt(merkleTree.root);
39647
39457
  invariant(calculatedRoot === expectedRoot, `Root mismatch: calculated ${calculatedRoot}, expected ${expectedRoot}`);
39648
39458
  return wasmPath;
39649
39459
  }
39650
39460
  const toProveInput = ({ merkleTree, publicAmount, extDataHash, nullifier0, nullifier1, commitment0, commitment1, vortexKeypair, inputUtxo0, inputUtxo1, outputUtxo0, outputUtxo1, }) => {
39651
39461
  return {
39652
- root: merkleTree.root(),
39462
+ root: BigInt(merkleTree.root),
39653
39463
  publicAmount,
39654
39464
  extDataHash,
39655
39465
  inputNullifier0: nullifier0,
@@ -39761,7 +39571,7 @@ const deposit = async ({ tx = new Transaction(), amount, unspentUtxos = [], vort
39761
39571
  const { proof: moveProof, tx: tx3 } = vortex.newProof({
39762
39572
  tx: tx2,
39763
39573
  proofPoints: fromHex('0x' + proof.proofSerializedHex),
39764
- root: merkleTree.root(),
39574
+ root: BigInt(merkleTree.root),
39765
39575
  publicValue: amountMinusFrontendFee,
39766
39576
  action: exports.Action.Deposit,
39767
39577
  extDataHash: extDataHashBigInt,
@@ -39862,7 +39672,7 @@ const withdraw = async ({ tx = new Transaction(), amount, unspentUtxos = [], vor
39862
39672
  const { proof: moveProof, tx: tx3 } = vortex.newProof({
39863
39673
  tx: tx2,
39864
39674
  proofPoints: fromHex('0x' + proof.proofSerializedHex),
39865
- root: merkleTree.root(),
39675
+ root: BigInt(merkleTree.root),
39866
39676
  publicValue: amount + relayerFee,
39867
39677
  action: exports.Action.Withdraw,
39868
39678
  extDataHash: extDataHashBigInt,
@@ -39891,7 +39701,6 @@ exports.INITIAL_SHARED_VERSION = INITIAL_SHARED_VERSION;
39891
39701
  exports.LSK_ENCRYPTED_OUTPUTS = LSK_ENCRYPTED_OUTPUTS;
39892
39702
  exports.LSK_FETCH_OFFSET = LSK_FETCH_OFFSET;
39893
39703
  exports.MERKLE_TREE_HEIGHT = MERKLE_TREE_HEIGHT;
39894
- exports.MerkleTree = MerkleTree;
39895
39704
  exports.OPT = OPT;
39896
39705
  exports.REGISTRY_OBJECT_ID = REGISTRY_OBJECT_ID;
39897
39706
  exports.ROOT_HISTORY_SIZE = ROOT_HISTORY_SIZE;
@@ -39904,6 +39713,7 @@ exports.VORTEX_SIGNATURE_DOMAIN = VORTEX_SIGNATURE_DOMAIN;
39904
39713
  exports.Vortex = Vortex;
39905
39714
  exports.VortexKeypair = VortexKeypair;
39906
39715
  exports.ZERO_VALUE = ZERO_VALUE;
39716
+ exports.buildMerkleTree = buildMerkleTree;
39907
39717
  exports.bytesToBigInt = bytesToBigInt;
39908
39718
  exports.computeExtDataHash = computeExtDataHash;
39909
39719
  exports.deposit = deposit;