-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a3fa956
commit badc0b3
Showing
7 changed files
with
851 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.vscode/* | ||
/dist | ||
/node_modules | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,185 @@ | ||
# starknetMerkleTree | ||
Typescript Library to handle Merkle Trees adapted for Starknet. | ||
<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> | ||
|
||
```diff | ||
+ Green Text | ||
- Red Text - | ||
**This library has not been audited ; use at your own risks.** | ||
|
||
This library is able to create 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 500 0000 leaves, each leave including 3 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'], | ||
]; | ||
const tree = Merkle.StarknetMerkleTree.create(airdrop, Merkle.HashType.Poseidon); | ||
``` | ||
|
||
### 🎰 Create a Merkle proof : | ||
```typescript | ||
const inp = 3; // Nth leaf of the input list | ||
const proof = tree.getProof(inp); | ||
``` | ||
|
||
### Hash a leaf : | ||
```typescript | ||
const inpData = tree.getInputData(inp); | ||
const leafHash = Merkle.StarknetMerkleTree.leafHash(inpData, Merkle.HashType.Poseidon); | ||
``` | ||
### 🔎 Verify a proof with Starknet.js : | ||
```typescript | ||
const inpData = tree.getInputData(inp); | ||
const isValid = tree.verify(inpData, proof); | ||
``` | ||
|
||
### 🔎 Verify a proof in the Starknet blockchain : | ||
|
||
A dedicated smart-contract is created, including only one value of the tree : the root. You send a proof (few numbers) to this contract, and it can say if an address is 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. | ||
> A Cairo 1 smart-contract is in preparation and will be released soon. It will show how to verify a Merkle proof in Starknet. Stay tune ; just need a couple of weeks to release it. | ||
> Additional scripts will be released soon. | ||
> A demo DAPP for an Airdrop is in preparation, and will be listed here. | ||
## 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']); | ||
``` | ||
|
||
### 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(["0x34e67d", '100'], proof); | ||
``` | ||
|
||
### 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 their leaves of interest. | ||
```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); | ||
``` | ||
|
||
### render() : | ||
Returns a visual representation of the tree that can be useful for debugging. | ||
```typescript | ||
console.log(tree.render()); | ||
``` | ||
|
||
### 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 = ['0x27d32a3033df4277caa9e9396100b7ca8c66a4ef8ea5f6765b91a7c17f0109c', '56','0']; | ||
const hashedLeaf: string = Merkle.hashDataToHex(leaf, Merkle.HashType.Pedersen); | ||
``` | ||
> 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"name": "starknet-merkle-tree", | ||
"version": "1.0.0", | ||
"description": "To use Merkle trees with Starknet", | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"jsdelivr": "dist/index.global.js", | ||
"unpkg": "dist/index.global.js", | ||
"types": "dist/index.d.ts", | ||
"exports": { | ||
".": { | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.js", | ||
"browser": "./dist/index.global.js", | ||
"types": "./dist/index.d.ts" | ||
} | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "tsup", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"author": "Philippe ROSTAN", | ||
"repository": "github:PhilippeR26/starknetMerkleTree", | ||
"keywords": [ | ||
"merkle", | ||
"starknet", | ||
"tree", | ||
"airdrop" | ||
], | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@types/node": "^20.10.8", | ||
"ts-node": "^10.9.2", | ||
"tsup": "^8.0.1", | ||
"typescript": "^5.3.3" | ||
}, | ||
"dependencies": { | ||
"starknet": "^5.24.3" | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.