UNPKG

@vechain/vebetterdao-contracts

Version:

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

160 lines (159 loc) 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const local_1 = require("@repo/config/contracts/envs/local"); const chai_1 = require("chai"); const hardhat_1 = require("hardhat"); const mocha_1 = require("mocha"); const helpers_1 = require("../helpers"); const common_1 = require("../helpers/common"); (0, mocha_1.describe)("VOT3 - V2 Upgrade - @shard19a", function () { (0, mocha_1.it)("Should deploy through full upgrade chain and report version 2", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3 } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); (0, chai_1.expect)(await vot3.version()).to.equal("2"); (0, chai_1.expect)(await vot3.getAddress()).to.not.equal(hardhat_1.ethers.ZeroAddress); }); (0, mocha_1.it)("Should have NavigatorRegistry set after initializeV2", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, navigatorRegistry } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); const lockedAmount = await vot3.getNavigatorLockedAmount(hardhat_1.ethers.ZeroAddress); (0, chai_1.expect)(lockedAmount).to.equal(0n); // NavigatorRegistry should be wired (0, chai_1.expect)(await navigatorRegistry.getAddress()).to.not.equal(hardhat_1.ethers.ZeroAddress); }); (0, mocha_1.it)("Should preserve B3TR reference after upgrade", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, b3tr } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); (0, chai_1.expect)(await vot3.b3tr()).to.equal(await b3tr.getAddress()); }); (0, mocha_1.it)("Should preserve roles after upgrade", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); (0, chai_1.expect)(await vot3.hasRole(await vot3.DEFAULT_ADMIN_ROLE(), owner.address)).to.be.true; (0, chai_1.expect)(await vot3.hasRole(await vot3.UPGRADER_ROLE(), owner.address)).to.be.true; (0, chai_1.expect)(await vot3.hasRole(await vot3.PAUSER_ROLE(), owner.address)).to.be.true; }); (0, mocha_1.it)("Should still allow convertToVOT3 and convertToB3TR after upgrade", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, b3tr, owner, otherAccount, minterAccount } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config, }); // Mint B3TR to owner so we can transfer const amount = hardhat_1.ethers.parseEther("100"); await b3tr.connect(minterAccount).mint(owner.address, amount); await b3tr.connect(owner).transfer(otherAccount.address, amount); // Approve and convert to VOT3 await b3tr.connect(otherAccount).approve(await vot3.getAddress(), amount); await vot3.connect(otherAccount).convertToVOT3(amount); (0, chai_1.expect)(await vot3.balanceOf(otherAccount.address)).to.equal(amount); // Convert back to B3TR await vot3.connect(otherAccount).convertToB3TR(amount); (0, chai_1.expect)(await vot3.balanceOf(otherAccount.address)).to.equal(0n); (0, chai_1.expect)(await b3tr.balanceOf(otherAccount.address)).to.equal(amount); }); (0, mocha_1.it)("Should enforce delegation lock after upgrade — transfer blocked for locked portion", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, b3tr, navigatorRegistry, owner, otherAccounts, minterAccount } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config, }); const navigator = otherAccounts[10]; const citizen = otherAccounts[11]; const recipient = otherAccounts[12]; // Mint B3TR to owner for distribution await b3tr.connect(minterAccount).mint(owner.address, hardhat_1.ethers.parseEther("10000000")); // Ensure VOT3 supply exists for max stake check await (0, common_1.getVot3Tokens)(owner, "10000000"); // Register navigator const stakeAmount = hardhat_1.ethers.parseEther("50000"); await b3tr.connect(owner).transfer(navigator.address, stakeAmount); await b3tr.connect(navigator).approve(await navigatorRegistry.getAddress(), stakeAmount); await navigatorRegistry.connect(navigator).register(stakeAmount, "ipfs://nav"); // Give citizen 1000 VOT3 await (0, common_1.getVot3Tokens)(citizen, "1000"); // Delegate 500 VOT3 const delegateAmount = hardhat_1.ethers.parseEther("500"); await navigatorRegistry.connect(citizen).delegate(navigator.address, delegateAmount); // Locked = 500, free = 500 (0, chai_1.expect)(await vot3.getNavigatorLockedAmount(citizen.address)).to.equal(delegateAmount); // Transfer 500 (free portion) should succeed await vot3.connect(citizen).transfer(recipient.address, hardhat_1.ethers.parseEther("500")); // Transfer 1 more wei should fail (would go below locked amount) await (0, chai_1.expect)(vot3.connect(citizen).transfer(recipient.address, 1n)).to.be.revertedWith("VOT3: transfer exceeds unlocked balance"); // Undelegate: lock released await navigatorRegistry.connect(citizen).undelegate(); (0, chai_1.expect)(await vot3.getNavigatorLockedAmount(citizen.address)).to.equal(0n); }); (0, mocha_1.it)("Should not allow re-initialization of V2", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3 } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); await (0, chai_1.expect)(vot3.initializeV2(hardhat_1.ethers.ZeroAddress)).to.be.reverted; }); (0, mocha_1.describe)("unlockedBalance", function () { (0, mocha_1.it)("Should return full balance when no delegation exists", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, otherAccounts } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); const citizen = otherAccounts[11]; const amount = hardhat_1.ethers.parseEther("1000"); await (0, common_1.getVot3Tokens)(citizen, "1000"); (0, chai_1.expect)(await vot3.unlockedBalance(citizen.address)).to.equal(amount); (0, chai_1.expect)(await vot3.unlockedBalance(citizen.address)).to.equal(await vot3.balanceOf(citizen.address)); }); (0, mocha_1.it)("Should return balance minus delegated amount", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, b3tr, navigatorRegistry, owner, otherAccounts, minterAccount } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); const navigator = otherAccounts[10]; const citizen = otherAccounts[11]; await b3tr.connect(minterAccount).mint(owner.address, hardhat_1.ethers.parseEther("10000000")); await (0, common_1.getVot3Tokens)(owner, "10000000"); const stakeAmount = hardhat_1.ethers.parseEther("50000"); await b3tr.connect(owner).transfer(navigator.address, stakeAmount); await b3tr.connect(navigator).approve(await navigatorRegistry.getAddress(), stakeAmount); await navigatorRegistry.connect(navigator).register(stakeAmount, "ipfs://nav"); await (0, common_1.getVot3Tokens)(citizen, "1000"); const delegateAmount = hardhat_1.ethers.parseEther("400"); await navigatorRegistry.connect(citizen).delegate(navigator.address, delegateAmount); const expected = hardhat_1.ethers.parseEther("1000") - delegateAmount; (0, chai_1.expect)(await vot3.unlockedBalance(citizen.address)).to.equal(expected); }); (0, mocha_1.it)("Should return zero when entire balance is delegated", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, b3tr, navigatorRegistry, owner, otherAccounts, minterAccount } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); const navigator = otherAccounts[10]; const citizen = otherAccounts[11]; await b3tr.connect(minterAccount).mint(owner.address, hardhat_1.ethers.parseEther("10000000")); await (0, common_1.getVot3Tokens)(owner, "10000000"); const stakeAmount = hardhat_1.ethers.parseEther("50000"); await b3tr.connect(owner).transfer(navigator.address, stakeAmount); await b3tr.connect(navigator).approve(await navigatorRegistry.getAddress(), stakeAmount); await navigatorRegistry.connect(navigator).register(stakeAmount, "ipfs://nav"); await (0, common_1.getVot3Tokens)(citizen, "1000"); await navigatorRegistry.connect(citizen).delegate(navigator.address, hardhat_1.ethers.parseEther("1000")); (0, chai_1.expect)(await vot3.unlockedBalance(citizen.address)).to.equal(0n); }); (0, mocha_1.it)("Should restore full balance after undelegation", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, b3tr, navigatorRegistry, owner, otherAccounts, minterAccount } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); const navigator = otherAccounts[10]; const citizen = otherAccounts[11]; await b3tr.connect(minterAccount).mint(owner.address, hardhat_1.ethers.parseEther("10000000")); await (0, common_1.getVot3Tokens)(owner, "10000000"); const stakeAmount = hardhat_1.ethers.parseEther("50000"); await b3tr.connect(owner).transfer(navigator.address, stakeAmount); await b3tr.connect(navigator).approve(await navigatorRegistry.getAddress(), stakeAmount); await navigatorRegistry.connect(navigator).register(stakeAmount, "ipfs://nav"); const citizenBalance = hardhat_1.ethers.parseEther("1000"); await (0, common_1.getVot3Tokens)(citizen, "1000"); await navigatorRegistry.connect(citizen).delegate(navigator.address, hardhat_1.ethers.parseEther("500")); (0, chai_1.expect)(await vot3.unlockedBalance(citizen.address)).to.equal(hardhat_1.ethers.parseEther("500")); await navigatorRegistry.connect(citizen).undelegate(); (0, chai_1.expect)(await vot3.unlockedBalance(citizen.address)).to.equal(citizenBalance); }); (0, mocha_1.it)("Should return zero for account with no tokens", async () => { const config = (0, local_1.createLocalConfig)(); const { vot3, otherAccounts } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config }); (0, chai_1.expect)(await vot3.unlockedBalance(otherAccounts[15].address)).to.equal(0n); }); }); });