add tests for proposal referenda
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 30s
Details
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 30s
Details
This commit is contained in:
parent
13a88767bd
commit
df5cbaba87
|
@ -58,7 +58,7 @@ function App() {
|
|||
|
||||
// In this effect, we initialize everything and add contract event listeners.
|
||||
useEffect(() => {
|
||||
if (!provider || !chainId || !account || balance === undefined) return;
|
||||
if (!provider || !chainId || !account || balance === undefined) return () => {};
|
||||
const DAOAddress = getContractAddressByChainId(chainId, 'DAO');
|
||||
const Work1Address = getContractAddressByChainId(chainId, 'Work1');
|
||||
const OnboardingAddress = getContractAddressByChainId(chainId, 'Onboarding');
|
||||
|
@ -145,8 +145,6 @@ function App() {
|
|||
/* --------------------------- BEGIN EVENT HANDLERS ------------------------------- */
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
||||
// TODO: Unsubscribe from events when effect is to be rerun
|
||||
|
||||
DAOContract.events.PostAdded({ fromBlock: 'latest' }).on('data', (event) => {
|
||||
console.log('event: post added');
|
||||
fetchPost(event.returnValues.postIndex);
|
||||
|
@ -170,6 +168,14 @@ function App() {
|
|||
OnboardingContract.events.AvailabilityStaked({ fromBlock: 'latest' }).on('data', () => {
|
||||
fetchReputation();
|
||||
});
|
||||
|
||||
return () => {
|
||||
DAOContract.events.PostAdded().off();
|
||||
DAOContract.events.ValidationPoolInitiated().off();
|
||||
DAOContract.events.ValidationPoolResolved().off();
|
||||
Work1Contract.events.AvailabilityStaked().off();
|
||||
OnboardingContract.events.AvailabilityStaked().off();
|
||||
};
|
||||
}, [provider, account, chainId, balance, dispatchValidationPool, dispatchPost]);
|
||||
|
||||
/* -------------------------------------------------------------------------------- */
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -75,6 +75,13 @@ function Proposals() {
|
|||
});
|
||||
}, [proposalsContract, account, reputation]);
|
||||
|
||||
const handleEvaluateAttestation = useCallback(async (proposalIndex) => {
|
||||
await proposalsContract.current.methods.evaluateAttestation(proposalIndex).send({
|
||||
from: account,
|
||||
gas: 1000000,
|
||||
});
|
||||
}, [proposalsContract, account]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<AddPostModal title="New Proposal" show={showAddProposal} setShow={setShowAddProposal} onSubmit={onSubmitProposal} />
|
||||
|
@ -102,7 +109,13 @@ function Proposals() {
|
|||
<td>{request.attestationTotal.toString()}</td>
|
||||
<td>
|
||||
{request.stage === 0n && (
|
||||
<Button onClick={() => handleAttest(request.id)}>Attest</Button>
|
||||
<>
|
||||
<Button onClick={() => handleAttest(request.id)}>Attest</Button>
|
||||
{' '}
|
||||
<Button onClick={() => handleEvaluateAttestation(request.id)}>
|
||||
Evaluate Attestation
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"DAO": "0x65B0922fe7F0c4012aa38704071f26aeF6F22650",
|
||||
"Work1": "0x95673D8710A8eD59f8551e9B12509D6812e0623e",
|
||||
"Onboarding": "0xc6b3b8A641c52F7bC13a9D444e1f0759CA3b87b4",
|
||||
"Proposals": "0x71cb20D63576a0Fa4F620a2E96C73F82848B09e1"
|
||||
"Proposals": "0x98550F017a8d7B9d759D59c1cA7B8D7B922e1dAf"
|
||||
},
|
||||
"sepolia": {
|
||||
"DAO": "0x8Cb4ab513A863ac29e855c85064ea53dec7dA24C",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"DAO": "0x65B0922fe7F0c4012aa38704071f26aeF6F22650",
|
||||
"Work1": "0x95673D8710A8eD59f8551e9B12509D6812e0623e",
|
||||
"Onboarding": "0xc6b3b8A641c52F7bC13a9D444e1f0759CA3b87b4",
|
||||
"Proposals": "0x71cb20D63576a0Fa4F620a2E96C73F82848B09e1"
|
||||
"Proposals": "0x98550F017a8d7B9d759D59c1cA7B8D7B922e1dAf"
|
||||
},
|
||||
"sepolia": {
|
||||
"DAO": "0x8Cb4ab513A863ac29e855c85064ea53dec7dA24C",
|
||||
|
|
|
@ -189,6 +189,7 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
1_000_000_000 * (stakedFor + stakedAgainst) <=
|
||||
totalSupply() * pool.params.quorumPPB
|
||||
) {
|
||||
// TODO: refund fee
|
||||
// TODO: refund stakes
|
||||
// Callback if requested
|
||||
if (pool.callbackOnValidate) {
|
||||
|
@ -206,15 +207,7 @@ contract DAO is ERC20("Reputation", "REP") {
|
|||
// A tie is resolved in favor of the validation pool.
|
||||
// This is especially important so that the DAO's first pool can pass,
|
||||
// when no reputation has yet been minted.
|
||||
// jconsole.log(
|
||||
// "staked for %d against %d, win ratio %d / %d",
|
||||
console.log("stakedFor", stakedFor);
|
||||
console.log("stakedAgainst", stakedAgainst);
|
||||
console.log(
|
||||
"winRatio",
|
||||
pool.params.winRatio[0],
|
||||
pool.params.winRatio[1]
|
||||
);
|
||||
|
||||
votePasses =
|
||||
stakedFor * pool.params.winRatio[1] >=
|
||||
(stakedFor + stakedAgainst) * pool.params.winRatio[0];
|
||||
|
|
|
@ -24,15 +24,15 @@ contract Proposals is DAOContract, IOnValidate {
|
|||
|
||||
struct Referendum {
|
||||
uint duration;
|
||||
uint fee;
|
||||
// Each referendum may retry up to 3x
|
||||
Pool[] pools;
|
||||
uint[3] retryCount;
|
||||
uint retryCount;
|
||||
}
|
||||
|
||||
struct Proposal {
|
||||
address sender;
|
||||
uint fee;
|
||||
uint remainingFee;
|
||||
uint postIndex;
|
||||
uint startTime;
|
||||
Stage stage;
|
||||
|
@ -66,9 +66,7 @@ contract Proposals is DAOContract, IOnValidate {
|
|||
proposal.referenda[1].duration = referendum1Duration;
|
||||
proposal.referenda[2].duration = referendum100Duration;
|
||||
proposal.fee = msg.value;
|
||||
proposal.referenda[0].fee = proposal.fee / 3;
|
||||
proposal.referenda[1].fee = proposal.fee / 3;
|
||||
proposal.referenda[2].fee = proposal.fee - (proposal.fee * 2) / 3;
|
||||
proposal.remainingFee = proposal.fee;
|
||||
emit NewProposal(proposalIndex);
|
||||
}
|
||||
|
||||
|
@ -93,7 +91,7 @@ contract Proposals is DAOContract, IOnValidate {
|
|||
// Whether to redistribute the binding portion of losing stakes in each referendum
|
||||
bool[3] referendaRedistributeLosingStakes = [false, false, true];
|
||||
// For each referendum, a numerator-denominator pair representing its quorum
|
||||
uint[2][3] referendaQuora = [[1, 10], [1, 2], [1, 3]];
|
||||
uint[2][3] referendaQuora = [[1, 10], [1, 10], [1, 10]];
|
||||
// Win ratios
|
||||
uint[2][3] referendaWinRatio = [[2, 3], [2, 3], [2, 3]];
|
||||
|
||||
|
@ -101,24 +99,20 @@ contract Proposals is DAOContract, IOnValidate {
|
|||
/// and to emit an event
|
||||
function initiateValidationPool(
|
||||
uint proposalIndex,
|
||||
uint referendumIndex
|
||||
uint referendumIndex,
|
||||
uint fee
|
||||
) internal {
|
||||
uint bindingPercent = referendaBindingPercent[referendumIndex];
|
||||
bool redistributeLosingStakes = referendaRedistributeLosingStakes[
|
||||
referendumIndex
|
||||
];
|
||||
Proposal storage proposal = proposals[proposalIndex];
|
||||
uint poolIndex = dao.initiateValidationPool{
|
||||
value: proposal.referenda[referendumIndex].fee
|
||||
}(
|
||||
proposal.remainingFee -= fee;
|
||||
uint poolIndex = dao.initiateValidationPool{value: fee}(
|
||||
proposal.postIndex,
|
||||
proposal.referenda[referendumIndex].duration,
|
||||
referendaQuora[referendumIndex],
|
||||
referendaWinRatio[referendumIndex],
|
||||
bindingPercent,
|
||||
redistributeLosingStakes,
|
||||
referendaBindingPercent[referendumIndex],
|
||||
referendaRedistributeLosingStakes[referendumIndex],
|
||||
true,
|
||||
abi.encode(proposalIndex, referendumIndex)
|
||||
abi.encode(proposalIndex, referendumIndex, fee)
|
||||
);
|
||||
Pool storage pool = proposal.referenda[referendumIndex].pools.push();
|
||||
pool.poolIndex = poolIndex;
|
||||
|
@ -137,14 +131,16 @@ contract Proposals is DAOContract, IOnValidate {
|
|||
msg.sender == address(dao),
|
||||
"onValidate may only be called by the DAO contract"
|
||||
);
|
||||
(uint proposalIndex, uint referendumIndex) = abi.decode(
|
||||
(uint proposalIndex, uint referendumIndex, uint fee) = abi.decode(
|
||||
callbackData,
|
||||
(uint, uint)
|
||||
(uint, uint, uint)
|
||||
);
|
||||
Proposal storage proposal = proposals[proposalIndex];
|
||||
if (!quorumMet) {
|
||||
proposal.stage = Stage.Failed;
|
||||
emit ProposalFailed(proposalIndex, "Quorum not met");
|
||||
proposal.remainingFee += fee;
|
||||
// TODO: Refund remaining fee
|
||||
return;
|
||||
}
|
||||
Referendum storage referendum = proposal.referenda[referendumIndex];
|
||||
|
@ -159,45 +155,50 @@ contract Proposals is DAOContract, IOnValidate {
|
|||
|
||||
// Handle Referendum 0%
|
||||
if (proposal.stage == Stage.Referendum0) {
|
||||
require(referendumIndex == 0, "Stage 0 index mismatch");
|
||||
// If vote passes (2/3 majority) and has >= 50% participation
|
||||
if (votePasses && participationAboveThreshold) {
|
||||
proposal.stage = Stage.Referendum1;
|
||||
} else if (referendum.retryCount[0] >= 3) {
|
||||
} else if (referendum.retryCount >= 2) {
|
||||
proposal.stage = Stage.Failed;
|
||||
emit ProposalFailed(proposalIndex, "Retry count exceeded");
|
||||
} else {
|
||||
referendum.retryCount[0] += 1;
|
||||
referendum.retryCount += 1;
|
||||
}
|
||||
// Handle Referendum 1%
|
||||
} else if (proposal.stage == Stage.Referendum1) {
|
||||
require(referendumIndex == 1, "Stage 1 index mismatch");
|
||||
if (votePasses && participationAboveThreshold) {
|
||||
proposal.stage = Stage.Referendum100;
|
||||
} else if (referendum.retryCount[1] >= 3) {
|
||||
} else if (referendum.retryCount >= 2) {
|
||||
proposal.stage = Stage.Failed;
|
||||
emit ProposalFailed(proposalIndex, "Retry count exceeded");
|
||||
} else {
|
||||
referendum.retryCount[1] += 1;
|
||||
referendum.retryCount += 1;
|
||||
}
|
||||
// Handle Referendum 100%
|
||||
} else if (proposal.stage == Stage.Referendum100) {
|
||||
require(referendumIndex == 2, "Stage 2 index mismatch");
|
||||
// Note that no retries are attempted for referendum 100%
|
||||
if (votePasses) {
|
||||
if (votePasses && participationAboveThreshold) {
|
||||
// TODO: The proposal has passed all referenda and should become "law"
|
||||
// This is an opportunity for some actions to occur
|
||||
// We should at least emit an event
|
||||
proposal.stage = Stage.Accepted;
|
||||
emit ProposalAccepted(proposalIndex);
|
||||
} else {
|
||||
} else if (referendum.retryCount >= 2) {
|
||||
proposal.stage = Stage.Failed;
|
||||
emit ProposalFailed(proposalIndex, "Binding pool was rejected");
|
||||
emit ProposalFailed(proposalIndex, "Retry count exceeded");
|
||||
} else {
|
||||
referendum.retryCount += 1;
|
||||
}
|
||||
}
|
||||
if (proposal.stage == Stage.Referendum0) {
|
||||
initiateValidationPool(proposalIndex, 0);
|
||||
initiateValidationPool(proposalIndex, 0, proposal.fee / 10);
|
||||
} else if (proposal.stage == Stage.Referendum1) {
|
||||
initiateValidationPool(proposalIndex, 1);
|
||||
initiateValidationPool(proposalIndex, 1, proposal.fee / 10);
|
||||
} else if (proposal.stage == Stage.Referendum100) {
|
||||
initiateValidationPool(proposalIndex, 2);
|
||||
initiateValidationPool(proposalIndex, 2, proposal.fee / 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,7 +232,7 @@ contract Proposals is DAOContract, IOnValidate {
|
|||
// It can only happen once because the stage advances, and we required it above.
|
||||
proposal.stage = Stage.Referendum0;
|
||||
// Initiate validation pool
|
||||
initiateValidationPool(proposalIndex, 0);
|
||||
initiateValidationPool(proposalIndex, 0, proposal.fee / 10);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ async function main() {
|
|||
await run('verify:verify', {
|
||||
address: contractAddresses[network].DAO,
|
||||
});
|
||||
console.log('Verified DAO contract');
|
||||
|
||||
await run('verify:verify', {
|
||||
address: contractAddresses[network].Work1,
|
||||
|
@ -23,7 +22,6 @@ async function main() {
|
|||
work1Price,
|
||||
],
|
||||
});
|
||||
console.log('Verified Work1 contract');
|
||||
|
||||
await run('verify:verify', {
|
||||
address: contractAddresses[network].Onboarding,
|
||||
|
@ -32,7 +30,13 @@ async function main() {
|
|||
onboardingPrice,
|
||||
],
|
||||
});
|
||||
console.log('Verified Onboarding contract');
|
||||
|
||||
await run('verify:verify', {
|
||||
address: contractAddresses[network].Proposals,
|
||||
constructorArguments: [
|
||||
contractAddresses[network].DAO,
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('Proposal', () => {
|
|||
true,
|
||||
false,
|
||||
callbackData,
|
||||
{ value: 100 },
|
||||
{ value: 1000 },
|
||||
);
|
||||
await dao.initiateValidationPool(
|
||||
1,
|
||||
|
@ -39,7 +39,7 @@ describe('Proposal', () => {
|
|||
true,
|
||||
false,
|
||||
callbackData,
|
||||
{ value: 100 },
|
||||
{ value: 1000 },
|
||||
);
|
||||
await time.increase(61);
|
||||
await dao.evaluateOutcome(0);
|
||||
|
@ -51,12 +51,15 @@ describe('Proposal', () => {
|
|||
}
|
||||
|
||||
it('Should deploy', async () => {
|
||||
const { dao, proposals, account1 } = await loadFixture(deploy);
|
||||
const {
|
||||
dao, proposals, account1, account2,
|
||||
} = await loadFixture(deploy);
|
||||
expect(dao).to.exist;
|
||||
expect(proposals).to.exist;
|
||||
expect(await dao.memberCount()).to.equal(2);
|
||||
expect(await dao.balanceOf(account1)).to.equal(100);
|
||||
expect(await dao.totalSupply()).to.equal(200);
|
||||
expect(await dao.balanceOf(account1)).to.equal(1000);
|
||||
expect(await dao.balanceOf(account2)).to.equal(1000);
|
||||
expect(await dao.totalSupply()).to.equal(2000);
|
||||
expect(await proposals.proposalCount()).to.equal(0);
|
||||
});
|
||||
|
||||
|
@ -66,7 +69,6 @@ describe('Proposal', () => {
|
|||
let account1;
|
||||
let account2;
|
||||
let proposal;
|
||||
let postIndex;
|
||||
|
||||
beforeEach(async () => {
|
||||
({
|
||||
|
@ -76,14 +78,10 @@ describe('Proposal', () => {
|
|||
account2,
|
||||
} = await loadFixture(deploy));
|
||||
|
||||
await dao.addPost(account1, 'proposal-content-id');
|
||||
postIndex = await dao.postCount() - BigInt(1);
|
||||
const post = await dao.posts(postIndex);
|
||||
expect(await post.contentId).to.equal('proposal-content-id');
|
||||
await proposals.propose(postIndex, 20, 20, 20, { value: 100 });
|
||||
await proposals.propose('proposal-content-id', 20, 20, 20, { value: 100 });
|
||||
expect(await proposals.proposalCount()).to.equal(1);
|
||||
proposal = await proposals.proposals(0);
|
||||
expect(proposal.postIndex).to.equal(postIndex);
|
||||
expect(proposal.postIndex).to.equal(2);
|
||||
expect(proposal.stage).to.equal(0);
|
||||
});
|
||||
|
||||
|
@ -92,24 +90,24 @@ describe('Proposal', () => {
|
|||
});
|
||||
|
||||
it('Can attest for a proposal', async () => {
|
||||
await proposals.connect(account1).attest(0, 50);
|
||||
await proposals.connect(account1).attest(0, 200);
|
||||
// Nonbinding, non-encumbering
|
||||
expect(await dao.balanceOf(account1)).to.equal(100);
|
||||
expect(await dao.balanceOf(account1)).to.equal(1000);
|
||||
});
|
||||
|
||||
describe('Evaluate attestation', () => {
|
||||
it('when threshold is met, advance to referendum 0% binding', async () => {
|
||||
console.log('total REP', await dao.totalSupply());
|
||||
await proposals.attest(0, 20);
|
||||
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(postIndex);
|
||||
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('threshold may be met by accumulation of attestations', async () => {
|
||||
await proposals.connect(account1).attest(0, 10);
|
||||
await proposals.connect(account2).attest(0, 20);
|
||||
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(postIndex);
|
||||
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);
|
||||
proposal = await proposals.proposals(0);
|
||||
expect(proposal.stage).to.equal(1);
|
||||
});
|
||||
|
@ -123,18 +121,236 @@ describe('Proposal', () => {
|
|||
await time.increase(365 * 86400 + 1); // 1 year + 1 second
|
||||
await proposals.evaluateAttestation(0);
|
||||
proposal = await proposals.proposals(0);
|
||||
expect(proposal.stage).to.equal(4); // Stage.Closed
|
||||
expect(proposal.stage).to.equal(4); // Stage.Failed
|
||||
});
|
||||
});
|
||||
|
||||
describe('Referendum 0% binding', () => {
|
||||
beforeEach(async () => {
|
||||
await proposals.attest(0, 20);
|
||||
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(postIndex);
|
||||
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('', async () => {
|
||||
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.stake(2, 200, true);
|
||||
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.stake(2, 1000, false);
|
||||
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);
|
||||
});
|
||||
|
||||
it('proposal fails if a referendum fails to meet participation rate 3 times', async () => {
|
||||
await dao.stake(2, 200, true);
|
||||
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.stake(3, 200, true);
|
||||
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.stake(4, 200, true);
|
||||
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.stake(2, 1000, true);
|
||||
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.stake(2, 1000, true);
|
||||
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);
|
||||
console.log('evaluated pool 2');
|
||||
});
|
||||
|
||||
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.stake(3, 200, true);
|
||||
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);
|
||||
});
|
||||
|
||||
it('referendum retries if it fails to meet win ratio', async () => {
|
||||
await dao.stake(3, 1000, false);
|
||||
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.stake(3, 200, true);
|
||||
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.stake(4, 200, true);
|
||||
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.stake(5, 200, true);
|
||||
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.stake(3, 1000, true);
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Referendum 10% binding', () => {
|
||||
beforeEach(async () => {
|
||||
await proposals.attest(0, 200);
|
||||
await expect(proposals.evaluateAttestation(0)).to.emit(dao, 'ValidationPoolInitiated').withArgs(2);
|
||||
await dao.stake(2, 1000, true);
|
||||
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.stake(3, 1000, true);
|
||||
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);
|
||||
});
|
||||
|
||||
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.stake(4, 200, true);
|
||||
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.stake(4, 1000, false);
|
||||
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.stake(4, 200, true);
|
||||
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.stake(5, 200, true);
|
||||
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.stake(6, 200, true);
|
||||
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).stake(4, 1000, true);
|
||||
await dao.connect(account2).stake(4, 1000, true);
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue