UNPKG

@vechain/vebetterdao-contracts

Version:

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

711 lines 340 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const hardhat_1 = require("hardhat"); const chai_1 = require("chai"); const helpers_1 = require("./helpers"); const mocha_1 = require("mocha"); const upgrades_core_1 = require("@openzeppelin/upgrades-core"); const ethers_1 = require("ethers"); const config_1 = require("./helpers/config"); const helpers_2 = require("../scripts/helpers"); const xnodes_1 = require("./helpers/xnodes"); const local_1 = require("@repo/config/contracts/envs/local"); (0, mocha_1.describe)("VeBetterPassport - @shard8-core", function () { (0, mocha_1.describe)("Contract parameters", function () { (0, mocha_1.it)("Should have contract addresses set correctly", async function () { const { veBetterPassport, xAllocationVoting, x2EarnApps, galaxyMember } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); // Verify contract addresses (0, chai_1.expect)(await veBetterPassport.getXAllocationVoting()).to.equal(await xAllocationVoting.getAddress()); (0, chai_1.expect)(await veBetterPassport.getX2EarnApps()).to.equal(await x2EarnApps.getAddress()); (0, chai_1.expect)(await veBetterPassport.getGalaxyMember()).to.equal(await galaxyMember.getAddress()); }); (0, mocha_1.it)("Should have correct roles set", async function () { const { veBetterPassport, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.DEFAULT_ADMIN_ROLE(), owner.address)).to.be.true; (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.SETTINGS_MANAGER_ROLE(), owner.address)).to.be.true; (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.ROLE_GRANTER(), owner.address)).to.be.true; (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.SIGNALER_ROLE(), owner.address)).to.be.true; (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.WHITELISTER_ROLE(), owner.address)).to.be.true; (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.ACTION_REGISTRAR_ROLE(), owner.address)).to.be.true; (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.ACTION_SCORE_MANAGER_ROLE(), owner.address)).to.be .true; }); (0, mocha_1.it)("Should have action score thresholds set correctly", async function () { const config = (0, config_1.createTestConfig)(); const { veBetterPassport } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config: { ...config, VEPASSPORT_BOT_SIGNALING_THRESHOLD: 5, VEPASSPORT_WHITELIST_THRESHOLD_PERCENTAGE: 20, VEPASSPORT_BLACKLIST_THRESHOLD_PERCENTAGE: 10, }, }); (0, chai_1.expect)(await veBetterPassport.thresholdPoPScore()).to.equal(0); (0, chai_1.expect)(await veBetterPassport.signalingThreshold()).to.equal(5); (0, chai_1.expect)(await veBetterPassport.whitelistThreshold()).to.equal(20); (0, chai_1.expect)(await veBetterPassport.blacklistThreshold()).to.equal(10); }); (0, mocha_1.it)("Should have rounds for cumulative score set correctly", async function () { const config = (0, config_1.createTestConfig)(); const { veBetterPassport } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config: { ...config, VEPASSPORT_ROUNDS_FOR_CUMULATIVE_PARTICIPATION_SCORE: 5, }, }); (0, chai_1.expect)(await veBetterPassport.roundsForCumulativeScore()).to.equal(5); }); (0, mocha_1.it)("Should have minimum galaxy member level set correctly", async function () { const config = (0, config_1.createTestConfig)(); const { veBetterPassport } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config: { ...config, VEPASSPORT_GALAXY_MEMBER_MINIMUM_LEVEL: 5, }, }); (0, chai_1.expect)(await veBetterPassport.getMinimumGalaxyMemberLevel()).to.equal(5); }); (0, mocha_1.it)("Should return correct eip712 domain separator", async function () { const { veBetterPassport } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); const domainSeparator = await veBetterPassport.eip712Domain(); (0, chai_1.expect)(domainSeparator).to.deep.equal([ "0x0f", "VeBetterPassport", "1", 1337n, await veBetterPassport.getAddress(), "0x0000000000000000000000000000000000000000000000000000000000000000", [], ]); }); }); }); // Upgrades section split to separate shard (0, mocha_1.describe)("VeBetterPassport Upgrades - @shard8d", function () { (0, mocha_1.describe)("Upgrades", function () { (0, mocha_1.it)("should return the correct version", async function () { const { veBetterPassport } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); (0, chai_1.expect)(await veBetterPassport.version()).to.equal("5"); }); (0, mocha_1.it)("Should not be able to initialize twice", async function () { const config = (0, config_1.createTestConfig)(); const { veBetterPassport, owner, x2EarnApps, xAllocationVoting, galaxyMember } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); await (0, chai_1.expect)(veBetterPassport.initialize({ x2EarnApps: await x2EarnApps.getAddress(), xAllocationVoting: await xAllocationVoting.getAddress(), galaxyMember: await galaxyMember.getAddress(), signalingThreshold: config.VEPASSPORT_BOT_SIGNALING_THRESHOLD, //signalingThreshold roundsForCumulativeScore: config.VEPASSPORT_ROUNDS_FOR_CUMULATIVE_PARTICIPATION_SCORE, //roundsForCumulativeScore minimumGalaxyMemberLevel: config.VEPASSPORT_GALAXY_MEMBER_MINIMUM_LEVEL, //galaxyMemberMinimumLevel blacklistThreshold: config.VEPASSPORT_BLACKLIST_THRESHOLD_PERCENTAGE, //blacklistThreshold whitelistThreshold: config.VEPASSPORT_WHITELIST_THRESHOLD_PERCENTAGE, //whitelistThreshold maxEntitiesPerPassport: config.VEPASSPORT_PASSPORT_MAX_ENTITIES, //maxEntitiesPerPassport decayRate: config.VEPASSPORT_DECAY_RATE, //decayRate }, { admin: owner.address, // admin botSignaler: owner.address, // botSignaler upgrader: owner.address, // upgrader settingsManager: owner.address, // settingsManager roleGranter: owner.address, // roleGranter blacklister: owner.address, // blacklister whitelister: owner.address, // whitelistManager actionRegistrar: owner.address, // actionRegistrar actionScoreManager: owner.address, // actionScoreManager resetSignaler: owner.address, // resetSignaler })).to.be.reverted; }); (0, mocha_1.it)("Should not be able to upgrade if without UPGRADER_ROLE", async function () { const { veBetterPassport, otherAccount, passportChecksLogic, passportConfigurator, passportDelegationLogic, passportPersonhoodLogic, passportPoPScoreLogic, passportSignalingLogic, passportEntityLogic, passportWhitelistAndBlacklistLogic, } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); // Deploy the implementation contract const Contract = await hardhat_1.ethers.getContractFactory("VeBetterPassport", { libraries: { PassportChecksLogic: await passportChecksLogic.getAddress(), PassportConfigurator: await passportConfigurator.getAddress(), PassportEntityLogic: await passportEntityLogic.getAddress(), PassportPersonhoodLogic: await passportPersonhoodLogic.getAddress(), PassportPoPScoreLogic: await passportPoPScoreLogic.getAddress(), PassportDelegationLogic: await passportDelegationLogic.getAddress(), PassportSignalingLogic: await passportSignalingLogic.getAddress(), PassportWhitelistAndBlacklistLogic: await passportWhitelistAndBlacklistLogic.getAddress(), }, }); const implementation = await Contract.deploy(); await implementation.waitForDeployment(); const UPGRADER_ROLE = await veBetterPassport.UPGRADER_ROLE(); (0, chai_1.expect)(await veBetterPassport.hasRole(UPGRADER_ROLE, otherAccount)).to.eql(false); await (0, chai_1.expect)(veBetterPassport.connect(otherAccount).upgradeToAndCall(await implementation.getAddress(), "0x")).to .be.reverted; }); (0, mocha_1.it)("User with UPGRADER_ROLE should be able to upgrade the contract", async function () { const { owner, veBetterPassport, passportChecksLogic, passportConfigurator, passportDelegationLogic, passportPersonhoodLogic, passportPoPScoreLogic, passportEntityLogic, passportSignalingLogic, passportWhitelistAndBlacklistLogic, } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); // Deploy the implementation contract // Deploy the implementation contract const Contract = await hardhat_1.ethers.getContractFactory("VeBetterPassport", { libraries: { PassportChecksLogic: await passportChecksLogic.getAddress(), PassportConfigurator: await passportConfigurator.getAddress(), PassportEntityLogic: await passportEntityLogic.getAddress(), PassportPersonhoodLogic: await passportPersonhoodLogic.getAddress(), PassportPoPScoreLogic: await passportPoPScoreLogic.getAddress(), PassportDelegationLogic: await passportDelegationLogic.getAddress(), PassportSignalingLogic: await passportSignalingLogic.getAddress(), PassportWhitelistAndBlacklistLogic: await passportWhitelistAndBlacklistLogic.getAddress(), }, }); const implementation = await Contract.deploy(); await implementation.waitForDeployment(); const currentImplAddress = await (0, upgrades_core_1.getImplementationAddress)(hardhat_1.ethers.provider, await veBetterPassport.getAddress()); const UPGRADER_ROLE = await veBetterPassport.UPGRADER_ROLE(); (0, chai_1.expect)(await veBetterPassport.hasRole(UPGRADER_ROLE, owner.address)).to.eql(true); await (0, chai_1.expect)(veBetterPassport.connect(owner).upgradeToAndCall(await implementation.getAddress(), "0x")).to.not.be .reverted; const newImplAddress = await (0, upgrades_core_1.getImplementationAddress)(hardhat_1.ethers.provider, await veBetterPassport.getAddress()); (0, chai_1.expect)(newImplAddress.toUpperCase()).to.not.eql(currentImplAddress.toUpperCase()); (0, chai_1.expect)(newImplAddress.toUpperCase()).to.eql((await implementation.getAddress()).toUpperCase()); }); (0, mocha_1.it)("Only user with UPGRADER_ROLE should be able to upgrade the contract", async function () { const { owner, veBetterPassport, otherAccount, passportChecksLogic, passportConfigurator, passportDelegationLogic, passportPersonhoodLogic, passportPoPScoreLogic, passportSignalingLogic, passportWhitelistAndBlacklistLogic, } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); // Deploy the implementation contract // Deploy the implementation contract const Contract = await hardhat_1.ethers.getContractFactory("VeBetterPassport", { libraries: { PassportChecksLogic: await passportChecksLogic.getAddress(), PassportConfigurator: await passportConfigurator.getAddress(), PassportEntityLogic: await passportDelegationLogic.getAddress(), PassportDelegationLogic: await passportDelegationLogic.getAddress(), PassportPersonhoodLogic: await passportPersonhoodLogic.getAddress(), PassportPoPScoreLogic: await passportPoPScoreLogic.getAddress(), PassportSignalingLogic: await passportSignalingLogic.getAddress(), PassportWhitelistAndBlacklistLogic: await passportWhitelistAndBlacklistLogic.getAddress(), }, }); const implementation = await Contract.deploy(); await implementation.waitForDeployment(); const currentImplAddress = await (0, upgrades_core_1.getImplementationAddress)(hardhat_1.ethers.provider, await veBetterPassport.getAddress()); await veBetterPassport.revokeRole(await veBetterPassport.UPGRADER_ROLE(), owner.address); // Revoke the UPGRADER_ROLE from the owner (0, chai_1.expect)(await veBetterPassport.hasRole(await veBetterPassport.UPGRADER_ROLE(), owner.address)).to.eql(false); await veBetterPassport.grantRole(await veBetterPassport.UPGRADER_ROLE(), otherAccount.address); // Grant the UPGRADER_ROLE to the otherAccount // Upgrade the VeBetterPassport implementation with NON-UPGRADER_ROLE user await (0, chai_1.expect)(veBetterPassport.connect(owner).upgradeToAndCall(await implementation.getAddress(), "0x")).to.be .reverted; // Upgrade the VeBetterPassport implementation with UPGRADER_ROLE user await (0, chai_1.expect)(veBetterPassport.connect(otherAccount).upgradeToAndCall(await implementation.getAddress(), "0x")).to .not.be.reverted; const newImplAddress = await (0, upgrades_core_1.getImplementationAddress)(hardhat_1.ethers.provider, await veBetterPassport.getAddress()); (0, chai_1.expect)(newImplAddress.toUpperCase()).to.not.eql(currentImplAddress.toUpperCase()); (0, chai_1.expect)(newImplAddress.toUpperCase()).to.eql((await implementation.getAddress()).toUpperCase()); }); (0, mocha_1.it)("Should not have any state conflicts after from V1 to V2, and then to V3", async function () { const config = (0, config_1.createTestConfig)(); config.VEPASSPORT_DECAY_RATE = 20; config.EMISSIONS_CYCLE_DURATION = 20; const { owner, otherAccount, treasury, galaxyMember, b3tr, timeLock: timelock, minterAccount, vot3, x2EarnApps, otherAccounts, passportChecksLogicV1, passportConfiguratorV1, passportDelegationLogicV1, passportPersonhoodLogicV1, passportPoPScoreLogicV1, passportSignalingLogicV1, passportEntityLogicV1, passportWhitelistAndBlacklistLogicV1, passportChecksLogicV2, passportConfiguratorV2, passportDelegationLogicV2, passportPersonhoodLogicV2, passportPoPScoreLogicV2, passportSignalingLogicV2, passportEntityLogicV2, passportWhitelistAndBlacklistLogicV2, passportChecksLogicV3, passportConfiguratorV3, passportDelegationLogicV3, passportPersonhoodLogicV3, passportPoPScoreLogicV3, passportSignalingLogicV3, passportWhitelistAndBlacklistLogicV3, passportEntityLogicV3, governorClockLogicLibV1, governorConfiguratorLibV1, governorDepositLogicLibV1, governorFunctionRestrictionsLogicLibV1, governorProposalLogicLibV1, governorQuorumLogicLibV1, governorStateLogicLibV1, governorVotesLogicLibV1, governorClockLogicLibV3, governorConfiguratorLibV3, governorDepositLogicLibV3, governorFunctionRestrictionsLogicLibV3, governorProposalLogicLibV3, governorQuorumLogicLibV3, governorStateLogicLibV3, governorVotesLogicLibV3, governorClockLogicLibV4, governorConfiguratorLibV4, governorDepositLogicLibV4, governorFunctionRestrictionsLogicLibV4, governorProposalLogicLibV4, governorQuorumLogicLibV4, governorStateLogicLibV4, governorVotesLogicLibV4, B3trContract, creators, } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, config, }); const veBetterPassportContractAddress = await (0, helpers_2.deployProxyOnly)("VeBetterPassportV1", { PassportChecksLogicV1: await passportChecksLogicV1.getAddress(), PassportConfiguratorV1: await passportConfiguratorV1.getAddress(), PassportEntityLogicV1: await passportEntityLogicV1.getAddress(), PassportDelegationLogicV1: await passportDelegationLogicV1.getAddress(), PassportPersonhoodLogicV1: await passportPersonhoodLogicV1.getAddress(), PassportPoPScoreLogicV1: await passportPoPScoreLogicV1.getAddress(), PassportSignalingLogicV1: await passportSignalingLogicV1.getAddress(), PassportWhitelistAndBlacklistLogicV1: await passportWhitelistAndBlacklistLogicV1.getAddress(), }); const x2EarnRewardsPool = (await (0, helpers_2.deployAndUpgrade)(["X2EarnRewardsPoolV1", "X2EarnRewardsPoolV2", "X2EarnRewardsPool"], [ [ owner.address, // admin owner.address, // contracts address manager owner.address, // upgrader //TODO: transferRole await b3tr.getAddress(), await x2EarnApps.getAddress(), ], [ owner.address, // impact admin address config.X_2_EARN_INITIAL_IMPACT_KEYS, // impact keys ], [veBetterPassportContractAddress], ], { versions: [undefined, 2, 3], })); const xAllocationPool = (await (0, helpers_2.deployAndUpgrade)(["XAllocationPoolV1", "XAllocationPool"], [ [ owner.address, // admin owner.address, // upgrader owner.address, // contractsAddressManager await b3tr.getAddress(), await treasury.getAddress(), await x2EarnApps.getAddress(), await x2EarnRewardsPool.getAddress(), ], [], ], { versions: [undefined, 2], })); const emissions = (await (0, helpers_2.deployAndUpgrade)(["EmissionsV1", "Emissions"], [ [ { minter: minterAccount.address, admin: owner.address, upgrader: owner.address, contractsAddressManager: owner.address, decaySettingsManager: owner.address, b3trAddress: await b3tr.getAddress(), destinations: [ await xAllocationPool.getAddress(), config.VOTE_2_EARN_POOL_ADDRESS, await treasury.getAddress(), config.MIGRATION_ADDRESS, ], initialXAppAllocation: config.INITIAL_X_ALLOCATION, cycleDuration: config.EMISSIONS_CYCLE_DURATION, decaySettings: [ config.EMISSIONS_X_ALLOCATION_DECAY_PERCENTAGE, config.EMISSIONS_VOTE_2_EARN_DECAY_PERCENTAGE, config.EMISSIONS_X_ALLOCATION_DECAY_PERIOD, config.EMISSIONS_VOTE_2_EARN_ALLOCATION_DECAY_PERIOD, ], treasuryPercentage: config.EMISSIONS_TREASURY_PERCENTAGE, maxVote2EarnDecay: config.EMISSIONS_MAX_VOTE_2_EARN_DECAY_PERCENTAGE, migrationAmount: config.MIGRATION_AMOUNT, }, ], [config.EMISSIONS_IS_NOT_ALIGNED], ], { versions: [undefined, 2], })); const voterRewards = (await (0, helpers_2.deployAndUpgrade)(["VoterRewardsV1", "VoterRewards"], [ [ owner.address, // admin owner.address, // upgrader // TODO: transferRole owner.address, // contractsAddressManager await emissions.getAddress(), await galaxyMember.getAddress(), await b3tr.getAddress(), config.VOTER_REWARDS_LEVELS, config.VOTER_REWARDS_MULTIPLIER, ], [], ], { versions: [undefined, 2], })); const xAllocationVoting = (await (0, helpers_2.deployAndUpgrade)(["XAllocationVotingV1", "XAllocationVotingV2"], [ [ { vot3Token: await vot3.getAddress(), quorumPercentage: config.X_ALLOCATION_VOTING_QUORUM_PERCENTAGE, initialVotingPeriod: config.EMISSIONS_CYCLE_DURATION - 1, timeLock: await timelock.getAddress(), voterRewards: await voterRewards.getAddress(), emissions: await emissions.getAddress(), admins: [await timelock.getAddress(), owner.address], upgrader: owner.address, contractsAddressManager: owner.address, x2EarnAppsAddress: await x2EarnApps.getAddress(), baseAllocationPercentage: config.X_ALLOCATION_POOL_BASE_ALLOCATION_PERCENTAGE, appSharesCap: config.X_ALLOCATION_POOL_APP_SHARES_MAX_CAP, votingThreshold: config.X_ALLOCATION_VOTING_VOTING_THRESHOLD, }, ], [veBetterPassportContractAddress], ], { versions: [undefined, 2], })); const veBetterPassportV1 = (await (0, helpers_2.initializeProxy)(veBetterPassportContractAddress, "VeBetterPassportV1", [ { x2EarnApps: await x2EarnApps.getAddress(), xAllocationVoting: await xAllocationVoting.getAddress(), galaxyMember: await galaxyMember.getAddress(), signalingThreshold: config.VEPASSPORT_BOT_SIGNALING_THRESHOLD, //signalingThreshold roundsForCumulativeScore: config.VEPASSPORT_ROUNDS_FOR_CUMULATIVE_PARTICIPATION_SCORE, //roundsForCumulativeScore minimumGalaxyMemberLevel: config.VEPASSPORT_GALAXY_MEMBER_MINIMUM_LEVEL, //galaxyMemberMinimumLevel blacklistThreshold: config.VEPASSPORT_BLACKLIST_THRESHOLD_PERCENTAGE, //blacklistThreshold whitelistThreshold: config.VEPASSPORT_WHITELIST_THRESHOLD_PERCENTAGE, //whitelistThreshold maxEntitiesPerPassport: config.VEPASSPORT_PASSPORT_MAX_ENTITIES, //maxEntitiesPerPassport decayRate: config.VEPASSPORT_DECAY_RATE, //decayRate }, { admin: owner.address, // admins botSignaler: owner.address, // botSignaler upgrader: owner.address, // upgrader settingsManager: owner.address, // settingsManager roleGranter: owner.address, // roleGranter blacklister: owner.address, // blacklister whitelister: owner.address, // whitelistManager actionRegistrar: owner.address, // actionRegistrar actionScoreManager: owner.address, // actionScoreManager }, ], { PassportChecksLogicV1: await passportChecksLogicV1.getAddress(), PassportConfiguratorV1: await passportConfiguratorV1.getAddress(), PassportEntityLogicV1: await passportEntityLogicV1.getAddress(), PassportDelegationLogicV1: await passportDelegationLogicV1.getAddress(), PassportPersonhoodLogicV1: await passportPersonhoodLogicV1.getAddress(), PassportPoPScoreLogicV1: await passportPoPScoreLogicV1.getAddress(), PassportSignalingLogicV1: await passportSignalingLogicV1.getAddress(), PassportWhitelistAndBlacklistLogicV1: await passportWhitelistAndBlacklistLogicV1.getAddress(), })); const governor = (await (0, helpers_2.deployAndUpgrade)(["B3TRGovernorV1", "B3TRGovernorV2", "B3TRGovernorV3", "B3TRGovernorV4"], [ [ { vot3Token: await vot3.getAddress(), timelock: await timelock.getAddress(), xAllocationVoting: await xAllocationVoting.getAddress(), b3tr: await b3tr.getAddress(), quorumPercentage: config.B3TR_GOVERNOR_QUORUM_PERCENTAGE, initialDepositThreshold: config.B3TR_GOVERNOR_DEPOSIT_THRESHOLD, initialMinVotingDelay: config.B3TR_GOVERNOR_MIN_VOTING_DELAY, initialVotingThreshold: config.B3TR_GOVERNOR_VOTING_THRESHOLD, voterRewards: await voterRewards.getAddress(), isFunctionRestrictionEnabled: true, }, { governorAdmin: owner.address, pauser: owner.address, contractsAddressManager: owner.address, proposalExecutor: owner.address, governorFunctionSettingsRoleAddress: owner.address, }, ], [], [], [veBetterPassportContractAddress], ], { versions: [undefined, 2, 3, 4], libraries: [ { GovernorClockLogicV1: await governorClockLogicLibV1.getAddress(), GovernorConfiguratorV1: await governorConfiguratorLibV1.getAddress(), GovernorDepositLogicV1: await governorDepositLogicLibV1.getAddress(), GovernorFunctionRestrictionsLogicV1: await governorFunctionRestrictionsLogicLibV1.getAddress(), GovernorProposalLogicV1: await governorProposalLogicLibV1.getAddress(), GovernorQuorumLogicV1: await governorQuorumLogicLibV1.getAddress(), GovernorStateLogicV1: await governorStateLogicLibV1.getAddress(), GovernorVotesLogicV1: await governorVotesLogicLibV1.getAddress(), }, { GovernorClockLogicV1: await governorClockLogicLibV1.getAddress(), GovernorConfiguratorV1: await governorConfiguratorLibV1.getAddress(), GovernorDepositLogicV1: await governorDepositLogicLibV1.getAddress(), GovernorFunctionRestrictionsLogicV1: await governorFunctionRestrictionsLogicLibV1.getAddress(), GovernorProposalLogicV1: await governorProposalLogicLibV1.getAddress(), GovernorQuorumLogicV1: await governorQuorumLogicLibV1.getAddress(), GovernorStateLogicV1: await governorStateLogicLibV1.getAddress(), GovernorVotesLogicV1: await governorVotesLogicLibV1.getAddress(), }, { GovernorClockLogicV3: await governorClockLogicLibV3.getAddress(), GovernorConfiguratorV3: await governorConfiguratorLibV3.getAddress(), GovernorDepositLogicV3: await governorDepositLogicLibV3.getAddress(), GovernorFunctionRestrictionsLogicV3: await governorFunctionRestrictionsLogicLibV3.getAddress(), GovernorProposalLogicV3: await governorProposalLogicLibV3.getAddress(), GovernorQuorumLogicV3: await governorQuorumLogicLibV3.getAddress(), GovernorStateLogicV3: await governorStateLogicLibV3.getAddress(), GovernorVotesLogicV3: await governorVotesLogicLibV3.getAddress(), }, { GovernorClockLogicV4: await governorClockLogicLibV4.getAddress(), GovernorConfiguratorV4: await governorConfiguratorLibV4.getAddress(), GovernorDepositLogicV4: await governorDepositLogicLibV4.getAddress(), GovernorFunctionRestrictionsLogicV4: await governorFunctionRestrictionsLogicLibV4.getAddress(), GovernorProposalLogicV4: await governorProposalLogicLibV4.getAddress(), GovernorQuorumLogicV4: await governorQuorumLogicLibV4.getAddress(), GovernorStateLogicV4: await governorStateLogicLibV4.getAddress(), GovernorVotesLogicV4: await governorVotesLogicLibV4.getAddress(), }, ], })); await veBetterPassportV1 .connect(owner) .grantRole(await veBetterPassportV1.ACTION_REGISTRAR_ROLE(), await x2EarnRewardsPool.getAddress()); // Grant admin role to voter rewards for registering x allocation voting await xAllocationVoting .connect(owner) .grantRole(await xAllocationVoting.DEFAULT_ADMIN_ROLE(), emissions.getAddress()); await voterRewards .connect(owner) .grantRole(await voterRewards.VOTE_REGISTRAR_ROLE(), await xAllocationVoting.getAddress()); await voterRewards.connect(owner).grantRole(await voterRewards.VOTE_REGISTRAR_ROLE(), await governor.getAddress()); await xAllocationPool.connect(owner).setXAllocationVotingAddress(await xAllocationVoting.getAddress()); await xAllocationPool.connect(owner).setEmissionsAddress(await emissions.getAddress()); // Set xAllocationGovernor in emissions await emissions.connect(owner).setXAllocationsGovernorAddress(await xAllocationVoting.getAddress()); const roundStarterRole = await xAllocationVoting.ROUND_STARTER_ROLE(); await xAllocationVoting .connect(owner) .grantRole(roundStarterRole, await emissions.getAddress()) .then(async (tx) => await tx.wait()); await xAllocationVoting .connect(owner) .grantRole(roundStarterRole, owner.address) .then(async (tx) => await tx.wait()); // Set XAllocation address in GalaxyMember await galaxyMember.connect(owner).setXAllocationsGovernorAddress(await xAllocationVoting.getAddress()); await (0, helpers_1.getVot3Tokens)(otherAccount, "10000"); await (0, helpers_1.getVot3Tokens)(owner, "10000"); await (0, helpers_1.getVot3Tokens)(otherAccounts[4], "10000"); const creator1 = creators[0]; const creator2 = creators[1]; //Add apps const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(otherAccounts[2].address)); const app2Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(otherAccounts[3].address)); const app3Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes(otherAccounts[4].address)); await x2EarnApps .connect(creator1) .submitApp(otherAccounts[2].address, otherAccounts[2].address, otherAccounts[2].address, "metadataURI"); await x2EarnApps .connect(creator2) .submitApp(otherAccounts[3].address, otherAccounts[3].address, otherAccounts[3].address, "metadataURI"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[4].address, otherAccounts[4].address, otherAccounts[4].address, "metadataURI"); await (0, xnodes_1.endorseApp)(app1Id, otherAccounts[2]); await (0, xnodes_1.endorseApp)(app2Id, otherAccounts[3]); await (0, xnodes_1.endorseApp)(app3Id, otherAccounts[4]); await emissions.connect(owner).setVote2EarnAddress(await voterRewards.getAddress()); // Set app security levels await veBetterPassportV1.connect(owner).setAppSecurity(app1Id, 1); await veBetterPassportV1.connect(owner).setAppSecurity(app2Id, 2); await veBetterPassportV1.connect(owner).setAppSecurity(app3Id, 3); // Grant action registrar role await veBetterPassportV1.grantRole(await veBetterPassportV1.ACTION_REGISTRAR_ROLE(), owner); (0, chai_1.expect)(await veBetterPassportV1.hasRole(await veBetterPassportV1.ACTION_REGISTRAR_ROLE(), owner.address)).to.be .true; // Bootstrap emissions // Grant minter role to emissions contract await b3tr.connect(owner).grantRole(await b3tr.MINTER_ROLE(), await emissions.getAddress()); // Bootstrap emissions await emissions.connect(minterAccount).bootstrap(); await emissions.connect(minterAccount).start(); // Whitelist function const funcSig = B3trContract.interface.getFunction("tokenDetails")?.selector; await governor.connect(owner).setWhitelistFunction(await b3tr.getAddress(), funcSig, true); // Create a proposal for next round // create a new proposal active from round 2 const address = await b3tr.getAddress(); const encodedFunctionCall = B3trContract.interface.encodeFunctionData("tokenDetails", []); const tx = await governor.connect(owner).propose([address], [0], [encodedFunctionCall], "test", "2", 0, { gasLimit: 10000000, }); const proposalId = await (0, helpers_1.getProposalIdFromTx)(tx); // pay deposit const proposalThreshold = await governor.proposalDepositThreshold(proposalId); await (0, helpers_1.getVot3Tokens)(owner, hardhat_1.ethers.formatEther(proposalThreshold)); // We also need to wait a block to update the proposer's votes snapshot await (0, helpers_1.waitForNextBlock)(); await vot3.connect(owner).approve(await governor.getAddress(), proposalThreshold); await governor.connect(owner).deposit(proposalThreshold, proposalId); // First round, participation score check is disabled // Register actions for round 1 await veBetterPassportV1.connect(owner).registerAction(otherAccount.address, app1Id); await veBetterPassportV1.connect(owner).registerAction(otherAccount.address, app2Id); // User's cumulative score = 100 (app1) + 200 (app2) = 300 (0, chai_1.expect)(await veBetterPassportV1.userRoundScore(otherAccount.address, 1)).to.equal(300); (0, chai_1.expect)(await veBetterPassportV1.getCumulativeScoreWithDecay(otherAccount, 1)).to.equal(300); await veBetterPassportV1.toggleCheck(4); // Vote // Note that `otherAccount` can vote because the participation score threshold is set to 0 await xAllocationVoting .connect(otherAccount) .castVote(1, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")]); await xAllocationVoting.connect(otherAccounts[4]).castVote(1, [app1Id], [hardhat_1.ethers.parseEther("1")]); // Set minimum participation score to 500 await veBetterPassportV1.setThresholdPoPScore(500); let blockNextCycle = await emissions.getNextCycleBlock(); await (0, helpers_1.waitForBlock)(Number(blockNextCycle)); await emissions.connect(minterAccount).distribute(); (0, chai_1.expect)(await xAllocationVoting.currentRoundId()).to.equal(2); (0, chai_1.expect)(await governor.state(proposalId)).to.equal(1); // User tries to vote both governance and x allocation voting but reverts due to not meeting the participation score threshold await (0, chai_1.expect)(xAllocationVoting .connect(otherAccount) .castVote(2, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")])).to.be.revertedWithCustomError(xAllocationVoting, "GovernorPersonhoodVerificationFailed"); await (0, chai_1.expect)(governor.connect(otherAccount).castVote(proposalId, 2)).to.be.revertedWithCustomError(xAllocationVoting, "GovernorPersonhoodVerificationFailed"); // Register actions for round 2 await veBetterPassportV1.connect(owner).registerAction(otherAccount, app2Id); await veBetterPassportV1.connect(owner).registerAction(otherAccount, app3Id); /* User's cumulative score: round 1 = 300 round 2 = 600 + (300 * 0.8) = 840 */ (0, chai_1.expect)(await veBetterPassportV1.getCumulativeScoreWithDecay(otherAccount, 2)).to.equal(840); // User now meets the participation score threshold and can vote await xAllocationVoting .connect(otherAccount) .castVote(2, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")]); await governor.connect(otherAccount).castVote(proposalId, 2); // Increase participation score threshold to 1000 await veBetterPassportV1.setThresholdPoPScore(1000); // Toggle GM level check await veBetterPassportV1.toggleCheck(5); // Upgrade to V2 const veBetterPassportV2 = (await (0, helpers_2.upgradeProxy)("VeBetterPassportV1", "VeBetterPassportV2", await veBetterPassportV1.getAddress(), [], { version: 2, libraries: { PassportChecksLogicV2: await passportChecksLogicV2.getAddress(), PassportConfiguratorV2: await passportConfiguratorV2.getAddress(), PassportEntityLogicV2: await passportEntityLogicV2.getAddress(), PassportDelegationLogicV2: await passportDelegationLogicV2.getAddress(), PassportPersonhoodLogicV2: await passportPersonhoodLogicV2.getAddress(), PassportPoPScoreLogicV2: await passportPoPScoreLogicV2.getAddress(), PassportSignalingLogicV2: await passportSignalingLogicV2.getAddress(), PassportWhitelistAndBlacklistLogicV2: await passportWhitelistAndBlacklistLogicV2.getAddress(), }, })); blockNextCycle = await emissions.getNextCycleBlock(); await (0, helpers_1.waitForBlock)(Number(blockNextCycle)); // Increase participation score threshold to 1000 await veBetterPassportV2.setThresholdPoPScore(1000); await emissions.distribute(); (0, chai_1.expect)(await xAllocationVoting.currentRoundId()).to.equal(3); // User tries to vote x allocation voting but reverts due to not meeting the participation score threshold await (0, chai_1.expect)(xAllocationVoting .connect(otherAccount) .castVote(3, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")])).to.be.revertedWithCustomError(xAllocationVoting, "GovernorPersonhoodVerificationFailed"); // Register action for round 3 await veBetterPassportV2.connect(owner).registerAction(otherAccount, app1Id); /* User's cumulative score: round 1 = 300 round 2 = 600 + (300 * 0.8) = 840 round 3 = 100 + (840 * 0.8) = 772 */ (0, chai_1.expect)(await veBetterPassportV2.getCumulativeScoreWithDecay(otherAccount, 3)).to.equal(772); // User still doesn't meet the participation score threshold and can't vote await (0, chai_1.expect)(xAllocationVoting .connect(otherAccount) .castVote(3, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")])).to.be.revertedWithCustomError(xAllocationVoting, "GovernorPersonhoodVerificationFailed"); // register more actions for round 3 await veBetterPassportV2.connect(owner).registerAction(otherAccount, app2Id); await veBetterPassportV2.connect(owner).registerAction(otherAccount, app3Id); /* User's cumulative score: round 1 = 300 round 2 = 600 + (300 * 0.8) = 840 round 3 = 700 + (840 * 0.8) = 1072 */ (0, chai_1.expect)(await veBetterPassportV2.getCumulativeScoreWithDecay(otherAccount, 3)).to.equal(1372); // User now meets the participation score threshold and can vote await xAllocationVoting .connect(otherAccount) .castVote(3, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")]); // "Before linking passport should have 0" (0, chai_1.expect)(await veBetterPassportV2.getCumulativeScoreWithDecay(owner, 3)).to.equal(0); // Before linking passport should not be considered person (0, chai_1.expect)((await veBetterPassportV2.isPersonAtTimepoint(owner.address, await xAllocationVoting.roundSnapshot(3)))[0]).to.be.equal(false); // Delegate passport to owner and try to vote await (0, helpers_1.linkEntityToPassportWithSignature)(veBetterPassportV2, owner, otherAccount, 3600); // After linking "other account" should be entity (0, chai_1.expect)(await veBetterPassportV2.isEntity(otherAccount.address)).to.be.true; // After linking owner should be passport (0, chai_1.expect)(await veBetterPassportV2.isPassport(owner.address)).to.be.true; // After linking passport should not be considered person at the beginning of the round (0, chai_1.expect)((await veBetterPassportV2.isPersonAtTimepoint(owner.address, await xAllocationVoting.roundSnapshot(3)))[0]).to.be.equal(false); (0, chai_1.expect)(await veBetterPassportV2.isPassport(owner.address)).to.be.true; // Owner can't vote yet because the delegation is checkpointed and is active from the next round await (0, chai_1.expect)(xAllocationVoting .connect(owner) .castVote(3, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")])).to.be.revertedWithCustomError(xAllocationVoting, "GovernorPersonhoodVerificationFailed"); blockNextCycle = await emissions.getNextCycleBlock(); await (0, helpers_1.waitForBlock)(Number(blockNextCycle)); // Mint user GM token await galaxyMember.connect(otherAccounts[4]).freeMint(); await galaxyMember.setMaxLevel(2); // Set user GM level to 2 await (0, helpers_1.upgradeNFTtoLevel)(1, 2, galaxyMember, b3tr, otherAccounts[4], minterAccount); // Checking if user is person based on GM level will not work in V2 because the check is not implemented (0, chai_1.expect)(await veBetterPassportV2.isPerson(otherAccounts[4].address)).to.deep.equal([ false, "User does not meet the criteria to be considered a person", ]); // Record contract storage state at this point let storageSlots = []; const initialSlot = BigInt("0x273c9387b78d9b22e6f3371bb3aa3a918f53507e8cacc54e4831933cbb844100"); // Slot 0 of VoterRewards for (let i = initialSlot; i < initialSlot + BigInt(50); i++) { storageSlots.push(await hardhat_1.ethers.provider.getStorage(await veBetterPassportV1.getAddress(), i)); } storageSlots = storageSlots.filter(slot => slot !== "0x0000000000000000000000000000000000000000000000000000000000000000"); // Upgrade to V3 const veBetterPassportV3 = (await (0, helpers_2.upgradeProxy)("VeBetterPassportV2", "VeBetterPassportV3", await veBetterPassportV2.getAddress(), [], { version: 3, libraries: { PassportChecksLogicV3: await passportChecksLogicV3.getAddress(), PassportConfiguratorV3: await passportConfiguratorV3.getAddress(), PassportEntityLogicV3: await passportEntityLogicV3.getAddress(), PassportDelegationLogicV3: await passportDelegationLogicV3.getAddress(), PassportPersonhoodLogicV3: await passportPersonhoodLogicV3.getAddress(), PassportPoPScoreLogicV3: await passportPoPScoreLogicV3.getAddress(), PassportSignalingLogicV3: await passportSignalingLogicV3.getAddress(), PassportWhitelistAndBlacklistLogicV3: await passportWhitelistAndBlacklistLogicV3.getAddress(), }, })); // Check that the storage slots are the same let storageSlotsAfter = []; for (let i = initialSlot; i < initialSlot + BigInt(100); i++) { storageSlotsAfter.push(await hardhat_1.ethers.provider.getStorage(await veBetterPassportV3.getAddress(), i)); } storageSlotsAfter = storageSlotsAfter.filter(slot => slot !== "0x0000000000000000000000000000000000000000000000000000000000000000"); // Check if storage slots are the same after upgrade for (let i = 0; i < storageSlots.length; i++) { (0, chai_1.expect)(storageSlots[i]).to.equal(storageSlotsAfter[i]); } await emissions.connect(minterAccount).distribute(); (0, chai_1.expect)(await xAllocationVoting.currentRoundId()).to.equal(4); // Checking if user is person based on GM level will work in V3 because the check is implemented (0, chai_1.expect)(await veBetterPassportV3.isPerson(otherAccounts[4].address)).to.deep.equal([ true, "User's selected Galaxy Member is above the minimum level", ]); // During linking points are not brought over, so we need to register some actions // on both the entity and the passport to see that they are grouped together and can vote (0, chai_1.expect)(await veBetterPassportV1.getCumulativeScoreWithDecay(otherAccount, 4)).to.equal(1097); // register more actions for round 4 (mixing entity and passport) await veBetterPassportV3.connect(owner).registerAction(otherAccount, app2Id); await veBetterPassportV3.connect(owner).registerAction(owner, app3Id); await veBetterPassportV3.connect(owner).registerAction(owner, app3Id); // new points should be added to the passport, entity should not have any new points added (0, chai_1.expect)(await veBetterPassportV3.getCumulativeScoreWithDecay(otherAccount, 4)).to.equal(1097); /* Passport's cumulative score: round 4 = 200 + 400 + 400 */ (0, chai_1.expect)(await veBetterPassportV3.getCumulativeScoreWithDecay(owner, 4)).to.equal(1000); // Now that we reached threshold passport should be considered person (0, chai_1.expect)((await veBetterPassportV3.isPersonAtTimepoint(owner.address, await xAllocationVoting.roundSnapshot(4)))[0]).to.be.equal(true); // Owner can vote now await xAllocationVoting .connect(owner) .castVote(4, [app1Id, app2Id, app3Id], [hardhat_1.ethers.parseEther("0"), hardhat_1.ethers.parseEther("900"), hardhat_1.ethers.parseEther("100")]); }); }); }); // Continue shard8 with smaller sections (0, mocha_1.describe)("VeBetterPassport Checks & Config - @shard8-core", function () { (0, mocha_1.describe)("Passport Checks", function () { (0, mocha_1.it)("Should initialize correctly", async function () { const { owner: settingsManager, veBetterPassport, otherAccount, } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true, }); // Verify non admin account cannot toggle checks by default await (0, chai_1.expect)(veB