@vechain/vebetterdao-contracts
Version:
Open-source repository that houses the smart contracts powering the decentralized VeBetterDAO on the VeChain Thor blockchain.
137 lines (136 loc) • 7.32 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const mocha_1 = require("mocha");
const chai_1 = require("chai");
const hardhat_1 = require("hardhat");
const typechain_types_1 = require("../../../typechain-types");
const common_1 = require("../../helpers/common");
const fixture_test_1 = require("../fixture.test");
/**
* V3 widens updateMilestoneMetadataURI from proposer-only to
* proposer + grants receiver + GRANTS_APPROVER_ROLE + GOVERNANCE_ROLE.
*
* In production the grants approver wallet acts as the proposer for nearly every grant, so the
* receiving app cannot persist expenditure reports under the V2 rule. V3 unblocks that flow.
*/
(0, mocha_1.describe)("GrantsManager - V3 Metadata URI Access - @shard4k", function () {
let governor;
let vot3;
let b3tr;
let minterAccount;
let proposer;
let secondaryAccount; // grants receiver
let outsider;
let approver;
let treasury;
let grantsManager;
let owner;
let voter;
let veBetterPassport;
let timeLock;
let grantsManagerAddress;
let treasuryAddress;
let emissions;
let xAllocationVoting;
let contractToPassToMethods;
let treasuryContract;
let grantsManagerInterface;
(0, mocha_1.beforeEach)(async function () {
const fixture = await (0, fixture_test_1.setupGovernanceFixtureWithEmissions)();
governor = fixture.governor;
vot3 = fixture.vot3;
b3tr = fixture.b3tr;
minterAccount = fixture.minterAccount;
proposer = fixture.proposer;
secondaryAccount = fixture.otherAccount;
treasury = fixture.treasury;
grantsManager = fixture.grantsManager;
owner = fixture.owner;
voter = fixture.voter;
veBetterPassport = fixture.veBetterPassport;
timeLock = fixture.timeLock;
emissions = fixture.emissions;
xAllocationVoting = fixture.xAllocationVoting;
outsider = fixture.otherAccounts[2];
approver = fixture.otherAccounts[3];
await emissions.connect(minterAccount).start();
await (0, fixture_test_1.setupProposer)(proposer, b3tr, vot3, minterAccount);
await (0, fixture_test_1.setupVoter)(voter, b3tr, vot3, minterAccount, owner, veBetterPassport);
await vot3.connect(proposer).approve(await governor.getAddress(), hardhat_1.ethers.parseEther("1000"));
grantsManagerAddress = await grantsManager.getAddress();
treasuryAddress = await treasury.getAddress();
treasuryContract = await hardhat_1.ethers.getContractFactory("Treasury");
contractToPassToMethods = {
b3tr,
vot3,
minterAccount,
governor,
treasury,
emissions,
xAllocationVoting,
veBetterPassport,
owner,
timeLock,
grantsManager,
};
grantsManagerInterface = typechain_types_1.GrantsManager__factory.createInterface();
});
async function createGrantWithSecondaryReceiver() {
const description = `metadata-access-${Date.now()}-${Math.random()}`;
const milestonesDetailsMetadataURI = "ipfs://Qm-initial";
const values = [hardhat_1.ethers.parseEther("10000"), hardhat_1.ethers.parseEther("10000")];
const { proposalId } = await (0, common_1.createProposalWithMultipleFunctionsAndExecuteItGrant)(proposer, voter, [treasury, treasury], treasuryContract, description, ["transferB3TR", "transferB3TR"], [
[grantsManagerAddress, values[0]],
[grantsManagerAddress, values[1]],
], "0", secondaryAccount.address, milestonesDetailsMetadataURI, contractToPassToMethods);
return BigInt(proposalId);
}
(0, mocha_1.it)("reports version 3", async () => {
(0, chai_1.expect)(await grantsManager.version()).to.equal(3n);
});
(0, mocha_1.it)("proposer can update milestone metadata URI", async () => {
const proposalId = await createGrantWithSecondaryReceiver();
const newURI = "ipfs://Qm-proposer";
await grantsManager.connect(proposer).updateMilestoneMetadataURI(proposalId, newURI);
(0, chai_1.expect)((await grantsManager.getGrantProposal(proposalId)).metadataURI).to.equal(newURI);
});
(0, mocha_1.it)("grants receiver can update milestone metadata URI (V3)", async () => {
const proposalId = await createGrantWithSecondaryReceiver();
const newURI = "ipfs://Qm-receiver";
await grantsManager.connect(secondaryAccount).updateMilestoneMetadataURI(proposalId, newURI);
(0, chai_1.expect)((await grantsManager.getGrantProposal(proposalId)).metadataURI).to.equal(newURI);
});
(0, mocha_1.it)("GRANTS_APPROVER_ROLE holder can update milestone metadata URI (V3)", async () => {
const proposalId = await createGrantWithSecondaryReceiver();
await grantsManager.connect(owner).grantRole(await grantsManager.GRANTS_APPROVER_ROLE(), approver.address);
const newURI = "ipfs://Qm-approver";
await grantsManager.connect(approver).updateMilestoneMetadataURI(proposalId, newURI);
(0, chai_1.expect)((await grantsManager.getGrantProposal(proposalId)).metadataURI).to.equal(newURI);
});
(0, mocha_1.it)("GOVERNANCE_ROLE holder can update milestone metadata URI (V3)", async () => {
const proposalId = await createGrantWithSecondaryReceiver();
await grantsManager.connect(owner).grantRole(await grantsManager.GOVERNANCE_ROLE(), owner.address);
const newURI = "ipfs://Qm-governance";
await grantsManager.connect(owner).updateMilestoneMetadataURI(proposalId, newURI);
(0, chai_1.expect)((await grantsManager.getGrantProposal(proposalId)).metadataURI).to.equal(newURI);
});
(0, mocha_1.it)("unrelated account cannot update milestone metadata URI", async () => {
const proposalId = await createGrantWithSecondaryReceiver();
await (0, chai_1.expect)(grantsManager.connect(outsider).updateMilestoneMetadataURI(proposalId, "ipfs://Qm-bad")).to.be.revertedWithCustomError({ interface: grantsManagerInterface }, "NotAuthorized");
});
(0, mocha_1.it)("emits MilestoneMetadataURIUpdated for every authorized writer", async () => {
const proposalId = await createGrantWithSecondaryReceiver();
await grantsManager.connect(owner).grantRole(await grantsManager.GRANTS_APPROVER_ROLE(), approver.address);
await (0, chai_1.expect)(grantsManager.connect(proposer).updateMilestoneMetadataURI(proposalId, "ipfs://Qm-p"))
.to.emit(grantsManager, "MilestoneMetadataURIUpdated")
.withArgs(proposalId, "ipfs://Qm-p");
await (0, chai_1.expect)(grantsManager.connect(secondaryAccount).updateMilestoneMetadataURI(proposalId, "ipfs://Qm-r"))
.to.emit(grantsManager, "MilestoneMetadataURIUpdated")
.withArgs(proposalId, "ipfs://Qm-r");
await (0, chai_1.expect)(grantsManager.connect(approver).updateMilestoneMetadataURI(proposalId, "ipfs://Qm-a"))
.to.emit(grantsManager, "MilestoneMetadataURIUpdated")
.withArgs(proposalId, "ipfs://Qm-a");
});
// Silence unused-import lint warnings for helpers referenced via contractToPassToMethods.
void common_1.waitForCurrentRoundToEnd;
});