/ utils / secretMultisig.js
secretMultisig.js
 1  const { MerkleTree } = require('./merkleTree.js');
 2  const { keccak256, bufferToHex, isValidAddress, setLengthLeft } = require('ethereumjs-util');
 3  const namehash = require('eth-ens-namehash');
 4  
 5  const MINIMUM_LIST_SIZE = 4096;
 6  const THRESHOLD = 100 * 10**18;
 7  const RECOVERY_ADDRESS = "0x2429242924292429242924292429242924292429";
 8  const ERC2429 = require('Embark/contracts/MultisigRecovery');
 9  
10  export default class SecretMultisig {
11  
12      constructor(userAddress, privateHash, addressList) {
13          if (addressList.length == 0){
14              throw new Error("Invalid Address List")
15          } 
16          
17          this.elements = addressList.map((v) => this.hashLeaf(v.address, v.weight));
18          if(this.elements.length < MINIMUM_LIST_SIZE) {
19              this.elements.push(... Array.from({length: MINIMUM_LIST_SIZE-this.elements.length}, (v,k) => hashFakeLeaf(privateHash, k)))
20          }
21          this.merkleTree = new MerkleTree(this.elements);
22          this.executeHash = this.hashExecute(privateHash, userAddress);
23          this.partialReveal = keccak256(this.executeHash);
24          this.publicHash = keccak256(Buffer.concat(
25              this.partialReveal, 
26              keccak256(this.merkleTree.getRoot())
27          ));
28      }
29  
30  
31      hashExecute = async (privateHash, userAddress) => keccak256(Buffer.concat(
32          privateHash, 
33          Buffer,from(ERC2429.address, 'hex'),
34          setLengthLeft(Buffer.from(Number.toString(await ERC2429.methods.nonce(userAddress).call(), 16), 'hex'), 32)
35      ));
36  
37      
38      hashLeaf = (ethereumAddress, weight) => keccak256(Buffer.concat(
39          this.hashAddress(ethereumAddress), 
40          setLengthLeft(Buffer.from(Number.toString(weight, 16), 'hex'), 32)
41      ));
42  
43      hashFakeLeaf = (privateHash, position) => keccak256(Buffer.concat(
44          privateHash,
45          setLengthLeft(Buffer.from(Number.toString(position, 16), 'hex'), 32)
46      ));
47  
48      hashAddress = (ethereumAddress) => keccak256(
49          isValidAddress(ethereumAddress) ? Buffer.concat(
50              Buffer.from('0x00', 'hex'),
51              setLengthLeft(Buffer.from(ethereumAddress, 'hex'), 32)
52          ) : Buffer.concat(
53              Buffer.from('0x01', 'hex'),
54              namehash(ethereumAddress)
55          )
56      );
57  
58      hashApproval = (approver_address, calldest, calldata) => keccak256(Buffer.concat(
59          this.hashAddress(approver_address),
60          this.hashCall(calldest, calldata)
61      ));
62  
63  
64      hashCall = (calldest, calldata) => keccak256(Buffer.concat(
65          this.partialReveal,
66          Buffer.from(calldest, 'hex'),
67          Buffer.from(calldata, 'hex')
68      ));
69  
70  }