UNPKG

@gooddollar/goodprotocol

Version:
294 lines (257 loc) 10.1 kB
import { ethers, upgrades } from "hardhat"; import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; import { expect } from "chai"; import { GReputation, CompoundVotingMachine } from "../../types"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address"; import { createDAO } from "../helpers"; const BN = ethers.BigNumber; export const NULL_ADDRESS = "0x0000000000000000000000000000000000000000"; let grep: GReputation, grepWithOwner: GReputation, identity, gd, bounty; let signers: SignerWithAddress[], founder, repOwner, rep1, rep2, rep3; const encodeParameters = (types, values) => ethers.utils.defaultAbiCoder.encode(types, values); describe("CompoundVotingMachine#CastVote", () => { let gov: any, root: SignerWithAddress, acct: SignerWithAddress; let trivialProposal, targets, values, signatures, callDatas; let proposalBlock, proposalId, voteDelay, votePeriod; before(async () => { [root, acct, ...signers] = await ethers.getSigners(); let { daoCreator, avatar, reputation, setDAOAddress, nameService, votingMachine } = await loadFixture(createDAO); gov = votingMachine; grep = (await ethers.getContractAt( "GReputation", reputation )) as GReputation; //this will give root minter permissions await setDAOAddress("GDAO_CLAIMERS", root.address); await grep.mint(root.address, ethers.BigNumber.from("1000000")); targets = [acct.address]; values = ["0"]; signatures = ["getBalanceOf(address)"]; callDatas = [encodeParameters(["address"], [acct.address])]; await gov["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "do nothing" ); proposalBlock = +(await ethers.provider.getBlockNumber()); proposalId = await gov.latestProposalIds(root.address); trivialProposal = await gov.proposals(proposalId); voteDelay = await gov.votingDelay().then(_ => _.toNumber()); votePeriod = await gov.votingPeriod().then(_ => _.toNumber()); }); describe("We must revert if:", () => { it("There does not exist a proposal with matching proposal id where the current block number is between the proposal's start block (exclusive) and end block (inclusive)", async () => { await expect(gov.castVote(proposalId, true)).to.revertedWith(/CompoundVotingMachine::_castVote: voting is closed/ ); }); it("Such proposal already has an entry in its voters set matching the sender", async () => { await gov.connect(signers[0]).castVote(proposalId, true); await expect( gov.connect(signers[0]).castVote(proposalId, true) ).to.revertedWith(/CompoundVotingMachine::_castVote: voter already voted/ ); }); }); describe("Otherwise", () => { it("we add the sender to the proposal's voters set", async () => { let receipt = await gov.getReceipt(proposalId, signers[2].address); expect(receipt.hasVoted).to.equal(false); await gov.connect(signers[2]).castVote(proposalId, true); receipt = await gov.getReceipt(proposalId, signers[2].address); expect(receipt.hasVoted).to.equal(true); }); describe("and we take the balance returned by GetPriorVotes for the given sender and the proposal's start block, which may be zero,", () => { it("and we add that ForVotes", async () => { let actor = signers[3]; await grep.mint(actor.address, ethers.BigNumber.from("100001")); await gov .connect(actor) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "do nothing" ); await ethers.provider.send("evm_mine", []); await ethers.provider.send("evm_mine", []); let proposalId = await gov.latestProposalIds(actor.address); let beforeFors = (await gov.proposals(proposalId)).forVotes; await gov.connect(actor).castVote(proposalId, true); let aftreFors = (await gov.proposals(proposalId)).forVotes; expect(aftreFors).to.equal( beforeFors.add(ethers.BigNumber.from("100001")) ); }); it("or AgainstVotes corresponding to the caller's support flag.", async () => { let actor = signers[4]; await grep.mint(actor.address, ethers.BigNumber.from("100001")); console.log( await grep.balanceOfLocal(actor.address).then(_ => _.toString()) ); let tx = await gov .connect(actor) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "do nothing" ); await ethers.provider.send("evm_mine", []); await ethers.provider.send("evm_mine", []); let proposalId = await gov.latestProposalIds(actor.address); let beforeAgainsts = (await gov.proposals(proposalId)).againstVotes; tx = await gov.connect(actor).castVote(proposalId, false); let afterAgainsts = (await gov.proposals(proposalId)).againstVotes; expect(afterAgainsts).to.equal( beforeAgainsts.add(ethers.BigNumber.from("100001")) ); }); describe("castVoteBySig", () => { const Domain = async gov => ({ name: await gov.name(), chainId: (await ethers.provider.getNetwork()).chainId, verifyingContract: gov.address }); const Types = { Ballot: [ { name: "proposalId", type: "uint256" }, { name: "support", type: "bool" } ] }; it("reverts if the signatory is invalid", async () => { await expect( gov.castVoteBySig( proposalId, false, 0, ethers.utils.hexZeroPad("0xbac", 32), ethers.utils.hexZeroPad("0xbada", 32) ) ).to.revertedWith(/CompoundVotingMachine::castVoteBySig: invalid signature/ ); }); describe("casts vote on behalf of the signatory", async () => { let receipt; it("should cast vote", async () => { let wallet = ethers.Wallet.createRandom({ gasPrice: 10000000 }); await acct.sendTransaction({ to: wallet.address, value: ethers.utils.parseEther("9999") }); wallet = wallet.connect(ethers.provider); let actor = wallet; await grep.mint(actor.address, ethers.BigNumber.from("100001")); await gov .connect(actor) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "do nothing" ); let proposalId = await gov.latestProposalIds(actor.address); const signature = await wallet._signTypedData( await Domain(gov), Types, { proposalId: proposalId, support: true } ); const sig = ethers.utils.splitSignature(signature); let beforeFors = (await gov.proposals(proposalId)).forVotes; await ethers.provider.send("evm_mine", []); let tx = await gov.castVoteBySig( proposalId, true, sig.v, sig.r, sig.s ); receipt = await tx.wait(); let afterFors = (await gov.proposals(proposalId)).forVotes; expect(afterFors).to.equal( beforeFors.add(ethers.BigNumber.from("100001")) ); }); xit("gas costs for cast vote by sig", async () => { expect(receipt.gasUsed.toNumber()).to.be.lt(80000); }); }); xit("gas costs for multiple sigs", async () => { let wallet = ethers.Wallet.createRandom(); wallet = wallet.connect(ethers.provider); let actor = wallet; await grep.mint(actor.address, ethers.BigNumber.from("100001")); await gov .connect(actor) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "do nothing" ); let proposalId = await gov.latestProposalIds(actor.address); const sigsFor = []; const sigsAgainst = []; const createSig = async () => { let wallet = ethers.Wallet.createRandom(); wallet = wallet.connect(ethers.provider); let actor = wallet; // await grep.mint(actor.address, ethers.BigNumber.from("1")); let support = Math.random() < 0.5; const signature = await wallet._signTypedData( await Domain(gov), Types, { proposalId: proposalId, support } ); const sig = ethers.utils.splitSignature(signature); if (support) sigsFor.push({ support, v: sig.v, r: sig.r, s: sig.s }); else sigsAgainst.push({ support, v: sig.v, r: sig.r, s: sig.s }); }; const ps = []; for (let i = 1; i < 100; i++) { ps.push(createSig()); } await Promise.all(ps); await ethers.provider.send("evm_mine", []); let tx = await gov.ecRecoverTest(proposalId, sigsFor, sigsAgainst); let receipt = await tx.wait(); console.log("gas for sigs:", { i: sigsFor.length + sigsAgainst.length, gas: receipt.gasUsed.toNumber() }); }); }); }); }); });