Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions contracts/Governance/GovernorBravoDelegate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,18 @@ contract GovernorBravoDelegate is GovernorBravoDelegateStorageV2, GovernorBravoE
return votes;
}

/**
* @notice Update address of XVS vault
* @dev Admin only. Update XVS Vault address
* @param xvsVault_ Address of XVS vault
*/
function _setXvsVault(address xvsVault_) external {
require(msg.sender == admin, "GovernorBravo::_setXvsVault: admin only");
require(xvsVault_ != address(0), "GovernorBravo::setXvsVault: invalid xvs address");
emit SetXvsVault(address(xvsVault), xvsVault_);
xvsVault = XvsVaultInterface(xvsVault_);
}

/**
* @notice Sets the new governance guardian
* @param newGuardian the address of the new guardian
Expand Down
3 changes: 3 additions & 0 deletions contracts/Governance/GovernorBravoInterfaces.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ contract GovernorBravoEvents {

/// @notice Emitted when the maximum number of operations in one proposal is updated
event ProposalMaxOperationsUpdated(uint oldMaxOperations, uint newMaxOperations);

///@notice Emitted when address of XVS vault updated
event SetXvsVault(address indexed oldXvsVault, address indexed newXvsVault);
}

/**
Expand Down
72 changes: 72 additions & 0 deletions tests/Fork/GovernanceBravoStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { expect } from "chai";
import { BigNumber, Signer } from "ethers";
import { ethers } from "hardhat";

import {
GovernorBravoDelegate,
GovernorBravoDelegate__factory,
GovernorBravoDelegator,
GovernorBravoDelegator__factory,
} from "../../typechain";
import { forking, initMainnetUser } from "./utils";

const delegatorProxyAddress = "0x2d56dC077072B53571b8252008C60e945108c75a";
const guardianAddress = "0x1C2CAc6ec528c20800B2fe734820D87b581eAA6B";
let governorBravoDelegator: GovernorBravoDelegator;
let admin: string;
let votingDelay: BigNumber;
let pendingAdmin: string;
let implementation: string;
let impersonatedGuardian: Signer;
let governorBravoDelegate: GovernorBravoDelegate;
let votingPeriod: BigNumber;
let proposalThreshold: BigNumber;
let initialProposalId: BigNumber;
let xvsVault: string;
let proposalMaxOperations: BigNumber;
let guardian: string;

async function configureBravo() {
impersonatedGuardian = await initMainnetUser(guardianAddress, ethers.utils.parseEther("2"));
governorBravoDelegator = GovernorBravoDelegator__factory.connect(delegatorProxyAddress, impersonatedGuardian);
governorBravoDelegate = GovernorBravoDelegate__factory.connect(delegatorProxyAddress, impersonatedGuardian);
}

const FORK_MAINNET = process.env.FORK == "true" && process.env.FORKED_NETWORK == "bscmainnet";
if (FORK_MAINNET) {
const blockNumber = 35984931;
forking(blockNumber, async () => {
describe("Governor Bravo Storage Layout Test", async () => {
before(async () => {
await configureBravo();
votingDelay = await governorBravoDelegate.votingDelay();
pendingAdmin = await governorBravoDelegate.pendingAdmin();
implementation = await governorBravoDelegate.implementation();
admin = await governorBravoDelegate.admin();
votingPeriod = await governorBravoDelegate.votingPeriod();
proposalThreshold = await governorBravoDelegate.proposalThreshold();
initialProposalId = await governorBravoDelegate.initialProposalId();
xvsVault = await governorBravoDelegate.xvsVault();
proposalMaxOperations = await governorBravoDelegate.proposalMaxOperations();
guardian = await governorBravoDelegate.guardian();
});
it("Verify states after upgrade", async () => {
const governorBravoDelegateFactory = await ethers.getContractFactory("GovernorBravoDelegate");
const governorBravoDelegateNew = await governorBravoDelegateFactory.deploy();
await governorBravoDelegateNew.deployed();
await governorBravoDelegator.connect(impersonatedGuardian)._setImplementation(governorBravoDelegateNew.address);

expect(votingDelay).equals(await governorBravoDelegate.votingDelay());
expect(pendingAdmin).equals(await governorBravoDelegate.pendingAdmin());
expect(implementation).not.equals(await governorBravoDelegate.implementation());
expect(admin).equals(await governorBravoDelegate.admin());
expect(votingPeriod).equals(await governorBravoDelegate.votingPeriod());
expect(proposalThreshold).equals(await governorBravoDelegate.proposalThreshold());
expect(initialProposalId).equals(await governorBravoDelegate.initialProposalId());
expect(xvsVault).equals(await governorBravoDelegate.xvsVault());
expect(proposalMaxOperations).equals(await governorBravoDelegate.proposalMaxOperations());
expect(guardian).equals(await governorBravoDelegate.guardian());
});
});
});
}
35 changes: 35 additions & 0 deletions tests/Fork/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { impersonateAccount, setBalance } from "@nomicfoundation/hardhat-network-helpers";
import { NumberLike } from "@nomicfoundation/hardhat-network-helpers/dist/src/types";
import { ethers } from "hardhat";
import { network } from "hardhat";

export const setForkBlock = async (blockNumber: number) => {
await network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: process.env[`ARCHIVE_NODE_${process.env.FORKED_NETWORK}`],
blockNumber,
},
},
],
});
};

export const forking = (blockNumber: number, fn: () => void) => {
describe(`At block #${blockNumber}`, () => {
before(async () => {
await setForkBlock(blockNumber);
});
fn();
});
};

export const initMainnetUser = async (user: string, balance?: NumberLike) => {
await impersonateAccount(user);
if (balance !== undefined) {
await setBalance(user, balance);
}
return ethers.getSigner(user);
};
56 changes: 56 additions & 0 deletions tests/Governance/GovernanceBravo/setterTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { FakeContract, MockContract, smock } from "@defi-wonderland/smock";
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import chai from "chai";
import { Signer } from "ethers";
import { ethers } from "hardhat";

import { GovernorBravoDelegate, GovernorBravoDelegate__factory, XVSVault } from "../../../typechain";

const { expect } = chai;
chai.use(smock.matchers);

let root: Signer;
let user: Signer;
let governorBravoDelegate: MockContract<GovernorBravoDelegate>;
let xvsVault: FakeContract<XVSVault>;

type GovernorBravoDelegateFixture = {
governorBravoDelegate: MockContract<GovernorBravoDelegate>;
xvsVault: FakeContract<XVSVault>;
};

async function governorBravoFixture(): Promise<GovernorBravoDelegateFixture> {
const GovernorBravoDelegateFactory = await smock.mock<GovernorBravoDelegate__factory>("GovernorBravoDelegate");
const governorBravoDelegate = await GovernorBravoDelegateFactory.deploy();
const xvsVault = await smock.fake<XVSVault>("XVSVault");
return { governorBravoDelegate, xvsVault };
}
describe("Governance Bravo Setter Test", async () => {
beforeEach(async () => {
[root, user] = await ethers.getSigners();
const contracts = await loadFixture(governorBravoFixture);
({ governorBravoDelegate, xvsVault } = contracts);
await governorBravoDelegate.setVariable("admin", await root.getAddress());
await governorBravoDelegate.setVariable("xvsVault", xvsVault.address);
});

describe("XvsVault setter in Governance Bravo", async () => {
it("Xvs vault address should be updated", async () => {
const newXvsVault = await smock.fake<XVSVault>("XVSVault");
expect(await governorBravoDelegate.xvsVault()).to.equal(xvsVault.address);
await governorBravoDelegate._setXvsVault(newXvsVault.address);
expect(await governorBravoDelegate.xvsVault()).to.equal(newXvsVault.address);
});
it("Revert on unauthorized access", async () => {
const newXvsVault = await smock.fake<XVSVault>("XVSVault");
await expect(governorBravoDelegate.connect(user)._setXvsVault(newXvsVault.address)).to.be.revertedWith(
"GovernorBravo::_setXvsVault: admin only",
);
});
it("Reverts on zero address", async () => {
await expect(governorBravoDelegate._setXvsVault(ethers.constants.AddressZero)).to.be.revertedWith(
"GovernorBravo::setXvsVault: invalid xvs address",
);
});
});
});