UNPKG

@gooddollar/goodprotocol

Version:
297 lines (243 loc) 9.7 kB
import hre, { 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, increaseTime } 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; let nameService; const encodeParameters = (types, values) => ethers.utils.defaultAbiCoder.encode(types, values); const advanceBlocks = async (blocks: number) => { let ps = []; for (let i = 0; i < blocks; i++) { ps.push(ethers.provider.send("evm_mine", [])); if (i % 5000 === 0) { await Promise.all(ps); ps = []; } } }; const states = [ "Pending", "Active", "ActiveTimelock", "Canceled", "Defeated", "Succeeded", "Expired", "Executed" ]; describe("CompoundVotingMachine#Guardian", () => { let gov: CompoundVotingMachine, root: SignerWithAddress, acct: SignerWithAddress; let queuePeriod, avatarGenericCall; let avatar, Controller; before(async () => { [root, acct, ...signers] = await ethers.getSigners(); let { daoCreator, controller, avatar: av, setSchemes, reputation, setDAOAddress, genericCall, nameService: ns, votingMachine } = await loadFixture(createDAO); Controller = controller; avatar = av; avatarGenericCall = genericCall; nameService = ns; grep = (await ethers.getContractAt( "GReputation", reputation )) as GReputation; gov = votingMachine; //this will give root minter permissions await setDAOAddress("GDAO_CLAIMERS", root.address); //set voting machiine as scheme with permissions await setSchemes([gov.address]); await grep.mint(root.address, ethers.BigNumber.from("1000000")); await grep.mint(acct.address, ethers.BigNumber.from("500000")); queuePeriod = await gov.queuePeriod().then(_ => _.toNumber()); }); it("should set guardian from initializer", async () => { const votingMachine = (await upgrades.deployProxy( await ethers.getContractFactory("CompoundVotingMachine"), [nameService.address, 5760, signers[2].address, NULL_ADDRESS], { kind: "uups" } )) as unknown as CompoundVotingMachine; expect(await votingMachine.guardian()).to.equal(signers[2].address); }); it("Should have deployer as guardian", async () => { expect(await gov.guardian()).to.equal(root.address); }); it("Should not be able to change guardian if not guardian or avatar", async () => { await expect( gov.connect(acct).setGuardian(acct.address) ).to.be.revertedWith(/CompoundVotingMachine: not avatar or guardian/); }); it("Should not be able to change guardian before foundation release time by avatar", async () => { const encoded = gov.interface.encodeFunctionData("setGuardian", [ acct.address ]); await avatarGenericCall(gov.address, encoded); expect(await gov.guardian()).to.equal(root.address); }); it("Should not be able to renounce guardian if not guardian", async () => { await expect(gov.connect(acct).renounceGuardian()).to.be.revertedWith( /CompoundVotingMachine: not guardian/ ); }); it("Should be able to set guardian by guardian before foundation expired", async () => { await gov.setGuardian(acct.address); expect(await gov.guardian()).to.equal(acct.address); await gov.connect(acct).setGuardian(root.address); //restore }); it("Should allow set guardian to fix bad guardian deployment", async () => { const badAddress = "0x4659176E962763e7C8A4eF965ecfD0fdf9f52057"; await gov.setGuardian(badAddress); expect(await gov.guardian()).to.equal(badAddress); await gov.connect(acct).fixGuardian(root.address); expect(await gov.guardian()).to.equal(root.address); }); it("Should be able to set guardian by avatar if foundation expired", async () => { await ethers.provider.send("evm_setNextBlockTimestamp", [1672531201]); //1672531200 await ethers.provider.send("evm_mine", []); const encoded = gov.interface.encodeFunctionData("setGuardian", [ acct.address ]); await avatarGenericCall(gov.address, encoded); expect(await gov.guardian()).to.equal(acct.address); }); it("Should be able to renounce guardian if guardian", async () => { await expect(gov.connect(acct).renounceGuardian()).to.not.reverted; expect(await gov.guardian()).to.equal(ethers.constants.AddressZero); }); it("Should be able to set guardian by avatar if foundation renounced", async () => { const CompoundVotingMachine = await ethers.getContractFactory( "CompoundVotingMachine" ); const gov2 = (await upgrades.deployProxy( CompoundVotingMachine, [nameService.address, 5760, root.address, NULL_ADDRESS], { kind: "uups" } )) as CompoundVotingMachine; await expect(gov2.renounceGuardian()).to.not.reverted; expect(await gov2.guardian()).to.equal(ethers.constants.AddressZero); const encoded = gov2.interface.encodeFunctionData("setGuardian", [ acct.address ]); await avatarGenericCall(gov2.address, encoded); expect(await gov2.guardian()).to.equal(acct.address); }); it("cancel when undelegated and proposer votes below threshold", async () => { await grep.delegateTo(signers[4].address); let targets = [acct.address]; let values = ["0"]; let signatures = ["getBalanceOf(address)"]; let callDatas = [encodeParameters(["address"], [acct.address])]; //new guardian signers[1] const encoded = gov.interface.encodeFunctionData("setGuardian", [ signers[1].address ]); await avatarGenericCall(gov.address, encoded); await gov .connect(signers[4]) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "do nothing" ); let proposalId = await gov.latestProposalIds(signers[4].address); await advanceBlocks(1); await expect(gov.cancel(proposalId)).to.be.revertedWith( /CompoundVotingMachine::cancel: proposer above threshold/ ); //should not be cancelable by anyone else buy guardian await gov.connect(signers[1]).cancel(proposalId); expect(states[await gov.state(proposalId)]).to.equal("Canceled"); await grep.delegateTo(root.address); //delegate back our votes }); it("Should not be able to pass proposal without guardian approval", async () => { let targets = [gov.address]; let values = ["0"]; let signatures = ["setGuardian(address)"]; let callDatas = [encodeParameters(["address"], [signers[1].address])]; await gov .connect(root) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "set guardian" ); let proposalBlock = +(await ethers.provider.getBlockNumber()); let proposalId = await gov.latestProposalIds(root.address); await advanceBlocks(1); await gov.connect(root).castVote(proposalId, true); await increaseTime(queuePeriod); expect(states[await gov.state(proposalId)]).to.equal("Succeeded"); await expect(gov.execute(proposalId)).revertedWith(/not approved/); }) it("Should be able to pass proposal to change guardian", async () => { let targets = [gov.address]; let values = ["0"]; let signatures = ["setGuardian(address)"]; let callDatas = [encodeParameters(["address"], [signers[2].address])]; await gov .connect(root) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "set guardian" ); let proposalBlock = +(await ethers.provider.getBlockNumber()); let proposalId = await gov.latestProposalIds(root.address); await advanceBlocks(1); await gov.connect(root).castVote(proposalId, true); await increaseTime(queuePeriod); expect(states[await gov.state(proposalId)]).to.equal("Succeeded"); await gov.connect(signers[1]).approveProposal(proposalId) await gov.execute(proposalId); expect(states[await gov.state(proposalId)]).to.equal("Executed"); //acct should now have 1M after proposal minted rep expect(await gov.guardian()).to.equal(signers[2].address); }); it("Should be able to pass proposal without approval if no guardian set", async () => { let targets = [gov.address]; let values = ["0"]; let signatures = ["setGuardian(address)"]; let callDatas = [encodeParameters(["address"], [signers[1].address])]; await gov.connect(signers[2]).renounceGuardian() expect(await gov.guardian()).equal(ethers.constants.AddressZero) await gov .connect(root) ["propose(address[],uint256[],string[],bytes[],string)"]( targets, values, signatures, callDatas, "set guardian" ); let proposalId = await gov.latestProposalIds(root.address); await advanceBlocks(1); await gov.connect(root).castVote(proposalId, true); await increaseTime(queuePeriod); expect(states[await gov.state(proposalId)]).to.equal("Succeeded"); await gov.execute(proposalId); expect(states[await gov.state(proposalId)]).to.equal("Executed"); //acct should now have 1M after proposal minted rep expect(await gov.guardian()).to.equal(signers[1].address); }); });