@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
JavaScript
"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);
});
});
});