-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathdistribution.go
75 lines (67 loc) · 2.12 KB
/
distribution.go
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
package main
import (
"fmt"
"math/big"
"sort"
solTree "github.com/0xKiwi/sol-merkle-tree-go"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
type TokenHolder struct {
addr common.Address
balance *big.Int
}
type ClaimInfo struct {
Amount string
Proof []string
}
// CreateDistributionTree uses sol-merkle-tree-go to construct a tree of balance items and returns a
// human readable mapping of address to claim info such as the proof, amount, and index.
func CreateDistributionTree(holderArray []*TokenHolder) (*solTree.MerkleTree, map[string]ClaimInfo, error) {
sort.Slice(holderArray, func(i, j int) bool {
return holderArray[i].balance.Cmp(holderArray[j].balance) > 0
})
nodes := make([][]byte, len(holderArray))
for i, user := range holderArray {
packed := append(
user.addr.Bytes(),
common.LeftPadBytes(user.balance.Bytes(), 32)...,
)
nodes[i] = crypto.Keccak256(packed)
}
tree, err := solTree.GenerateTreeFromHashedItems(nodes)
if err != nil {
return nil, nil, fmt.Errorf("could not generate trie: %v", err)
}
addrToProof := make(map[string]ClaimInfo, len(holderArray))
for i, holder := range holderArray {
proof, err := tree.MerkleProof(nodes[i])
if err != nil {
return nil, nil, fmt.Errorf("could not generate proof: %v", err)
}
addrToProof[holder.addr.String()] = ClaimInfo{
Amount: holder.balance.String(),
Proof: stringArrayFrom2DBytes(proof),
}
}
distributionRoot := tree.Root()
addrToProof["root"] = ClaimInfo{Proof: []string{fmt.Sprintf("%#x", distributionRoot)}}
return tree, addrToProof, nil
}
// ArrayFromAddrBalMap takes a string mapping of address -> balance and converts it into an array for sorting and easier usage.
func ArrayFromAddrBalMap(stringMap map[string]string) ([]*TokenHolder, error) {
i := 0
balArray := make([]*TokenHolder, len(stringMap))
for addr, bal := range stringMap {
bigInt, ok := big.NewInt(0).SetString(bal, 10)
if !ok {
return nil, fmt.Errorf("could not cast %s to big int", bal)
}
balArray[i] = &TokenHolder{
addr: common.HexToAddress(addr),
balance: bigInt,
}
i++
}
return balArray, nil
}