This repository has been archived by the owner on Jun 28, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmerkle-tree.js
79 lines (59 loc) · 2.03 KB
/
merkle-tree.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
const ethers = require('ethers');
function processDistribution(dist) {
dist = dist.map(d => {
return {
account: d.account.toLowerCase(),
token: d.token.toLowerCase(),
claimable: d.claimable,
leaf: ethers.utils.concat([ d.account, d.token, ethers.utils.hexZeroPad(d.claimable, 32) ]),
};
});
return dist.sort((a,b) => Buffer.compare(a.leaf, b.leaf));
}
function hashLevel(level) {
let nextLevel = [];
for (let i = 0; i < level.length; i += 2) {
if (i === level.length - 1) nextLevel.push(level[i]); // odd number of nodes at this level
else nextLevel.push(ethers.utils.keccak256(ethers.utils.concat([level[i], level[i+1]].sort())));
}
return nextLevel;
}
function root(items) {
if (items.length === 0) throw("can't build merkle tree with empty items");
items = processDistribution(items);
let level = items.map(d => ethers.utils.keccak256(d.leaf));
while (level.length > 1) {
level = hashLevel(level);
}
return level[0];
}
function proof(items, account, token) {
account = account.toLowerCase();
token = token.toLowerCase();
items = processDistribution(items);
let level = items.map(d => ethers.utils.keccak256(d.leaf));
let origIndex = items.findIndex((i) => i.account === account && i.token == token);
if (origIndex === -1) throw("item not found in items: " + item);
let witnesses = [];
let index = origIndex;
while (level.length > 1) {
let nextIndex = Math.floor(index / 2);
if (nextIndex * 2 === index) { // left side
if (index < level.length - 1) { // only if we're not the last in a level with odd number of nodes
witnesses.push(level[index + 1]);
}
} else { // right side
witnesses.push(level[index - 1]);
}
index = nextIndex;
level = hashLevel(level);
}
return {
item: items[origIndex],
witnesses,
};
}
module.exports = {
root,
proof,
};