@ensdomains/merkle-builder 0.0.1 → 0.0.2

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.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  * Matches [Ethereum](https://ethereum.org/developers/docs/apis/json-rpc/) and [Foundry](https://getfoundry.sh/) results
5
5
  * Memory efficient (copy-on-write, shared subexpressions)
6
6
  * Compute efficient (branch nodes hash once)
7
- * Multiple storage encodings (object, bytes, JSON)
7
+ * Multiple storage encodings (object, [bytes](./src/coder.ts), [JSON](./src/json.ts))
8
8
 
9
9
  #### Roadmap
10
10
 
@@ -34,10 +34,10 @@
34
34
 
35
35
  * Replicate `eth_getProof` for [`L2ReverseRegistrar`](https://github.com/ensdomains/ens-contracts/blob/staging/contracts/reverseRegistrar/L2ReverseRegistrar.sol) (requires [`.env`](./.env.sample) for provider)
36
36
  * `bun demo/app.ts -c <chain>`
37
- * ✅️ [`op`](https://optimistic.etherscan.io/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `88` names as of `2026-01-09`
38
- * ✅️ [`base`](https://basescan.org/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `1,584,359` names as of `2026-01-09`
39
- * ✅️ [`arb`](https://arbiscan.io/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `146` names as of `2025-01-09`
40
- * ✅️ [`linea`](https://lineascan.build/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `74` names as of `2025-01-09`
41
- * ✅️ [`scroll`](https://scrollscan.com/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `47` names as of `2025-01-09`
37
+ * ✅️ [`op`](https://optimistic.etherscan.io/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `95` names as of `2026-01-25`
38
+ * ✅️ [`base`](https://basescan.org/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `1,846,927` names as of `2026-01-25`
39
+ * ✅️ [`arb`](https://arbiscan.io/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `151` names as of `2026-01-25`
40
+ * ✅️ [`linea`](https://lineascan.build/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `77` names as of `2026-01-25`
41
+ * ✅️ [`scroll`](https://scrollscan.com/address/0x0000000000D8e504002cC26E3Ec46D81971C1664) &rarr; `49` names as of `2026-01-25`
42
42
  * Deserialize from *trunk* and *limb* with precomputed hashes, perform surgery, and produce correct `eth_getProof`
43
43
  * `bun demo/memory.ts -c <chain> -d <depth>`
package/dist/index.cjs CHANGED
@@ -642,7 +642,7 @@ function fromJSON(json) {
642
642
  }
643
643
  }
644
644
  }
645
- throw new TypeError("invalid json");
645
+ throw Object.assign(new TypeError("invalid json"), { json });
646
646
  }
647
647
  function nibbleStr(path) {
648
648
  return Array.from(path, toNibbleChar).join("");
@@ -807,7 +807,7 @@ function mimcHash(v) {
807
807
  }
808
808
 
809
809
  // src/surgery.ts
810
- function pluckLimbs(node, depth) {
810
+ function pluckLimbs(node, depth, exact) {
811
811
  if (!node || depth <= 0) return { trunk: node, limbs: [] };
812
812
  const queue = [];
813
813
  if (isBranch(node)) {
@@ -827,30 +827,27 @@ function pluckLimbs(node, depth) {
827
827
  trunk: void 0,
828
828
  limbs: [[node.path.subarray(0, depth), leaf]]
829
829
  };
830
- } else {
831
- return { trunk: node, limbs: [] };
832
830
  }
833
831
  const limbs = [];
834
832
  while (queue.length) {
835
833
  const [parent, path] = queue.pop();
836
- const rest = depth - path.length - 1;
837
834
  parent.children.forEach((child, i) => {
838
835
  if (!child) return;
839
- if (!rest) {
836
+ if (path.length + 1 === depth) {
840
837
  parent.children[i] = void 0;
841
838
  limbs.push([Uint8Array.of(...path, i), child]);
842
839
  } else if (isBranch(child)) {
843
840
  queue.push([child, [...path, i]]);
844
- } else if (child.path.length > rest) {
841
+ } else if (isExtension(child) && path.length + child.path.length <= depth) {
842
+ queue.push([child.child, [...path, i, ...child.path]]);
843
+ } else if (exact) {
845
844
  parent.children[i] = void 0;
846
- const copy = { ...child };
847
- copy.path = child.path.subarray(rest);
845
+ const full = [...path, i, ...child.path];
846
+ const rest = new Uint8Array(full.slice(depth));
848
847
  limbs.push([
849
- Uint8Array.of(...path, i, ...child.path.subarray(0, rest)),
850
- copy
848
+ new Uint8Array(full.slice(0, depth)),
849
+ isLeaf(child) ? newLeaf(rest, child.data) : rest.length ? { path: rest, child: child.child } : child.child
851
850
  ]);
852
- } else if (isExtension(child)) {
853
- queue.push([child.child, [...path, i, ...child.path]]);
854
851
  }
855
852
  });
856
853
  }
package/dist/index.d.cts CHANGED
@@ -74,7 +74,7 @@ declare function insertBytes(node: MaybeNode, slot: Uint8Array, value: Uint8Arra
74
74
  declare function mimcHash(v: bigint[]): bigint;
75
75
 
76
76
  type Limb = [path: Uint8Array, node: Node];
77
- declare function pluckLimbs(node: MaybeNode, depth: number): {
77
+ declare function pluckLimbs(node: MaybeNode, depth: number, exact?: boolean): {
78
78
  trunk: MaybeNode;
79
79
  limbs: Limb[];
80
80
  };
package/dist/index.d.ts CHANGED
@@ -74,7 +74,7 @@ declare function insertBytes(node: MaybeNode, slot: Uint8Array, value: Uint8Arra
74
74
  declare function mimcHash(v: bigint[]): bigint;
75
75
 
76
76
  type Limb = [path: Uint8Array, node: Node];
77
- declare function pluckLimbs(node: MaybeNode, depth: number): {
77
+ declare function pluckLimbs(node: MaybeNode, depth: number, exact?: boolean): {
78
78
  trunk: MaybeNode;
79
79
  limbs: Limb[];
80
80
  };
package/dist/index.js CHANGED
@@ -580,7 +580,7 @@ function fromJSON(json) {
580
580
  }
581
581
  }
582
582
  }
583
- throw new TypeError("invalid json");
583
+ throw Object.assign(new TypeError("invalid json"), { json });
584
584
  }
585
585
  function nibbleStr(path) {
586
586
  return Array.from(path, toNibbleChar).join("");
@@ -745,7 +745,7 @@ function mimcHash(v) {
745
745
  }
746
746
 
747
747
  // src/surgery.ts
748
- function pluckLimbs(node, depth) {
748
+ function pluckLimbs(node, depth, exact) {
749
749
  if (!node || depth <= 0) return { trunk: node, limbs: [] };
750
750
  const queue = [];
751
751
  if (isBranch(node)) {
@@ -765,30 +765,27 @@ function pluckLimbs(node, depth) {
765
765
  trunk: void 0,
766
766
  limbs: [[node.path.subarray(0, depth), leaf]]
767
767
  };
768
- } else {
769
- return { trunk: node, limbs: [] };
770
768
  }
771
769
  const limbs = [];
772
770
  while (queue.length) {
773
771
  const [parent, path] = queue.pop();
774
- const rest = depth - path.length - 1;
775
772
  parent.children.forEach((child, i) => {
776
773
  if (!child) return;
777
- if (!rest) {
774
+ if (path.length + 1 === depth) {
778
775
  parent.children[i] = void 0;
779
776
  limbs.push([Uint8Array.of(...path, i), child]);
780
777
  } else if (isBranch(child)) {
781
778
  queue.push([child, [...path, i]]);
782
- } else if (child.path.length > rest) {
779
+ } else if (isExtension(child) && path.length + child.path.length <= depth) {
780
+ queue.push([child.child, [...path, i, ...child.path]]);
781
+ } else if (exact) {
783
782
  parent.children[i] = void 0;
784
- const copy = { ...child };
785
- copy.path = child.path.subarray(rest);
783
+ const full = [...path, i, ...child.path];
784
+ const rest = new Uint8Array(full.slice(depth));
786
785
  limbs.push([
787
- Uint8Array.of(...path, i, ...child.path.subarray(0, rest)),
788
- copy
786
+ new Uint8Array(full.slice(0, depth)),
787
+ isLeaf(child) ? newLeaf(rest, child.data) : rest.length ? { path: rest, child: child.child } : child.child
789
788
  ]);
790
- } else if (isExtension(child)) {
791
- queue.push([child.child, [...path, i, ...child.path]]);
792
789
  }
793
790
  });
794
791
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensdomains/merkle-builder",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Low-level Merkle-Patricia storage trie implementation",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",