@vechain/vebetterdao-contracts
Version:
Open-source repository that houses the smart contracts powering the decentralized VeBetterDAO on the VeChain Thor blockchain.
206 lines (205 loc) • 8.59 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.GRANT_PROPOSAL_TYPE = exports.STANDARD_PROPOSAL_TYPE = void 0;
exports.setupGovernanceFixture = setupGovernanceFixture;
exports.setupProposer = setupProposer;
exports.setupVoter = setupVoter;
exports.setupSupporter = setupSupporter;
exports.startNewRoundAndGetRoundId = startNewRoundAndGetRoundId;
exports.validateProposalEvents = validateProposalEvents;
exports.setupGovernanceFixtureWithEmissions = setupGovernanceFixtureWithEmissions;
const helpers_1 = require("../helpers");
const hardhat_1 = require("hardhat");
const chai_1 = require("chai");
const common_1 = require("../helpers/common");
//Constants for proposal types
exports.STANDARD_PROPOSAL_TYPE = hardhat_1.ethers.toBigInt(0);
exports.GRANT_PROPOSAL_TYPE = hardhat_1.ethers.toBigInt(1);
async function setupGovernanceFixture() {
const deployInstances = await (0, helpers_1.getOrDeployContractInstances)({
forceDeploy: true,
});
//Setup deploy instances
const governor = deployInstances?.governor;
const vot3 = deployInstances?.vot3;
const b3tr = deployInstances?.b3tr;
const treasury = deployInstances?.treasury;
const owner = deployInstances?.owner;
const timeLock = deployInstances?.timeLock;
const xAllocationVoting = deployInstances?.xAllocationVoting;
const voterRewards = deployInstances?.voterRewards;
const emissions = deployInstances?.emissions;
const governorClockLogicLibV1 = deployInstances?.governorClockLogicLibV1;
const governorConfiguratorLibV1 = deployInstances?.governorConfiguratorLibV1;
const governorDepositLogicLibV1 = deployInstances?.governorDepositLogicLibV1;
const governorFunctionRestrictionsLogicLibV1 = deployInstances?.governorFunctionRestrictionsLogicLibV1;
const governorProposalLogicLibV1 = deployInstances?.governorProposalLogicLibV1;
const governorQuorumLogicLibV1 = deployInstances?.governorQuorumLogicLibV1;
const governorStateLogicLibV1 = deployInstances?.governorStateLogicLibV1;
const governorVotesLogicLibV1 = deployInstances?.governorVotesLogicLibV1;
const b3trContract = deployInstances?.B3trContract;
const veBetterPassport = deployInstances?.veBetterPassport;
const minterAccount = deployInstances?.minterAccount;
const grantsManager = deployInstances?.grantsManager;
const x2EarnApps = deployInstances?.x2EarnApps;
const creators = deployInstances?.creators;
const galaxyMember = deployInstances?.galaxyMember;
//Setup other accounts
const otherAccounts = deployInstances?.otherAccounts;
const otherAccount = deployInstances?.otherAccount;
if (!otherAccounts || otherAccounts.length < 2) {
throw new Error("Other accounts are not correctly set");
}
//Setup proposer and voter
const proposer = otherAccounts[0];
const voter = otherAccounts[1];
if (!governor ||
!vot3 ||
!b3tr ||
!treasury ||
!owner ||
!timeLock ||
!xAllocationVoting ||
!voterRewards ||
!emissions ||
!governorClockLogicLibV1 ||
!governorConfiguratorLibV1 ||
!governorDepositLogicLibV1 ||
!governorFunctionRestrictionsLogicLibV1 ||
!governorProposalLogicLibV1 ||
!governorQuorumLogicLibV1 ||
!governorStateLogicLibV1 ||
!governorVotesLogicLibV1 ||
!b3trContract ||
!veBetterPassport ||
!minterAccount ||
!otherAccount ||
!grantsManager ||
!x2EarnApps ||
!creators ||
!galaxyMember) {
throw new Error("Deploy instances are not correctly set");
}
return {
governor,
vot3,
b3tr,
treasury,
owner,
timeLock,
xAllocationVoting,
voterRewards,
otherAccounts,
proposer,
voter,
emissions,
governorClockLogicLibV1,
governorConfiguratorLibV1,
governorDepositLogicLibV1,
governorFunctionRestrictionsLogicLibV1,
governorProposalLogicLibV1,
governorQuorumLogicLibV1,
governorStateLogicLibV1,
governorVotesLogicLibV1,
b3trContract,
veBetterPassport,
minterAccount,
otherAccount,
grantsManager,
x2EarnApps,
creators,
galaxyMember,
};
}
// Common test helpers
async function setupProposer(account, b3tr, vot3, minterAccount, amount = "1000") {
await b3tr.connect(minterAccount).mint(account, hardhat_1.ethers.parseEther(amount));
await b3tr.connect(account).approve(await vot3.getAddress(), hardhat_1.ethers.parseEther("9"));
await vot3.connect(account).convertToVOT3(hardhat_1.ethers.parseEther("9"), { gasLimit: 10000000 });
}
async function setupVoter(voter, b3tr, vot3, minterAccount, owner, veBetterPassport) {
await (0, common_1.getVot3Tokens)(voter, "10000", {
b3tr,
vot3,
minterAccount,
});
const isCheckEnabled = await veBetterPassport.isCheckEnabled(1);
if (!isCheckEnabled) {
await veBetterPassport.connect(owner).toggleCheck(1);
}
// whitelist voter
await veBetterPassport.connect(owner).whitelist(voter.address);
(0, chai_1.expect)(await veBetterPassport.isCheckEnabled(1)).to.be.true;
// expect voter to be person
(0, chai_1.expect)(await veBetterPassport.isPerson(voter.address)).to.deep.equal([true, "User is whitelisted"]);
}
async function setupSupporter(supporter, vot3, amount, governor) {
await (0, common_1.getVot3Tokens)(supporter, hardhat_1.ethers.formatEther(amount));
await vot3.connect(supporter).approve(await governor.getAddress(), amount);
}
async function startNewRoundAndGetRoundId(emissions, xAllocationVoting) {
// to ensure that test will work correctly before creating a proposal we wait for current round to end
// and start a new one
if ((await emissions.nextCycle()) === 0n) {
// if emissions are not started yet, we need to bootstrap and start them
await (0, common_1.bootstrapAndStartEmissions)({ emissions, xAllocationVoting });
}
else {
// otherwise we need to wait for the current round to end and start the next one
await (0, common_1.waitForCurrentRoundToEnd)({ emissions, xAllocationVoting });
await emissions.distribute();
}
return ((await xAllocationVoting.currentRoundId()) + 1n).toString();
}
async function validateProposalEvents(governor, receipt, expectedType, proposerAddress, description) {
if (!receipt) {
throw new Error("Receipt is null");
}
// Define required events based on proposal type
const requiredEvents = ["ProposalCreated", "ProposalCreatedWithType"];
// Find all relevant events in one pass
const foundEvents = {};
for (const log of receipt.logs) {
try {
const decoded = governor.interface.parseLog({
topics: [...log.topics],
data: log.data,
});
if (decoded && requiredEvents.includes(decoded.name)) {
foundEvents[decoded.name] = decoded;
}
}
catch {
// Skip logs that can't be decoded
}
}
// Validate all required events are present
for (const eventName of requiredEvents) {
if (!foundEvents[eventName]) {
throw new Error(`Required event ${eventName} not found`);
}
}
// Validate ProposalCreated event details
const proposalCreated = foundEvents["ProposalCreated"];
if (proposalCreated.args[1] !== proposerAddress) {
throw new Error(`Expected proposer ${proposerAddress}, got ${proposalCreated.args[1]}`);
}
if (proposalCreated.args[6] !== description) {
throw new Error(`Expected description ${description}, got ${proposalCreated.args[6]}`);
}
// Validate ProposalCreatedWithType event details
const proposalCreatedWithType = foundEvents["ProposalCreatedWithType"];
if (proposalCreatedWithType.args[1] !== hardhat_1.ethers.toBigInt(expectedType)) {
throw new Error(`Expected type ${expectedType}, got ${proposalCreatedWithType.args[1]}`);
}
return {
proposalId: proposalCreated.args[0],
decodedProposalCreatedEvent: proposalCreated,
decodedProposalCreatedWithTypeEvent: proposalCreatedWithType,
};
}
async function setupGovernanceFixtureWithEmissions() {
const fixture = await setupGovernanceFixture();
await (0, common_1.bootstrapEmissions)({ emissions: fixture.emissions });
return fixture;
}