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 }