dgf-prototype/ethereum/test/Proposals.js

381 lines
15 KiB
JavaScript
Raw Normal View History

2024-03-26 21:32:41 -05:00
const {
time,
loadFixture,
} = require('@nomicfoundation/hardhat-toolbox/network-helpers');
const { expect } = require('chai');
const { ethers } = require('hardhat');
const { beforeEach } = require('mocha');
const deployDAO = require('./util/deploy-dao');
2024-03-26 21:32:41 -05:00
describe('Proposal', () => {
async function deploy() {
// Contracts are deployed using the first signer/account by default
const [account1, account2] = await ethers.getSigners();
2024-06-28 13:44:18 -05:00
const { dao, forum } = await deployDAO();
2024-03-26 21:32:41 -05:00
const Proposals = await ethers.getContractFactory('Proposals');
const proposals = await Proposals.deploy(dao.target);
2024-06-28 13:44:18 -05:00
await forum.addPost([{ weightPPM: 1000000, authorAddress: account1 }], 'some-content-id', []);
await forum.addPost([{ weightPPM: 1000000, authorAddress: account2 }], 'some-other-content-id', []);
2024-03-26 21:32:41 -05:00
const callbackData = ethers.AbiCoder.defaultAbiCoder().encode([], []);
2024-03-28 15:06:14 -05:00
await dao.initiateValidationPool(
'some-content-id',
2024-03-28 15:06:14 -05:00
60,
[1, 3],
[1, 2],
100,
true,
false,
callbackData,
2024-03-29 10:59:29 -05:00
{ value: 1000 },
2024-03-28 15:06:14 -05:00
);
await dao.initiateValidationPool(
'some-other-content-id',
2024-03-28 15:06:14 -05:00
60,
[1, 3],
[1, 2],
100,
true,
false,
callbackData,
2024-03-29 10:59:29 -05:00
{ value: 1000 },
2024-03-28 15:06:14 -05:00
);
2024-03-26 21:32:41 -05:00
await time.increase(61);
await dao.evaluateOutcome(0);
await dao.evaluateOutcome(1);
return {
2024-06-28 13:44:18 -05:00
dao, forum, proposals, account1, account2,
2024-03-26 21:32:41 -05:00
};
}
it('Should deploy', async () => {
2024-03-29 10:59:29 -05:00
const {
dao, proposals, account1, account2,
} = await loadFixture(deploy);
2024-03-26 21:32:41 -05:00
expect(dao).to.exist;
expect(proposals).to.exist;
expect(await dao.memberCount()).to.equal(2);
2024-03-29 10:59:29 -05:00
expect(await dao.balanceOf(account1)).to.equal(1000);
expect(await dao.balanceOf(account2)).to.equal(1000);
expect(await dao.totalSupply()).to.equal(2000);
2024-03-26 21:32:41 -05:00
expect(await proposals.proposalCount()).to.equal(0);
});
describe('Attestation', () => {
let dao;
2024-06-28 13:44:18 -05:00
let forum;
2024-03-26 21:32:41 -05:00
let proposals;
let account1;
2024-03-26 21:43:46 -05:00
let account2;
2024-03-26 21:32:41 -05:00
let proposal;
beforeEach(async () => {
({
dao,
2024-06-28 13:44:18 -05:00
forum,
2024-03-26 21:32:41 -05:00
proposals,
account1,
2024-03-26 21:43:46 -05:00
account2,
2024-03-26 21:32:41 -05:00
} = await loadFixture(deploy));
2024-03-30 17:21:26 -05:00
const emptyCallbackData = ethers.AbiCoder.defaultAbiCoder().encode([], []);
2024-06-28 13:44:18 -05:00
await forum.addPost([{ authorAddress: account1, weightPPM: 1000000 }], 'proposal-content-id', []);
2024-04-28 16:51:35 -05:00
await proposals.propose('proposal-content-id', [20, 20, 20], false, emptyCallbackData, { value: 100 });
2024-03-26 21:32:41 -05:00
expect(await proposals.proposalCount()).to.equal(1);
proposal = await proposals.proposals(0);
expect(proposal.postId).to.equal('proposal-content-id');
2024-03-26 21:32:41 -05:00
expect(proposal.stage).to.equal(0);
});
it('Can submit a proposal', async () => {
2024-06-28 13:44:18 -05:00
const post = await forum.getPost('proposal-content-id');
expect(post.authors).to.have.length(1);
expect(post.authors[0].weightPPM).to.equal(1000000);
expect(post.authors[0].authorAddress).to.equal(account1);
2024-03-26 21:32:41 -05:00
});
it('Can attest for a proposal', async () => {
2024-03-29 10:59:29 -05:00
await proposals.connect(account1).attest(0, 200);
2024-03-26 21:32:41 -05:00
// Nonbinding, non-encumbering
2024-03-29 10:59:29 -05:00
expect(await dao.balanceOf(account1)).to.equal(1000);
2024-03-26 21:32:41 -05:00
});
describe('Evaluate attestation', () => {
it('when threshold is met, advance to referendum 0% binding', async () => {
2024-03-29 10:59:29 -05:00
await proposals.attest(0, 200);
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(2);
2024-03-26 21:43:46 -05:00
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(1);
});
it('threshold may be met by accumulation of attestations', async () => {
2024-03-29 10:59:29 -05:00
await proposals.connect(account1).attest(0, 100);
await proposals.connect(account2).attest(0, 100);
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(2);
2024-03-26 21:32:41 -05:00
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(1);
});
it('when threshold is not met, and duration has not elapsed, do nothing', async () => {
await proposals.evaluateAttestation(0);
expect(proposal.stage).to.equal(0);
});
it('when threshold is not met, and duration has elapsed, close the proposal', async () => {
await time.increase(365 * 86400 + 1); // 1 year + 1 second
await proposals.evaluateAttestation(0);
proposal = await proposals.proposals(0);
2024-03-29 10:59:29 -05:00
expect(proposal.stage).to.equal(4); // Stage.Failed
2024-03-26 21:32:41 -05:00
});
});
2024-03-26 21:43:46 -05:00
describe('Referendum 0% binding', () => {
beforeEach(async () => {
2024-03-29 10:59:29 -05:00
await proposals.attest(0, 200);
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(2);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(1);
});
it('proposal dies if it fails to meet quorum', async () => {
await time.increase(21);
await expect(dao.evaluateOutcome(2)).to.emit(dao, 'ValidationPoolResolved').withArgs(2, false, false);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(4); // Stage.Failed
});
it('referendum retries if it fails to meet participation rate', async () => {
await dao.stakeOnValidationPool(2, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(2))
.to.emit(dao, 'ValidationPoolResolved').withArgs(2, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(3);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(1);
});
it('referendum retries if it fails to meet win ratio', async () => {
await dao.stakeOnValidationPool(2, 1000, false);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(2))
.to.emit(dao, 'ValidationPoolResolved').withArgs(2, false, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(3);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(1);
2024-03-29 18:08:30 -05:00
const pools = await proposals.getPools(0);
expect(pools[0][0].started).to.be.true;
expect(pools[0][1].started).to.be.true;
expect(pools[0][2].started).to.be.false;
expect(pools[0][0].completed).to.be.true;
expect(pools[0][1].completed).to.be.false;
expect(pools[0][2].completed).to.be.false;
2024-03-29 10:59:29 -05:00
});
it('proposal fails if a referendum fails to meet participation rate 3 times', async () => {
await dao.stakeOnValidationPool(2, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(2))
.to.emit(dao, 'ValidationPoolResolved').withArgs(2, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(3);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(1);
await dao.stakeOnValidationPool(3, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(3))
.to.emit(dao, 'ValidationPoolResolved').withArgs(3, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(4);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(1);
await dao.stakeOnValidationPool(4, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(4))
.to.emit(dao, 'ValidationPoolResolved').withArgs(4, true, true);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(4);
});
it('advances to next referendum if it meets participation rate and win ratio', async () => {
await dao.stakeOnValidationPool(2, 1000, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(2))
.to.emit(dao, 'ValidationPoolResolved').withArgs(2, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(3);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(2);
});
});
describe('Referendum 1% binding', () => {
beforeEach(async () => {
await proposals.attest(0, 200);
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(2);
await dao.stakeOnValidationPool(2, 1000, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(2))
.to.emit(dao, 'ValidationPoolResolved').withArgs(2, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(3);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(2);
2024-03-26 21:43:46 -05:00
});
2024-03-29 18:08:30 -05:00
afterEach(async () => {
2024-06-29 12:57:07 -05:00
const pool = await dao.getValidationPool(3);
expect(pool.props.resolved).to.be.true;
2024-03-29 18:08:30 -05:00
});
2024-03-29 10:59:29 -05:00
it('proposal dies if it fails to meet quorum', async () => {
await time.increase(21);
await expect(dao.evaluateOutcome(3)).to.emit(dao, 'ValidationPoolResolved').withArgs(3, false, false);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(4); // Stage.Failed
});
it('referendum retries if it fails to meet participation rate', async () => {
await dao.stakeOnValidationPool(3, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(3))
.to.emit(dao, 'ValidationPoolResolved').withArgs(3, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(4);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(2);
});
2024-03-26 21:43:46 -05:00
2024-03-29 10:59:29 -05:00
it('referendum retries if it fails to meet win ratio', async () => {
await dao.stakeOnValidationPool(3, 1000, false);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(3))
.to.emit(dao, 'ValidationPoolResolved').withArgs(3, false, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(4);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(2);
});
it('proposal fails if a referendum fails to meet participation rate 3 times', async () => {
await dao.stakeOnValidationPool(3, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(3))
.to.emit(dao, 'ValidationPoolResolved').withArgs(3, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(4);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(2);
await dao.stakeOnValidationPool(4, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(4))
.to.emit(dao, 'ValidationPoolResolved').withArgs(4, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(5);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(2);
await dao.stakeOnValidationPool(5, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(5))
.to.emit(dao, 'ValidationPoolResolved').withArgs(5, true, true);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(4);
});
it('advances to next referendum if it meets participation rate and win ratio', async () => {
await dao.stakeOnValidationPool(3, 1000, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(3))
.to.emit(dao, 'ValidationPoolResolved').withArgs(3, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(4);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(3);
});
});
2024-03-29 18:08:30 -05:00
describe('Referendum 100% binding', () => {
2024-03-29 10:59:29 -05:00
beforeEach(async () => {
await proposals.attest(0, 200);
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(2);
await dao.stakeOnValidationPool(2, 1000, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(2))
.to.emit(dao, 'ValidationPoolResolved').withArgs(2, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(3);
await dao.stakeOnValidationPool(3, 1000, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(3))
.to.emit(dao, 'ValidationPoolResolved').withArgs(3, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(4);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(3);
});
2024-03-29 18:08:30 -05:00
afterEach(async () => {
2024-06-29 12:57:07 -05:00
const pool = await dao.getValidationPool(4);
expect(pool.props.resolved).to.be.true;
2024-03-29 18:08:30 -05:00
});
2024-03-29 10:59:29 -05:00
it('proposal dies if it fails to meet quorum', async () => {
await time.increase(21);
await expect(dao.evaluateOutcome(4)).to.emit(dao, 'ValidationPoolResolved').withArgs(4, false, false);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(4); // Stage.Failed
});
it('referendum retries if it fails to meet participation rate', async () => {
await dao.stakeOnValidationPool(4, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(4))
.to.emit(dao, 'ValidationPoolResolved').withArgs(4, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(5);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(3);
});
it('referendum retries if it fails to meet win ratio', async () => {
await dao.stakeOnValidationPool(4, 1000, false);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(4))
.to.emit(dao, 'ValidationPoolResolved').withArgs(4, false, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(5);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(3);
});
it('proposal fails if a referendum fails to meet participation rate 3 times', async () => {
await dao.stakeOnValidationPool(4, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(4))
.to.emit(dao, 'ValidationPoolResolved').withArgs(4, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(5);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(3);
await dao.stakeOnValidationPool(5, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(5))
.to.emit(dao, 'ValidationPoolResolved').withArgs(5, true, true)
.to.emit(dao, 'ValidationPoolInitiated').withArgs(6);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(3);
await dao.stakeOnValidationPool(6, 200, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(6))
.to.emit(dao, 'ValidationPoolResolved').withArgs(6, true, true);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(4);
});
it('advances to accepted stage if it meets participation rate and win ratio', async () => {
await dao.connect(account1).stakeOnValidationPool(4, 1000, true);
await dao.connect(account2).stakeOnValidationPool(4, 1000, true);
2024-03-29 10:59:29 -05:00
await time.increase(21);
await expect(dao.evaluateOutcome(4))
.to.emit(dao, 'ValidationPoolResolved').withArgs(4, true, true);
proposal = await proposals.proposals(0);
expect(proposal.stage).to.equal(5);
2024-03-26 21:43:46 -05:00
});
});
2024-03-26 21:32:41 -05:00
});
});