UNPKG

@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
"use strict"; 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; }