UNPKG

@vechain/vebetterdao-contracts

Version:

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

641 lines (640 loc) 49.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const chai_1 = require("chai"); const hardhat_1 = require("hardhat"); const mocha_1 = require("mocha"); const helpers_1 = require("../helpers"); const xnodes_1 = require("../helpers/xnodes"); (0, mocha_1.describe)("X-Apps - Team Management - @shard15b", function () { (0, mocha_1.describe)("Admin address", function () { (0, mocha_1.it)("Admin can update the admin address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const admin = await x2EarnApps.appAdmin(app1Id); (0, chai_1.expect)(admin).to.eql(otherAccounts[0].address); await x2EarnApps.connect(owner).setAppAdmin(app1Id, otherAccounts[1].address); const updatedAdmin = await x2EarnApps.appAdmin(app1Id); (0, chai_1.expect)(updatedAdmin).to.eql(otherAccounts[1].address); (0, chai_1.expect)(updatedAdmin).to.not.eql(admin); }); (0, mocha_1.it)("Cannot update the admin address of a non-existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); const newAdminAddress = hardhat_1.ethers.Wallet.createRandom().address; await (0, chai_1.expect)(x2EarnApps.connect(owner).setAppAdmin(app1Id, newAdminAddress)).to.be.reverted; }); (0, mocha_1.it)("Cannot set the admin address of an app to ZERO address", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, helpers_1.catchRevert)(x2EarnApps.connect(otherAccounts[0]).setAppAdmin(app1Id, helpers_1.ZERO_ADDRESS)); }); (0, mocha_1.it)("User with DEFAULT_ADMIN_ROLE can update the admin address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const admin = await x2EarnApps.appAdmin(app1Id); (0, chai_1.expect)(admin).to.eql(otherAccounts[0].address); await x2EarnApps.connect(otherAccounts[0]).setAppAdmin(app1Id, otherAccounts[1].address); const updatedAdmin = await x2EarnApps.appAdmin(app1Id); (0, chai_1.expect)(updatedAdmin).to.eql(otherAccounts[1].address); (0, chai_1.expect)(updatedAdmin).to.not.eql(admin); }); (0, mocha_1.it)("Non admins cannot update the admin address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); // check that is not admin (0, chai_1.expect)(await x2EarnApps.isAppAdmin(app1Id, otherAccounts[1].address)).to.eql(false); await (0, helpers_1.catchRevert)(x2EarnApps.connect(otherAccounts[1]).setAppAdmin(app1Id, otherAccounts[1].address)); // user without DEFAULT_ADMIN_ROLE (0, chai_1.expect)(await x2EarnApps.hasRole(await x2EarnApps.DEFAULT_ADMIN_ROLE(), otherAccounts[0].address)).to.eql(false); await (0, helpers_1.catchRevert)(x2EarnApps.connect(otherAccounts[1]).setAppAdmin(app1Id, otherAccounts[2].address)); }); }); (0, mocha_1.describe)("Team wallet address", function () { (0, mocha_1.it)("Should be able to fetch app team wallet address", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const teamWalletAddress = await x2EarnApps.teamWalletAddress(app1Id); (0, chai_1.expect)(teamWalletAddress).to.eql(otherAccounts[0].address); }); (0, mocha_1.it)("Governance admin role can update the team wallet address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const appReceiverAddress1 = await x2EarnApps.teamWalletAddress(app1Id); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, owner.address); (0, chai_1.expect)(isAdmin).to.be.true; await x2EarnApps.connect(owner).updateTeamWalletAddress(app1Id, otherAccounts[1].address); const appReceiverAddress2 = await x2EarnApps.teamWalletAddress(app1Id); (0, chai_1.expect)(appReceiverAddress2).to.eql(otherAccounts[1].address); (0, chai_1.expect)(appReceiverAddress1).to.not.eql(appReceiverAddress2); }); (0, mocha_1.it)("App admin can update the team wallet address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); const appAdmin = otherAccounts[9]; await x2EarnApps.connect(owner).submitApp(otherAccounts[0].address, appAdmin.address, "My app", "metadataURI"); const appReceiverAddress1 = await x2EarnApps.teamWalletAddress(app1Id); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, appAdmin.address); (0, chai_1.expect)(isAdmin).to.be.false; (0, chai_1.expect)(await x2EarnApps.isAppAdmin(app1Id, appAdmin.address)).to.be.true; await x2EarnApps.connect(appAdmin).updateTeamWalletAddress(app1Id, otherAccounts[1].address); const appReceiverAddress2 = await x2EarnApps.teamWalletAddress(app1Id); (0, chai_1.expect)(appReceiverAddress2).to.eql(otherAccounts[1].address); (0, chai_1.expect)(appReceiverAddress1).to.not.eql(appReceiverAddress2); }); (0, mocha_1.it)("Moderators cannot update the team wallet address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const appReceiverAddress1 = await x2EarnApps.teamWalletAddress(app1Id); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, owner.address); (0, chai_1.expect)(isAdmin).to.be.true; await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[1].address); const isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[1]).updateTeamWalletAddress(app1Id, otherAccounts[1].address)).to.be .reverted; const appReceiverAddress2 = await x2EarnApps.teamWalletAddress(app1Id); (0, chai_1.expect)(appReceiverAddress2).to.eql(appReceiverAddress1); }); (0, mocha_1.it)("Moderators cannot update the team wallet address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const appReceiverAddress1 = await x2EarnApps.teamWalletAddress(app1Id); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, owner.address); (0, chai_1.expect)(isAdmin).to.be.true; await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[1].address); const isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[1]).updateTeamWalletAddress(app1Id, otherAccounts[1].address)).to.be .reverted; const appReceiverAddress2 = await x2EarnApps.teamWalletAddress(app1Id); (0, chai_1.expect)(appReceiverAddress2).to.eql(appReceiverAddress1); }); (0, mocha_1.it)("Non-admin cannot update the team wallet address of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const appReceiverAddress1 = await x2EarnApps.teamWalletAddress(app1Id); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, otherAccounts[1].address); (0, chai_1.expect)(isAdmin).to.be.false; await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[1]).updateTeamWalletAddress(app1Id, otherAccounts[1].address)).to.be .reverted; const appReceiverAddress2 = await x2EarnApps.teamWalletAddress(app1Id); (0, chai_1.expect)(appReceiverAddress2).to.eql(appReceiverAddress1); }); (0, mocha_1.it)("Cannot update the team wallet address of a non-existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); const newTeamWalletAddress = hardhat_1.ethers.Wallet.createRandom().address; await (0, chai_1.expect)(x2EarnApps.connect(owner).updateTeamWalletAddress(app1Id, newTeamWalletAddress)).to.be.reverted; }); (0, mocha_1.it)("Team wallet address cannot be updated to ZERO address", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, helpers_1.catchRevert)(x2EarnApps.connect(otherAccounts[0]).updateTeamWalletAddress(app1Id, helpers_1.ZERO_ADDRESS)); }); }); (0, mocha_1.describe)("App Moderators", function () { (0, mocha_1.it)("By default there is no moderator for an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[0].address); (0, chai_1.expect)(isModerator).to.be.false; const moderators = await x2EarnApps.appModerators(app1Id); (0, chai_1.expect)(moderators).to.eql([]); }); (0, mocha_1.it)("DEFAULT_ADMIN_ROLE can add a moderator to an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, owner.address); (0, chai_1.expect)(isAdmin).to.be.true; await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[1].address); const isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; }); (0, mocha_1.it)("DEFAULT_ADMIN_ROLE can remove a moderator from an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[1].address); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, owner.address); (0, chai_1.expect)(isAdmin).to.be.true; let isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; await x2EarnApps.connect(owner).removeAppModerator(app1Id, otherAccounts[1].address); isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.false; }); (0, mocha_1.it)("App admin can add a moderator to an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); const appAdmin = otherAccounts[9]; await x2EarnApps.connect(owner).submitApp(otherAccounts[0].address, appAdmin.address, "My app", "metadataURI"); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, appAdmin.address); (0, chai_1.expect)(isAdmin).to.be.false; (0, chai_1.expect)(await x2EarnApps.isAppAdmin(app1Id, appAdmin.address)).to.be.true; await x2EarnApps.connect(appAdmin).addAppModerator(app1Id, otherAccounts[1].address); const isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; }); (0, mocha_1.it)("App admin can remove a moderator from an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); const appAdmin = otherAccounts[9]; await x2EarnApps.connect(owner).submitApp(otherAccounts[0].address, appAdmin.address, "My app", "metadataURI"); await x2EarnApps.connect(appAdmin).addAppModerator(app1Id, otherAccounts[1].address); await x2EarnApps.connect(appAdmin).addAppModerator(app1Id, otherAccounts[2].address); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, appAdmin.address); (0, chai_1.expect)(isAdmin).to.be.false; (0, chai_1.expect)(await x2EarnApps.isAppAdmin(app1Id, appAdmin.address)).to.be.true; let isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; await x2EarnApps.connect(appAdmin).removeAppModerator(app1Id, otherAccounts[2].address); isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[2].address); (0, chai_1.expect)(isModerator).to.be.false; (0, chai_1.expect)(await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address)).to.be.true; }); (0, mocha_1.it)("Can correctly fetch all moderators of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[1].address); await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[2].address); const moderators = await x2EarnApps.appModerators(app1Id); (0, chai_1.expect)(moderators).to.eql([otherAccounts[1].address, otherAccounts[2].address]); }); (0, mocha_1.it)("Can know if an address is a moderator of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[1].address); let isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[2].address); (0, chai_1.expect)(isModerator).to.be.false; }); (0, mocha_1.it)("Cannot add a moderator to a non-existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await (0, chai_1.expect)(x2EarnApps.connect(owner).addAppModerator(app1Id, owner.address)).to.be.reverted; }); (0, mocha_1.it)("Cannot remove a moderator from a non-existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await (0, chai_1.expect)(x2EarnApps.connect(owner).removeAppModerator(app1Id, owner.address)).to.be.reverted; }); (0, mocha_1.it)("Cannot add ZERO_ADDRESS as a moderator of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).addAppModerator(app1Id, helpers_1.ZERO_ADDRESS)).to.be.reverted; }); (0, mocha_1.it)("Cannot remove ZERO_ADDRESS as a moderator of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).removeAppModerator(app1Id, helpers_1.ZERO_ADDRESS)).to.be.reverted; }); (0, mocha_1.it)("Non admin or user without DEFAULT_ADMIN_ROLE cannot add a moderator to an app", async function () { const { x2EarnApps, otherAccounts } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).addAppModerator(app1Id, otherAccounts[0].address)).to.be .reverted; }); (0, mocha_1.it)("Non admin or user without DEFAULT_ADMIN_ROLE cannot remove a moderator from an app", async function () { const { x2EarnApps, otherAccounts } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).removeAppModerator(app1Id, otherAccounts[0].address)).to.be .reverted; }); (0, mocha_1.it)("Removing a moderator from an app does not affect other moderators of the app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[1].address); await x2EarnApps.connect(owner).addAppModerator(app1Id, otherAccounts[2].address); let isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.true; isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[2].address); (0, chai_1.expect)(isModerator).to.be.true; await x2EarnApps.connect(owner).removeAppModerator(app1Id, otherAccounts[1].address); isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isModerator).to.be.false; isModerator = await x2EarnApps.isAppModerator(app1Id, otherAccounts[2].address); (0, chai_1.expect)(isModerator).to.be.true; }); (0, mocha_1.it)("An error is thrown when trying to remove a non existing moderator from an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(owner).removeAppModerator(app1Id, otherAccounts[1].address)).to.be.reverted; }); (0, mocha_1.it)("Cannot remove a moderator with ZERO_ADDRESS from an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(owner).removeAppModerator(app1Id, helpers_1.ZERO_ADDRESS)).to.be.reverted; }); (0, mocha_1.it)("Cannot remove moderator of non existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); await (0, chai_1.expect)(x2EarnApps.connect(owner).removeAppModerator(app1Id, owner.address)).to.be.reverted; }); (0, mocha_1.it)("Cannot have exceed the maximum number of moderators for an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = hardhat_1.ethers.keccak256(hardhat_1.ethers.toUtf8Bytes("My app")); const appAdmin = otherAccounts[9]; await x2EarnApps.connect(owner).submitApp(otherAccounts[0].address, appAdmin.address, "My app", "metadataURI"); const limit = await x2EarnApps.MAX_MODERATORS(); const addModeratorPromises = []; for (let i = 1; i <= limit; i++) { const randomWallet = hardhat_1.ethers.Wallet.createRandom(); addModeratorPromises.push(x2EarnApps.connect(appAdmin).addAppModerator(app1Id, randomWallet.address)); } // Wait for all addAppModerator transactions to complete await Promise.all(addModeratorPromises); await (0, chai_1.expect)(x2EarnApps.connect(appAdmin).addAppModerator(app1Id, otherAccounts[10].address)).to.be.reverted; // check that having 100 moderators do not affect the app const moderators = await x2EarnApps.appModerators(app1Id); (0, chai_1.expect)(moderators.length).to.eql(100); // check that the last moderator is not the one that failed (0, chai_1.expect)(moderators[99]).to.not.eql(otherAccounts[10].address); (0, chai_1.expect)(await x2EarnApps.isAppModerator(app1Id, otherAccounts[10].address)).to.be.false; }); }); (0, mocha_1.describe)("Reward distributors", function () { (0, mocha_1.it)("Admin can add a reward distributor to an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addRewardDistributor(app1Id, otherAccounts[1].address); const isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isDistributor).to.be.true; }); (0, mocha_1.it)("Admin can remove a reward distributor from an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addRewardDistributor(app1Id, otherAccounts[1].address); let isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isDistributor).to.be.true; await x2EarnApps.connect(owner).removeRewardDistributor(app1Id, otherAccounts[1].address); isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isDistributor).to.be.false; }); (0, mocha_1.it)("Cannot add a reward distributor to a non-existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await (0, chai_1.expect)(x2EarnApps.connect(owner).addRewardDistributor(app1Id, owner.address)).to.be.reverted; }); (0, mocha_1.it)("Cannot remove a reward distributor from a non-existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await (0, chai_1.expect)(x2EarnApps.connect(owner).removeRewardDistributor(app1Id, owner.address)).to.be.reverted; }); (0, mocha_1.it)("Cannot add ZERO_ADDRESS as a reward distributor of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).addRewardDistributor(app1Id, helpers_1.ZERO_ADDRESS)).to.be.reverted; }); (0, mocha_1.it)("Cannot remove ZERO_ADDRESS as a reward distributor of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).removeRewardDistributor(app1Id, helpers_1.ZERO_ADDRESS)).to.be.reverted; }); (0, mocha_1.it)("Cannot remove a non existing reward distributor from an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(owner).removeRewardDistributor(app1Id, otherAccounts[1].address)).to.be.reverted; }); (0, mocha_1.it)("When having more than one distributor, updating one address won't affect the others", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addRewardDistributor(app1Id, otherAccounts[1].address); await x2EarnApps.connect(owner).addRewardDistributor(app1Id, otherAccounts[2].address); let isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isDistributor).to.be.true; isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[2].address); (0, chai_1.expect)(isDistributor).to.be.true; await x2EarnApps.connect(owner).removeRewardDistributor(app1Id, otherAccounts[1].address); isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isDistributor).to.be.false; isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[2].address); (0, chai_1.expect)(isDistributor).to.be.true; }); (0, mocha_1.it)("Can correctly fetch all reward distributors of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addRewardDistributor(app1Id, otherAccounts[1].address); await x2EarnApps.connect(owner).addRewardDistributor(app1Id, otherAccounts[2].address); const distributors = await x2EarnApps.rewardDistributors(app1Id); (0, chai_1.expect)(distributors).to.eql([otherAccounts[1].address, otherAccounts[2].address]); }); (0, mocha_1.it)("Can know if an address is a reward distributor of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).addRewardDistributor(app1Id, otherAccounts[1].address); let isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[1].address); (0, chai_1.expect)(isDistributor).to.be.true; isDistributor = await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[2].address); (0, chai_1.expect)(isDistributor).to.be.false; }); (0, mocha_1.it)("Cannot add a reward distributor to an app if not an admin", async function () { const { x2EarnApps, otherAccounts } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).addRewardDistributor(app1Id, otherAccounts[1].address)).to.be .reverted; }); (0, mocha_1.it)("Cannot remove a reward distributor from an app if not an admin", async function () { const { x2EarnApps, otherAccounts } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).removeRewardDistributor(app1Id, otherAccounts[1].address)).to.be .reverted; }); (0, mocha_1.it)("Cannot have exceed the maximum number of reward distributors for an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const limit = await x2EarnApps.MAX_REWARD_DISTRIBUTORS(); const app1Id = await x2EarnApps.hashAppName("My app"); const appAdmin = otherAccounts[9]; await x2EarnApps.connect(owner).submitApp(otherAccounts[0].address, appAdmin.address, "My app", "metadataURI"); const addDistributorPromises = []; for (let i = 1; i <= limit; i++) { const randomWallet = hardhat_1.ethers.Wallet.createRandom(); addDistributorPromises.push(x2EarnApps.connect(appAdmin).addRewardDistributor(app1Id, randomWallet.address)); } // Wait for all addRewardDistributor transactions to complete await Promise.all(addDistributorPromises); await (0, chai_1.expect)(x2EarnApps.connect(appAdmin).addRewardDistributor(app1Id, otherAccounts[10].address)).to.be.reverted; // check that having 100 distributors do not affect the app const distributors = await x2EarnApps.rewardDistributors(app1Id); (0, chai_1.expect)(distributors.length).to.eql(100); // check that the last distributor is not the one that failed (0, chai_1.expect)(distributors[99]).to.not.eql(otherAccounts[10].address); (0, chai_1.expect)(await x2EarnApps.isRewardDistributor(app1Id, otherAccounts[10].address)).to.be.false; }); }); (0, mocha_1.describe)("Team allocation percentage", function () { (0, mocha_1.it)("By default, the team allocation percentage of an app is 0", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); const teamAllocationPercentage = await x2EarnApps.teamAllocationPercentage(app1Id); (0, chai_1.expect)(teamAllocationPercentage).to.eql(0n); }); (0, mocha_1.it)("Admin can update the team allocation percentage of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, 50); let teamAllocationPercentage = await x2EarnApps.teamAllocationPercentage(app1Id); (0, chai_1.expect)(teamAllocationPercentage).to.eql(50n); await x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, 60); teamAllocationPercentage = await x2EarnApps.teamAllocationPercentage(app1Id); (0, chai_1.expect)(teamAllocationPercentage).to.eql(60n); }); (0, mocha_1.it)("Admin can remove the team allocation percentage of an app by setting it to 0", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, 50); let teamAllocationPercentage = await x2EarnApps.teamAllocationPercentage(app1Id); (0, chai_1.expect)(teamAllocationPercentage).to.eql(50n); }); (0, mocha_1.it)("Cannot update the team allocation percentage of a non-existing app", async function () { const { x2EarnApps, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const appId = await x2EarnApps.hashAppName("non-existing app"); await (0, chai_1.expect)(x2EarnApps.connect(owner).setTeamAllocationPercentage(appId, 50)).to.be.reverted; }); (0, mocha_1.it)("Cannot update the team allocation percentage of an app to more than 100", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, chai_1.expect)(x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, 101)).to.be.reverted; }); (0, mocha_1.it)("Cannot update the team allocation percentage of an app to less than 0", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); // uint256 cannot be negative, so ethers will throw an encoding error try { await x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, -1); chai_1.expect.fail("Should have thrown an error"); } catch (error) { (0, chai_1.expect)(error.code).to.equal("INVALID_ARGUMENT"); } }); (0, mocha_1.it)("Non-admin cannot update the team allocation percentage of an app", async function () { const { x2EarnApps, otherAccounts } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const app1Id = await x2EarnApps.hashAppName("My app"); await (0, chai_1.expect)(x2EarnApps.connect(otherAccounts[0]).setTeamAllocationPercentage(app1Id, 50)).to.be.reverted; }); (0, mocha_1.it)("User with DEFAULT_ADMIN_ROLE can update the team allocation percentage of an app", async function () { const { x2EarnApps, otherAccounts, owner } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const adminRole = await x2EarnApps.DEFAULT_ADMIN_ROLE(); const isAdmin = await x2EarnApps.hasRole(adminRole, owner.address); (0, chai_1.expect)(isAdmin).to.be.true; const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, 50); let teamAllocationPercentage = await x2EarnApps.teamAllocationPercentage(app1Id); (0, chai_1.expect)(teamAllocationPercentage).to.eql(50n); }); (0, mocha_1.it)("Team allocation percentage of an app is 0 and apps need to withdraw, then they can change this", async function () { const { x2EarnApps, otherAccounts, owner, xAllocationVoting, xAllocationPool, b3tr, x2EarnRewardsPool, veBetterPassport, } = await (0, helpers_1.getOrDeployContractInstances)({ forceDeploy: true }); const voter = otherAccounts[1]; await (0, helpers_1.getVot3Tokens)(voter, "1"); await veBetterPassport.whitelist(voter.address); await veBetterPassport.toggleCheck(1); const app1Id = await x2EarnApps.hashAppName("My app"); await x2EarnApps .connect(owner) .submitApp(otherAccounts[0].address, otherAccounts[0].address, "My app", "metadataURI"); await (0, xnodes_1.endorseApp)(app1Id, otherAccounts[0]); await x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, 0); let teamAllocationPercentage = await x2EarnApps.teamAllocationPercentage(app1Id); (0, chai_1.expect)(teamAllocationPercentage).to.eql(0n); // start round await (0, helpers_1.bootstrapAndStartEmissions)(); // vote let roundId = await xAllocationVoting.currentRoundId(); await xAllocationVoting.connect(voter).castVote(roundId, [app1Id], [hardhat_1.ethers.parseEther("1")]); await (0, helpers_1.waitForCurrentRoundToEnd)(); // get balance of team wallet address const teamWalletAddress = await x2EarnApps.teamWalletAddress(app1Id); const teamWalletBalanceBefore = await b3tr.balanceOf(teamWalletAddress); (0, chai_1.expect)(teamWalletBalanceBefore).to.eql(0n); const x2EarnRewardsPoolBalanceBefore = await b3tr.balanceOf(await x2EarnRewardsPool.getAddress()); let appEarnings = await xAllocationPool.roundEarnings(roundId, app1Id); // admin claims for app await xAllocationPool.connect(owner).claim(roundId, app1Id); // all funds should have been sent to the x2EarnRewardsPool contract const teamWalletBalanceAfter = await b3tr.balanceOf(teamWalletAddress); const x2EarnRewardsPoolBalanceAfter = await b3tr.balanceOf(await x2EarnRewardsPool.getAddress()); (0, chai_1.expect)(teamWalletBalanceAfter).to.eql(0n); (0, chai_1.expect)(x2EarnRewardsPoolBalanceAfter).to.eql(x2EarnRewardsPoolBalanceBefore + appEarnings[0]); // admin should be able to withdraw the funds await x2EarnRewardsPool.connect(otherAccounts[0]).withdraw(appEarnings[0], app1Id, ""); const x2EarnRewardsPoolBalanceAfterWithdraw = await b3tr.balanceOf(await x2EarnRewardsPool.getAddress()); (0, chai_1.expect)(x2EarnRewardsPoolBalanceAfterWithdraw).to.eql(x2EarnRewardsPoolBalanceAfter - appEarnings[0]); const teamWalletBalanceAfterWithdraw = await b3tr.balanceOf(teamWalletAddress); (0, chai_1.expect)(teamWalletBalanceAfterWithdraw).to.eql(appEarnings[0]); // now we start a new round and the app can change the team allocation percentage await (0, helpers_1.startNewAllocationRound)(); roundId = await xAllocationVoting.currentRoundId(); await xAllocationVoting.connect(voter).castVote(roundId, [app1Id], [hardhat_1.ethers.parseEther("1")]); await x2EarnApps.connect(owner).setTeamAllocationPercentage(app1Id, 30); teamAllocationPercentage = await x2EarnApps.teamAllocationPercentage(app1Id); (0, chai_1.expect)(teamAllocationPercentage).to.eql(30n); await (0, helpers_1.waitForCurrentRoundToEnd)(); appEarnings = await xAllocationPool.roundEarnings(roundId, app1Id); // admin claims for app await xAllocationPool.connect(owner).claim(roundId, app1Id); // now the team wallet should have received some funds const teamWalletBalanceAfter2 = await b3tr.balanceOf(teamWalletAddress); (0, chai_1.expect)(teamWalletBalanceAfter2).to.eql(teamWalletBalanceAfterWithdraw + (appEarnings[0] * 30n) / 100n); // 70% of funds should have been sent to the x2EarnRewardsPool contract const x2EarnRewardsPoolBalanceAfter2 = await b3tr.balanceOf(await x2EarnRewardsPool.getAddress()); (0, chai_1.expect)(x2EarnRewardsPoolBalanceAfter2).to.eql(x2EarnRewardsPoolBalanceAfterWithdraw + (appEarnings[0] * 70n) / 100n); // admin of app can deposit back the funds to the x2EarnRewardsPool await b3tr.connect(otherAccounts[0]).approve(await x2EarnRewardsPool.getAddress(), teamWalletBalanceAfter2); await x2EarnRewardsPool.connect(otherAccounts[0]).deposit(teamWalletBalanceAfter2.toString(), app1Id); const x2EarnRewardsPoolBalanceAfter3 = await b3tr.balanceOf(await x2EarnRewardsPool.getAddress()); (0, chai_1.expect)(x2EarnRewardsPoolBalanceAfter3).to.eql(x2EarnRewardsPoolBalanceAfter2 + teamWalletBalanceAfter2); (0, chai_1.expect)(await b3tr.balanceOf(teamWalletAddress)).to.eql(0n); }); }); });