# starknet-merkle-tree

> To use Merkle trees with Starknet

Latest version **1.1.1** (published 2026-01-28) · MIT license · 0 weekly downloads

## Install

```sh
npm install starknet-merkle-tree
pnpm add starknet-merkle-tree
yarn add starknet-merkle-tree
bun add starknet-merkle-tree
```

## Health

**Score 60/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.1.1 |
| Published | 2026-01-28 |
| First published | 2024-01-10 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 3 |
| Unpacked size | 106.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 12 |
| Author | Philippe ROSTAN |
| Maintainers | philipper26 |
| Keywords | merkle, starknet, tree, airdrop |

## Links

- npm: https://www.npmjs.com/package/starknet-merkle-tree
- Repository: https://github.com/PhilippeR26/starknetMerkleTree
- Homepage: https://github.com/PhilippeR26/starknetMerkleTree#readme
- Issues: https://github.com/PhilippeR26/starknetMerkleTree/issues
- npm.io page: https://npm.io/package/starknet-merkle-tree

## Dependencies (3)

- [dotenv](https://npm.io/package/dotenv.md) ^17.2.3
- [starknet](https://npm.io/package/starknet.md) ^9.3.0
- [@starknet-io/types-js](https://npm.io/package/@starknet-io/types-js.md) ^0.10.0

## Alternatives

- [lodash.startswith](https://npm.io/package/lodash.startswith.md) — 769.7K weekly downloads
- [@tarojs/service](https://npm.io/package/@tarojs/service.md) — 33.9K weekly downloads
- [io.extendreality.tilia.indicators.spatialtargets.unity](https://npm.io/package/io.extendreality.tilia.indicators.spatialtargets.unity.md) — 131 weekly downloads
- [@rtarojs/taro](https://npm.io/package/@rtarojs/taro.md) — 90 weekly downloads
- [node-branch-io](https://npm.io/package/node-branch-io.md) — 50 weekly downloads

## Recent versions

- 1.1.1 (latest) — 2026-01-28
- 1.1.0 — 2026-01-26
- 1.0.5 — 2024-10-30
- 1.0.4 — 2024-10-28
- 1.0.3 — 2024-10-28
- 1.0.2 — 2024-01-29
- 1.0.1 — 2024-01-14
- 1.0.0 — 2024-01-10

## README

<h1 style="text-align: center;"> Starknet Merkle Tree</h1>
 
<p align="center">
  <img src="./public/tree.jpg" />
</p>

<h2 style="text-align: center;"> Typescript library for Merkle trees adapted for Starknet</h1>
<br></br>

**This library has not been audited ; use at your own risks.**

> **Stars are highly appreciated! Thanks in advance.**

This library is able to create and handle Merkle trees, using very efficient and specifics hashes for the Starknet blockchain. You can use :
- Pedersen hash (by default)
- Poseidon hash (the most efficient one)

You can also generates some Merkle proofs, store the tree, hash a leave of the tree, and many other things.  
This library has been tested with success with trees up to one million leaves, each leaf including 3 felt252 numbers.

**This lib will be very useful if you have to code an airdrop.**

## 🛠️ Installation 🛠️ :

```bash
npm install starknet-merkle-tree
```

## Quick example :

```typescript
import * as Merkle from "starknet-merkle-tree";
```

### 🌲 Create a Merkle tree :

The Merkle tree will be created with an array of strings as input.  
For an Airdrop, you needs a list of granted addresses, and optionally the quantity of token to distribute to each one.
```typescript
// address + quantity (u256.low + u256.high)
const airdrop: Merkle.InputForMerkle[] = [
  ['0x69b49c2cc8b16e80e86bfc5b0614a59aa8c9b601569c7b80dde04d3f3151b79', '256','0'],
  ['0x3cad9a072d3cf29729ab2fad2e08972b8cfde01d4979083fb6d15e8e66f8ab1', '25','0'],
  ['0x27d32a3033df4277caa9e9396100b7ca8c66a4ef8ea5f6765b91a7c17f0109c', '56','0'],
  ['0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a', '26','0'],
  ['0x53c615080d35defd55569488bc48c1a91d82f2d2ce6199463e095b4a4ead551', '56','0'],
    ];
const tree = Merkle.StarknetMerkleTree.create(airdrop, Merkle.HashType.Poseidon);
```
> [!TIP]
> For large trees, increase the memory allocation to node.js (4096 by default):  
> `node --max-old-space-size=16000 ./node_modules/.bin/ts-node ./myScript.ts`  
> Here 16 Gb are affected.

### 🫚 Get the root of the tree :
```typescript
const root = tree.root;
```

### 🎰 Create a Merkle proof :
```typescript
const inp = 3; // Nth leaf of the input list
// or
const inp = ['0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a', '26','0']; // leaf content

const proof = tree.getProof(inp);
```

### Hash a leaf :
```typescript
const inp = 3; // Nth leaf of the input list
const inpData = tree.getInputData(inp);
const leafHash = Merkle.StarknetMerkleTree.leafHash(inpData, Merkle.HashType.Poseidon);
```
### 🔎 Verify a proof with your JS/TS script :
```typescript
const inp = 3; // Nth leaf of the input list
const inpData = tree.getInputData(inp);
const isValid = tree.verify(inpData, proof);
```

### 🔎 Verify a proof in the Starknet blockchain :

You have to deploy a new instance of an existing smart-contract. There is one contract dedicated for Pedersen hash, and one other for Poseidon hash. These contracts are already declared in Starknet Mainnet and Sepolia Testnet, with the following class hashes :

| Tree hash |  Class hash | 
| :---: | ---: |
| **Pedersen** |  `0x3e59df2708031668e491d704e24fe3a16af9b3e4512262909306b77faa1029a` | 
| **Poseidon** | `0x161559a8660eb7323125b37b4c2db2519b34260a020464034b68a50d7090ee2`| 

So, you will not have to pay fees to declare this part of the airdrop code ; it's already made.
You have to deploy this contract (called here contract 1) with only one parameter in the constructor : the tree root.

You have to create/declare/deploy your dedicated smart-contract (called here contract 2) to handle the Airdrop (list of already performed airdrops, distribution of tokens, timing, administration, etc..).  
This contract 2 has to call the contract 1 to verify if the data are correct and are part of the Merkle tree. 
Contract 1 is able to say if an address and the corresponding data are included in the tree or not. Just by storing a felt252 in Starknet, you can check that an address is included in a list of thousand of addresses, and trigger a distribution of token to this address.

You can find a documentation of this contract 1 [here](https://github.com/PhilippeR26/starknetMerkleTree/blob/main/cairo/merkleTreeVerify.md).

> Some Typescript demo files are available [here](https://github.com/PhilippeR26/starknetMerkleTree/tree/main/typescript).

> A demo DAPP for an Airdrop is available. You can test it and analyze the source code [here](https://github.com/PhilippeR26/Airdrop-for-Starknet).

## Performances

Each leaf includes 3 felt252.  
With my core i5 laptop:

__Pedersen Hash :__

|Qty of leaves|1k|100k|1M|
|:---:|---:|---:|---:|
|v1.0 duration (s)|20.1|1 933.1|19 924.4|
|v1.1 duration (s)|10.8|1 068.0|11 256.3|
|Improvement|x1.9|x1.8|x1.8|

__Poseidon Hash :__

|Qty of leaves|1k|100k|1M|
|:---:|---:|---:|---:|
|v1.0 duration (s)|2.0|186.3|1 942.4|
|v1.1 duration (s)|1.3|117.6|1 227.8|
|Improvement|x1.6|x1.6|x1.6|

> [!NOTE]
> You can notice that Poseidon hash is 9 times faster than Pedersen hash.

## API :

### Types :

```typescript
type InputForMerkle = string | string[];

enum HashType {
  Pedersen = "Pedersen",
  Poseidon = "Poseidon",
}
```

### StarknetMerkleTree.create() :

Creates a standard Merkle tree out of an array. Data are Hex strings or decimal strings.
```typescript
const data: Merkle.inputForMerkle[] = [
    ['0x69b49c2cc8b16e80e86bfc5b0614a59aa8c9b601569c7b80dde04d3f3151b79', '256', '0'],
    ['0x3cad9a072d3cf29729ab2fad2e08972b8cfde01d4979083fb6d15e8e66f8ab1', '25', '0'],
    ['0x27d32a3033df4277caa9e9396100b7ca8c66a4ef8ea5f6765b91a7c17f0109c', '56', '0'],
    ['0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a', '26', '0'],
    ['0x53c615080d35defd55569488bc48c1a91d82f2d2ce6199463e095b4a4ead551', '56', '0'],
];
const tree = Merkle.StarknetMerkleTree.create(data, Merkle.HashType.Pedersen);
```


### getProof() :
Returns a proof for the Nth value in the tree. Indices refer to the position of the values in the array from which the tree was constructed. Also accepts a value instead of an index, but this will be less efficient. It will fail if the value is not found in the tree.
```typescript
const proof1 = tree.getProof(3);
const proof2 = tree.getProof(["0x43af5", "100", "0"]);
// result =
[
  '0x40a6dba21b22596e979a1555a278ca58c11b5cd5e46f5801c1af8c4ab518845',
  '0x7957d036cf1e60858a601df12e0fb2921114d4b5facccf638163e0bb2be3c34',
  '0x12677ed42d2f73c92413c30d04d0b88e771bf2595c7060df46f095f2132eca2'
]
```

### verify() :
Returns a boolean that is `true` when the proof verifies that the value is contained in the tree.
```typescript
const result1 = tree.verify(3, proof);
const result2 = tree.verify(["0x43af5", "100", "0"], proof);
// result = true
```

### dump() :
Returns a description of the Merkle tree for distribution. It contains all the necessary information to reproduce the tree, find the relevant leaves, and generate proofs. You should distribute this to users in a web application so they can generate proofs for some leaves.
```typescript
fs.writeFileSync('data/treeTestPoseidon.json', JSON.stringify(tree.dump(),undefined,2));
```

### load() :
Loads the tree from a description previously saved or dumped.
```typescript
const tree = Merkle.StarknetMerkleTree.load(
    JSON.parse(fs.readFileSync('./src/scripts/merkleTree/treeTestPoseidon.json', 'ascii'))
);
```

###  validate() :
Verify the consistency of the tree. Useful after a load(). Take care that this method is time-consuming. Throw an error if validation fail.
```typescript
tree.validate();
```

### root :
The root of the tree is a commitment on the values of the tree. It can be published in a smart contract, to later prove that its values are part of the tree.
```typescript
console.log(tree.root);
// result = 0x4bad3f80e8041eb3d32432fa4aed9f904db8c8ab34109879a99da696a0c5a81
```

### render() :
Returns a visual representation of the tree that can be useful for debugging.
```typescript
console.log(tree.render());
// result = 
0) 0x4bad3f80e8041eb3d32432fa4aed9f904db8c8ab34109879a99da696a0c5a81
├─ 1) 0x4f9ffba9cb60723ecb53299f6b2359a9d32a1aa316ffcf83022c58d822abc55
│  ├─ 3) 0x1cd0fa9d323f2de54979140bab80cb8077ac24e098c685da5ac6a4d9a17c25c
│  │  ├─ 7) 0x6e5bfc0a35b74af4395c2a60a7735c0f0cbcfba515e91d4edd3f7ea70287cbc
│  │  └─ 8) 0x40a6dba21b22596e979a1555a278ca58c11b5cd5e46f5801c1af8c4ab518845
│  └─ 4) 0x7957d036cf1e60858a601df12e0fb2921114d4b5facccf638163e0bb2be3c34
└─ 2) 0x12677ed42d2f73c92413c30d04d0b88e771bf2595c7060df46f095f2132eca2
   ├─ 5) 0x77dc74ab2217383b4c2a772e491f8177277af576fd426f8c59f9c64d7ef258b
   └─ 6) 0x707142fb4ad00584910740c7d8207669b429cb93ce1985870b5fa5096ced91c
```

### getInputData() :
return the nth data used for the tree creation.
```typescript
const data= tree.getInputData(3);
// result = ['0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a', '26', '0']
```

### hashDataToHex() :

Hash a leaf. Returns an hex string.
```typescript
const leaf: InputForMerkle = ['0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a', '26', '0'];
const hashedLeaf: string = Merkle.hashDataToHex(leaf, Merkle.HashType.Pedersen);
// result = 0x6e5bfc0a35b74af4395c2a60a7735c0f0cbcfba515e91d4edd3f7ea70287cbc
```
> Identical to `Merkle.StarknetMerkleTree.leafHash()` .
> `Merkle.hashDataToBigint()` is similar, with a `bigint` result.

### computePoseidonHashOnElements() :

Calculate the Poseidon hash of an array of hex strings.
```typescript
const hash: bigint = Merkle.computePoseidonHashOnElements(["0x10e", "0xc4", "0x1c"]);
```

### hashPair() :

Calculate the hash of 2 bigint.

```typescript
const hash: bigint = Merkle.hashPair(200n, 300n, Merkle.HashType.Pedersen);
```

## ⚖️ License :

MIT

## 🙏 Inspiration :

Documentation and this code from OpenZeppelin were an inspiration : [repo](https://github.com/OpenZeppelin/merkle-tree)

---
_Source: https://npm.io/package/starknet-merkle-tree · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
