mirror of
https://github.com/status-im/topic-democracy.git
synced 2025-02-24 08:08:11 +00:00
add tests
This commit is contained in:
parent
e2199110c8
commit
6bc051e211
@ -21,6 +21,27 @@ config({
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Delegations: Root, Sticker Market, ENS Usernames, Version Listings
|
||||
* Functions:
|
||||
* - Root
|
||||
* - Sticker Market
|
||||
* - change controller : Absolute Majority
|
||||
* - change rates : Simple Majority
|
||||
* - purgconte pack : Simple Majority
|
||||
* - ENS Usernames
|
||||
* - change controller : Simple Majority
|
||||
* - migrate registry :
|
||||
* - change price
|
||||
* - Version Listing
|
||||
* - change developer address
|
||||
* - remove version
|
||||
* - add release category (android,ios,linux,etc)
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
contract("DelegationBase", function() {
|
||||
this.timeout(0);
|
||||
var defaultDelegate;
|
||||
@ -129,6 +150,7 @@ contract("DelegationBase", function() {
|
||||
})
|
||||
|
||||
it("Child a2 delegate to a4", async function () {
|
||||
|
||||
result = await ChildDelegation.methods.delegate(accounts[4]).send({from: accounts[2]})
|
||||
const delegateArgs = result.events.Delegate.returnValues;
|
||||
assert.equal(delegateArgs.who, accounts[2])
|
||||
@ -137,6 +159,7 @@ contract("DelegationBase", function() {
|
||||
result = await ChildDelegation.methods.delegatedTo(accounts[2]).call()
|
||||
assert.equal(result, accounts[4])
|
||||
|
||||
|
||||
result = await ChildDelegation.methods.delegationOf(accounts[0]).call()
|
||||
assert.equal(result, defaultDelegate)
|
||||
result = await ChildDelegation.methods.delegationOf(accounts[1]).call()
|
||||
@ -144,7 +167,27 @@ contract("DelegationBase", function() {
|
||||
result = await ChildDelegation.methods.delegationOf(accounts[2]).call()
|
||||
assert.equal(result, defaultDelegate)
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
it("default delegate should be able to delegate", async function () {
|
||||
await ChildDelegation.methods.delegate(accounts[6]).send({from: accounts[6]})
|
||||
newDelegate = await ChildDelegation.methods.delegationOf(accounts[6]).call()
|
||||
result = await ChildDelegation.methods.delegate(accounts[6]).send({from: defaultDelegate})
|
||||
const delegateArgs = result.events.Delegate.returnValues;
|
||||
assert.equal(delegateArgs.who, defaultDelegate)
|
||||
assert.equal(delegateArgs.to, accounts[6])
|
||||
|
||||
result = await ChildDelegation.methods.delegatedTo(defaultDelegate).call()
|
||||
assert.equal(result, accounts[6])
|
||||
|
||||
result = await ChildDelegation.methods.delegationOf(accounts[0]).call()
|
||||
assert.equal(result, newDelegate)
|
||||
result = await ChildDelegation.methods.delegationOf(accounts[1]).call()
|
||||
assert.equal(result, newDelegate)
|
||||
result = await ChildDelegation.methods.delegationOf(accounts[2]).call()
|
||||
assert.equal(result, newDelegate)
|
||||
|
||||
|
||||
})
|
||||
})
|
378
test/proposal.js
Normal file
378
test/proposal.js
Normal file
@ -0,0 +1,378 @@
|
||||
const utils = require("../utils/testUtils")
|
||||
|
||||
|
||||
const DefaultDelegation = require('Embark/contracts/DefaultDelegation');
|
||||
const DelegationFactory = require('Embark/contracts/DelegationFactory');
|
||||
const MiniMeToken = require('Embark/contracts/MiniMeToken');
|
||||
const Delegation = require('Embark/contracts/Delegation');
|
||||
const ProposalFactory = require('Embark/contracts/ProposalFactory');
|
||||
const Proposal = require('Embark/contracts/Proposal');
|
||||
const ProposalBase = require('Embark/contracts/ProposalBase');
|
||||
|
||||
config({
|
||||
contracts: {
|
||||
"MiniMeTokenFactory": {
|
||||
},
|
||||
"MiniMeToken": {
|
||||
"args": [
|
||||
"$MiniMeTokenFactory",
|
||||
utils.zeroAddress,
|
||||
0,
|
||||
"TestMiniMeToken",
|
||||
18,
|
||||
"TST",
|
||||
true
|
||||
]
|
||||
},
|
||||
"DefaultDelegation": {
|
||||
"args": [ "$accounts[5]" ]
|
||||
},
|
||||
"DelegationBase": {
|
||||
"args": [ utils.zeroAddress ]
|
||||
},
|
||||
"DelegationInit": {},
|
||||
"DelegationFactory": {
|
||||
"args": ["$DelegationBase", "$DelegationInit", utils.zeroAddress]
|
||||
},
|
||||
"ProposalBase": {},
|
||||
"ProposalInit": {},
|
||||
"ProposalFactory": {
|
||||
"args": ["$ProposalBase", "$ProposalInit", utils.zeroAddress]
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
function mintTokens(accounts, amount) {
|
||||
return Promise.all(
|
||||
accounts.map((account) => {
|
||||
return MiniMeToken.methods.generateTokens(account, amount).send({from: accounts[0]});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function newDelegation(topDelegation) {
|
||||
return new Promise((resolve, reject) => {
|
||||
DelegationFactory.methods.createDelegation(topDelegation).send().on('receipt', (receipt) => {
|
||||
resolve(new web3.eth.Contract(Delegation._jsonInterface, receipt.events.InstanceCreated.returnValues[0]));
|
||||
}).on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async function addGas(call, from, amount=21000) {
|
||||
return call.send({
|
||||
gas: await call.estimateGas({gas: 8000000})+amount,
|
||||
from: from
|
||||
});
|
||||
}
|
||||
|
||||
async function tabulateDirect(proposal, account) {
|
||||
return addGas(proposal.methods.tabulateDirect(account), web3.eth.defaultAccount);
|
||||
}
|
||||
|
||||
async function tabulateDelegated(proposal, account) {
|
||||
return addGas(proposal.methods.tabulateDelegated(account), web3.eth.defaultAccount);
|
||||
}
|
||||
|
||||
async function tabulateSigned(proposal, sig) {
|
||||
return addGas(
|
||||
proposal.methods.tabulateSigned(
|
||||
sig.vote,
|
||||
sig.position,
|
||||
sig.proof,
|
||||
sig.signature
|
||||
),
|
||||
web3.eth.defaultAccount
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
contract("Proposal", function() {
|
||||
this.timeout(0);
|
||||
const initialBalance = 17 * 10 ^ 18;
|
||||
var defaultDelegate;
|
||||
var accounts;
|
||||
var RootDelegation;
|
||||
var ChildDelegation;
|
||||
|
||||
before(function(done) {
|
||||
defaultDelegate = DefaultDelegation._address;
|
||||
web3.eth.getAccounts().then((res) => {
|
||||
web3.eth.defaultAccount = res[0]
|
||||
accounts = res;
|
||||
//let contactList = require("./contacts.json")
|
||||
//contacts = Object.keys(contactList).map((key) => { return { name: contactList[key].name.en, address: utils.pubKeyToAddress(key), pubKey: key }})
|
||||
//res = accounts.concat(contacts.map((obj) => {return obj.address } ));
|
||||
mintTokens(res, initialBalance).then((mintReceipts) => {
|
||||
newDelegation(defaultDelegate).then((createdRoot) => {
|
||||
RootDelegation = createdRoot;
|
||||
newDelegation(RootDelegation._address).then((createdChild) => {
|
||||
ChildDelegation = createdChild;
|
||||
Promise.all([
|
||||
// root: 0 -> 1 -> 2 -> 3 (-> 5)
|
||||
RootDelegation.methods.delegate(accounts[1]).send({from: accounts[0]}),
|
||||
RootDelegation.methods.delegate(accounts[2]).send({from: accounts[1]}),
|
||||
RootDelegation.methods.delegate(accounts[3]).send({from: accounts[2]}),
|
||||
// root: 4 -> 4
|
||||
RootDelegation.methods.delegate(accounts[4]).send({from: accounts[4]}),
|
||||
|
||||
// root: 6 -> 7 -> 8 -> 9 -> 6 (circular)
|
||||
RootDelegation.methods.delegate(accounts[7]).send({from: accounts[6]}),
|
||||
RootDelegation.methods.delegate(accounts[8]).send({from: accounts[7]}),
|
||||
RootDelegation.methods.delegate(accounts[9]).send({from: accounts[8]}),
|
||||
RootDelegation.methods.delegate(accounts[6]).send({from: accounts[9]}),
|
||||
// child: 5 -> 6
|
||||
ChildDelegation.methods.delegate(accounts[7]).send({from: accounts[5]})
|
||||
]).then((delegateReceipts) => {
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const QUORUM_QUALIFIED = 0;
|
||||
const QUORUM_MAJORITY = 1;
|
||||
const QUORUM_SIMPLE = 2;
|
||||
|
||||
const VOTE_NULL = 0;
|
||||
const VOTE_REJECT = 1;
|
||||
const VOTE_APPROVE = 2;
|
||||
|
||||
var testProposal;
|
||||
var blockStart
|
||||
it("create proposal by factory", async function () {
|
||||
let tabulationBlockDelay = 50;
|
||||
blockStart = await web3.eth.getBlockNumber() + 10;
|
||||
let blockEndDelay = 10;
|
||||
receipt = await ProposalFactory.methods.createProposal(
|
||||
MiniMeToken._address,
|
||||
RootDelegation._address,
|
||||
"0xDA0",
|
||||
tabulationBlockDelay,
|
||||
blockStart,
|
||||
blockEndDelay,
|
||||
QUORUM_QUALIFIED
|
||||
).send()
|
||||
testProposal = new web3.eth.Contract(ProposalBase._jsonInterface, receipt.events.InstanceCreated.returnValues[0]);
|
||||
|
||||
});
|
||||
|
||||
it("rejects signed and direct votes while not voting period ", async function () {
|
||||
assert(await web3.eth.getBlockNumber() < blockStart, "Wrong block number")
|
||||
assert(await utils.assertEVMException(testProposal.methods.voteDirect(VOTE_APPROVE).send({from: accounts[0]}), "Voting not started"), "Didnt rejected")
|
||||
assert(await utils.assertEVMException(testProposal.methods.voteSigned(utils.zeroBytes32).send({from: accounts[0]}), "Voting not started"), "Didnt rejected")
|
||||
});
|
||||
|
||||
|
||||
it("increases block number to vote block start", async function () {
|
||||
await utils.setBlockNumber(blockStart);
|
||||
assert(await web3.eth.getBlockNumber() >= blockStart, "Wrong block number")
|
||||
});
|
||||
|
||||
|
||||
it("direct vote", async function () {
|
||||
let receipt = await testProposal.methods.voteDirect(VOTE_APPROVE).send({from: accounts[5]});
|
||||
assert.equal(receipt.events.Voted.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Voted.returnValues[1], accounts[5]);
|
||||
});
|
||||
|
||||
const { MerkleTree } = require('../utils/merkleTree.js');
|
||||
var sigs = [];
|
||||
|
||||
|
||||
it("signed vote at voting period", async function () {
|
||||
let vote = VOTE_APPROVE;
|
||||
let approveHash = await testProposal.methods.getVoteHash(vote).call();
|
||||
let signatures = await Promise.all(accounts.map((address) => {
|
||||
//in web app should web3.eth.personal.sign(approveHash, address)
|
||||
return web3.eth.sign(approveHash, address);
|
||||
}))
|
||||
let merkleTree = new MerkleTree(signatures);
|
||||
let merkleRoot = merkleTree.getHexRoot();
|
||||
|
||||
let receipt = await testProposal.methods.voteSigned(merkleRoot).send({from: accounts[0]})
|
||||
let position = 0;
|
||||
assert.equal(receipt.events.VoteSignatures.returnValues[0], position)
|
||||
assert.equal(receipt.events.VoteSignatures.returnValues[1], merkleRoot);
|
||||
for(var i = 0; i < signatures.length; i++) {
|
||||
sigs.push ({
|
||||
position: position,
|
||||
vote: vote,
|
||||
signature: signatures[i],
|
||||
proof: merkleTree.getHexProof(signatures[i]),
|
||||
signer: accounts[i]
|
||||
})
|
||||
|
||||
}
|
||||
});
|
||||
var voteBlockEnd;
|
||||
it("tests under block end", async function () {
|
||||
voteBlockEnd = await testProposal.methods.voteBlockEnd().call();
|
||||
assert(await web3.eth.getBlockNumber() <= voteBlockEnd, "Current block number is too low for testing");
|
||||
})
|
||||
|
||||
it("reject tabulateDirect when voting not ended", async function () {
|
||||
assert(await utils.assertEVMException(tabulateDirect(testProposal, accounts[5]), "Block end not reached"), "Didnt rejected")
|
||||
});
|
||||
|
||||
it("reject tabulateDelegated when voting not ended", async function () {
|
||||
assert(await utils.assertEVMException(tabulateDelegated(testProposal, accounts[0]), "Block end not reached"), "Didnt rejected")
|
||||
});
|
||||
|
||||
it("reject tabulateSigned when voting not ended", async function () {
|
||||
assert(await utils.assertEVMException(tabulateSigned(testProposal, sigs[0]), "Block end not reached"), "Didnt rejected")
|
||||
});
|
||||
|
||||
it("increases block number to vote block end", async function () {
|
||||
await utils.setBlockNumber(voteBlockEnd+1);
|
||||
assert(await web3.eth.getBlockNumber() > voteBlockEnd, "Wrong block number")
|
||||
});
|
||||
|
||||
it("rejects direct votes when voting period ended", async function () {
|
||||
assert(await utils.assertEVMException(testProposal.methods.voteDirect(VOTE_APPROVE).send({from: accounts[1]}), "Voting ended"), "Didnt rejected")
|
||||
});
|
||||
|
||||
it("rejects signed votes when voting period ended", async function () {
|
||||
assert(await utils.assertEVMException(testProposal.methods.voteSigned(utils.zeroBytes32).send({from: accounts[0]}), "Voting ended"), "Didnt rejected")
|
||||
});
|
||||
|
||||
it("reject tabulates when no delegate voted", async function () {;
|
||||
assert(await utils.assertEVMException(tabulateDelegated(testProposal, accounts[4]), "No delegate vote found"), "Didnt rejected 2")
|
||||
});
|
||||
|
||||
|
||||
it("tabulates influence from self voter", async function () {
|
||||
let receipt = await tabulateDirect(testProposal, accounts[5]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[5]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[5]);
|
||||
|
||||
});
|
||||
|
||||
it("tabulates influence from default delegate", async function () {
|
||||
receipt = await tabulateDelegated(testProposal, accounts[3]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[5]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[3]);
|
||||
|
||||
});
|
||||
|
||||
it("tabulates influence from voteSigned ", async function () {
|
||||
let sig = sigs[2];
|
||||
let receipt = await tabulateSigned(testProposal, sig);
|
||||
assert.equal(receipt.events.Voted.returnValues[0], sig.vote, "emit Voted wrong Vote")
|
||||
assert.equal(receipt.events.Voted.returnValues[1], sig.signer, "emit Voted wrong address");
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], sig.vote, "emit Claimed wrong Vote")
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], sig.signer, "emit Claimed wrong claimer");
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], sig.signer, "emit Claimed wrong source");
|
||||
});
|
||||
|
||||
|
||||
it("should not tabulate for delegate if voted ", async function () {
|
||||
assert(await utils.assertEVMException(tabulateDelegated(testProposal, accounts[2]), "Not delegatable"), "Didnt rejected ")
|
||||
assert(await utils.assertEVMException(tabulateDelegated(testProposal, accounts[5]), "Not delegatable"), "Didnt rejected 2")
|
||||
});
|
||||
|
||||
it("tabulates influence from direct delegate ", async function () {
|
||||
let receipt = await tabulateDelegated(testProposal, accounts[1]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[2]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[1])
|
||||
});
|
||||
|
||||
it("tabulates influence from indirect delegate", async function () {
|
||||
let receipt = await tabulateDelegated(testProposal, accounts[0]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[2]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[0])
|
||||
});
|
||||
|
||||
it("should not tabulate influence from circular delegation chain when none voted", async function () {
|
||||
assert(await utils.assertEVMException(tabulateDelegated(testProposal, accounts[7]), "revert"), "Didnt rejected ")
|
||||
});
|
||||
|
||||
|
||||
it("tabulates signature from circular delegation", async function () {
|
||||
await tabulateSigned(testProposal, sigs[7]);
|
||||
})
|
||||
|
||||
it("tabulates influence from circular direct delegate", async function () {
|
||||
var receipt = await tabulateDelegated(testProposal, accounts[6]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[7]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[6])
|
||||
})
|
||||
|
||||
it("tabulates influence from circular indirect delegate", async function () {
|
||||
receipt = await tabulateDelegated(testProposal, accounts[9]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[7]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[9])
|
||||
})
|
||||
it("tabulates influence from circular delegate of claiming delegate", async function () {
|
||||
receipt = await tabulateDelegated(testProposal, accounts[8]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[7]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[8])
|
||||
})
|
||||
|
||||
it("retabulates influence to self vote", async function () {
|
||||
sig = sigs[6];
|
||||
receipt = await tabulateSigned(testProposal, sig);
|
||||
assert.equal(receipt.events.Voted.returnValues[0], sig.vote, "emit Voted wrong Vote")
|
||||
assert.equal(receipt.events.Voted.returnValues[1], sig.signer, "emit Voted wrong address");
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], sig.vote, "emit Claimed wrong Vote")
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], sig.signer, "emit Claimed wrong claimer");
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], sig.signer, "emit Claimed wrong source");
|
||||
|
||||
});
|
||||
|
||||
it("retabulates influence to indirect delegate", async function () {
|
||||
receipt = await tabulateDelegated(testProposal, accounts[8]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[6]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[8])
|
||||
});
|
||||
|
||||
it("retabulates influence to direct delegate", async function () {
|
||||
receipt = await tabulateDelegated(testProposal, accounts[9]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[0], VOTE_APPROVE)
|
||||
assert.equal(receipt.events.Claimed.returnValues[1], accounts[6]);
|
||||
assert.equal(receipt.events.Claimed.returnValues[2], accounts[9])
|
||||
});
|
||||
|
||||
it("create proposal by factory", async function () {
|
||||
let tabulationBlockDelay = 50;
|
||||
blockStart = await web3.eth.getBlockNumber();
|
||||
let blockEndDelay = 10;
|
||||
receipt = await ProposalFactory.methods.createProposal(
|
||||
MiniMeToken._address,
|
||||
ChildDelegation._address,
|
||||
"0xDA0",
|
||||
tabulationBlockDelay,
|
||||
blockStart,
|
||||
blockEndDelay,
|
||||
QUORUM_QUALIFIED
|
||||
).send()
|
||||
testProposal = new web3.eth.Contract(ProposalBase._jsonInterface, receipt.events.InstanceCreated.returnValues[0]);
|
||||
});
|
||||
|
||||
it("child delegation default parent chain break", async function () {
|
||||
|
||||
});
|
||||
it("child delegation indirect parent chain break", async function () {
|
||||
|
||||
});
|
||||
it("child delegation parent chain full break", async function () {
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
133
utils/merkleTree.js
Normal file
133
utils/merkleTree.js
Normal file
@ -0,0 +1,133 @@
|
||||
const { sha3, bufferToHex } = require('ethereumjs-util');
|
||||
|
||||
class MerkleTree {
|
||||
constructor(elements) {
|
||||
// Filter empty strings and hash elements
|
||||
this.elements = elements.filter(el => el).map(el => sha3(el));
|
||||
|
||||
// Deduplicate elements
|
||||
this.elements = this.bufDedup(this.elements);
|
||||
// Sort elements
|
||||
this.elements.sort(Buffer.compare);
|
||||
|
||||
// Create layers
|
||||
this.layers = this.getLayers(this.elements);
|
||||
}
|
||||
|
||||
getLayers(elements) {
|
||||
if (elements.length == 0) {
|
||||
return [[""]];
|
||||
}
|
||||
|
||||
const layers = [];
|
||||
layers.push(elements);
|
||||
|
||||
// Get next layer until we reach the root
|
||||
while (layers[layers.length - 1].length > 1) {
|
||||
layers.push(this.getNextLayer(layers[layers.length - 1]));
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
|
||||
getNextLayer(elements) {
|
||||
return elements.reduce((layer, el, idx, arr) => {
|
||||
if (idx % 2 === 0) {
|
||||
// Hash the current element with its pair element
|
||||
layer.push(this.combinedHash(el, arr[idx + 1]));
|
||||
}
|
||||
|
||||
return layer;
|
||||
}, []);
|
||||
}
|
||||
|
||||
combinedHash(first, second) {
|
||||
if (!first) { return second; }
|
||||
if (!second) { return first; }
|
||||
|
||||
return sha3(this.sortAndConcat(first, second));
|
||||
}
|
||||
|
||||
getRoot() {
|
||||
return this.layers[this.layers.length - 1][0];
|
||||
}
|
||||
|
||||
getHexRoot() {
|
||||
return bufferToHex(this.getRoot());
|
||||
}
|
||||
|
||||
getProof(el) {
|
||||
let idx = this.bufIndexOf(el, this.elements);
|
||||
|
||||
if (idx === -1) {
|
||||
throw new Error("Element does not exist in Merkle tree");
|
||||
}
|
||||
|
||||
return this.layers.reduce((proof, layer) => {
|
||||
const pairElement = this.getPairElement(idx, layer);
|
||||
|
||||
if (pairElement) {
|
||||
proof.push(pairElement);
|
||||
}
|
||||
|
||||
idx = Math.floor(idx / 2);
|
||||
|
||||
return proof;
|
||||
}, []);
|
||||
}
|
||||
|
||||
getHexProof(el) {
|
||||
const proof = this.getProof(el);
|
||||
|
||||
return this.bufArrToHex(proof);
|
||||
}
|
||||
|
||||
getPairElement(idx, layer) {
|
||||
const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1;
|
||||
|
||||
if (pairIdx < layer.length) {
|
||||
return layer[pairIdx];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bufIndexOf(el, arr) {
|
||||
let hash;
|
||||
|
||||
// Convert element to 32 byte hash if it is not one already
|
||||
if (el.length !== 32 || !Buffer.isBuffer(el)) {
|
||||
hash = sha3(el);
|
||||
} else {
|
||||
hash = el;
|
||||
}
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (hash.equals(arr[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bufDedup(elements) {
|
||||
return elements.filter((el, idx) => {
|
||||
return this.bufIndexOf(el, elements) === idx;
|
||||
});
|
||||
}
|
||||
|
||||
bufArrToHex(arr) {
|
||||
if (arr.some(el => !Buffer.isBuffer(el))) {
|
||||
throw new Error("Array is not an array of buffers");
|
||||
}
|
||||
|
||||
return arr.map(el => '0x' + el.toString('hex'));
|
||||
}
|
||||
|
||||
sortAndConcat(...args) {
|
||||
return Buffer.concat([...args].sort(Buffer.compare));
|
||||
}
|
||||
}
|
||||
|
||||
exports.MerkleTree = MerkleTree;
|
@ -43,6 +43,13 @@ exports.addressToBytes32 = (address) => {
|
||||
return "0x" + stringed.substring(stringed.length - 64, stringed.length);
|
||||
}
|
||||
|
||||
exports.pubKeyToAddress = (contactCode) => {
|
||||
if(contactCode.length != 132 || contactCode.substring(0,4) != "0x04") {
|
||||
throw "Invalid contact code: " +contactCode;
|
||||
}
|
||||
return web3.utils.toChecksumAddress("0x" + web3.utils.soliditySha3({t: 'bytes', v: ("0x" + contactCode.substring(4))}).substring(26));
|
||||
}
|
||||
|
||||
|
||||
// OpenZeppelin's expectThrow helper -
|
||||
// Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js
|
||||
@ -200,6 +207,73 @@ exports.ensureException = function(error) {
|
||||
assert(isException(error), error.toString());
|
||||
};
|
||||
|
||||
const NO_ERROR = 0;
|
||||
const FATAL_ERROR = 1;
|
||||
const OUT_OF_GAS = 2;
|
||||
const USER_ERROR = 3;
|
||||
|
||||
exports.getEVMException = async function(sendFn) {
|
||||
var error = null;
|
||||
try {
|
||||
await sendFn.estimateGas();
|
||||
} catch(e) {
|
||||
var a = e.toString().split(": ");
|
||||
if(a[0] != "RuntimeError" || a[1] != "VM Exception while processing transaction") {
|
||||
throw e;
|
||||
}
|
||||
|
||||
switch (a[3]){
|
||||
case "out of gas":
|
||||
case "invalid opcode":
|
||||
case "invalid JUMP":
|
||||
case "stack overflow":
|
||||
case "revert":
|
||||
error = a[3]
|
||||
break;
|
||||
default:
|
||||
if(a[3].startsWith("revert ")){
|
||||
error = a[3].substring(7)
|
||||
} else {
|
||||
error = a[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.assertEVMException = async function(sendFn, error="") {
|
||||
try {
|
||||
await sendFn;
|
||||
return false;
|
||||
} catch (e) {
|
||||
let strError = e.toString();
|
||||
if(error == ""){
|
||||
return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert');
|
||||
} else {
|
||||
return strError.includes(error);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
exports.strictEVMException = async function(sendFn, error="") {
|
||||
try {
|
||||
await sendFn;
|
||||
return false;
|
||||
} catch (e) {
|
||||
let strError = e.toString();
|
||||
if(error == ""){
|
||||
return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert');
|
||||
} else {
|
||||
return strError.includes(error);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
function isException(error) {
|
||||
let strError = error.toString();
|
||||
return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert');
|
||||
@ -207,33 +281,100 @@ function isException(error) {
|
||||
|
||||
exports.increaseTime = async (amount) => {
|
||||
return new Promise(function(resolve, reject) {
|
||||
web3.currentProvider.sendAsync(
|
||||
web3.currentProvider.send(
|
||||
{
|
||||
jsonrpc: '2.0',
|
||||
method: 'evm_increaseTime',
|
||||
params: [+amount],
|
||||
id: new Date().getSeconds()
|
||||
},
|
||||
async (error) => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return reject(err);
|
||||
}
|
||||
await web3.currentProvider.sendAsync(
|
||||
{
|
||||
jsonrpc: '2.0',
|
||||
method: 'evm_mine',
|
||||
params: [],
|
||||
id: new Date().getSeconds()
|
||||
}, (error) => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return reject(err);
|
||||
}
|
||||
resolve();
|
||||
}, (error) => {
|
||||
if (error) {
|
||||
reject(err);
|
||||
} else {
|
||||
web3.currentProvider.send({
|
||||
jsonrpc: '2.0',
|
||||
method: 'evm_mine',
|
||||
params: [],
|
||||
id: new Date().getSeconds()
|
||||
}, (error) => {
|
||||
if (error) {
|
||||
reject(err);
|
||||
}else {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
exports.setTime = async (timestamp) => {
|
||||
return new Promise(function(resolve, reject) {
|
||||
web3.currentProvider.send({
|
||||
jsonrpc: '2.0',
|
||||
method: 'evm_mine',
|
||||
params: [+timestamp],
|
||||
id: new Date().getSeconds()
|
||||
}, (error,s)=>{
|
||||
if(error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.increaseBlock = (amount) => {
|
||||
return new Promise(function(resolve, reject) {
|
||||
web3.currentProvider.send(
|
||||
{
|
||||
jsonrpc: '2.0',
|
||||
method: 'evm_mine',
|
||||
params: [],
|
||||
id: new Date().getSeconds()
|
||||
},
|
||||
(error,s)=>{
|
||||
if(error) {
|
||||
reject(error);
|
||||
} else {
|
||||
if(amount == 1) {
|
||||
resolve()
|
||||
}else {
|
||||
exports.increaseBlock(amount-1).then(() => {
|
||||
resolve();
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.setBlockNumber = (newBlockNumber) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
web3.eth.getBlockNumber().then((blockNumber) => {
|
||||
if(blockNumber > newBlockNumber) {
|
||||
reject("Cannot go back");
|
||||
} else if (blockNumber < newBlockNumber) {
|
||||
exports.increaseBlock(newBlockNumber - blockNumber).then(()=>{
|
||||
resolve();
|
||||
})
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.addGas = (call, from, amount=1010) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
call.estimateGas().then((gas) => {
|
||||
call.send({
|
||||
gas: gas+amount,
|
||||
from: from
|
||||
}).on('error', reject).then(resolve);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user