UNPKG

@vechain/vebetterdao-contracts

Version:

Open-source repository that houses the smart contracts powering the decentralized VeBetterDAO on the VeChain Thor blockchain.

585 lines (584 loc) 41.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fixture_test_1 = require("./fixture.test"); const hardhat_1 = require("hardhat"); const common_1 = require("../helpers/common"); const xnodes_1 = require("../helpers/xnodes"); const mocha_1 = require("mocha"); const chai_1 = require("chai"); const helpers_1 = require("../helpers"); (0, mocha_1.describe)("Voting power with proposal deposit - @shard4b", function () { let vot3; let b3tr; let minterAccount; let proposer; let creator; let x2EarnApps; let xAllocationVoting; let voter; let veBetterPassport; let owner; let emissions; let governor; let endorser1; (0, mocha_1.beforeEach)(async function () { const fixture = await (0, fixture_test_1.setupGovernanceFixtureWithEmissions)(); vot3 = fixture.vot3; b3tr = fixture.b3tr; minterAccount = fixture.minterAccount; proposer = fixture.proposer; creator = fixture.creators; x2EarnApps = fixture.x2EarnApps; xAllocationVoting = fixture.xAllocationVoting; voter = fixture.voter; veBetterPassport = fixture.veBetterPassport; owner = fixture.owner; emissions = fixture.emissions; governor = fixture.governor; endorser1 = fixture.otherAccounts[5]; // Setup proposer for all tests await (0, fixture_test_1.setupProposer)(proposer, b3tr, vot3, minterAccount); }); (0, mocha_1.describe)("Backward compatibility", function () { (0, mocha_1.it)("Should be able to vote in xApps allocation without proposal deposit if no deposit is done", async function () { await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); // submit app const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); await (0, xnodes_1.endorseApp)(app1Id, voter); await vot3.connect(voter).delegate(voter.address); await (0, common_1.moveBlocks)(2); const round1 = await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await xAllocationVoting.connect(voter).castVote(round1, [app1Id], [hardhat_1.ethers.parseEther("100")]); // Check the voting power const roundSnapshot = await xAllocationVoting.roundSnapshot(round1); const votingPower = await xAllocationVoting.getVotes(voter.address, roundSnapshot); (0, chai_1.expect)(votingPower).to.equal(hardhat_1.ethers.parseEther("10000")); // 10000 because we had 10000 vot3 tokens at snapshot }); (0, mocha_1.it)("Should be able to vote on allocation with the proposal deposit", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Get the deposit threshold for the proposal type const depositThreshold = await governor.depositThresholdByProposalType(fixture_test_1.STANDARD_PROPOSAL_TYPE); //Get user the balance of deposit await (0, common_1.getVot3Tokens)(voter, hardhat_1.ethers.formatEther(depositThreshold)); const expectedVot3BalanceBeforeDeposit = expectedVot3Balance + depositThreshold; (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3BalanceBeforeDeposit); //Start emissions await emissions.connect(minterAccount).start(); //Round 2 const roundIdBeforeVotesDeposit = await xAllocationVoting.currentRoundId(); //Allowance for the deposit await vot3.connect(voter).approve(await governor.getAddress(), depositThreshold); // Create the proposal const tx = await governor .connect(voter) .propose([await b3tr.getAddress()], [0], [(await hardhat_1.ethers.getContractFactory("B3TR")).interface.encodeFunctionData("tokenDetails", [])], `${this?.test?.title}`, (Number(roundIdBeforeVotesDeposit) + 2).toString(), 0, { gasLimit: 10000000, }); //Deposit into the proposal the exact threshold await tx.wait(); const proposalId = await (0, common_1.getProposalIdFromTx)(tx, false, { governor }); const txForDeposit = await governor.connect(voter).deposit(depositThreshold, proposalId); await txForDeposit.wait(); //Wait for round to end await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); //Start new round await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const roundIdAfterVotesDeposit = await xAllocationVoting.currentRoundId(); const roundSnapshotBeforeVotes = await xAllocationVoting.roundSnapshot(roundIdBeforeVotesDeposit); const roundSnapshotAfterVotes = await xAllocationVoting.roundSnapshot(roundIdAfterVotesDeposit); const votingPowerForAllocationAfterVotes = await xAllocationVoting.getVotes(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInAllocationBeforeVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInGovernorBeforeVotes = await governor.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInAllocationAfterVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInGovernorAfter = await governor.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); //Both deposit voting power should be 0 because no deposit was done (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInGovernorBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(depositvotingpowerInGovernorBeforeVotes); //Both deposit voting power should be equal the threshold and same for the governor (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInGovernorAfter).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositvotingpowerInGovernorAfter); // getVotes already includes deposit voting power for non-delegated users const txForVote = await xAllocationVoting .connect(voter) .castVote(roundIdAfterVotesDeposit, [app1Id], [votingPowerForAllocationAfterVotes]); await txForVote.wait(); const appVotes = await xAllocationVoting.getAppVotes(roundIdAfterVotesDeposit, app1Id); (0, chai_1.expect)(votingPowerForAllocationAfterVotes).to.equal(appVotes); }); (0, mocha_1.it)("Should be able to vote on allocation with the proposal deposit if deposit twice", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Get the deposit threshold for the proposal type const depositThreshold = await governor.depositThresholdByProposalType(fixture_test_1.STANDARD_PROPOSAL_TYPE); //Get user the balance of deposit await (0, common_1.getVot3Tokens)(voter, hardhat_1.ethers.formatEther(depositThreshold)); const expectedVot3BalanceBeforeDeposit = expectedVot3Balance + depositThreshold; (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3BalanceBeforeDeposit); //Start emissions await emissions.connect(minterAccount).start(); //Round 2 const roundIdBeforeVotesDeposit = await xAllocationVoting.currentRoundId(); //Allowance for the deposit await vot3.connect(voter).approve(await governor.getAddress(), depositThreshold); // Create the proposal const tx = await governor .connect(voter) .propose([await b3tr.getAddress()], [0], [(await hardhat_1.ethers.getContractFactory("B3TR")).interface.encodeFunctionData("tokenDetails", [])], `${this?.test?.title}`, (Number(roundIdBeforeVotesDeposit) + 2).toString(), 0, { gasLimit: 10000000, }); //Deposit into the proposal the exact threshold in 2 operations await tx.wait(); const proposalId = await (0, common_1.getProposalIdFromTx)(tx, false, { governor }); const txForDeposit = await governor.connect(voter).deposit(depositThreshold / 2n, proposalId); await txForDeposit.wait(); //Wait few blocks to simulate the time between the 2 deposits await (0, common_1.moveBlocks)(10); const txForDeposit2 = await governor.connect(voter).deposit(depositThreshold / 2n, proposalId); await txForDeposit2.wait(); //Wait for round to end await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); //Start new round await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const roundIdAfterVotesDeposit = await xAllocationVoting.currentRoundId(); const roundSnapshotBeforeVotes = await xAllocationVoting.roundSnapshot(roundIdBeforeVotesDeposit); const roundSnapshotAfterVotes = await xAllocationVoting.roundSnapshot(roundIdAfterVotesDeposit); const votingPowerForAllocationAfterVotes = await xAllocationVoting.getVotes(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInAllocationBeforeVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInGovernorBeforeVotes = await governor.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInAllocationAfterVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInGovernorAfter = await governor.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); //Both deposit voting power should be 0 because no deposit was done (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInGovernorBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(depositvotingpowerInGovernorBeforeVotes); //Both deposit voting power should be equal the threshold and same for the governor (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInGovernorAfter).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositvotingpowerInGovernorAfter); // getVotes already includes deposit voting power for non-delegated users const txForVote = await xAllocationVoting .connect(voter) .castVote(roundIdAfterVotesDeposit, [app1Id], [votingPowerForAllocationAfterVotes]); await txForVote.wait(); const appVotes = await xAllocationVoting.getAppVotes(roundIdAfterVotesDeposit, app1Id); (0, chai_1.expect)(votingPowerForAllocationAfterVotes).to.equal(appVotes); }); (0, mocha_1.it)("Should be able to vote on allocation with the proposal deposit if the proposal is created already with a deposit", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Get the deposit threshold for the proposal type const depositThreshold = await governor.depositThresholdByProposalType(fixture_test_1.STANDARD_PROPOSAL_TYPE); //Get user the balance of deposit await (0, common_1.getVot3Tokens)(voter, hardhat_1.ethers.formatEther(depositThreshold)); const expectedVot3BalanceBeforeDeposit = expectedVot3Balance + depositThreshold; (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3BalanceBeforeDeposit); //Start emissions await emissions.connect(minterAccount).start(); //Round 2 const roundIdBeforeVotesDeposit = await xAllocationVoting.currentRoundId(); //Allowance for the deposit await vot3.connect(voter).approve(await governor.getAddress(), depositThreshold); // Create the proposal already supporting the deposit threshold const tx = await governor .connect(voter) .propose([await b3tr.getAddress()], [0], [(await hardhat_1.ethers.getContractFactory("B3TR")).interface.encodeFunctionData("tokenDetails", [])], `${this?.test?.title}`, (Number(roundIdBeforeVotesDeposit) + 2).toString(), depositThreshold, { gasLimit: 10000000, }); await tx.wait(); //Wait for round to end await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); //Start new round await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const roundIdAfterVotesDeposit = await xAllocationVoting.currentRoundId(); const roundSnapshotBeforeVotes = await xAllocationVoting.roundSnapshot(roundIdBeforeVotesDeposit); const roundSnapshotAfterVotes = await xAllocationVoting.roundSnapshot(roundIdAfterVotesDeposit); const votingPowerForAllocationAfterVotes = await xAllocationVoting.getVotes(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInAllocationBeforeVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInGovernorBeforeVotes = await governor.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInAllocationAfterVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInGovernorAfter = await governor.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); //Both deposit voting power should be 0 because no deposit was done (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInGovernorBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(depositvotingpowerInGovernorBeforeVotes); //Both deposit voting power should be equal the threshold and same for the governor (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInGovernorAfter).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositvotingpowerInGovernorAfter); // getVotes already includes deposit voting power for non-delegated users const txForVote = await xAllocationVoting .connect(voter) .castVote(roundIdAfterVotesDeposit, [app1Id], [votingPowerForAllocationAfterVotes]); await txForVote.wait(); const appVotes = await xAllocationVoting.getAppVotes(roundIdAfterVotesDeposit, app1Id); (0, chai_1.expect)(votingPowerForAllocationAfterVotes).to.equal(appVotes); }); (0, mocha_1.it)("Should NOT be able to vote on allocation with the proposal deposit if the value is higher than the total voting power", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Get the deposit threshold for the proposal type const depositThreshold = await governor.depositThresholdByProposalType(fixture_test_1.STANDARD_PROPOSAL_TYPE); //Get user the balance of deposit await (0, common_1.getVot3Tokens)(voter, hardhat_1.ethers.formatEther(depositThreshold)); const expectedVot3BalanceBeforeDeposit = expectedVot3Balance + depositThreshold; (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3BalanceBeforeDeposit); //Start emissions await emissions.connect(minterAccount).start(); //Round 2 const roundIdBeforeVotesDeposit = await xAllocationVoting.currentRoundId(); //Allowance for the deposit await vot3.connect(voter).approve(await governor.getAddress(), depositThreshold); // Create the proposal already supporting the deposit threshold const tx = await governor .connect(voter) .propose([await b3tr.getAddress()], [0], [(await hardhat_1.ethers.getContractFactory("B3TR")).interface.encodeFunctionData("tokenDetails", [])], `${this?.test?.title}`, (Number(roundIdBeforeVotesDeposit) + 2).toString(), depositThreshold, { gasLimit: 10000000, }); await tx.wait(); //Wait for round to end await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); //Start new round await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const roundIdAfterVotesDeposit = await xAllocationVoting.currentRoundId(); const roundSnapshotBeforeVotes = await xAllocationVoting.roundSnapshot(roundIdBeforeVotesDeposit); const roundSnapshotAfterVotes = await xAllocationVoting.roundSnapshot(roundIdAfterVotesDeposit); const votingPowerForAllocationAfterVotes = await xAllocationVoting.getVotes(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInAllocationBeforeVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInGovernorBeforeVotes = await governor.getDepositVotingPower(voter.address, roundSnapshotBeforeVotes); const depositvotingpowerInAllocationAfterVotes = await xAllocationVoting.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); const depositvotingpowerInGovernorAfter = await governor.getDepositVotingPower(voter.address, roundSnapshotAfterVotes); //Both deposit voting power should be 0 because no deposit was done (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInGovernorBeforeVotes).to.equal(0); (0, chai_1.expect)(depositvotingpowerInAllocationBeforeVotes).to.equal(depositvotingpowerInGovernorBeforeVotes); //Both deposit voting power should be equal the threshold and same for the governor (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInGovernorAfter).to.equal(depositThreshold); (0, chai_1.expect)(depositvotingpowerInAllocationAfterVotes).to.equal(depositvotingpowerInGovernorAfter); //Sum of the voting power and the deposit voting power to get the total vote available for the voter to vote on the allocation const totalVoteWithDeposit = votingPowerForAllocationAfterVotes + depositvotingpowerInAllocationAfterVotes; await (0, helpers_1.catchRevert)(xAllocationVoting.connect(voter).castVote(roundIdAfterVotesDeposit, [app1Id], [totalVoteWithDeposit + 1n])); const appVotes = await xAllocationVoting.getAppVotes(roundIdAfterVotesDeposit, app1Id); //App should not have any votes because the total vote with the deposit is higher than the total voting power and tx reverted (0, chai_1.expect)(appVotes).to.equal(0); }); (0, mocha_1.it)("Should be able to vote on allocation even if no deposit was done", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Start emissions await emissions.connect(minterAccount).start(); //Wait for round to end await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); //Start new round await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const currentRoundId = await xAllocationVoting.currentRoundId(); const currentRoundSnapshot = await xAllocationVoting.roundSnapshot(currentRoundId); const votingPowerForAllocationAfterVotes = await xAllocationVoting.getVotes(voter.address, currentRoundSnapshot); const depositVotingPower = await xAllocationVoting.getDepositVotingPower(voter.address, currentRoundSnapshot); (0, chai_1.expect)(votingPowerForAllocationAfterVotes).to.equal(expectedVot3Balance); (0, chai_1.expect)(depositVotingPower).to.equal(0); const txForVote = await xAllocationVoting .connect(voter) .castVote(currentRoundId, [app1Id], [votingPowerForAllocationAfterVotes]); await txForVote.wait(); const appVotes = await xAllocationVoting.getAppVotes(currentRoundId, app1Id); //The app should have the total vote with the deposit as voting power as well (0, chai_1.expect)(votingPowerForAllocationAfterVotes).to.equal(appVotes); }); }); (0, mocha_1.describe)("Voting with deposits VP", function () { (0, mocha_1.it)("Should NOT count the deposit VP in the proposal VP", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Get the deposit threshold for the proposal type const depositThreshold = await governor.depositThresholdByProposalType(fixture_test_1.STANDARD_PROPOSAL_TYPE); //Get user the balance of deposit await (0, common_1.getVot3Tokens)(voter, hardhat_1.ethers.formatEther(depositThreshold)); const totalVot3 = expectedVot3Balance + depositThreshold; // 10 000 vot3 mint + expectedvot3 (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(totalVot3); //Start emissions await emissions.connect(minterAccount).start(); //Round 1 const roundIdBeforeVotesDeposit = await xAllocationVoting.currentRoundId(); //Allowance for the deposit await vot3.connect(voter).approve(await governor.getAddress(), depositThreshold); // Create the proposal already supporting the deposit threshold const tx = await governor.connect(voter).propose([await b3tr.getAddress()], [0], [(await hardhat_1.ethers.getContractFactory("B3TR")).interface.encodeFunctionData("tokenDetails", [])], `${this?.test?.title}`, (Number(roundIdBeforeVotesDeposit) + 2).toString(), // In 2 round possible to withdraw, meanwhile VP is either consumed by castVote, or stored depositThreshold, { gasLimit: 10000000, }); await tx.wait(); await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); const proposalVP = await xAllocationVoting.getVotes(voter.address, await xAllocationVoting.roundSnapshot(await xAllocationVoting.currentRoundId())); const proposalDepositVP = await xAllocationVoting.getDepositVotingPower(voter.address, await xAllocationVoting.roundSnapshot(await xAllocationVoting.currentRoundId())); // getVotes now includes deposit VP for allocation voting (0, chai_1.expect)(proposalVP).to.equal(totalVot3); (0, chai_1.expect)(proposalDepositVP).to.equal(depositThreshold); }); }); (0, mocha_1.describe)("Withdrawing(claim back) deposits", function () { (0, mocha_1.it)("Deposits VP should be transferred to the VOT3 balance VP when withdrawing", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Get the deposit threshold for the proposal type const depositThreshold = await governor.depositThresholdByProposalType(fixture_test_1.STANDARD_PROPOSAL_TYPE); //Get user the balance of deposit await (0, common_1.getVot3Tokens)(voter, hardhat_1.ethers.formatEther(depositThreshold)); const totalVot3 = expectedVot3Balance + depositThreshold; // 10 000 vot3 mint + expectedvot3 (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(totalVot3); //Start emissions await emissions.connect(minterAccount).start(); //Round 1 const roundIdBeforeVotesDeposit = await xAllocationVoting.currentRoundId(); //Allowance for the deposit await vot3.connect(voter).approve(await governor.getAddress(), depositThreshold); // Create the proposal already supporting the deposit threshold const tx = await governor.connect(voter).propose([await b3tr.getAddress()], [0], [(await hardhat_1.ethers.getContractFactory("B3TR")).interface.encodeFunctionData("tokenDetails", [])], `${this?.test?.title}`, (Number(roundIdBeforeVotesDeposit) + 2).toString(), // In 2 round possible to withdraw, meanwhile VP is either consumed by castVote, or stored depositThreshold, { gasLimit: 10000000, }); await tx.wait(); const proposalId = await (0, common_1.getProposalIdFromTx)(tx, true, { governor }); await (0, common_1.waitForProposalToBeActive)(proposalId, { governor }); // ROUND 3 -> withdraw possible await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const currentRoundId = await xAllocationVoting.currentRoundId(); const currentRoundSnapshot = await xAllocationVoting.roundSnapshot(currentRoundId); await (0, common_1.waitForNextBlock)(); const votingPowerAfterVotes = await xAllocationVoting.getVotes(voter.address, currentRoundSnapshot); const depositVPAfterVotes = await xAllocationVoting.getDepositVotingPower(voter.address, currentRoundSnapshot); // getVotes already includes deposits, so it equals the total (0, chai_1.expect)(votingPowerAfterVotes).to.equal(totalVot3); (0, chai_1.expect)(depositVPAfterVotes).to.equal(depositThreshold); // claim the deposit back await governor.withdraw(proposalId, voter.address); // it goes back to the balance (getvotes is increased) of the voter // get the clock const now = await governor.clock(); await (0, common_1.waitForNextBlock)(); const vpAfterClaimBack_now = await xAllocationVoting.getVotes(voter.address, now); const depositVPAfterClaimBackDeposit_now = await xAllocationVoting.getDepositVotingPower(voter.address, now); (0, chai_1.expect)(depositVPAfterClaimBackDeposit_now).to.equal(0); // withdraw the deposits (0, chai_1.expect)(vpAfterClaimBack_now).to.equal(totalVot3); // deposits goes back in the principal balance await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const currentRoundIdAfterWithdraw = await xAllocationVoting.currentRoundId(); const txForVote = await xAllocationVoting .connect(voter) .castVote(currentRoundIdAfterWithdraw, [app1Id], [vpAfterClaimBack_now]); await txForVote.wait(); const appVotes = await xAllocationVoting.getAppVotes(currentRoundIdAfterWithdraw, app1Id); (0, chai_1.expect)(vpAfterClaimBack_now).to.equal(appVotes); await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); const roundAtSnapshot = await xAllocationVoting.currentRoundId(); const atSnapshot = await xAllocationVoting.roundSnapshot(roundAtSnapshot); const vpAfterSpendingVOT3 = await xAllocationVoting.getVotes(voter.address, atSnapshot); const depositsVPAfterSpendingVOT3 = await xAllocationVoting.getDepositVotingPower(voter.address, atSnapshot); (0, chai_1.expect)(vpAfterSpendingVOT3).to.equal(totalVot3); (0, chai_1.expect)(depositsVPAfterSpendingVOT3).to.equal(0); }); (0, mocha_1.it)("Should be able to deposit multiple times, increasing the deposit VP", async function () { //Submit the app await x2EarnApps .connect(owner) .submitApp(creator[0].address, creator[0].address, creator[0].address, "metadataURI"); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(creator[0].address)); //Endorse App await (0, xnodes_1.endorseApp)(app1Id, endorser1); //Setup voter + start new round await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport); const expectedVot3Balance = hardhat_1.ethers.parseEther("10000"); (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3Balance); //Get the deposit threshold for the proposal type const depositThreshold = await governor.depositThresholdByProposalType(fixture_test_1.STANDARD_PROPOSAL_TYPE); //Get user the balance of deposit await (0, common_1.getVot3Tokens)(voter, hardhat_1.ethers.formatEther(depositThreshold)); await (0, common_1.getVot3Tokens)(owner, hardhat_1.ethers.formatEther(depositThreshold)); const expectedVot3BalanceBeforeDeposits = expectedVot3Balance + depositThreshold; // 10 000 vot3 mint + expectedvot3 (0, chai_1.expect)(await vot3.balanceOf(voter.address)).to.equal(expectedVot3BalanceBeforeDeposits); (0, chai_1.expect)(await vot3.balanceOf(owner.address)).to.equal(depositThreshold); //Start emissions await emissions.connect(minterAccount).start(); //Round 1 const roundIdBeforeVotesDeposit = await xAllocationVoting.currentRoundId(); //Allowance for the deposit await vot3.connect(voter).approve(await governor.getAddress(), depositThreshold); const depositThresholdReduced = depositThreshold / BigInt(2); // 2 times less const remainingDivided = (depositThreshold - depositThresholdReduced) / BigInt(2); const voterDepositSecondTime = remainingDivided; const depositor2Deposit = remainingDivided; await vot3.connect(owner).approve(await governor.getAddress(), depositor2Deposit); // Create the proposal already supporting the deposit threshold const tx = await governor.connect(voter).propose([await b3tr.getAddress()], [0], [(await hardhat_1.ethers.getContractFactory("B3TR")).interface.encodeFunctionData("tokenDetails", [])], `${this?.test?.title}`, (Number(roundIdBeforeVotesDeposit) + 2).toString(), // In 2 round possible to withdraw, meanwhile VP is either consumed by castVote, or stored depositThresholdReduced, { gasLimit: 10000000, }); await tx.wait(); const proposalId = await (0, common_1.getProposalIdFromTx)(tx, true, { governor }); // remaing vot3 deposited by the voter and the depositor2 await governor.connect(voter).deposit(voterDepositSecondTime, proposalId, { gasLimit: 10000000 }); await governor.connect(owner).deposit(depositor2Deposit, proposalId, { gasLimit: 10000000 }); const voterBalance = await vot3.balanceOf(voter.address); const depositor2Balance = await vot3.balanceOf(owner.address); await (0, common_1.waitForProposalToBeActive)(proposalId, { governor }); await (0, common_1.waitForCurrentRoundToEnd)({ xAllocationVoting }); await (0, common_1.startNewAllocationRound)({ emissions, xAllocationVoting, minterAccount, }); await (0, common_1.waitForNextBlock)(); await (0, common_1.waitForNextBlock)(); const nowSnapshot = await xAllocationVoting.roundSnapshot(await xAllocationVoting.currentRoundId()); const vpVoter = await xAllocationVoting.getVotes(voter.address, nowSnapshot); const depositVPVoter = await xAllocationVoting.getDepositVotingPower(voter.address, nowSnapshot); // getVotes includes deposits for allocation voting const voterTotalDeposits = voterDepositSecondTime + depositThresholdReduced; (0, chai_1.expect)(vpVoter).to.equal(voterBalance + voterTotalDeposits); (0, chai_1.expect)(depositVPVoter).to.equal(voterTotalDeposits); const vpDepositor2 = await xAllocationVoting.getVotes(owner.address, nowSnapshot); const depositVPDepositor2 = await xAllocationVoting.getDepositVotingPower(owner.address, nowSnapshot); (0, chai_1.expect)(vpDepositor2).to.equal(depositor2Balance + depositor2Deposit); (0, chai_1.expect)(depositVPDepositor2).to.equal(depositor2Deposit); await governor.withdraw(proposalId, voter.address); await governor.withdraw(proposalId, owner.address); const afterWithrawSnapshot = await xAllocationVoting.roundSnapshot(await governor.clock()); const depositVPAfterWithdrawVoter = await xAllocationVoting.getDepositVotingPower(voter.address, afterWithrawSnapshot); const depositVPAfterWithdrawDepositor2 = await xAllocationVoting.getDepositVotingPower(owner.address, afterWithrawSnapshot); (0, chai_1.expect)(depositVPAfterWithdrawVoter).to.equal(0); // after withdraw the voter has no deposit (0, chai_1.expect)(depositVPAfterWithdrawDepositor2).to.equal(0); // after withdraw the depositor2 has no deposit }); }); });