@vechain/vebetterdao-contracts
Version:
Open-source repository that houses the smart contracts powering the decentralized VeBetterDAO on the VeChain Thor blockchain.
488 lines (487 loc) • 32.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const hardhat_1 = require("hardhat");
const chai_1 = require("chai");
const mocha_1 = require("mocha");
const local_1 = require("@repo/config/contracts/envs/local");
const deploy_1 = require("../helpers/deploy");
const common_1 = require("../helpers/common");
(0, mocha_1.describe)("NavigatorRegistry - @shard19a", function () {
let navigatorRegistry;
let xAllocationVoting;
let b3tr;
let vot3;
let treasury;
let owner;
let otherAccount;
let minterAccount;
let otherAccounts;
const config = (0, local_1.createLocalConfig)();
const STAKE_AMOUNT = hardhat_1.ethers.parseEther("50000");
const METADATA_URI = "ipfs://navigator-metadata";
// Ensure VOT3 supply exists so max stake calculation is non-zero
const ensureVot3Supply = async () => {
const supply = await vot3.totalSupply();
if (supply === 0n) {
// Mint and convert enough B3TR -> VOT3 to create supply
await (0, common_1.getVot3Tokens)(owner, "10000000");
}
};
// Helper: mint B3TR for account and approve NavigatorRegistry
const fundAndApprove = async (account, amount) => {
await b3tr.connect(minterAccount).mint(account.address, amount);
const registryAddress = await navigatorRegistry.getAddress();
await b3tr.connect(account).approve(registryAddress, amount);
};
// Helper: advance blocks past the exit effective deadline
const advancePastExitDeadline = async (navigatorAddr) => {
const filter = navigatorRegistry.filters.ExitAnnounced(navigatorAddr);
const events = await navigatorRegistry.queryFilter(filter);
const effectiveDeadline = events[events.length - 1].args.effectiveDeadline;
const currentBlock = await xAllocationVoting.clock();
if (currentBlock < effectiveDeadline) {
await (0, common_1.moveBlocks)(Number(effectiveDeadline - currentBlock) + 1);
}
};
// Helper: register a navigator with default stake (ensures VOT3 supply first)
const registerNavigator = async (account, amount = STAKE_AMOUNT, uri = METADATA_URI) => {
await ensureVot3Supply();
await fundAndApprove(account, amount);
await navigatorRegistry.connect(account).register(amount, uri);
};
(0, mocha_1.beforeEach)(async function () {
const deployment = await (0, deploy_1.getOrDeployContractInstances)({ forceDeploy: true });
if (!deployment)
throw new Error("Failed to deploy contracts");
navigatorRegistry = deployment.navigatorRegistry;
xAllocationVoting = deployment.xAllocationVoting;
b3tr = deployment.b3tr;
vot3 = deployment.vot3;
treasury = deployment.treasury;
owner = deployment.owner;
otherAccount = deployment.otherAccount;
minterAccount = deployment.minterAccount;
otherAccounts = deployment.otherAccounts;
});
// ======================== 1. Initialization ======================== //
(0, mocha_1.describe)("Initialization", function () {
(0, mocha_1.it)("version() returns '1'", async function () {
(0, chai_1.expect)(await navigatorRegistry.version()).to.equal("1");
});
(0, mocha_1.it)("BASIS_POINTS returns 10000", async function () {
(0, chai_1.expect)(await navigatorRegistry.BASIS_POINTS()).to.equal(10000n);
});
(0, mocha_1.it)("getMinStake returns config value", async function () {
(0, chai_1.expect)(await navigatorRegistry.getMinStake()).to.equal(config.NAVIGATOR_MIN_STAKE);
});
(0, mocha_1.it)("getFeeLockPeriod returns config value", async function () {
(0, chai_1.expect)(await navigatorRegistry.getFeeLockPeriod()).to.equal(config.NAVIGATOR_FEE_LOCK_PERIOD);
});
(0, mocha_1.it)("getFeePercentage returns config value", async function () {
(0, chai_1.expect)(await navigatorRegistry.getFeePercentage()).to.equal(config.NAVIGATOR_FEE_PERCENTAGE);
});
(0, mocha_1.it)("getReportInterval returns config value", async function () {
(0, chai_1.expect)(await navigatorRegistry.getReportInterval()).to.equal(config.NAVIGATOR_REPORT_INTERVAL);
});
(0, mocha_1.it)("getMinorSlashPercentage returns config value", async function () {
(0, chai_1.expect)(await navigatorRegistry.getMinorSlashPercentage()).to.equal(config.NAVIGATOR_MINOR_SLASH_PERCENTAGE);
});
(0, mocha_1.it)("getPreferenceCutoffPeriod returns config value", async function () {
(0, chai_1.expect)(await navigatorRegistry.getPreferenceCutoffPeriod()).to.equal(config.NAVIGATOR_PREFERENCE_CUTOFF_PERIOD);
});
(0, mocha_1.it)("should not allow reinitialization", async function () {
await (0, chai_1.expect)(navigatorRegistry.initialize({
admin: owner.address,
upgrader: owner.address,
governance: owner.address,
b3trToken: await b3tr.getAddress(),
vot3Token: await vot3.getAddress(),
treasury: await treasury.getAddress(),
minStake: STAKE_AMOUNT,
maxStakePercentage: 100,
feeLockPeriod: 4,
feePercentage: 2000,
exitNoticePeriod: 1,
reportInterval: 2,
minorSlashPercentage: 1000,
preferenceCutoffPeriod: 8640,
voterRewards: owner.address,
xAllocationVoting: owner.address,
relayerRewardsPool: owner.address,
})).to.be.reverted;
});
});
// ======================== 2. Registration & Staking ======================== //
(0, mocha_1.describe)("Registration & Staking", function () {
(0, mocha_1.describe)("register()", function () {
(0, mocha_1.it)("should register a navigator with correct stake, metadata, and emit event", async function () {
const navigator = otherAccounts[10];
await ensureVot3Supply();
await fundAndApprove(navigator, STAKE_AMOUNT);
const tx = await navigatorRegistry.connect(navigator).register(STAKE_AMOUNT, METADATA_URI);
(0, chai_1.expect)(await navigatorRegistry.isNavigator(navigator.address)).to.be.true;
(0, chai_1.expect)(await navigatorRegistry.getStake(navigator.address)).to.equal(STAKE_AMOUNT);
(0, chai_1.expect)(await navigatorRegistry.getMetadataURI(navigator.address)).to.equal(METADATA_URI);
await (0, chai_1.expect)(tx)
.to.emit(navigatorRegistry, "NavigatorRegistered")
.withArgs(navigator.address, STAKE_AMOUNT, METADATA_URI);
});
(0, mocha_1.it)("should revert with StakeBelowMinimum when stake is below minimum", async function () {
const navigator = otherAccounts[10];
const lowStake = hardhat_1.ethers.parseEther("100");
await fundAndApprove(navigator, lowStake);
await (0, chai_1.expect)(navigatorRegistry.connect(navigator).register(lowStake, METADATA_URI)).to.be.revertedWithCustomError(navigatorRegistry, "StakeBelowMinimum");
});
(0, mocha_1.it)("should revert with AlreadyRegistered when registering twice", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
// Fund again and try to register a second time
await fundAndApprove(navigator, STAKE_AMOUNT);
await (0, chai_1.expect)(navigatorRegistry.connect(navigator).register(STAKE_AMOUNT, METADATA_URI)).to.be.revertedWithCustomError(navigatorRegistry, "AlreadyRegistered");
});
(0, mocha_1.it)("should revert with DelegatorCannotRegister when caller is currently delegating", async function () {
const existingNavigator = otherAccounts[10];
const delegator = otherAccounts[11];
await registerNavigator(existingNavigator);
// delegator gets VOT3 and delegates to the existing navigator
await (0, common_1.getVot3Tokens)(delegator, "1000");
await navigatorRegistry.connect(delegator).delegate(existingNavigator.address, hardhat_1.ethers.parseEther("500"));
// delegator tries to register as a navigator while still delegating
await fundAndApprove(delegator, STAKE_AMOUNT);
await (0, chai_1.expect)(navigatorRegistry.connect(delegator).register(STAKE_AMOUNT, METADATA_URI)).to.be.revertedWithCustomError(navigatorRegistry, "DelegatorCannotRegister");
});
(0, mocha_1.it)("should allow registration after delegator undelegates", async function () {
const existingNavigator = otherAccounts[10];
const delegator = otherAccounts[11];
await registerNavigator(existingNavigator);
// delegator delegates then undelegates
await (0, common_1.getVot3Tokens)(delegator, "1000");
await navigatorRegistry.connect(delegator).delegate(existingNavigator.address, hardhat_1.ethers.parseEther("500"));
await navigatorRegistry.connect(delegator).undelegate();
// Now registration should succeed
await fundAndApprove(delegator, STAKE_AMOUNT);
await navigatorRegistry.connect(delegator).register(STAKE_AMOUNT, METADATA_URI);
(0, chai_1.expect)(await navigatorRegistry.isNavigator(delegator.address)).to.be.true;
});
(0, mocha_1.it)("should allow registration when previous navigator was deactivated (stale delegation)", async function () {
const existingNavigator = otherAccounts[10];
const delegator = otherAccounts[11];
await registerNavigator(existingNavigator);
// delegator delegates
await (0, common_1.getVot3Tokens)(delegator, "1000");
await navigatorRegistry.connect(delegator).delegate(existingNavigator.address, hardhat_1.ethers.parseEther("500"));
// Governance deactivates the navigator — delegation becomes stale
await navigatorRegistry.connect(owner).deactivateNavigator(existingNavigator.address, 0, false);
// Delegator should be able to register since their navigator is dead
await fundAndApprove(delegator, STAKE_AMOUNT);
await navigatorRegistry.connect(delegator).register(STAKE_AMOUNT, METADATA_URI);
(0, chai_1.expect)(await navigatorRegistry.isNavigator(delegator.address)).to.be.true;
});
});
(0, mocha_1.describe)("addStake()", function () {
(0, mocha_1.it)("should increase stake and emit event", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
const additionalStake = hardhat_1.ethers.parseEther("10000");
await fundAndApprove(navigator, additionalStake);
const tx = await navigatorRegistry.connect(navigator).addStake(additionalStake);
const expectedTotal = STAKE_AMOUNT + additionalStake;
(0, chai_1.expect)(await navigatorRegistry.getStake(navigator.address)).to.equal(expectedTotal);
await (0, chai_1.expect)(tx)
.to.emit(navigatorRegistry, "StakeAdded")
.withArgs(navigator.address, additionalStake, expectedTotal);
});
(0, mocha_1.it)("should revert when caller is not a navigator", async function () {
const nonNavigator = otherAccounts[11];
const amount = hardhat_1.ethers.parseEther("10000");
await fundAndApprove(nonNavigator, amount);
await (0, chai_1.expect)(navigatorRegistry.connect(nonNavigator).addStake(amount)).to.be.revertedWithCustomError(navigatorRegistry, "NotRegistered");
});
});
(0, mocha_1.describe)("withdrawStake()", function () {
(0, mocha_1.it)("should allow withdrawal after exit notice period elapses", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
await (0, common_1.bootstrapAndStartEmissions)();
await navigatorRegistry.connect(navigator).announceExit();
await advancePastExitDeadline(navigator.address);
const tx = await navigatorRegistry.connect(navigator).withdrawStake(STAKE_AMOUNT);
(0, chai_1.expect)(await navigatorRegistry.getStake(navigator.address)).to.equal(0n);
await (0, chai_1.expect)(tx).to.emit(navigatorRegistry, "StakeWithdrawn").withArgs(navigator.address, STAKE_AMOUNT, 0n);
});
(0, mocha_1.it)("should revert with NavigatorStillActive when navigator has not announced exit", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
await (0, chai_1.expect)(navigatorRegistry.connect(navigator).withdrawStake(STAKE_AMOUNT)).to.be.revertedWithCustomError(navigatorRegistry, "NavigatorStillActive");
});
(0, mocha_1.it)("should revert with InsufficientStake when withdrawing more than staked", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
await (0, common_1.bootstrapAndStartEmissions)();
await navigatorRegistry.connect(navigator).announceExit();
await advancePastExitDeadline(navigator.address);
const tooMuch = STAKE_AMOUNT + hardhat_1.ethers.parseEther("1");
await (0, chai_1.expect)(navigatorRegistry.connect(navigator).withdrawStake(tooMuch)).to.be.revertedWithCustomError(navigatorRegistry, "InsufficientStake");
});
});
(0, mocha_1.describe)("reduceStake()", function () {
(0, mocha_1.it)("should allow active navigator to reduce stake and emit StakeWithdrawn", async function () {
const navigator = otherAccounts[10];
const extraStake = hardhat_1.ethers.parseEther("100000");
await registerNavigator(navigator, extraStake);
const reduceAmount = hardhat_1.ethers.parseEther("10000");
const remaining = extraStake - reduceAmount;
const tx = await navigatorRegistry.connect(navigator).reduceStake(reduceAmount);
(0, chai_1.expect)(await navigatorRegistry.getStake(navigator.address)).to.equal(remaining);
await (0, chai_1.expect)(tx)
.to.emit(navigatorRegistry, "StakeWithdrawn")
.withArgs(navigator.address, reduceAmount, remaining);
});
(0, mocha_1.it)("should revert with StakeBelowMinimum when reducing below min stake", async function () {
const navigator = otherAccounts[10];
const minStake = await navigatorRegistry.getMinStake();
// Register with exactly min stake
await registerNavigator(navigator, minStake);
// Reducing by any amount should revert since we're at the minimum
await (0, chai_1.expect)(navigatorRegistry.connect(navigator).reduceStake(1n)).to.be.revertedWithCustomError(navigatorRegistry, "StakeBelowMinimum");
});
(0, mocha_1.it)("should revert when reducing would break delegation capacity", async function () {
const navigator = otherAccounts[10];
// Register with extra stake so we can reduce
const extraStake = hardhat_1.ethers.parseEther("100000");
await registerNavigator(navigator, extraStake);
// Delegate close to capacity: 100K stake * 10 = 1M capacity, delegate 600K
const citizen = otherAccounts[11];
await (0, common_1.getVot3Tokens)(citizen, "600000");
await navigatorRegistry.connect(citizen).delegate(navigator.address, hardhat_1.ethers.parseEther("600000"));
// Reducing 50K would leave 50K stake, capacity = 500K < 600K delegated
await (0, chai_1.expect)(navigatorRegistry.connect(navigator).reduceStake(hardhat_1.ethers.parseEther("50000"))).to.be.revertedWithCustomError(navigatorRegistry, "StakeBelowMinimum");
});
(0, mocha_1.it)("should revert with InsufficientStake when reducing more than staked", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
const tooMuch = STAKE_AMOUNT + hardhat_1.ethers.parseEther("1");
await (0, chai_1.expect)(navigatorRegistry.connect(navigator).reduceStake(tooMuch)).to.be.revertedWithCustomError(navigatorRegistry, "InsufficientStake");
});
(0, mocha_1.it)("should revert when caller is not a navigator", async function () {
const nonNavigator = otherAccounts[11];
await (0, chai_1.expect)(navigatorRegistry.connect(nonNavigator).reduceStake(hardhat_1.ethers.parseEther("1000"))).to.be.revertedWithCustomError(navigatorRegistry, "NotRegistered");
});
});
(0, mocha_1.describe)("Delegation Capacity", function () {
(0, mocha_1.it)("getDelegationCapacity should be stake * 10", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
const capacity = await navigatorRegistry.getDelegationCapacity(navigator.address);
(0, chai_1.expect)(capacity).to.equal(STAKE_AMOUNT * 10n);
});
(0, mocha_1.it)("getRemainingCapacity should decrease after delegation", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
const citizen = otherAccounts[12];
const delegateAmount = hardhat_1.ethers.parseEther("100000"); // 100k VOT3
// Give citizen VOT3 tokens
await (0, common_1.getVot3Tokens)(citizen, "100000");
// Delegate
await navigatorRegistry.connect(citizen).delegate(navigator.address, delegateAmount);
const remaining = await navigatorRegistry.getRemainingCapacity(navigator.address);
const expectedRemaining = STAKE_AMOUNT * 10n - delegateAmount;
(0, chai_1.expect)(remaining).to.equal(expectedRemaining);
});
});
});
// ======================== 3. Governance Setters ======================== //
(0, mocha_1.describe)("Governance Setters", function () {
// ---- Numeric setters with GOVERNANCE_ROLE ---- //
(0, mocha_1.describe)("setMinStake", function () {
(0, mocha_1.it)("should update minStake", async function () {
const newValue = hardhat_1.ethers.parseEther("100000");
await navigatorRegistry.connect(owner).setMinStake(newValue);
(0, chai_1.expect)(await navigatorRegistry.getMinStake()).to.equal(newValue);
});
(0, mocha_1.it)("should revert with InvalidParameter when value is 0", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setMinStake(0)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert when caller lacks GOVERNANCE_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setMinStake(1)).to.be.reverted;
});
});
(0, mocha_1.describe)("setMaxStakePercentage", function () {
(0, mocha_1.it)("should update maxStakePercentage", async function () {
// Create some VOT3 supply so getMaxStake returns non-zero
await (0, common_1.getVot3Tokens)(owner, "1000000");
await navigatorRegistry.connect(owner).setMaxStakePercentage(500);
const maxStake = await navigatorRegistry.getMaxStake();
(0, chai_1.expect)(maxStake).to.be.gt(0n);
});
(0, mocha_1.it)("should revert with InvalidParameter when value is 0", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setMaxStakePercentage(0)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert with InvalidParameter when value exceeds BASIS_POINTS", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setMaxStakePercentage(10001)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert when caller lacks GOVERNANCE_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setMaxStakePercentage(500)).to.be.reverted;
});
});
(0, mocha_1.describe)("setFeeLockPeriod", function () {
(0, mocha_1.it)("should update feeLockPeriod", async function () {
await navigatorRegistry.connect(owner).setFeeLockPeriod(8);
(0, chai_1.expect)(await navigatorRegistry.getFeeLockPeriod()).to.equal(8);
});
(0, mocha_1.it)("should revert with InvalidParameter when value is 0", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setFeeLockPeriod(0)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert when caller lacks GOVERNANCE_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setFeeLockPeriod(8)).to.be.reverted;
});
});
(0, mocha_1.describe)("setFeePercentage", function () {
(0, mocha_1.it)("should update feePercentage", async function () {
await navigatorRegistry.connect(owner).setFeePercentage(3000);
(0, chai_1.expect)(await navigatorRegistry.getFeePercentage()).to.equal(3000);
});
(0, mocha_1.it)("should revert with InvalidParameter when value exceeds BASIS_POINTS", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setFeePercentage(10001)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert when caller lacks GOVERNANCE_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setFeePercentage(3000)).to.be.reverted;
});
});
(0, mocha_1.describe)("setReportInterval", function () {
(0, mocha_1.it)("should update reportInterval", async function () {
await navigatorRegistry.connect(owner).setReportInterval(5);
(0, chai_1.expect)(await navigatorRegistry.getReportInterval()).to.equal(5);
});
(0, mocha_1.it)("should revert with InvalidParameter when value is 0", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setReportInterval(0)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert when caller lacks GOVERNANCE_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setReportInterval(5)).to.be.reverted;
});
});
(0, mocha_1.describe)("setMinorSlashPercentage", function () {
(0, mocha_1.it)("should update minorSlashPercentage", async function () {
await navigatorRegistry.connect(owner).setMinorSlashPercentage(2000);
(0, chai_1.expect)(await navigatorRegistry.getMinorSlashPercentage()).to.equal(2000);
});
(0, mocha_1.it)("should revert with InvalidParameter when value is 0", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setMinorSlashPercentage(0)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert with InvalidParameter when value exceeds BASIS_POINTS", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setMinorSlashPercentage(10001)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert when caller lacks GOVERNANCE_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setMinorSlashPercentage(2000)).to.be.reverted;
});
});
(0, mocha_1.describe)("setPreferenceCutoffPeriod", function () {
(0, mocha_1.it)("should update preferenceCutoffPeriod", async function () {
await navigatorRegistry.connect(owner).setPreferenceCutoffPeriod(4320);
(0, chai_1.expect)(await navigatorRegistry.getPreferenceCutoffPeriod()).to.equal(4320);
});
(0, mocha_1.it)("should revert with InvalidParameter when value is 0", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setPreferenceCutoffPeriod(0)).to.be.revertedWithCustomError(navigatorRegistry, "InvalidParameter");
});
(0, mocha_1.it)("should revert when caller lacks GOVERNANCE_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setPreferenceCutoffPeriod(4320)).to.be.reverted;
});
});
// ---- Address setters with DEFAULT_ADMIN_ROLE ---- //
(0, mocha_1.describe)("setXAllocationVoting", function () {
(0, mocha_1.it)("should update xAllocationVoting address", async function () {
const newAddress = otherAccounts[13].address;
await navigatorRegistry.connect(owner).setXAllocationVoting(newAddress);
});
(0, mocha_1.it)("should revert with ZeroAddress when address is zero", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setXAllocationVoting(hardhat_1.ethers.ZeroAddress)).to.be.revertedWithCustomError(navigatorRegistry, "ZeroAddress");
});
(0, mocha_1.it)("should revert when caller lacks DEFAULT_ADMIN_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setXAllocationVoting(otherAccounts[13].address)).to.be
.reverted;
});
});
(0, mocha_1.describe)("setRelayerRewardsPool", function () {
(0, mocha_1.it)("should update relayerRewardsPool address", async function () {
const newAddress = otherAccounts[14].address;
await navigatorRegistry.connect(owner).setRelayerRewardsPool(newAddress);
});
(0, mocha_1.it)("should revert with ZeroAddress when address is zero", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setRelayerRewardsPool(hardhat_1.ethers.ZeroAddress)).to.be.revertedWithCustomError(navigatorRegistry, "ZeroAddress");
});
(0, mocha_1.it)("should revert when caller lacks DEFAULT_ADMIN_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setRelayerRewardsPool(otherAccounts[14].address)).to.be
.reverted;
});
});
(0, mocha_1.describe)("setVoterRewards", function () {
(0, mocha_1.it)("should update voterRewards address", async function () {
const newAddress = otherAccounts[15].address;
await navigatorRegistry.connect(owner).setVoterRewards(newAddress);
});
(0, mocha_1.it)("should revert with ZeroAddress when address is zero", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(owner).setVoterRewards(hardhat_1.ethers.ZeroAddress)).to.be.revertedWithCustomError(navigatorRegistry, "ZeroAddress");
});
(0, mocha_1.it)("should revert when caller lacks DEFAULT_ADMIN_ROLE", async function () {
await (0, chai_1.expect)(navigatorRegistry.connect(otherAccount).setVoterRewards(otherAccounts[15].address)).to.be.reverted;
});
});
});
(0, mocha_1.describe)("getStatus()", function () {
(0, mocha_1.it)("should return NONE (0) for unregistered address", async function () {
const status = await navigatorRegistry.getStatus(otherAccounts[10].address);
(0, chai_1.expect)(status).to.equal(0n);
});
(0, mocha_1.it)("should return ACTIVE (1) after registration", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
const status = await navigatorRegistry.getStatus(navigator.address);
(0, chai_1.expect)(status).to.equal(1n);
});
(0, mocha_1.it)("should return EXITING (2) after announceExit while notice period is active", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
await (0, common_1.bootstrapAndStartEmissions)();
await navigatorRegistry.connect(navigator).announceExit();
const status = await navigatorRegistry.getStatus(navigator.address);
(0, chai_1.expect)(status).to.equal(2n);
});
(0, mocha_1.it)("should return DEACTIVATED (3) after notice period elapses", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
await (0, common_1.bootstrapAndStartEmissions)();
await navigatorRegistry.connect(navigator).announceExit();
(0, chai_1.expect)(await navigatorRegistry.getStatus(navigator.address)).to.equal(2n);
await advancePastExitDeadline(navigator.address);
const status = await navigatorRegistry.getStatus(navigator.address);
(0, chai_1.expect)(status).to.equal(3n);
});
(0, mocha_1.it)("should return DEACTIVATED (3) after governance deactivation", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
await navigatorRegistry.connect(owner).deactivateNavigator(navigator.address, 0, false);
const status = await navigatorRegistry.getStatus(navigator.address);
(0, chai_1.expect)(status).to.equal(3n);
});
(0, mocha_1.it)("should return DEACTIVATED (3) for governance-deactivated even if exit was also announced", async function () {
const navigator = otherAccounts[10];
await registerNavigator(navigator);
await (0, common_1.bootstrapAndStartEmissions)();
await navigatorRegistry.connect(navigator).announceExit();
(0, chai_1.expect)(await navigatorRegistry.getStatus(navigator.address)).to.equal(2n);
// Governance deactivates while exiting
await navigatorRegistry.connect(owner).deactivateNavigator(navigator.address, 0, false);
const status = await navigatorRegistry.getStatus(navigator.address);
(0, chai_1.expect)(status).to.equal(3n);
});
(0, mocha_1.it)("should still return ACTIVE (1) for an active navigator after another is deactivated", async function () {
const nav1 = otherAccounts[10];
const nav2 = otherAccounts[11];
await registerNavigator(nav1);
await registerNavigator(nav2);
await navigatorRegistry.connect(owner).deactivateNavigator(nav1.address, 0, false);
(0, chai_1.expect)(await navigatorRegistry.getStatus(nav1.address)).to.equal(3n);
(0, chai_1.expect)(await navigatorRegistry.getStatus(nav2.address)).to.equal(1n);
});
});
});