@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
JavaScript
"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
});
});
});