-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdistribution.js
142 lines (109 loc) · 3.48 KB
/
distribution.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
'use strict';
var fs = require('fs');
var path = require('path');
var ethers = require('ethers');
var contractArtifacts = require('./artifacts/contracts/MerkleDistributor1155.sol/MerkleDistributor1155.json');
function reduceMerkleBranches(leaves) {
var output = [];
while (leaves.length) {
var left = leaves.shift();
var right = (leaves.length === 0) ? left: leaves.shift();
output.push(ethers.utils.keccak256(left + right.substring(2)));
}
output.forEach(function(leaf) {
leaves.push(leaf);
});
}
var t0 = (new Date()).getTime()
function now() {
return (new Date()).getTime() - t0;
}
function expandLeaves(balances) {
var addresses = Object.keys(balances);
addresses.sort(function(a, b) {
var al = a.toLowerCase(), bl = b.toLowerCase();
if (al < bl) { return -1; }
if (al > bl) { return 1; }
return 0;
});
return addresses.map(function(a, i) { return { address: a.toLowerCase(), balance: balances[a], index: i }; });
}
function getLeaves(balances) {
var leaves = expandLeaves(balances);
return leaves.map(function(leaf) {
return ethers.utils.solidityKeccak256(["uint256", "address", "uint256"], [leaf.index, leaf.address, leaf.balance]);
});
}
function computeRootHash(balances) {
var leaves = getLeaves(balances);
while (leaves.length > 1) {
reduceMerkleBranches(leaves);
}
return leaves[0];
}
function computeMerkleProof(balances, index) {
var leaves = getLeaves(balances);
if (index == null) { throw new Error('address not found'); }
var path = index;
var proof = [ ];
while (leaves.length > 1) {
if ((path % 2) == 1) {
proof.push(leaves[path - 1])
} else {
proof.push(leaves[path + 1])
}
// Reduce the merkle tree one level
reduceMerkleBranches(leaves);
// Move up
path = parseInt(path / 2);
}
return proof;
}
function Distribution(balances) {
if (!(this instanceof Distribution)) { throw new Error('missing new') ;}
this.balances = balances;
var rootHash = null;
Object.defineProperty(this, 'rootHash', {
get: function() {
if (rootHash == null) {
rootHash = computeRootHash(balances);
}
return rootHash;
}
});
}
Distribution.prototype.getIndex = function(address) {
address = address.toLowerCase();
var leaves = expandLeaves(this.balances);
var index = null;
for (var i = 0; i < leaves.length; i++) {
if (i != leaves[i].index) { throw new Error('bad index mapping'); }
if (leaves[i].address === address) { return leaves[i].index; }
}
throw new Error('address not found');
}
Distribution.prototype.getAddress = function(index) {
var leaves = expandLeaves(this.balances);
return leaves[index].address;
}
Distribution.prototype.getAmount = function(index) {
var leaves = expandLeaves(this.balances);
return leaves[index].balance;
}
Distribution.prototype.getMerkleProof = function(index) {
return computeMerkleProof(this.balances, index);
}
Distribution.prototype.getMerkleTree = function() {
var leaves = expandLeaves(this.balances);
var proofs = [];
for(let i = 0; i < leaves.length; i++){
leaves[i].proof = computeMerkleProof(this.balances, i)
}
var tree = {
merkleRoot: this.rootHash,
amount: leaves.length,
leaves: leaves
};
return tree;
}
module.exports = Distribution;