diff --git a/protocol/governance/test/Elections.test.js b/protocol/governance/test/Elections.test.js deleted file mode 100644 index 1986efce8b..0000000000 --- a/protocol/governance/test/Elections.test.js +++ /dev/null @@ -1,715 +0,0 @@ -// const { ethers } = hre; -// const assert = require('assert/strict'); -// const assertBn = require('@synthetixio/core-utils/utils/assertions/assert-bignumber'); - -// const assertRevert = require('@synthetixio/core-utils/utils/assertions/assert-revert'); -// const { bootstrap } = require('@synthetixio/router/dist/utils/tests'); -// const initializer = require('@synthetixio/core-modules/test/helpers/initializer'); -// const { -// getTime, -// fastForwardTo, -// takeSnapshot, -// restoreSnapshot, -// } = require('@synthetixio/core-utils/utils/hardhat/rpc'); - -// const { daysToSeconds } = require('@synthetixio/core-utils/utils/misc/dates'); -// const { -// ElectionPeriod, -// } = require('@synthetixio/core-modules/test/contracts/modules/ElectionModule/helpers/election-helper'); -// const { -// simulateDebtShareData, -// simulateCrossChainDebtShareData, -// expectedDebtShare, -// expectedVotePower, -// expectedCrossChainDebtShare, -// getCrossChainMerkleTree, -// } = require('./helpers/debt-share-helper'); -// const { findEvent } = require('@synthetixio/core-utils/utils/ethers/events'); - -// describe('SynthetixElectionModule - general elections', function () { -// const { proxyAddress } = bootstrap(initializer); - -// let ElectionModule, DebtShare, CouncilToken; - -// let owner; -// let user1, user2, user3, user4, user5, user6, user7, user8, user9; - -// let receipt; - -// let merkleTree; - -// let snapshotId; - -// const epochData = [ -// { -// index: 0, -// debtShareSnapshotId: 42, -// blockNumber: 21000000, -// winners: () => [user4.address, user5.address], -// }, -// { -// index: 1, -// debtShareSnapshotId: 1337, -// blockNumber: 23100007, -// winners: () => [user4.address, user6.address], -// }, -// { -// index: 2, -// debtShareSnapshotId: 2192, -// blockNumber: 30043001, -// winners: () => [user6.address, user5.address], -// }, -// ]; - -// // TODO: when your testing crosschain functionality, -// // add tests specifically for receivers, check for ccip and mothership, etc. - -// before('identify signers', async () => { -// [owner, user1, user2, user3, user4, user5, user6, user7, user8, user9] = -// await ethers.getSigners(); -// }); - -// before('identify modules', async () => { -// ElectionModule = await ethers.getContractAt( -// 'contracts/modules/ElectionModule.sol:ElectionModule', -// proxyAddress() -// ); -// }); - -// before('deploy debt shares mock', async function () { -// const factory = await ethers.getContractFactory('DebtShareMock'); -// DebtShare = await factory.deploy(); -// }); - -// describe('when the election module is initialized', function () { -// before('initialize', async function () { -// const now = await getTime(ethers.provider); -// const epochEndDate = now + daysToSeconds(90); -// const votingPeriodStartDate = epochEndDate - daysToSeconds(7); -// const nominationPeriodStartDate = votingPeriodStartDate - daysToSeconds(7); - -// await ElectionModule[ -// 'initializeElectionModule(string,string,address[],uint8,uint64,uint64,uint64,address)' -// ]( -// 'Spartan Council Token', -// 'SCT', -// [owner.address], -// 1, -// nominationPeriodStartDate, -// votingPeriodStartDate, -// epochEndDate, -// DebtShare.address -// ); -// }); - -// before('set next epoch seat count to 2', async function () { -// (await ElectionModule.setNextEpochSeatCount(2)).wait(); -// }); - -// before('identify the council token', async function () { -// CouncilToken = await ethers.getContractAt( -// 'CouncilToken', -// await ElectionModule.getCouncilToken() -// ); -// }); - -// it('shows the expected NFT owners', async function () { -// assertBn.equal(await CouncilToken.balanceOf(owner.address), 1); -// assertBn.equal(await CouncilToken.balanceOf(user1.address), 0); -// assertBn.equal(await CouncilToken.balanceOf(user2.address), 0); -// assertBn.equal(await CouncilToken.balanceOf(user3.address), 0); -// }); - -// it('shows that the election module is initialized', async function () { -// assert.equal(await ElectionModule.isElectionModuleInitialized(), true); -// }); - -// it('shows that the DebtShare contract is connected', async function () { -// assert.equal(await ElectionModule.getDebtShareContract(), DebtShare.address); -// }); - -// describe('when re setting the debt share contract', function () { -// describe('with the same address', function () { -// it('reverts', async function () { -// await assertRevert(ElectionModule.setDebtShareContract(DebtShare.address), 'NoChange'); -// }); -// }); - -// describe('with an invalid address', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.setDebtShareContract('0x0000000000000000000000000000000000000000'), -// 'ZeroAddress' -// ); -// }); -// }); - -// describe('with an EOA', function () { -// it('reverts', async function () { -// await assertRevert(ElectionModule.setDebtShareContract(owner.address), 'NotAContract'); -// }); -// }); - -// describe('with a different address', function () { -// before('deploy debt shares mock', async function () { -// const factory = await ethers.getContractFactory('DebtShareMock'); -// DebtShare = await factory.deploy(); -// }); - -// before('set the new debt share contract', async function () { -// const tx = await ElectionModule.setDebtShareContract(DebtShare.address); -// receipt = await tx.wait(); -// }); - -// it('emitted a DebtShareContractSet event', async function () { -// const event = findEvent({ receipt, eventName: 'DebtShareContractSet' }); - -// assert.ok(event); -// assertBn.equal(event.args.contractAddress, DebtShare.address); -// }); - -// it('shows that the DebtShare contract is connected', async function () { -// assert.equal(await ElectionModule.getDebtShareContract(), DebtShare.address); -// }); -// }); -// }); - -// epochData.forEach(function (epoch) { -// describe(`epoch ${epoch.index} with debt share snapshot ${epoch.debtShareSnapshotId}`, function () { -// it(`shows that the current epoch index is ${epoch.index}`, async function () { -// assertBn.equal(await ElectionModule.getEpochIndex(), epoch.index); -// }); - -// it('shows that the current period is Administration', async function () { -// assertBn.equal(await ElectionModule.getCurrentPeriod(), ElectionPeriod.Administration); -// }); - -// describe('before a debt share snapshot is set', function () { -// describe('when trying to retrieve the current debt share snapshot id', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.getDebtShareSnapshotId(), -// 'DebtShareSnapshotIdNotSet' -// ); -// }); -// }); - -// describe('when trying to retrieve the current debt share of a user', function () { -// it('returns zero', async function () { -// assertBn.equal(await ElectionModule.getDebtShare(user1.address), 0); -// }); -// }); -// }); - -// describe('before a merkle root is set', function () { -// describe('when trying to retrieve the current cross chain merkle root', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.getCrossChainDebtShareMerkleRoot(), -// 'MerkleRootNotSet' -// ); -// }); -// }); - -// describe('when trying to retrieve the current cross chain merkle root block number', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.getCrossChainDebtShareMerkleRootBlockNumber(), -// 'MerkleRootNotSet' -// ); -// }); -// }); - -// describe('when trying to retrieve the current cross chain debt share of a user', function () { -// it('returns zero', async function () { -// assertBn.equal(await ElectionModule.getDeclaredCrossChainDebtShare(user1.address), 0); -// }); -// }); -// }); - -// describe('before the nomination period begins', function () { -// describe('when trying to set the debt share id', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.setDebtShareSnapshotId(0), -// 'NotCallableInCurrentPeriod' -// ); -// }); -// }); - -// describe('when trying to set the cross chain debt share merkle root', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.setCrossChainDebtShareMerkleRoot( -// '0x000000000000000000000000000000000000000000000000000000000000beef', -// 1337 -// ), -// 'NotCallableInCurrentPeriod' -// ); -// }); -// }); -// }); - -// describe('when advancing to the nominations period', function () { -// before('fast forward', async function () { -// await fastForwardTo( -// await ElectionModule.getNominationPeriodStartDate(), -// ethers.provider -// ); -// }); - -// describe('when the current epochs debt share snapshot id is set', function () { -// before('simulate debt share data', async function () { -// await simulateDebtShareData(DebtShare, [user1, user2, user3, user4, user5]); -// }); - -// before('set snapshot id', async function () { -// const tx = await ElectionModule.setDebtShareSnapshotId(epoch.debtShareSnapshotId); -// receipt = await tx.wait(); -// }); - -// it('emitted a DebtShareSnapshotIdSet event', async function () { -// const event = findEvent({ receipt, eventName: 'DebtShareSnapshotIdSet' }); - -// assert.ok(event); -// assertBn.equal(event.args.snapshotId, epoch.debtShareSnapshotId); -// }); - -// it('shows that the snapshot id is set', async function () { -// assertBn.equal( -// await ElectionModule.getDebtShareSnapshotId(), -// epoch.debtShareSnapshotId -// ); -// }); - -// it('shows that users have the expected debt shares', async function () { -// assert.deepEqual( -// await ElectionModule.getDebtShare(user1.address), -// expectedDebtShare(user1.address, epoch.debtShareSnapshotId) -// ); -// assert.deepEqual( -// await ElectionModule.getDebtShare(user2.address), -// expectedDebtShare(user2.address, epoch.debtShareSnapshotId) -// ); -// assert.deepEqual( -// await ElectionModule.getDebtShare(user3.address), -// expectedDebtShare(user3.address, epoch.debtShareSnapshotId) -// ); -// assert.deepEqual( -// await ElectionModule.getDebtShare(user4.address), -// expectedDebtShare(user4.address, epoch.debtShareSnapshotId) -// ); -// assert.deepEqual( -// await ElectionModule.getDebtShare(user5.address), -// expectedDebtShare(user5.address, epoch.debtShareSnapshotId) -// ); -// }); - -// describe('when cross chain debt share data is collected', function () { -// before('simulate cross chain debt share data', async function () { -// await simulateCrossChainDebtShareData([user1, user2, user3]); - -// merkleTree = getCrossChainMerkleTree(epoch.debtShareSnapshotId); -// }); - -// describe('when a user attempts to declare cross chain debt shares and the merkle root is not set', function () { -// before('take snapshot', async function () { -// snapshotId = await takeSnapshot(ethers.provider); -// }); - -// after('restore snapshot', async function () { -// await restoreSnapshot(snapshotId, ethers.provider); -// }); - -// before('fast forward', async function () { -// await fastForwardTo( -// await ElectionModule.getVotingPeriodStartDate(), -// ethers.provider -// ); -// }); - -// it('reverts', async function () { -// merkleTree = getCrossChainMerkleTree(epoch.debtShareSnapshotId); - -// await assertRevert( -// ElectionModule.declareCrossChainDebtShare( -// user1.address, -// expectedCrossChainDebtShare(user1.address, epoch.debtShareSnapshotId), -// merkleTree.claims[user1.address].proof -// ), -// 'MerkleRootNotSet' -// ); -// }); -// }); - -// describe('when the current epochs cross chain debt share merkle root is set', function () { -// before('set the merkle root', async function () { -// const tx = await ElectionModule.setCrossChainDebtShareMerkleRoot( -// merkleTree.merkleRoot, -// epoch.blockNumber -// ); -// receipt = await tx.wait(); -// }); - -// before('nominate', async function () { -// (await ElectionModule.connect(user4).nominate()).wait(); -// (await ElectionModule.connect(user5).nominate()).wait(); -// (await ElectionModule.connect(user6).nominate()).wait(); -// (await ElectionModule.connect(user7).nominate()).wait(); -// (await ElectionModule.connect(user8).nominate()).wait(); -// (await ElectionModule.connect(user9).nominate()).wait(); -// }); - -// it('emitted a CrossChainDebtShareMerkleRootSet event', async function () { -// const event = findEvent({ -// receipt, -// eventName: 'CrossChainDebtShareMerkleRootSet', -// }); - -// assert.ok(event); -// assertBn.equal(event.args.merkleRoot, merkleTree.merkleRoot); -// assertBn.equal(event.args.blocknumber, epoch.blockNumber); -// }); - -// it('shows that the merkle root is set', async function () { -// assert.equal( -// await ElectionModule.getCrossChainDebtShareMerkleRoot(), -// merkleTree.merkleRoot -// ); -// }); - -// it('shows that the merkle root block number is set', async function () { -// assertBn.equal( -// await ElectionModule.getCrossChainDebtShareMerkleRootBlockNumber(), -// epoch.blockNumber -// ); -// }); - -// describe('when users declare their cross chain debt shares in the wrong period', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.declareCrossChainDebtShare( -// user1.address, -// expectedCrossChainDebtShare(user1.address, epoch.debtShareSnapshotId), -// merkleTree.claims[user1.address].proof -// ), -// 'NotCallableInCurrentPeriod' -// ); -// }); -// }); - -// describe('when advancing to the voting period', function () { -// before('fast forward', async function () { -// await fastForwardTo( -// await ElectionModule.getVotingPeriodStartDate(), -// ethers.provider -// ); -// }); - -// it('shows that the current period is Voting', async function () { -// assertBn.equal(await ElectionModule.getCurrentPeriod(), ElectionPeriod.Vote); -// }); - -// describe('when users declare their cross chain debt shares incorrectly', function () { -// describe('when a user declares a wrong amount', function () { -// it('reverts', async function () { -// const { proof } = merkleTree.claims[user2.address]; - -// await assertRevert( -// ElectionModule.declareCrossChainDebtShare( -// user2.address, -// ethers.utils.parseEther('10000000'), -// proof -// ), -// 'InvalidMerkleProof' -// ); -// }); -// }); - -// describe('when a user with no entry in the tree declares an amount', function () { -// it('reverts', async function () { -// const { proof } = merkleTree.claims[user2.address]; - -// await assertRevert( -// ElectionModule.declareCrossChainDebtShare( -// user4.address, -// ethers.utils.parseEther('1000'), -// proof -// ), -// 'InvalidMerkleProof' -// ); -// }); -// }); - -// describe('when a user uses the wrong tree to declare', function () { -// it('reverts', async function () { -// const anotherTree = getCrossChainMerkleTree(666); -// const { amount, proof } = anotherTree.claims[user2.address]; - -// await assertRevert( -// ElectionModule.declareCrossChainDebtShare(user2.address, amount, proof), -// 'InvalidMerkleProof' -// ); -// }); -// }); -// }); - -// describe('when users declare their cross chain debt shares correctly', function () { -// async function declare(user) { -// const { amount, proof } = merkleTree.claims[user.address]; - -// const tx = await ElectionModule.declareCrossChainDebtShare( -// user.address, -// amount, -// proof -// ); -// receipt = await tx.wait(); -// } - -// async function declareAndCast(user, candidates) { -// const { amount, proof } = merkleTree.claims[user.address]; - -// const tx = await ElectionModule.connect(user).declareAndCast( -// amount, -// proof, -// candidates -// ); -// receipt = await tx.wait(); -// } - -// before('declare', async function () { -// await declare(user1); -// await declare(user2); -// // Note: Intentionally not declaring for user3 -// }); - -// describe('when a user attempts to re-declare cross chain debt shares', function () { -// it('reverts', async function () { -// const { amount, proof } = merkleTree.claims[user1.address]; - -// await assertRevert( -// ElectionModule.declareCrossChainDebtShare(user1.address, amount, proof), -// 'CrossChainDebtShareAlreadyDeclared' -// ); -// }); -// }); - -// it('emitted a CrossChainDebtShareDeclared event', async function () { -// const event = findEvent({ -// receipt, -// eventName: 'CrossChainDebtShareDeclared', -// }); - -// assert.ok(event); -// assertBn.equal(event.args.user, user2.address); -// assertBn.equal( -// event.args.debtShare, -// expectedCrossChainDebtShare(user2.address, epoch.debtShareSnapshotId) -// ); -// }); - -// it('shows that users have declared their cross chain debt shares', async function () { -// assertBn.equal( -// await ElectionModule.getDeclaredCrossChainDebtShare(user1.address), -// expectedCrossChainDebtShare(user1.address, epoch.debtShareSnapshotId) -// ); -// assertBn.equal( -// await ElectionModule.getDeclaredCrossChainDebtShare(user2.address), -// expectedCrossChainDebtShare(user2.address, epoch.debtShareSnapshotId) -// ); -// }); - -// it('shows that users have the expected vote power (cross chain component is now declared)', async function () { -// assert.deepEqual( -// await ElectionModule.getVotePower(user1.address), -// expectedVotePower(user1.address, epoch.debtShareSnapshotId) -// ); -// assert.deepEqual( -// await ElectionModule.getVotePower(user2.address), -// expectedVotePower(user2.address, epoch.debtShareSnapshotId) -// ); -// }); - -// describe('when a user tries to vote for more than one candidate', function () { -// it('reverts', async function () { -// await assertRevert( -// ElectionModule.connect(user1).cast([user4.address, user5.address]), -// 'TooManyCandidates' -// ); -// }); -// }); - -// describe('when users cast votes', function () { -// let ballot1, ballot2, ballot3; - -// before('vote', async function () { -// await ElectionModule.connect(user1).cast([user4.address]); -// await ElectionModule.connect(user2).cast([user4.address]); -// await declareAndCast(user3, [user5.address]); // user3 didn't declare cross chain debt shares yet -// await ElectionModule.connect(user4).cast([user6.address]); -// await ElectionModule.connect(user5).cast([user4.address]); -// }); - -// before('identify ballots', async function () { -// ballot1 = await ElectionModule.calculateBallotId([user4.address]); -// ballot2 = await ElectionModule.calculateBallotId([user5.address]); -// ballot3 = await ElectionModule.calculateBallotId([user6.address]); -// }); - -// it('keeps track of which ballot each user voted on', async function () { -// assert.equal(await ElectionModule.getBallotVoted(user1.address), ballot1); -// assert.equal(await ElectionModule.getBallotVoted(user2.address), ballot1); -// assert.equal(await ElectionModule.getBallotVoted(user3.address), ballot2); -// assert.equal(await ElectionModule.getBallotVoted(user4.address), ballot3); -// assert.equal(await ElectionModule.getBallotVoted(user5.address), ballot1); -// }); - -// it('keeps track of the candidates of each ballot', async function () { -// assert.deepEqual(await ElectionModule.getBallotCandidates(ballot1), [ -// user4.address, -// ]); -// assert.deepEqual(await ElectionModule.getBallotCandidates(ballot2), [ -// user5.address, -// ]); -// assert.deepEqual(await ElectionModule.getBallotCandidates(ballot3), [ -// user6.address, -// ]); -// }); - -// it('keeps track of vote power in each ballot', async function () { -// const votesBallot1 = expectedVotePower( -// user1.address, -// epoch.debtShareSnapshotId -// ) -// .add(expectedVotePower(user2.address, epoch.debtShareSnapshotId)) -// .add(expectedVotePower(user5.address, epoch.debtShareSnapshotId)); -// const votesBallot2 = expectedVotePower( -// user3.address, -// epoch.debtShareSnapshotId -// ); -// const votesBallot3 = expectedVotePower( -// user4.address, -// epoch.debtShareSnapshotId -// ); - -// assertBn.equal(await ElectionModule.getBallotVotes(ballot1), votesBallot1); -// assertBn.equal(await ElectionModule.getBallotVotes(ballot2), votesBallot2); -// assertBn.equal(await ElectionModule.getBallotVotes(ballot3), votesBallot3); -// }); - -// describe('when voting ends', function () { -// before('fast forward', async function () { -// await fastForwardTo( -// await ElectionModule.getEpochEndDate(), -// ethers.provider -// ); -// }); - -// it('shows that the current period is Evaluation', async function () { -// assertBn.equal( -// await ElectionModule.getCurrentPeriod(), -// ElectionPeriod.Evaluation -// ); -// }); - -// describe('when the election is evaluated', function () { -// before('evaluate', async function () { -// (await ElectionModule.evaluate(0)).wait(); -// }); - -// it('shows that the election is evaluated', async function () { -// assert.equal(await ElectionModule.isElectionEvaluated(), true); -// }); - -// it('shows each candidates votes', async function () { -// const votesUser4 = expectedVotePower( -// user1.address, -// epoch.debtShareSnapshotId -// ) -// .add(expectedVotePower(user2.address, epoch.debtShareSnapshotId)) -// .add(expectedVotePower(user5.address, epoch.debtShareSnapshotId)); -// const votesUser5 = expectedVotePower( -// user3.address, -// epoch.debtShareSnapshotId -// ); -// const votesUser6 = expectedVotePower( -// user4.address, -// epoch.debtShareSnapshotId -// ); - -// assertBn.equal( -// await ElectionModule.getCandidateVotes(user4.address), -// votesUser4 -// ); -// assertBn.equal( -// await ElectionModule.getCandidateVotes(user5.address), -// votesUser5 -// ); -// assertBn.equal( -// await ElectionModule.getCandidateVotes(user6.address), -// votesUser6 -// ); -// assertBn.equal( -// await ElectionModule.getCandidateVotes(user7.address), -// 0 -// ); -// assertBn.equal( -// await ElectionModule.getCandidateVotes(user8.address), -// 0 -// ); -// assertBn.equal( -// await ElectionModule.getCandidateVotes(user9.address), -// 0 -// ); -// }); - -// it('shows the election winners', async function () { -// assert.deepEqual( -// await ElectionModule.getElectionWinners(), -// epoch.winners() -// ); -// }); - -// describe('when the election is resolved', function () { -// before('resolve', async function () { -// (await ElectionModule.resolve()).wait(); -// }); - -// it('shows the expected NFT owners', async function () { -// const winners = epoch.winners(); - -// assertBn.equal( -// await CouncilToken.balanceOf(owner.address), -// winners.includes(owner.address) ? 1 : 0 -// ); -// assertBn.equal( -// await CouncilToken.balanceOf(user4.address), -// winners.includes(user4.address) ? 1 : 0 -// ); -// assertBn.equal( -// await CouncilToken.balanceOf(user5.address), -// winners.includes(user5.address) ? 1 : 0 -// ); -// assertBn.equal( -// await CouncilToken.balanceOf(user6.address), -// winners.includes(user6.address) ? 1 : 0 -// ); -// assertBn.equal( -// await CouncilToken.balanceOf(user7.address), -// winners.includes(user7.address) ? 1 : 0 -// ); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); -// }); diff --git a/protocol/governance/test/bootstrap.ts b/protocol/governance/test/bootstrap.ts index 6d7dd5badc..713b8fb536 100644 --- a/protocol/governance/test/bootstrap.ts +++ b/protocol/governance/test/bootstrap.ts @@ -29,11 +29,13 @@ export function bootstrap() { before(restoreSnapshot); before('load contracts', function () { - contracts.CoreRouter = getContract('CoreRouter'); - contracts.CoreProxy = getContract('CoreProxy'); - contracts.AccountProxy = getContract('AccountProxy'); - contracts.DebtShareMock = getContract('DebtShareMock'); - contracts.CouncilTokenRouter = getContract('CouncilTokenRouter'); + Object.assign(contracts, { + CoreRouter: getContract('CoreRouter'), + CoreProxy: getContract('CoreProxy'), + AccountProxy: getContract('AccountProxy'), + DebtShareMock: getContract('DebtShareMock'), + CouncilTokenRouter: getContract('CouncilTokenRouter'), + } satisfies Contracts); }); return { diff --git a/protocol/governance/test/constants.ts b/protocol/governance/test/constants.ts new file mode 100644 index 0000000000..f35d66bcec --- /dev/null +++ b/protocol/governance/test/constants.ts @@ -0,0 +1,6 @@ +export enum ElectionPeriod { + Administration = 0, + Nomination = 1, + Vote = 2, + Evaluation = 3, +} diff --git a/protocol/governance/test/helpers/debt-share-helper.js b/protocol/governance/test/helpers/debt-share-helper.js deleted file mode 100644 index 11bfbf7625..0000000000 --- a/protocol/governance/test/helpers/debt-share-helper.js +++ /dev/null @@ -1,133 +0,0 @@ -const { ethers } = hre; -const { bnSqrt } = require('@synthetixio/core-utils/utils/ethers/bignumber'); -const { parseBalanceMap } = require('@synthetixio/core-utils/utils/merkle-tree/parse-balance-tree'); - -let _debtShareData = {}; -let _crossChainDebtShareData = {}; - -async function simulateDebtShareData(DebtShare, users) { - const [user1, user2, user3, user4, user5] = users; - - _debtShareData = { - 42: { - [user1.address]: ethers.utils.parseEther('1000'), - [user2.address]: ethers.utils.parseEther('24000'), - [user3.address]: ethers.utils.parseEther('200000'), - [user4.address]: ethers.utils.parseEther('30000'), - [user5.address]: ethers.utils.parseEther('20'), - }, - 1337: { - [user1.address]: ethers.utils.parseEther('0'), - [user2.address]: ethers.utils.parseEther('30000'), - [user3.address]: ethers.utils.parseEther('21000'), - [user4.address]: ethers.utils.parseEther('459000'), - [user5.address]: ethers.utils.parseEther('100'), - }, - 2192: { - [user1.address]: ethers.utils.parseEther('500'), - [user2.address]: ethers.utils.parseEther('10'), - [user3.address]: ethers.utils.parseEther('2500'), - [user4.address]: ethers.utils.parseEther('50000'), - [user5.address]: ethers.utils.parseEther('1'), - }, - }; - - async function simulateDebtShareBalance(user, balance, periodId) { - const tx = await DebtShare.setBalanceOfOnPeriod(user.address, balance, periodId); - await tx.wait(); - } - - async function simulateDebtShareBalances(periodId) { - await simulateDebtShareBalance(user1, _debtShareData[periodId][user1.address], periodId); - await simulateDebtShareBalance(user2, _debtShareData[periodId][user2.address], periodId); - await simulateDebtShareBalance(user3, _debtShareData[periodId][user3.address], periodId); - await simulateDebtShareBalance(user4, _debtShareData[periodId][user4.address], periodId); - await simulateDebtShareBalance(user5, _debtShareData[periodId][user5.address], periodId); - } - - await simulateDebtShareBalances('42'); - await simulateDebtShareBalances('1337'); - await simulateDebtShareBalances('2192'); -} - -async function simulateCrossChainDebtShareData(users) { - const [user1, user2, user3] = users; - - _crossChainDebtShareData = { - 42: { - [user1.address]: ethers.utils.parseEther('1000000'), - [user2.address]: ethers.utils.parseEther('240000'), - [user3.address]: ethers.utils.parseEther('1000'), - }, - 1337: { - [user1.address]: ethers.utils.parseEther('205000'), - [user2.address]: ethers.utils.parseEther('300000'), - [user3.address]: ethers.utils.parseEther('2100'), - }, - 2192: { - [user1.address]: ethers.utils.parseEther('1'), - [user2.address]: ethers.utils.parseEther('35000'), - [user3.address]: ethers.utils.parseEther('250000'), - }, - 666: { - [user1.address]: ethers.utils.parseEther('666'), - [user2.address]: ethers.utils.parseEther('666'), - [user3.address]: ethers.utils.parseEther('666'), - }, - }; - - function stringifyBalances(balances) { - Object.keys(balances).forEach((user) => (balances[user] = balances[user].toString())); - - return balances; - } - - _crossChainDebtShareData[42].merkleTree = parseBalanceMap( - stringifyBalances(_crossChainDebtShareData[42]) - ); - _crossChainDebtShareData[1337].merkleTree = parseBalanceMap( - stringifyBalances(_crossChainDebtShareData[1337]) - ); - _crossChainDebtShareData[2192].merkleTree = parseBalanceMap( - stringifyBalances(_crossChainDebtShareData[2192]) - ); - _crossChainDebtShareData[666].merkleTree = parseBalanceMap( - stringifyBalances(_crossChainDebtShareData[666]) - ); -} - -function expectedDebtShare(user, periodId) { - if (!_debtShareData[periodId] || !_debtShareData[periodId][user]) { - return 0; - } - - return _debtShareData[periodId][user]; -} - -function expectedCrossChainDebtShare(user, periodId) { - if (!_crossChainDebtShareData[periodId] || !_crossChainDebtShareData[periodId][user]) { - return 0; - } - - return _crossChainDebtShareData[periodId][user]; -} - -function expectedVotePower(user, periodId) { - const debtShare = expectedDebtShare(user, periodId); - const crossChainDebtShare = expectedCrossChainDebtShare(user, periodId); - - return bnSqrt(debtShare.add(crossChainDebtShare)); -} - -function getCrossChainMerkleTree(periodId) { - return _crossChainDebtShareData[periodId].merkleTree; -} - -module.exports = { - simulateDebtShareData, - simulateCrossChainDebtShareData, - expectedDebtShare, - expectedCrossChainDebtShare, - expectedVotePower, - getCrossChainMerkleTree, -}; diff --git a/protocol/governance/test/helpers/debt-share-helper.ts b/protocol/governance/test/helpers/debt-share-helper.ts new file mode 100644 index 0000000000..0ea28a95a2 --- /dev/null +++ b/protocol/governance/test/helpers/debt-share-helper.ts @@ -0,0 +1,125 @@ +import { bnSqrt } from '@synthetixio/core-utils/utils/ethers/bignumber'; +import { parseBalanceMap } from '@synthetixio/core-utils/utils/merkle-tree/parse-balance-tree'; +import { ethers } from 'ethers'; + +import type { DebtShareMock } from '../generated/typechain'; + +interface DebtShareData { + [chainId: number]: { + [address: string]: ethers.BigNumber; + }; +} + +interface MerkleTreeData { + [chainId: number]: ReturnType; +} + +let _debtShareData: DebtShareData = {}; +let _crossChainDebtShareData: DebtShareData = {}; +const _crossChainMerkleTreeData: MerkleTreeData = {}; + +export async function simulateDebtShareData(DebtShare: DebtShareMock, users: ethers.Signer[]) { + const addresses = await Promise.all(users.map((u) => u.getAddress())); + + _debtShareData = { + 42: { + [addresses[0]]: ethers.utils.parseEther('1000'), + [addresses[1]]: ethers.utils.parseEther('24000'), + [addresses[2]]: ethers.utils.parseEther('200000'), + [addresses[3]]: ethers.utils.parseEther('30000'), + [addresses[4]]: ethers.utils.parseEther('20'), + }, + 1337: { + [addresses[0]]: ethers.utils.parseEther('0'), + [addresses[1]]: ethers.utils.parseEther('30000'), + [addresses[2]]: ethers.utils.parseEther('21000'), + [addresses[3]]: ethers.utils.parseEther('459000'), + [addresses[4]]: ethers.utils.parseEther('100'), + }, + 2192: { + [addresses[0]]: ethers.utils.parseEther('500'), + [addresses[1]]: ethers.utils.parseEther('10'), + [addresses[2]]: ethers.utils.parseEther('2500'), + [addresses[3]]: ethers.utils.parseEther('50000'), + [addresses[4]]: ethers.utils.parseEther('1'), + }, + }; + + for (const periodId of Object.keys(_debtShareData)) { + const balances = _debtShareData[Number.parseInt(periodId)]! as DebtShareData[number]; + for (const address of Object.keys(balances)) { + const balance = balances[address]; + const tx = await DebtShare.setBalanceOfOnPeriod(address, balance, periodId); + await tx.wait(); + } + } +} + +export async function simulateCrossChainDebtShareData(users: ethers.Signer[]) { + const addresses = await Promise.all(users.map((u) => u.getAddress())); + + _crossChainDebtShareData = { + 42: { + [addresses[0]]: ethers.utils.parseEther('1000000'), + [addresses[1]]: ethers.utils.parseEther('240000'), + [addresses[2]]: ethers.utils.parseEther('1000'), + }, + 1337: { + [addresses[0]]: ethers.utils.parseEther('205000'), + [addresses[1]]: ethers.utils.parseEther('300000'), + [addresses[2]]: ethers.utils.parseEther('2100'), + }, + 2192: { + [addresses[0]]: ethers.utils.parseEther('1'), + [addresses[1]]: ethers.utils.parseEther('35000'), + [addresses[2]]: ethers.utils.parseEther('250000'), + }, + 666: { + [addresses[0]]: ethers.utils.parseEther('666'), + [addresses[1]]: ethers.utils.parseEther('666'), + [addresses[2]]: ethers.utils.parseEther('666'), + }, + }; + + for (const key of Object.keys(_crossChainDebtShareData)) { + const periodId = Number.parseInt(key); + _crossChainMerkleTreeData[periodId] = parseBalanceMap( + _stringifyBalances(_crossChainDebtShareData[periodId]) + ); + } +} + +function _stringifyBalances(balances: DebtShareData[number]) { + return Object.fromEntries( + Object.entries(balances).map(([user, balance]) => [user, balance.toString()]) + ); +} + +export async function expectedDebtShare( + user: ethers.Signer, + periodId: number +): Promise { + const address = await user.getAddress(); + return _debtShareData[periodId]?.[address] || ethers.BigNumber.from(0); +} + +export async function expectedCrossChainDebtShare( + user: ethers.Signer, + periodId: number +): Promise { + const address = await user.getAddress(); + return _crossChainDebtShareData[periodId]?.[address] || ethers.BigNumber.from(0); +} + +export async function expectedVotePower( + user: ethers.Signer, + periodId: number +): Promise { + const debtShare = await expectedDebtShare(user, periodId); + const crossChainDebtShare = await expectedCrossChainDebtShare(user, periodId); + return bnSqrt(debtShare.add(crossChainDebtShare)); +} + +export function getCrossChainMerkleTree(periodId: number) { + return _crossChainMerkleTreeData[periodId]!; +} diff --git a/protocol/governance/test/integration/Elections.test.ts b/protocol/governance/test/integration/Elections.test.ts new file mode 100644 index 0000000000..4074be206b --- /dev/null +++ b/protocol/governance/test/integration/Elections.test.ts @@ -0,0 +1,679 @@ +import assertBn from '@synthetixio/core-utils/utils/assertions/assert-bignumber'; +import assertRevert from '@synthetixio/core-utils/utils/assertions/assert-revert'; +import { findEvent, findSingleEvent } from '@synthetixio/core-utils/utils/ethers/events'; +import { + fastForwardTo, + getTime, + restoreSnapshot, + takeSnapshot, +} from '@synthetixio/core-utils/utils/hardhat/rpc'; +import { parseBalanceMap } from '@synthetixio/core-utils/utils/merkle-tree/parse-balance-tree'; +import { daysToSeconds } from '@synthetixio/core-utils/utils/misc/dates'; +import assert from 'assert/strict'; +import { ethers } from 'ethers'; +import hre from 'hardhat'; +import { bootstrap } from '../bootstrap'; +import { ElectionPeriod } from '../constants'; +import { DebtShareMock } from '../generated/typechain'; +import { + expectedCrossChainDebtShare, + expectedDebtShare, + expectedVotePower, + getCrossChainMerkleTree, + simulateCrossChainDebtShareData, + simulateDebtShareData, +} from '../helpers/debt-share-helper'; + +describe('SynthetixElectionModule - general elections', function () { + const { c, getSigners } = bootstrap(); + + let owner: ethers.Signer; + let users: ethers.Signer[]; + let addresses: string[]; + + let merkleTree: ReturnType; + let snapshotId: string; + + const epochData = [ + { + index: 0, + debtShareSnapshotId: 42, + blockNumber: 21000000, + winners: () => [addresses[3]!, addresses[4]!], + }, + { + index: 1, + debtShareSnapshotId: 1337, + blockNumber: 23100007, + winners: () => [addresses[3]!, addresses[5]!], + }, + { + index: 2, + debtShareSnapshotId: 2192, + blockNumber: 30043001, + winners: () => [addresses[5]!, addresses[4]!], + }, + ]; + + // TODO: when your testing crosschain functionality, + // add tests specifically for receivers, check for ccip and mothership, etc. + + before('identify signers', async function () { + [owner, ...users] = getSigners(); + addresses = await Promise.all(users.map((u) => u.getAddress())); + }); + + describe('when the election module is initialized', function () { + before('set next epoch seat count to 2', async function () { + const tx = await c.CoreProxy.setNextEpochSeatCount(2); + await tx.wait(); + }); + + it('shows the expected NFT owners', async function () { + assertBn.equal(await c.AccountProxy.balanceOf(await owner.getAddress()), 1); + assertBn.equal(await c.AccountProxy.balanceOf(addresses[0]!), 0); + assertBn.equal(await c.AccountProxy.balanceOf(addresses[1]!), 0); + assertBn.equal(await c.AccountProxy.balanceOf(addresses[2]!), 0); + }); + + it('shows that the election module is initialized', async function () { + assert.equal(await c.CoreProxy.isElectionModuleInitialized(), true); + }); + + it('shows that the DebtShare contract is connected', async function () { + assert.equal(await c.CoreProxy.getDebtShareContract(), c.DebtShareMock.address); + }); + + describe('when re setting the debt share contract', function () { + describe('with the same address', function () { + it('reverts', async function () { + await assertRevert(c.CoreProxy.setDebtShareContract(c.DebtShareMock.address), 'NoChange'); + }); + }); + + describe('with an invalid address', function () { + it('reverts', async function () { + await assertRevert( + c.CoreProxy.setDebtShareContract(ethers.constants.AddressZero), + 'ZeroAddress' + ); + }); + }); + + describe('with an EOA', function () { + it('reverts', async function () { + await assertRevert(c.CoreProxy.setDebtShareContract(addresses[0]), 'NotAContract'); + }); + }); + + describe('with a different address', function () { + let DebtShare: DebtShareMock; + let receipt: ethers.ContractReceipt; + + before('deploy debt shares mock', async function () { + const factory = await hre.ethers.getContractFactory('DebtShareMock'); + DebtShare = await factory.deploy(); + }); + + before('set the new debt share contract', async function () { + const tx = await c.CoreProxy.setDebtShareContract(DebtShare.address); + receipt = await tx.wait(); + }); + + it('emitted a DebtShareContractSet event', async function () { + const event = findSingleEvent({ receipt, eventName: 'DebtShareContractSet' }); + assert.ok(event); + assertBn.equal(event.args.contractAddress, DebtShare.address); + }); + + it('shows that the DebtShare contract is connected', async function () { + assert.equal(await c.CoreProxy.getDebtShareContract(), DebtShare.address); + }); + }); + }); + + // epochData.forEach(function (epoch) { + // describe(`epoch ${epoch.index} with debt share snapshot ${epoch.debtShareSnapshotId}`, function () { + // it(`shows that the current epoch index is ${epoch.index}`, async function () { + // assertBn.equal(await c.CoreProxy.getEpochIndex(), epoch.index); + // }); + + // it('shows that the current period is Administration', async function () { + // assertBn.equal(await c.CoreProxy.getCurrentPeriod(), ElectionPeriod.Administration); + // }); + + // describe('before a debt share snapshot is set', function () { + // describe('when trying to retrieve the current debt share snapshot id', function () { + // it('reverts', async function () { + // await assertRevert( + // c.CoreProxy.getDebtShareSnapshotId(), + // 'DebtShareSnapshotIdNotSet' + // ); + // }); + // }); + + // describe('when trying to retrieve the current debt share of a user', function () { + // it('returns zero', async function () { + // assertBn.equal(await c.CoreProxy.getDebtShare(addresses[0]!), 0); + // }); + // }); + // }); + + // describe('before a merkle root is set', function () { + // describe('when trying to retrieve the current cross chain merkle root', function () { + // it('reverts', async function () { + // await assertRevert( + // c.CoreProxy.getCrossChainDebtShareMerkleRoot(), + // 'MerkleRootNotSet' + // ); + // }); + // }); + + // describe('when trying to retrieve the current cross chain merkle root block number', function () { + // it('reverts', async function () { + // await assertRevert( + // c.CoreProxy.getCrossChainDebtShareMerkleRootBlockNumber(), + // 'MerkleRootNotSet' + // ); + // }); + // }); + + // describe('when trying to retrieve the current cross chain debt share of a user', function () { + // it('returns zero', async function () { + // assertBn.equal(await c.CoreProxy.getDeclaredCrossChainDebtShare(addresses[0]!), 0); + // }); + // }); + // }); + + // describe('before the nomination period begins', function () { + // describe('when trying to set the debt share id', function () { + // it('reverts', async function () { + // await assertRevert( + // c.CoreProxy.setDebtShareSnapshotId(0), + // 'NotCallableInCurrentPeriod' + // ); + // }); + // }); + + // describe('when trying to set the cross chain debt share merkle root', function () { + // it('reverts', async function () { + // await assertRevert( + // c.CoreProxy.setCrossChainDebtShareMerkleRoot( + // '0x000000000000000000000000000000000000000000000000000000000000beef', + // 1337 + // ), + // 'NotCallableInCurrentPeriod' + // ); + // }); + // }); + // }); + + // describe('when advancing to the nominations period', function () { + // before('fast forward', async function () { + // await fastForwardTo( + // await c.CoreProxy.getNominationPeriodStartDate(), + // ethers.provider + // ); + // }); + + // describe('when the current epochs debt share snapshot id is set', function () { + // before('simulate debt share data', async function () { + // await simulateDebtShareData(DebtShare, [ + // users[0]!, + // users[1]!, + // users[2]!, + // users[3]!, + // users[4]!, + // ]); + // }); + + // before('set snapshot id', async function () { + // const tx = await c.CoreProxy.setDebtShareSnapshotId(epoch.debtShareSnapshotId); + // receipt = await tx.wait(); + // }); + + // it('emitted a DebtShareSnapshotIdSet event', async function () { + // const event = findEvent({ receipt, eventName: 'DebtShareSnapshotIdSet' }); + + // assert.ok(event); + // assertBn.equal(event.args.snapshotId, epoch.debtShareSnapshotId); + // }); + + // it('shows that the snapshot id is set', async function () { + // assertBn.equal( + // await c.CoreProxy.getDebtShareSnapshotId(), + // epoch.debtShareSnapshotId + // ); + // }); + + // it('shows that users have the expected debt shares', async function () { + // assert.deepEqual( + // await c.CoreProxy.getDebtShare(addresses[0]!), + // await expectedDebtShare(users[0]!, epoch.debtShareSnapshotId) + // ); + // assert.deepEqual( + // await c.CoreProxy.getDebtShare(addresses[1]!), + // await expectedDebtShare(users[1]!, epoch.debtShareSnapshotId) + // ); + // assert.deepEqual( + // await c.CoreProxy.getDebtShare(addresses[2]!), + // await expectedDebtShare(users[2]!, epoch.debtShareSnapshotId) + // ); + // assert.deepEqual( + // await c.CoreProxy.getDebtShare(addresses[3]!), + // await expectedDebtShare(users[3]!, epoch.debtShareSnapshotId) + // ); + // assert.deepEqual( + // await c.CoreProxy.getDebtShare(addresses[4]!), + // await expectedDebtShare(users[4]!, epoch.debtShareSnapshotId) + // ); + // }); + + // describe('when cross chain debt share data is collected', function () { + // before('simulate cross chain debt share data', async function () { + // await simulateCrossChainDebtShareData([users[0]!, users[1]!, users[2]!]); + + // merkleTree = getCrossChainMerkleTree(epoch.debtShareSnapshotId); + // }); + + // describe('when a user attempts to declare cross chain debt shares and the merkle root is not set', function () { + // before('take snapshot', async function () { + // snapshotId = await takeSnapshot(ethers.provider); + // }); + + // after('restore snapshot', async function () { + // await restoreSnapshot(snapshotId, ethers.provider); + // }); + + // before('fast forward', async function () { + // await fastForwardTo( + // await c.CoreProxy.getVotingPeriodStartDate(), + // ethers.provider + // ); + // }); + + // it('reverts', async function () { + // merkleTree = getCrossChainMerkleTree(epoch.debtShareSnapshotId); + + // await assertRevert( + // c.CoreProxy.declareCrossChainDebtShare( + // addresses[0]!, + // await expectedCrossChainDebtShare(users[0]!, epoch.debtShareSnapshotId), + // merkleTree.claims[addresses[0]!].proof + // ), + // 'MerkleRootNotSet' + // ); + // }); + // }); + + // describe('when the current epochs cross chain debt share merkle root is set', function () { + // before('set the merkle root', async function () { + // const tx = await c.CoreProxy.setCrossChainDebtShareMerkleRoot( + // merkleTree.merkleRoot, + // epoch.blockNumber + // ); + // receipt = await tx.wait(); + // }); + + // before('nominate', async function () { + // (await c.CoreProxy.connect(users[3]!).nominate()).wait(); + // (await c.CoreProxy.connect(users[4]!).nominate()).wait(); + // (await c.CoreProxy.connect(users[5]!).nominate()).wait(); + // (await c.CoreProxy.connect(users[6]!).nominate()).wait(); + // (await c.CoreProxy.connect(users[7]!).nominate()).wait(); + // (await c.CoreProxy.connect(users[8]!).nominate()).wait(); + // }); + + // it('emitted a CrossChainDebtShareMerkleRootSet event', async function () { + // const event = findEvent({ + // receipt, + // eventName: 'CrossChainDebtShareMerkleRootSet', + // }); + + // assert.ok(event); + // assertBn.equal(event.args.merkleRoot, merkleTree.merkleRoot); + // assertBn.equal(event.args.blocknumber, epoch.blockNumber); + // }); + + // it('shows that the merkle root is set', async function () { + // assert.equal( + // await c.CoreProxy.getCrossChainDebtShareMerkleRoot(), + // merkleTree.merkleRoot + // ); + // }); + + // it('shows that the merkle root block number is set', async function () { + // assertBn.equal( + // await c.CoreProxy.getCrossChainDebtShareMerkleRootBlockNumber(), + // epoch.blockNumber + // ); + // }); + + // describe('when users declare their cross chain debt shares in the wrong period', function () { + // it('reverts', async function () { + // await assertRevert( + // c.CoreProxy.declareCrossChainDebtShare( + // addresses[0]!, + // await expectedCrossChainDebtShare(users[0]!, epoch.debtShareSnapshotId), + // merkleTree.claims[addresses[0]!].proof + // ), + // 'NotCallableInCurrentPeriod' + // ); + // }); + // }); + + // describe('when advancing to the voting period', function () { + // before('fast forward', async function () { + // await fastForwardTo( + // await c.CoreProxy.getVotingPeriodStartDate(), + // ethers.provider + // ); + // }); + + // it('shows that the current period is Voting', async function () { + // assertBn.equal(await c.CoreProxy.getCurrentPeriod(), ElectionPeriod.Vote); + // }); + + // describe('when users declare their cross chain debt shares incorrectly', function () { + // describe('when a user declares a wrong amount', function () { + // it('reverts', async function () { + // const { proof } = merkleTree.claims[addresses[1]!]; + + // await assertRevert( + // c.CoreProxy.declareCrossChainDebtShare( + // addresses[1]!, + // ethers.utils.parseEther('10000000'), + // proof + // ), + // 'InvalidMerkleProof' + // ); + // }); + // }); + + // describe('when a user with no entry in the tree declares an amount', function () { + // it('reverts', async function () { + // const { proof } = merkleTree.claims[addresses[1]!]; + + // await assertRevert( + // c.CoreProxy.declareCrossChainDebtShare( + // addresses[3]!, + // ethers.utils.parseEther('1000'), + // proof + // ), + // 'InvalidMerkleProof' + // ); + // }); + // }); + + // describe('when a user uses the wrong tree to declare', function () { + // it('reverts', async function () { + // const anotherTree = getCrossChainMerkleTree(666); + // const { amount, proof } = anotherTree.claims[addresses[1]!]; + + // await assertRevert( + // c.CoreProxy.declareCrossChainDebtShare(addresses[1]!, amount, proof), + // 'InvalidMerkleProof' + // ); + // }); + // }); + // }); + + // describe('when users declare their cross chain debt shares correctly', function () { + // async function declare(user) { + // const { amount, proof } = merkleTree.claims[user.address]; + + // const tx = await c.CoreProxy.declareCrossChainDebtShare( + // user.address, + // amount, + // proof + // ); + // receipt = await tx.wait(); + // } + + // async function declareAndCast(user, candidates) { + // const { amount, proof } = merkleTree.claims[user.address]; + + // const tx = await c.CoreProxy.connect(user).declareAndCast( + // amount, + // proof, + // candidates + // ); + // receipt = await tx.wait(); + // } + + // before('declare', async function () { + // await declare(users[0]!); + // await declare(users[1]!); + // // Note: Intentionally not declaring for users[2]! + // }); + + // describe('when a user attempts to re-declare cross chain debt shares', function () { + // it('reverts', async function () { + // const { amount, proof } = merkleTree.claims[addresses[0]!]; + + // await assertRevert( + // c.CoreProxy.declareCrossChainDebtShare(addresses[0]!, amount, proof), + // 'CrossChainDebtShareAlreadyDeclared' + // ); + // }); + // }); + + // it('emitted a CrossChainDebtShareDeclared event', async function () { + // const event = findEvent({ + // receipt, + // eventName: 'CrossChainDebtShareDeclared', + // }); + + // assert.ok(event); + // assertBn.equal(event.args.user, addresses[1]!); + // assertBn.equal( + // event.args.debtShare, + // await expectedCrossChainDebtShare(users[1]!, epoch.debtShareSnapshotId) + // ); + // }); + + // it('shows that users have declared their cross chain debt shares', async function () { + // assertBn.equal( + // await c.CoreProxy.getDeclaredCrossChainDebtShare(addresses[0]!), + // await expectedCrossChainDebtShare(users[0]!, epoch.debtShareSnapshotId) + // ); + // assertBn.equal( + // await c.CoreProxy.getDeclaredCrossChainDebtShare(addresses[1]!), + // await expectedCrossChainDebtShare(users[1]!, epoch.debtShareSnapshotId) + // ); + // }); + + // it('shows that users have the expected vote power (cross chain component is now declared)', async function () { + // assert.deepEqual( + // await c.CoreProxy.getVotePower(addresses[0]!), + // expectedVotePower(addresses[0]!, epoch.debtShareSnapshotId) + // ); + // assert.deepEqual( + // await c.CoreProxy.getVotePower(addresses[1]!), + // expectedVotePower(addresses[1]!, epoch.debtShareSnapshotId) + // ); + // }); + + // describe('when a user tries to vote for more than one candidate', function () { + // it('reverts', async function () { + // await assertRevert( + // c.CoreProxy.connect(users[0]!).cast([addresses[3]!, addresses[4]!]), + // 'TooManyCandidates' + // ); + // }); + // }); + + // describe('when users cast votes', function () { + // let ballot1, ballot2, ballot3; + + // before('vote', async function () { + // await c.CoreProxy.connect(users[0]!).cast([addresses[3]!]); + // await c.CoreProxy.connect(users[1]!).cast([addresses[3]!]); + // await declareAndCast(users[2]!, [addresses[4]!]); // users[2]! didn't declare cross chain debt shares yet + // await c.CoreProxy.connect(users[3]!).cast([addresses[5]!]); + // await c.CoreProxy.connect(users[4]!).cast([addresses[3]!]); + // }); + + // before('identify ballots', async function () { + // ballot1 = await c.CoreProxy.calculateBallotId([addresses[3]!]); + // ballot2 = await c.CoreProxy.calculateBallotId([addresses[4]!]); + // ballot3 = await c.CoreProxy.calculateBallotId([addresses[5]!]); + // }); + + // it('keeps track of which ballot each user voted on', async function () { + // assert.equal(await c.CoreProxy.getBallotVoted(addresses[0]!), ballot1); + // assert.equal(await c.CoreProxy.getBallotVoted(addresses[1]!), ballot1); + // assert.equal(await c.CoreProxy.getBallotVoted(addresses[2]!), ballot2); + // assert.equal(await c.CoreProxy.getBallotVoted(addresses[3]!), ballot3); + // assert.equal(await c.CoreProxy.getBallotVoted(addresses[4]!), ballot1); + // }); + + // it('keeps track of the candidates of each ballot', async function () { + // assert.deepEqual(await c.CoreProxy.getBallotCandidates(ballot1), [ + // addresses[3]!, + // ]); + // assert.deepEqual(await c.CoreProxy.getBallotCandidates(ballot2), [ + // addresses[4]!, + // ]); + // assert.deepEqual(await c.CoreProxy.getBallotCandidates(ballot3), [ + // addresses[5]!, + // ]); + // }); + + // it('keeps track of vote power in each ballot', async function () { + // const votesBallot1 = expectedVotePower( + // addresses[0]!, + // epoch.debtShareSnapshotId + // ) + // .add(expectedVotePower(addresses[1]!, epoch.debtShareSnapshotId)) + // .add(expectedVotePower(addresses[4]!, epoch.debtShareSnapshotId)); + // const votesBallot2 = expectedVotePower( + // addresses[2]!, + // epoch.debtShareSnapshotId + // ); + // const votesBallot3 = expectedVotePower( + // addresses[3]!, + // epoch.debtShareSnapshotId + // ); + + // assertBn.equal(await c.CoreProxy.getBallotVotes(ballot1), votesBallot1); + // assertBn.equal(await c.CoreProxy.getBallotVotes(ballot2), votesBallot2); + // assertBn.equal(await c.CoreProxy.getBallotVotes(ballot3), votesBallot3); + // }); + + // describe('when voting ends', function () { + // before('fast forward', async function () { + // await fastForwardTo( + // await c.CoreProxy.getEpochEndDate(), + // ethers.provider + // ); + // }); + + // it('shows that the current period is Evaluation', async function () { + // assertBn.equal( + // await c.CoreProxy.getCurrentPeriod(), + // ElectionPeriod.Evaluation + // ); + // }); + + // describe('when the election is evaluated', function () { + // before('evaluate', async function () { + // (await c.CoreProxy.evaluate(0)).wait(); + // }); + + // it('shows that the election is evaluated', async function () { + // assert.equal(await c.CoreProxy.isElectionEvaluated(), true); + // }); + + // it('shows each candidates votes', async function () { + // const votesUser4 = expectedVotePower( + // addresses[0]!, + // epoch.debtShareSnapshotId + // ) + // .add(expectedVotePower(addresses[1]!, epoch.debtShareSnapshotId)) + // .add(expectedVotePower(addresses[4]!, epoch.debtShareSnapshotId)); + // const votesUser5 = expectedVotePower( + // addresses[2]!, + // epoch.debtShareSnapshotId + // ); + // const votesUser6 = expectedVotePower( + // addresses[3]!, + // epoch.debtShareSnapshotId + // ); + + // assertBn.equal( + // await c.CoreProxy.getCandidateVotes(addresses[3]!), + // votesUser4 + // ); + // assertBn.equal( + // await c.CoreProxy.getCandidateVotes(addresses[4]!), + // votesUser5 + // ); + // assertBn.equal( + // await c.CoreProxy.getCandidateVotes(addresses[5]!), + // votesUser6 + // ); + // assertBn.equal( + // await c.CoreProxy.getCandidateVotes(addresses[6]!), + // 0 + // ); + // assertBn.equal( + // await c.CoreProxy.getCandidateVotes(addresses[7]!), + // 0 + // ); + // assertBn.equal( + // await c.CoreProxy.getCandidateVotes(addresses[8]!), + // 0 + // ); + // }); + + // it('shows the election winners', async function () { + // assert.deepEqual( + // await c.CoreProxy.getElectionWinners(), + // epoch.winners() + // ); + // }); + + // describe('when the election is resolved', function () { + // before('resolve', async function () { + // (await c.CoreProxy.resolve()).wait(); + // }); + + // it('shows the expected NFT owners', async function () { + // const winners = epoch.winners(); + + // assertBn.equal( + // await CouncilToken.balanceOf(await owner.getAddress()), + // winners.includes(await owner.getAddress()) ? 1 : 0 + // ); + // assertBn.equal( + // await CouncilToken.balanceOf(addresses[3]!), + // winners.includes(addresses[3]!) ? 1 : 0 + // ); + // assertBn.equal( + // await CouncilToken.balanceOf(addresses[4]!), + // winners.includes(addresses[4]!) ? 1 : 0 + // ); + // assertBn.equal( + // await CouncilToken.balanceOf(addresses[5]!), + // winners.includes(addresses[5]!) ? 1 : 0 + // ); + // assertBn.equal( + // await CouncilToken.balanceOf(addresses[6]!), + // winners.includes(addresses[6]!) ? 1 : 0 + // ); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + }); +}); diff --git a/protocol/governance/test/Initialize.test.ts b/protocol/governance/test/integration/Initialize.test.ts similarity index 97% rename from protocol/governance/test/Initialize.test.ts rename to protocol/governance/test/integration/Initialize.test.ts index bdc015c33e..f11004a8a1 100644 --- a/protocol/governance/test/Initialize.test.ts +++ b/protocol/governance/test/integration/Initialize.test.ts @@ -4,8 +4,8 @@ import { daysToSeconds } from '@synthetixio/core-utils/utils/misc/dates'; import assert from 'assert/strict'; import { ethers } from 'ethers'; import hre from 'hardhat'; -import { bootstrap } from './bootstrap'; -import { CoreProxy, CoreProxy__factory } from './generated/typechain'; +import { bootstrap } from '../bootstrap'; +import { CoreProxy, CoreProxy__factory } from '../generated/typechain'; describe('SynthetixElectionModule (initialization)', () => { const { c, getSigners } = bootstrap();