UNPKG

@vechain/vebetterdao-contracts

Version:

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

177 lines (176 loc) 9.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const hardhat_1 = require("hardhat"); const chai_1 = require("chai"); const mocha_1 = require("mocha"); const helpers_1 = require("../helpers"); const helpers_2 = require("../helpers"); const xnodes_1 = require("../helpers/xnodes"); (0, mocha_1.describe)("XAllocationVoting - V10 Double Process Prevention - @shard14c", function () { let navigatorRegistry; let xAllocationVoting; let b3tr; let vot3; let emissions; let veBetterPassport; let x2EarnApps; let relayerRewardsPool; let owner; let minterAccount; let otherAccounts; let creators; let nav1; let citizenA; let autoUser; let relayer1; let relayer2; let app1Id; let app2Id; const STAKE = hardhat_1.ethers.parseEther("50000"); const DELEGATE_AMT = hardhat_1.ethers.parseEther("500"); const fundAndApprove = async (acct, amount) => { await b3tr.connect(owner).transfer(acct.address, amount); await b3tr.connect(acct).approve(await navigatorRegistry.getAddress(), amount); }; const advanceRound = async () => { const cur = await xAllocationVoting.currentRoundId(); await (0, helpers_2.waitForRoundToEnd)(Number(cur)); await emissions.distribute(); return xAllocationVoting.currentRoundId(); }; async function advancePastSkipWindow(roundId) { const skipWindow = await xAllocationVoting.citizenSkipWindowBlocks(); const deadline = await xAllocationVoting.roundDeadline(roundId); const currentBlock = BigInt(await hardhat_1.ethers.provider.getBlockNumber()); const blocksToMine = deadline - currentBlock - skipWindow; if (blocksToMine > 0n) await (0, helpers_1.moveBlocks)(Number(blocksToMine)); } async function setup() { const d = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); if (!d) throw new Error("deploy failed"); navigatorRegistry = d.navigatorRegistry; xAllocationVoting = d.xAllocationVoting; b3tr = d.b3tr; vot3 = d.vot3; emissions = d.emissions; veBetterPassport = d.veBetterPassport; x2EarnApps = d.x2EarnApps; relayerRewardsPool = d.relayerRewardsPool; owner = d.owner; minterAccount = d.minterAccount; otherAccounts = d.otherAccounts; creators = d.creators; nav1 = otherAccounts[8]; citizenA = otherAccounts[10]; autoUser = otherAccounts[13]; relayer1 = otherAccounts[15]; relayer2 = otherAccounts[3]; await b3tr.connect(minterAccount).mint(owner.address, hardhat_1.ethers.parseEther("10000000")); await (0, helpers_1.getVot3Tokens)(owner, "10000000"); // Apps await x2EarnApps.connect(creators[0]).submitApp(creators[0].address, creators[0].address, "App1", "uri"); app1Id = await x2EarnApps.hashAppName("App1"); await (0, xnodes_1.endorseApp)(app1Id, otherAccounts[4]); await x2EarnApps.connect(creators[1]).submitApp(creators[1].address, creators[1].address, "App2", "uri"); app2Id = await x2EarnApps.hashAppName("App2"); await (0, xnodes_1.endorseApp)(app2Id, otherAccounts[5]); // Passport if (!(await veBetterPassport.isCheckEnabled(1))) await veBetterPassport.toggleCheck(1); await veBetterPassport.whitelist(citizenA.address); await veBetterPassport.whitelist(autoUser.address); // VOT3 await (0, helpers_1.getVot3Tokens)(citizenA, "1000"); await (0, helpers_1.getVot3Tokens)(autoUser, "100"); // Register navigator await fundAndApprove(nav1, STAKE); await navigatorRegistry.connect(nav1).register(STAKE, "ipfs://nav1"); // Register relayers await relayerRewardsPool.registerRelayer(relayer1.address); await relayerRewardsPool.registerRelayer(relayer2.address); await relayerRewardsPool.connect(owner).setRelayerFeePercentage(10); await (0, helpers_2.bootstrapAndStartEmissions)(); await (0, helpers_1.waitForNextBlock)(); } (0, mocha_1.describe)("Version check", function () { (0, mocha_1.beforeEach)(setup); (0, mocha_1.it)("should report version 10", async function () { (0, chai_1.expect)(await xAllocationVoting.version()).to.equal("10"); }); }); (0, mocha_1.describe)("castVoteOnBehalfOf double-process prevention", function () { (0, mocha_1.beforeEach)(setup); (0, mocha_1.it)("should revert on retry after successful auto-vote", async function () { // Enable auto-voting for user await xAllocationVoting.connect(autoUser).setUserVotingPreferences([app1Id]); await xAllocationVoting.connect(autoUser).toggleAutoVoting(autoUser.address); // Start a new round const roundId = await advanceRound(); // Relayer1 votes on behalf of autoUser await xAllocationVoting.connect(relayer1).castVoteOnBehalfOf(autoUser.address, roundId); // Relayer2 retries — should revert await (0, chai_1.expect)(xAllocationVoting.connect(relayer2).castVoteOnBehalfOf(autoUser.address, roundId)).to.be.revertedWithCustomError(xAllocationVoting, "VoteAlreadyProcessed"); }); (0, mocha_1.it)("should revert on retry after auto-vote skip", async function () { // Enable auto-voting for user with an app, then remove personhood await xAllocationVoting.connect(autoUser).setUserVotingPreferences([app1Id]); await xAllocationVoting.connect(autoUser).toggleAutoVoting(autoUser.address); // Remove personhood so the vote will be skipped await veBetterPassport.removeFromWhitelist(autoUser.address); // Start a new round const roundId = await advanceRound(); // Relayer1 tries — skipped (not a person) await (0, chai_1.expect)(xAllocationVoting.connect(relayer1).castVoteOnBehalfOf(autoUser.address, roundId)).to.emit(xAllocationVoting, "AutoVoteSkipped"); // Relayer2 retries — should revert await (0, chai_1.expect)(xAllocationVoting.connect(relayer2).castVoteOnBehalfOf(autoUser.address, roundId)).to.be.revertedWithCustomError(xAllocationVoting, "VoteAlreadyProcessed"); }); }); (0, mocha_1.describe)("castNavigatorVote double-process prevention", function () { (0, mocha_1.beforeEach)(setup); (0, mocha_1.it)("should revert on retry after successful navigator vote", async function () { // Delegate citizen to navigator await vot3.connect(citizenA).approve(await navigatorRegistry.getAddress(), DELEGATE_AMT); await navigatorRegistry.connect(citizenA).delegate(nav1.address, DELEGATE_AMT); // Start a new round const roundId = await advanceRound(); // Navigator sets preferences await navigatorRegistry.connect(nav1).setAllocationPreferences(roundId, [app1Id, app2Id], [5000, 5000]); // Relayer1 votes on behalf of citizen await xAllocationVoting.connect(relayer1).castNavigatorVote(citizenA.address, roundId); // Relayer2 retries — should revert await (0, chai_1.expect)(xAllocationVoting.connect(relayer2).castNavigatorVote(citizenA.address, roundId)).to.be.revertedWithCustomError(xAllocationVoting, "VoteAlreadyProcessed"); }); (0, mocha_1.it)("should revert on retry after navigator vote skip (dead navigator)", async function () { // Delegate citizen to navigator await vot3.connect(citizenA).approve(await navigatorRegistry.getAddress(), DELEGATE_AMT); await navigatorRegistry.connect(citizenA).delegate(nav1.address, DELEGATE_AMT); // Start a new round const roundId = await advanceRound(); // Deactivate navigator (governance action) await navigatorRegistry.connect(owner).deactivateNavigator(nav1.address, 0, false); // Relayer1 tries — skip (dead navigator) await (0, chai_1.expect)(xAllocationVoting.connect(relayer1).castNavigatorVote(citizenA.address, roundId)) .to.emit(xAllocationVoting, "NavigatorVoteSkipped") .withArgs(citizenA.address, nav1.address, roundId); // Relayer2 retries — should revert await (0, chai_1.expect)(xAllocationVoting.connect(relayer2).castNavigatorVote(citizenA.address, roundId)).to.be.revertedWithCustomError(xAllocationVoting, "VoteAlreadyProcessed"); }); (0, mocha_1.it)("should revert on retry after navigator vote skip (no preferences past skip window)", async function () { // Delegate citizen to navigator await vot3.connect(citizenA).approve(await navigatorRegistry.getAddress(), DELEGATE_AMT); await navigatorRegistry.connect(citizenA).delegate(nav1.address, DELEGATE_AMT); // Start a new round (navigator does NOT set prefs) const roundId = await advanceRound(); // Advance past skip window await advancePastSkipWindow(roundId); // Relayer1 skips await (0, chai_1.expect)(xAllocationVoting.connect(relayer1).castNavigatorVote(citizenA.address, roundId)) .to.emit(xAllocationVoting, "NavigatorVoteSkipped") .withArgs(citizenA.address, nav1.address, roundId); // Relayer2 retries — should revert await (0, chai_1.expect)(xAllocationVoting.connect(relayer2).castNavigatorVote(citizenA.address, roundId)).to.be.revertedWithCustomError(xAllocationVoting, "VoteAlreadyProcessed"); }); }); });