From 85d54956de9aee8c37a6b15a5391215116f9ae53 Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Wed, 18 Oct 2023 13:11:19 -0300 Subject: [PATCH 1/4] refactor: update governance deployments --- copy_contracts.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/copy_contracts.sh b/copy_contracts.sh index 898a20e4..588afa0d 100755 --- a/copy_contracts.sh +++ b/copy_contracts.sh @@ -18,13 +18,13 @@ rm -rf contracts/protocol/contracts/test mkdir -p ./contracts/governance/contracts/Governance mkdir -p ./contracts/governance/contracts/legacy -cp ./node_modules/@venusprotocol/governance-contracts/contracts/legacy/GovernorBravoDelegateV1.sol ./contracts/governance/contracts/legacy/GovernorBravoDelegateV1.sol -cp ./node_modules/@venusprotocol/governance-contracts/contracts/legacy/GovernorBravoInterfaces.sol ./contracts/governance/contracts/legacy/GovernorBravoInterfaces.sol -cp ./node_modules/@venusprotocol/governance-contracts/contracts/legacy/GovernorBravoDelegator.sol ./contracts/governance/contracts/legacy/GovernorBravoDelegator.sol +cp -rf ./node_modules/@venusprotocol/governance-contracts/contracts/legacy ./contracts/governance/contracts cp ./node_modules/@venusprotocol/governance-contracts/contracts/Governance/GovernorBravoInterfaces.sol ./contracts/governance/contracts/Governance/GovernorBravoInterfaces.sol rm contracts/protocol/contracts/Governance/GovernorBravoDelegate.sol rm contracts/protocol/contracts/Governance/GovernorBravoDelegator.sol +rm contracts/protocol/contracts/Governance/GovernorAlpha.sol +rm contracts/protocol/contracts/Governance/GovernorAlpha2.sol rm contracts/protocol/contracts/Governance/Timelock.sol rm -rf contracts/protocol/contracts/Lens/VenusLens.sol From 50c80d8179e89c95a3c5898f4fc9d4918dbeb29d Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Fri, 20 Oct 2023 12:42:13 -0300 Subject: [PATCH 2/4] tests: add governance bravo tests --- deploy/018-governance.ts | 7 + subgraphs/venus-governance/schema.graphql | 2 +- .../tests/integration/bravo.ts | 379 ++++++++++++++++++ .../tests/integration/index.ts | 2 +- .../queries/proposalByIdQuery.graphql | 1 + .../queries/proposalsQuery.graphql | 1 + 6 files changed, 390 insertions(+), 2 deletions(-) create mode 100644 subgraphs/venus-governance/tests/integration/bravo.ts diff --git a/deploy/018-governance.ts b/deploy/018-governance.ts index 6dfdd8e0..300a5a94 100644 --- a/deploy/018-governance.ts +++ b/deploy/018-governance.ts @@ -125,6 +125,13 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { log: true, autoMine: true, }); + + await deploy('GovernorBravoDelegate', { + from: deployer, + args: [], + log: true, + autoMine: true, + }); }; func.tags = ['Governance']; diff --git a/subgraphs/venus-governance/schema.graphql b/subgraphs/venus-governance/schema.graphql index 39e3bb26..c0b77821 100644 --- a/subgraphs/venus-governance/schema.graphql +++ b/subgraphs/venus-governance/schema.graphql @@ -26,7 +26,7 @@ type Delegate @entity { enum PROPOSAL_TYPE { NORMAL - FASTRACK + FAST_TRACK CRITICAL } diff --git a/subgraphs/venus-governance/tests/integration/bravo.ts b/subgraphs/venus-governance/tests/integration/bravo.ts new file mode 100644 index 00000000..3b13cc85 --- /dev/null +++ b/subgraphs/venus-governance/tests/integration/bravo.ts @@ -0,0 +1,379 @@ +import { mine } from '@nomicfoundation/hardhat-network-helpers'; +import '@nomiclabs/hardhat-ethers'; +import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { Contract } from 'ethers'; +import { ethers, network } from 'hardhat'; +import { waitForSubgraphToBeSynced } from 'venus-subgraph-utils'; + +import subgraphClient from '../../subgraph-client/index'; +import { SYNC_DELAY, mockAddress } from './utils/constants'; + +describe('GovernorBravo', function () { + let signers: SignerWithAddress[]; + let governorBravo: Contract; + let governorBravoDelegator: Contract; + + before(async function () { + this.timeout(50000000); // sometimes it takes a long time + signers = await ethers.getSigners(); + governorBravoDelegator = await ethers.getContract('GovernorBravoDelegatorV1'); + const governorBravoDelegateV1 = await ethers.getContract('GovernorBravoDelegateV1'); + governorBravo = await ethers.getContractAt( + 'GovernorBravoDelegateV1', + governorBravoDelegator.address, + ); + + // Setup first governor Bravo + await governorBravoDelegator._setImplementation(governorBravoDelegateV1.address); + const governorAlpha2 = await ethers.getContract('GovernorAlpha2'); + + // Impersonating timelock for convenience + const timelock = await ethers.getContract('Timelock'); + + await signers[0].sendTransaction({ + to: timelock.address, + value: ethers.utils.parseEther('1.0'), // Sends exactly 1.0 ether + }); + + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [timelock.address], + }); + const timelockSigner = await ethers.getSigner(timelock.address); + + await timelock.connect(timelockSigner).setPendingAdmin(governorBravoDelegator.address); + + await network.provider.request({ + method: 'hardhat_stopImpersonatingAccount', + params: [timelock.address], + }); + + await governorBravo._initiate(governorAlpha2.address); + // Finished setup + await waitForSubgraphToBeSynced(SYNC_DELAY); + }); + + describe('GovernorBravo V1', function () { + it('should index created proposal before routes successfully', async function () { + const [_, _1, _2, _3, user4] = signers; + + const callData = ethers.utils.defaultAbiCoder.encode(['address'], [mockAddress]); + + const vip = [ + ['0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396'], // targets + ['0'], // values + ['setPendingAdmin(address)'], // signatures + [callData], // params + 'Bravo Test proposal', // description + ]; + + const tx = await governorBravo.connect(user4).propose(...vip); + await tx.wait(1); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('22'); + expect(proposal.id).to.be.equal('22'); + expect(proposal.description).to.be.equal('Bravo Test proposal'); + expect(proposal.executionEta).to.be.null; + expect(proposal.targets).to.deep.equal([ + '0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396'.toLowerCase(), + ]); + expect(proposal.values).to.deep.equal(['0']); + expect(proposal.signatures).to.deep.equal(['setPendingAdmin(address)']); + expect(proposal.calldatas).to.deep.equal([callData]); + expect(proposal.type).to.equal('NORMAL'); + }); + + it('index for vote cast Bravo V1', async function () { + const [_, user1, user2] = signers; + + await mine(1); + + await governorBravo.connect(user1).castVote('22', 0); + await governorBravo.connect(user2).castVote('22', 1); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('22'); + expect(proposal.votes.length).to.be.equal(2); + + const { + data: { delegate: delegate1 }, + } = await subgraphClient.getDelegateById(user1.address.toLowerCase()); + + expect(delegate1.votes[1].id).to.equal(`${user1.address.toLowerCase()}-22`); + expect(delegate1.votes[1].support).to.equal('AGAINST'); + expect(delegate1.votes[1].votes).to.equal('700000000000000000000000'); + expect(delegate1.votes[1].proposal.id).to.equal('22'); + expect(delegate1.proposals.length).to.equal(1); + + const { + data: { delegate: delegate2 }, + } = await subgraphClient.getDelegateById(user2.address.toLowerCase()); + expect(delegate2.votes[1].id).to.equal(`${user2.address.toLowerCase()}-22`); + expect(delegate2.votes[1].support).to.equal('FOR'); + expect(delegate2.votes[1].votes).to.equal('200000000000000000000000'); + expect(delegate2.votes[1].proposal.id).to.equal('22'); + expect(delegate2.proposals).to.deep.equal([]); + }); + + it('should index cancelled proposal event', async function () { + await governorBravo.connect(signers[0]).cancel('22'); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('22'); + + expect(proposal.canceled).to.equal(true); + }); + + it('should index queued proposal event', async function () { + const user4 = signers[4]; + const user3 = signers[3]; + const callData = ethers.utils.defaultAbiCoder.encode(['address'], [mockAddress]); + const vip = [ + ['0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396'], // targets + ['0'], // values + ['setPendingAdmin(address)'], // signatures + [callData], // params + 'Bravo Test proposal 23', // description + ]; + + await governorBravo.connect(user4).propose(...vip); + mine(1); + await governorBravo.connect(user3).castVote('23', 1); + await governorBravo.connect(user4).castVote('23', 1); + + let votingPeriod = +(await governorBravo.votingPeriod()); + while (votingPeriod > 0) { + votingPeriod--; + await mine(1); + } + await waitForSubgraphToBeSynced(SYNC_DELAY); + + await governorBravo.queue(23); + + const governorAlpha2Timelock = await ethers.getContract('Timelock'); + const eta = + (await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp + + +(await governorAlpha2Timelock.delay()); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('23'); + + expect(proposal.queued).to.equal(true); + expect(proposal.executionEta).to.equal(eta.toString()); + + await ethers.provider.send('evm_setNextBlockTimestamp', [eta + 1]); + }); + + it('should index succeeded proposal event', async function () { + await governorBravo.execute('23'); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('23'); + + expect(proposal.executed).to.equal(true); + }); + }); + + describe('GovernorBravo2', function () { + before(async () => { + const governorBravoDelegatorV2 = await ethers.getContract('GovernorBravoDelegate'); + const xvsVaultProxy = await ethers.getContract('XVSVaultProxy'); + const xvsVault = await ethers.getContractAt('XVSVault', xvsVaultProxy.address); + const timelock = await ethers.getContract('Timelock'); + + await governorBravoDelegator._setImplementation(governorBravoDelegatorV2.address); + governorBravo = await ethers.getContractAt('GovernorBravoDelegate', governorBravo.address); + const minVotingDelay = await governorBravo.MIN_VOTING_DELAY(); + const minVotingPeriod = await governorBravo.MIN_VOTING_PERIOD(); + const minProposalThreshold = await governorBravo.MIN_PROPOSAL_THRESHOLD(); + + const proposalConfigs = [ + { + votingDelay: minVotingDelay, + votingPeriod: minVotingPeriod.add(3), + proposalThreshold: minProposalThreshold.add(1), + }, + { + votingDelay: minVotingDelay, + votingPeriod: minVotingPeriod.add(2), + proposalThreshold: minProposalThreshold.add(2), + }, + { + votingDelay: minVotingDelay, + votingPeriod: minVotingPeriod.add(1), + proposalThreshold: minProposalThreshold.add(3), + }, + ]; + + const timelocks = [timelock.address, timelock.address, timelock.address]; + + governorBravo.initialize(xvsVault.address, proposalConfigs, timelocks, signers[0].address); + }); + + it('should index created proposal with routes successfully', async function () { + const [_, _1, _2, _3, user4] = signers; + const callData = ethers.utils.defaultAbiCoder.encode(['address'], [governorBravo.address]); + + const vip = [ + ['0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396'], // targets + ['0'], // values + ['setPendingAdmin(address)'], // signatures + [callData], // params + 'Test proposal 24', // description + 1, // route + ]; + + const tx = await governorBravo.connect(user4).propose(...vip); + await tx.wait(1); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('24'); + expect(proposal.id).to.be.equal('24'); + expect(proposal.description).to.be.equal('Test proposal 24'); + expect(proposal.executionEta).to.be.null; + expect(proposal.targets).to.deep.equal([ + '0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396'.toLowerCase(), + ]); + expect(proposal.values).to.deep.equal(['0']); + expect(proposal.signatures).to.deep.equal(['setPendingAdmin(address)']); + expect(proposal.calldatas).to.deep.equal([callData]); + expect(proposal.type).to.equal('FAST_TRACK'); + }); + + it('index for vote cast', async function () { + const [_, user1, user2, user3, user4] = signers; + + await mine(1); + + await governorBravo.connect(user1).castVote('24', 0); + await governorBravo.connect(user2).castVote('24', 2); + await governorBravo.connect(user3).castVote('24', 1); + await governorBravo.connect(user4).castVote('24', 1); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('1'); + expect(proposal.votes.length).to.be.equal(4); + + const { + data: { delegate: delegate1 }, + } = await subgraphClient.getDelegateById(user1.address.toLowerCase()); + + expect(delegate1.votes[2].id).to.equal(`${user1.address.toLowerCase()}-24`); + expect(delegate1.votes[2].support).to.equal('AGAINST'); + expect(delegate1.votes[2].votes).to.equal('700000000000000000000000'); + expect(delegate1.votes[2].proposal.id).to.equal('24'); + expect(delegate1.proposals.length).to.equal(1); + + const { + data: { delegate: delegate2 }, + } = await subgraphClient.getDelegateById(user2.address.toLowerCase()); + expect(delegate2.votes[2].id).to.equal(`${user2.address.toLowerCase()}-24`); + expect(delegate2.votes[2].support).to.equal('ABSTAIN'); + expect(delegate2.votes[2].votes).to.equal('200000000000000000000000'); + expect(delegate1.votes[2].proposal.id).to.equal('24'); + expect(delegate2.proposals.length).to.equal(0); + + const { + data: { delegate: delegate4 }, + } = await subgraphClient.getDelegateById(user4.address.toLowerCase()); + expect(delegate4.proposals.length).to.equal(4); + }); + + it('should index cancelled proposal event', async function () { + await governorBravo.connect(signers[0]).cancel('24'); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('24'); + + expect(proposal.canceled).to.equal(true); + }); + + it('should index queued proposal event', async function () { + const user3 = signers[3]; + const user4 = signers[4]; + const callData = ethers.utils.defaultAbiCoder.encode(['address'], [mockAddress]); + const vip = [ + ['0x939bD8d64c0A9583A7Dcea9933f7b21697ab6396'], // targets + ['0'], // values + ['setPendingAdmin(address)'], // signatures + [callData], // params + 'Bravo Test proposal 25', // description + 0, + ]; + + const tx = await governorBravo.connect(user4).propose(...vip); // + await tx.wait(1); + + await mine(1); + + await governorBravo.connect(user3).castVote('25', 1); + await governorBravo.connect(user4).castVote('25', 1); + + await mine(1); + + let votingPeriod = +(await governorBravo.proposalConfigs(0)).votingPeriod; + + while (votingPeriod > 0) { + votingPeriod--; + await mine(1); + } + await waitForSubgraphToBeSynced(SYNC_DELAY); + + await governorBravo.queue(25); + + const governorBravoTimelock = await ethers.getContract('Timelock'); + const eta = + (await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp + + +(await governorBravoTimelock.delay()); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('25'); + + expect(proposal.queued).to.equal(true); + expect(proposal.executionEta).to.equal(eta.toString()); + + await ethers.provider.send('evm_setNextBlockTimestamp', [eta + 1]); + }); + + it('should index succeeded proposal event', async function () { + await governorBravo.execute('25'); + + await waitForSubgraphToBeSynced(SYNC_DELAY); + + const { + data: { proposal }, + } = await subgraphClient.getProposalById('25'); + + expect(proposal.executed).to.equal(true); + }); + }); +}); diff --git a/subgraphs/venus-governance/tests/integration/index.ts b/subgraphs/venus-governance/tests/integration/index.ts index 78652357..12487e1d 100644 --- a/subgraphs/venus-governance/tests/integration/index.ts +++ b/subgraphs/venus-governance/tests/integration/index.ts @@ -1,6 +1,6 @@ import './setup'; import './xvsVault'; import './alpha'; -// import './bravo'; +import './bravo'; import './accessControlManager'; diff --git a/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql b/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql index 61e98f37..89b4f54f 100644 --- a/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql +++ b/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql @@ -15,6 +15,7 @@ query ProposalById($id: ID!) { queued canceled executed + type votes { id votes diff --git a/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql b/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql index 78f26d30..b2420b92 100644 --- a/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql +++ b/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql @@ -15,6 +15,7 @@ query Proposals { queued canceled executed + type votes { id votes From 2e94731fa6f734367ac029ec4bec64740886547a Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Tue, 24 Oct 2023 08:38:25 -0300 Subject: [PATCH 3/4] refactor: remove manually set timeouts in favor of config --- subgraphs/isolated-pools/tests/integration/pool.ts | 1 - subgraphs/isolated-pools/tests/integration/poolRegistry.ts | 2 -- subgraphs/isolated-pools/tests/integration/setup.ts | 1 - subgraphs/isolated-pools/tests/integration/vTokens.ts | 2 -- .../tests/integration/accessControlManager.ts | 2 -- subgraphs/venus-governance/tests/integration/alpha.ts | 4 ---- subgraphs/venus-governance/tests/integration/bravo.ts | 1 - subgraphs/venus-governance/tests/integration/setup.ts | 1 - subgraphs/venus-governance/tests/integration/xvsVault.ts | 1 - 9 files changed, 15 deletions(-) diff --git a/subgraphs/isolated-pools/tests/integration/pool.ts b/subgraphs/isolated-pools/tests/integration/pool.ts index 714a67d0..df1d9e36 100644 --- a/subgraphs/isolated-pools/tests/integration/pool.ts +++ b/subgraphs/isolated-pools/tests/integration/pool.ts @@ -15,7 +15,6 @@ describe('Pools', function () { const syncDelay = 6000; before(async function () { - this.timeout(500000); // sometimes it takes a long time const signers = await ethers.getSigners(); [root] = await ethers.getSigners(); acc1 = signers[1]; diff --git a/subgraphs/isolated-pools/tests/integration/poolRegistry.ts b/subgraphs/isolated-pools/tests/integration/poolRegistry.ts index c753ab91..27289da2 100644 --- a/subgraphs/isolated-pools/tests/integration/poolRegistry.ts +++ b/subgraphs/isolated-pools/tests/integration/poolRegistry.ts @@ -19,8 +19,6 @@ describe('Pool Registry', function () { const syncDelay = 2000; before(async function () { - this.timeout(500000); // sometimes it takes a long time - [root] = await ethers.getSigners(); poolRegistry = await ethers.getContract('PoolRegistry'); diff --git a/subgraphs/isolated-pools/tests/integration/setup.ts b/subgraphs/isolated-pools/tests/integration/setup.ts index 85e73d98..c404b06a 100644 --- a/subgraphs/isolated-pools/tests/integration/setup.ts +++ b/subgraphs/isolated-pools/tests/integration/setup.ts @@ -4,7 +4,6 @@ import { SUBGRAPH_ACCOUNT, SUBGRAPH_NAME, SYNC_DELAY } from './constants'; describe('Deploy Subgraph', function () { it('should deploy subgraph', async function () { - this.timeout(500000); // sometimes it takes a long time const root = `${__dirname}/../..`; await deploy({ diff --git a/subgraphs/isolated-pools/tests/integration/vTokens.ts b/subgraphs/isolated-pools/tests/integration/vTokens.ts index e604ff14..d5a3fd50 100644 --- a/subgraphs/isolated-pools/tests/integration/vTokens.ts +++ b/subgraphs/isolated-pools/tests/integration/vTokens.ts @@ -31,8 +31,6 @@ describe('VToken events', function () { const borrowAmount = scaleValue(0.000025, 18); before(async function () { - this.timeout(500000); // sometimes it takes a long time - const signers = await ethers.getSigners(); [_root, liquidator, borrower, liquidator2, borrower2, supplier1, supplier2] = signers; diff --git a/subgraphs/venus-governance/tests/integration/accessControlManager.ts b/subgraphs/venus-governance/tests/integration/accessControlManager.ts index d4a32766..392b5a93 100644 --- a/subgraphs/venus-governance/tests/integration/accessControlManager.ts +++ b/subgraphs/venus-governance/tests/integration/accessControlManager.ts @@ -8,8 +8,6 @@ import { SYNC_DELAY } from './utils/constants'; describe('AccessControlManager', function () { before(async function () { - this.timeout(50000000); // sometimes it takes a long time - await waitForSubgraphToBeSynced(SYNC_DELAY); }); diff --git a/subgraphs/venus-governance/tests/integration/alpha.ts b/subgraphs/venus-governance/tests/integration/alpha.ts index 0d0f5116..a1452fb9 100644 --- a/subgraphs/venus-governance/tests/integration/alpha.ts +++ b/subgraphs/venus-governance/tests/integration/alpha.ts @@ -21,7 +21,6 @@ describe('GovernorAlpha', function () { let user4: SignerWithAddress; before(async function () { - this.timeout(10000000); // sometimes it takes a long time governorAlpha = await ethers.getContract('GovernorAlpha'); governorAlpha2 = await ethers.getContract('GovernorAlpha2'); signers = await ethers.getSigners(); @@ -121,9 +120,6 @@ describe('GovernorAlpha', function () { }); describe('Alpha2', function () { - before(async function () { - this.timeout(10000000); // sometimes it takes a long time - }); it('indexes created proposals - alpha2', async function () { const [_, user1] = signers; await enfranchiseAccount(user1, scaleValue(600000, 18)); diff --git a/subgraphs/venus-governance/tests/integration/bravo.ts b/subgraphs/venus-governance/tests/integration/bravo.ts index 3b13cc85..2ddf37fc 100644 --- a/subgraphs/venus-governance/tests/integration/bravo.ts +++ b/subgraphs/venus-governance/tests/integration/bravo.ts @@ -15,7 +15,6 @@ describe('GovernorBravo', function () { let governorBravoDelegator: Contract; before(async function () { - this.timeout(50000000); // sometimes it takes a long time signers = await ethers.getSigners(); governorBravoDelegator = await ethers.getContract('GovernorBravoDelegatorV1'); const governorBravoDelegateV1 = await ethers.getContract('GovernorBravoDelegateV1'); diff --git a/subgraphs/venus-governance/tests/integration/setup.ts b/subgraphs/venus-governance/tests/integration/setup.ts index b3b9d768..d1658cea 100644 --- a/subgraphs/venus-governance/tests/integration/setup.ts +++ b/subgraphs/venus-governance/tests/integration/setup.ts @@ -4,7 +4,6 @@ import { SUBGRAPH_ACCOUNT, SUBGRAPH_NAME, SYNC_DELAY } from './utils/constants'; describe('Deploy Subgraph', function () { it('should deploy subgraph', async function () { - this.timeout(600000); // sometimes it takes a long time const root = `${__dirname}/../..`; await deploy({ diff --git a/subgraphs/venus-governance/tests/integration/xvsVault.ts b/subgraphs/venus-governance/tests/integration/xvsVault.ts index ff7169da..ff5e818f 100644 --- a/subgraphs/venus-governance/tests/integration/xvsVault.ts +++ b/subgraphs/venus-governance/tests/integration/xvsVault.ts @@ -16,7 +16,6 @@ describe('XVS Vault and Delegation', function () { const amount = scaleValue(100000, 18); before(async function () { - this.timeout(50000000); // sometimes it takes a long time signers = await ethers.getSigners(); xvs = await ethers.getContract('XVS'); From 25f225af78a3b289cd296d07c1548e7fbdb222ac Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Tue, 24 Oct 2023 18:48:58 -0300 Subject: [PATCH 4/4] test: add governance entity tests --- subgraphs/venus-governance/schema.graphql | 19 +---- .../venus-governance/src/constants/index.ts | 4 ++ .../venus-governance/src/mappings/bravo.ts | 2 + .../venus-governance/src/operations/create.ts | 2 +- .../venus-governance/src/operations/get.ts | 71 +++---------------- .../venus-governance/src/operations/update.ts | 23 +++++- .../venus-governance/src/utilities/ids.ts | 4 +- .../venus-governance/subgraph-client/index.ts | 6 ++ .../tests/integration/bravo.ts | 35 ++++++++- .../queries/governanceQuery.graphql | 15 ++++ .../tests/integration/utils/constants.ts | 1 + .../tests/unit/Bravo/index.test.ts | 34 ++------- 12 files changed, 100 insertions(+), 116 deletions(-) create mode 100644 subgraphs/venus-governance/tests/integration/queries/governanceQuery.graphql diff --git a/subgraphs/venus-governance/schema.graphql b/subgraphs/venus-governance/schema.graphql index c0b77821..9395b2cf 100644 --- a/subgraphs/venus-governance/schema.graphql +++ b/subgraphs/venus-governance/schema.graphql @@ -105,7 +105,7 @@ type Governance @entity { id: ID! "Number of proposals created" - proposals: BigInt! + totalProposals: BigInt! "Total number of accounts delegates that can participate in governance by voting or creating proposals" totalDelegates: BigInt! @@ -135,23 +135,6 @@ type Governance @entity { proposalMaxOperations: BigInt! } -type GovernanceRoute @entity { - "Index of the governance route" - id: ID! - "Governor implementation the route belongs to" - governor: Bytes! - "Address of timelock contract for route" - timelock: Bytes! - "Queue execution delay in blocks" - queueDelayBlocks: BigInt! - "The delay before voting on a proposal may take place, once proposed, in blocks" - votingDelayBlocks: BigInt! - "The duration of voting on a proposal, in blocks" - votingPeriodBlocks: BigInt! - "The number of votes required in order for a voter to become a proposer" - proposalThresholdMantissa: BigInt! -} - enum PermissionStatus { GRANTED, REVOKED diff --git a/subgraphs/venus-governance/src/constants/index.ts b/subgraphs/venus-governance/src/constants/index.ts index 0e2165d0..02756775 100644 --- a/subgraphs/venus-governance/src/constants/index.ts +++ b/subgraphs/venus-governance/src/constants/index.ts @@ -4,6 +4,10 @@ export const BIGINT_ZERO = BigInt.fromI32(0); export const BIGINT_ONE = BigInt.fromI32(1); export const BIGDECIMAL_ZERO = new BigDecimal(BIGINT_ZERO); +// Ids +export const GOVERNANCE = 'GOVERNANCE'; +export const SEPERATOR = '-'; + // Vote support export const FOR = 'FOR'; export const AGAINST = 'AGAINST'; diff --git a/subgraphs/venus-governance/src/mappings/bravo.ts b/subgraphs/venus-governance/src/mappings/bravo.ts index d5ebaccb..07c36c67 100644 --- a/subgraphs/venus-governance/src/mappings/bravo.ts +++ b/subgraphs/venus-governance/src/mappings/bravo.ts @@ -16,6 +16,7 @@ import { createProposal, createVoteBravo } from '../operations/create'; import { getGovernanceEntity } from '../operations/get'; import { getOrCreateDelegate } from '../operations/getOrCreate'; import { + updateGovernanceEntity, updateProposalCanceled, updateProposalExecuted, updateProposalQueued, @@ -54,6 +55,7 @@ export function handleNewImplementation(event: NewImplementation): void { const governance = getGovernanceEntity(); governance.implementation = event.params.newImplementation; governance.save(); + updateGovernanceEntity(); } export function handleNewPendingAdmin(event: NewPendingAdmin): void { diff --git a/subgraphs/venus-governance/src/operations/create.ts b/subgraphs/venus-governance/src/operations/create.ts index 2acc7f58..ec0903d5 100644 --- a/subgraphs/venus-governance/src/operations/create.ts +++ b/subgraphs/venus-governance/src/operations/create.ts @@ -13,7 +13,7 @@ export function createProposal(event: E): Proposal { const governance = getGovernanceEntity(); - governance.proposals = governance.proposals.plus(BIGINT_ONE); + governance.totalProposals = governance.totalProposals.plus(BIGINT_ONE); governance.save(); const targets = event.params.targets.map((address: Address) => Bytes.fromHexString(address.toHexString()), diff --git a/subgraphs/venus-governance/src/operations/get.ts b/subgraphs/venus-governance/src/operations/get.ts index 24711309..fe83c213 100644 --- a/subgraphs/venus-governance/src/operations/get.ts +++ b/subgraphs/venus-governance/src/operations/get.ts @@ -1,22 +1,20 @@ -import { Address, BigInt, log } from '@graphprotocol/graph-ts'; +import { Address, log } from '@graphprotocol/graph-ts'; -import { GovernorBravoDelegate2 } from '../../generated/GovernorBravoDelegate2/GovernorBravoDelegate2'; -import { Timelock } from '../../generated/GovernorBravoDelegate2/Timelock'; -import { Delegate, Governance, GovernanceRoute, Proposal } from '../../generated/schema'; +import { Delegate, Governance, Proposal } from '../../generated/schema'; import { BIGINT_ZERO } from '../constants'; -import { governorBravoDelegatorAddress, nullAddress } from '../constants/addresses'; -import { getDelegateId } from '../utilities/ids'; +import { nullAddress } from '../constants/addresses'; +import { getDelegateId, getGovernanceId } from '../utilities/ids'; /** * While technically this function does also create, we don't care because it only happens once as the id is a constant. + * The initial values are mocked because they are updated when an implementation is set * @returns Governance */ export const getGovernanceEntity = (): Governance => { - let governance = Governance.load(governorBravoDelegatorAddress.toHex()); + let governance = Governance.load(getGovernanceId()); if (!governance) { - const governorBravoDelegate2 = GovernorBravoDelegate2.bind(governorBravoDelegatorAddress); - governance = new Governance(governorBravoDelegatorAddress.toHex()); - governance.proposals = BIGINT_ZERO; + governance = new Governance(getGovernanceId()); + governance.totalProposals = BIGINT_ZERO; governance.totalDelegates = BIGINT_ZERO; governance.totalVoters = BIGINT_ZERO; governance.totalVotesMantissa = BIGINT_ZERO; @@ -26,59 +24,6 @@ export const getGovernanceEntity = (): Governance => { governance.guardian = nullAddress; governance.quorumVotesMantissa = BIGINT_ZERO; governance.proposalMaxOperations = BIGINT_ZERO; - - // There is only one active governance entity - // but while indexing proposals created with previous governance contracts all these calls will fail - // This method only exists on the latest governance interface so if it succeeds we can safely index the contract - const normalProposalConfigResult = governorBravoDelegate2.try_proposalConfigs(new BigInt(0)); - if (normalProposalConfigResult.reverted === false) { - governance.admin = governorBravoDelegate2.admin(); - governance.implementation = governorBravoDelegate2.implementation(); - governance.guardian = governorBravoDelegate2.guardian(); - governance.quorumVotesMantissa = governorBravoDelegate2.quorumVotes(); - governance.proposalMaxOperations = governorBravoDelegate2.proposalMaxOperations(); - // Governance Routes are set in initialization - // Normal - const normalProposalConfig = normalProposalConfigResult.value; - const normalTimelockAddress = governorBravoDelegate2.proposalTimelocks(new BigInt(0)); - const normalTimelock = Timelock.bind(normalTimelockAddress); - const normalGovernanceRoute = new GovernanceRoute('0'); - normalGovernanceRoute.governor = governorBravoDelegatorAddress; - normalGovernanceRoute.timelock = normalTimelockAddress; - normalGovernanceRoute.queueDelayBlocks = normalTimelock.delay(); - normalGovernanceRoute.votingDelayBlocks = normalProposalConfig.getVotingDelay(); - normalGovernanceRoute.votingPeriodBlocks = normalProposalConfig.getVotingPeriod(); - normalGovernanceRoute.proposalThresholdMantissa = normalProposalConfig.getProposalThreshold(); - normalGovernanceRoute.save(); - // Fast track - const fastTrackProposalConfig = governorBravoDelegate2.proposalConfigs(new BigInt(1)); - const fastTrackTimelockAddress = governorBravoDelegate2.proposalTimelocks(new BigInt(1)); - const fastTrackTimelock = Timelock.bind(normalTimelockAddress); - const fastTrackGovernanceRoute = new GovernanceRoute('1'); - fastTrackGovernanceRoute.governor = governorBravoDelegatorAddress; - fastTrackGovernanceRoute.timelock = fastTrackTimelockAddress; - fastTrackGovernanceRoute.queueDelayBlocks = fastTrackTimelock.delay(); - fastTrackGovernanceRoute.votingDelayBlocks = fastTrackProposalConfig.getVotingDelay(); - fastTrackGovernanceRoute.votingPeriodBlocks = fastTrackProposalConfig.getVotingPeriod(); - fastTrackGovernanceRoute.proposalThresholdMantissa = - fastTrackProposalConfig.getProposalThreshold(); - fastTrackGovernanceRoute.save(); - // Critical - const criticalProposalConfig = governorBravoDelegate2.proposalConfigs(new BigInt(2)); - const criticalTimelockAddress = governorBravoDelegate2.proposalTimelocks(new BigInt(2)); - const criticalTimelock = Timelock.bind(normalTimelockAddress); - const criticalGovernanceRoute = new GovernanceRoute('2'); - criticalGovernanceRoute.governor = governorBravoDelegatorAddress; - criticalGovernanceRoute.timelock = criticalTimelockAddress; - criticalGovernanceRoute.queueDelayBlocks = criticalTimelock.delay(); - criticalGovernanceRoute.votingDelayBlocks = criticalProposalConfig.getVotingDelay(); - criticalGovernanceRoute.votingPeriodBlocks = criticalProposalConfig.getVotingPeriod(); - criticalGovernanceRoute.proposalThresholdMantissa = - criticalProposalConfig.getProposalThreshold(); - criticalGovernanceRoute.save(); - } - - governance.save(); } return governance as Governance; diff --git a/subgraphs/venus-governance/src/operations/update.ts b/subgraphs/venus-governance/src/operations/update.ts index 90ce90c9..722bfc45 100644 --- a/subgraphs/venus-governance/src/operations/update.ts +++ b/subgraphs/venus-governance/src/operations/update.ts @@ -1,5 +1,8 @@ +import { GovernorBravoDelegate2 } from '../../generated/GovernorBravoDelegate2/GovernorBravoDelegate2'; +import { Governance } from '../../generated/schema'; import { BIGINT_ONE } from '../constants'; -import { nullAddress } from '../constants/addresses'; +import { governorBravoDelegatorAddress, nullAddress } from '../constants/addresses'; +import { getGovernanceId } from '../utilities/ids'; import { getGovernanceEntity, getProposal } from './get'; import { getOrCreateDelegate } from './getOrCreate'; @@ -44,8 +47,10 @@ export function updateDelegateChanged(event: E): void { const oldDelegate = oldDelegateResult.entity; oldDelegate.delegateCount = oldDelegate.delegateCount - 1; oldDelegate.save(); + } - governance.totalDelegates = governance.totalDelegates.minus(BIGINT_ONE); + if (fromDelegate == nullAddress.toHexString()) { + governance.totalDelegates = governance.totalDelegates.plus(BIGINT_ONE); governance.save(); } @@ -54,8 +59,10 @@ export function updateDelegateChanged(event: E): void { const newDelegate = newDelegateResult.entity; newDelegate.delegateCount = newDelegate.delegateCount + 1; newDelegate.save(); + } - governance.totalDelegates = governance.totalDelegates.plus(BIGINT_ONE); + if (fromDelegate == nullAddress.toHexString()) { + governance.totalDelegates = governance.totalDelegates.minus(BIGINT_ONE); governance.save(); } } @@ -76,3 +83,13 @@ export function updateDelegateVoteChanged(event: E): void { governance.totalVotesMantissa = governance.totalVotesMantissa.plus(votesDifference); governance.save(); } + +export function updateGovernanceEntity(): void { + const governorBravoDelegate2 = GovernorBravoDelegate2.bind(governorBravoDelegatorAddress); + const governance = Governance.load(getGovernanceId())!; + governance.quorumVotesMantissa = governorBravoDelegate2.quorumVotes(); + governance.admin = governorBravoDelegate2.admin(); + governance.guardian = governorBravoDelegate2.guardian(); + governance.proposalMaxOperations = governorBravoDelegate2.proposalMaxOperations(); + governance.save(); +} diff --git a/subgraphs/venus-governance/src/utilities/ids.ts b/subgraphs/venus-governance/src/utilities/ids.ts index 6db7fd40..ac63891d 100644 --- a/subgraphs/venus-governance/src/utilities/ids.ts +++ b/subgraphs/venus-governance/src/utilities/ids.ts @@ -1,6 +1,6 @@ import { Address, BigInt } from '@graphprotocol/graph-ts'; -const SEPERATOR = '-'; +import { GOVERNANCE, SEPERATOR } from '../constants'; export const getVoteId = (voter: Address, proposalId: BigInt): string => [voter.toHexString(), proposalId.toString()].join(SEPERATOR); @@ -13,3 +13,5 @@ export const getPermissionId = ( [accountAddress.toHexString(), contractAddress.toHexString(), functionSig].join(SEPERATOR); export const getDelegateId = (account: Address): string => account.toHexString(); + +export const getGovernanceId = (): string => GOVERNANCE; diff --git a/subgraphs/venus-governance/subgraph-client/index.ts b/subgraphs/venus-governance/subgraph-client/index.ts index 04a43258..b494905a 100644 --- a/subgraphs/venus-governance/subgraph-client/index.ts +++ b/subgraphs/venus-governance/subgraph-client/index.ts @@ -4,6 +4,7 @@ import { Client as UrqlClient, createClient } from 'urql/core'; import { DelegateByIdDocument, DelegatesDocument, + GovernanceDocument, PermissionsDocument, ProposalByIdDocument, ProposalsDocument, @@ -51,6 +52,11 @@ class SubgraphClient { const result = await this.query(PermissionsDocument, {}); return result; } + + async getGovernance() { + const result = await this.query(GovernanceDocument, {}); + return result; + } } export default new SubgraphClient( diff --git a/subgraphs/venus-governance/tests/integration/bravo.ts b/subgraphs/venus-governance/tests/integration/bravo.ts index 2ddf37fc..168c8465 100644 --- a/subgraphs/venus-governance/tests/integration/bravo.ts +++ b/subgraphs/venus-governance/tests/integration/bravo.ts @@ -191,11 +191,28 @@ describe('GovernorBravo', function () { }); describe('GovernorBravo2', function () { - before(async () => { + it('should update GovernorEntity when setting implementation', async function () { + const timelock = await ethers.getContract('Timelock'); + const governorBravoDelegateV1 = await ethers.getContract('GovernorBravoDelegateV1'); + // Assert original values + let { + data: { governance }, + } = await subgraphClient.getGovernance(); + + expect(governance.totalProposals).to.equal('4'); + expect(governance.totalDelegates).to.equal('4'); + expect(governance.totalVoters).to.equal('4'); + expect(governance.totalVotesMantissa).to.equal('1700000000000000000000000'); + expect(governance.quorumVotesMantissa).to.equal('600000000000000000000000'); + expect(governance.implementation).to.equal(governorBravoDelegateV1.address.toLowerCase()); + expect(governance.pendingAdmin).to.equal(null); + expect(governance.admin).to.equal(signers[0].address.toLowerCase()); + expect(governance.guardian).to.equal(signers[0].address.toLowerCase()); + expect(governance.proposalMaxOperations).to.equal('10'); + const governorBravoDelegatorV2 = await ethers.getContract('GovernorBravoDelegate'); const xvsVaultProxy = await ethers.getContract('XVSVaultProxy'); const xvsVault = await ethers.getContractAt('XVSVault', xvsVaultProxy.address); - const timelock = await ethers.getContract('Timelock'); await governorBravoDelegator._setImplementation(governorBravoDelegatorV2.address); governorBravo = await ethers.getContractAt('GovernorBravoDelegate', governorBravo.address); @@ -223,7 +240,19 @@ describe('GovernorBravo', function () { const timelocks = [timelock.address, timelock.address, timelock.address]; - governorBravo.initialize(xvsVault.address, proposalConfigs, timelocks, signers[0].address); + await governorBravo.initialize( + xvsVault.address, + proposalConfigs, + timelocks, + signers[0].address, + ); + await waitForSubgraphToBeSynced(SYNC_DELAY); + // Assert updated values + ({ + data: { governance }, + } = await subgraphClient.getGovernance()); + + expect(governance.implementation).to.equal(governorBravoDelegatorV2.address.toLowerCase()); }); it('should index created proposal with routes successfully', async function () { diff --git a/subgraphs/venus-governance/tests/integration/queries/governanceQuery.graphql b/subgraphs/venus-governance/tests/integration/queries/governanceQuery.graphql new file mode 100644 index 00000000..994c4a00 --- /dev/null +++ b/subgraphs/venus-governance/tests/integration/queries/governanceQuery.graphql @@ -0,0 +1,15 @@ +query Governance { + governance(id: "GOVERNANCE") { + id + totalProposals + totalDelegates + totalVoters + totalVotesMantissa + quorumVotesMantissa + implementation + pendingAdmin + admin + guardian + proposalMaxOperations + } +} diff --git a/subgraphs/venus-governance/tests/integration/utils/constants.ts b/subgraphs/venus-governance/tests/integration/utils/constants.ts index 972629ab..28eee096 100644 --- a/subgraphs/venus-governance/tests/integration/utils/constants.ts +++ b/subgraphs/venus-governance/tests/integration/utils/constants.ts @@ -5,3 +5,4 @@ export const SUBGRAPH_NAME = 'venus-governance'; export const SYNC_DELAY = 2000; export const mockAddress = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'; +export const nullAddress = '0x0000000000000000000000000000000000000000'; diff --git a/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts b/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts index a49681ea..52b90b37 100644 --- a/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts +++ b/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts @@ -17,7 +17,7 @@ import { ProposalQueued, } from '../../../generated/GovernorBravoDelegate/GovernorBravoDelegate'; import { Delegate } from '../../../generated/schema'; -import { governorBravoDelegatorAddress } from '../../../src/constants/addresses'; +import { GOVERNANCE } from '../../../src/constants'; import { handleBravoVoteCast, handleNewAdmin, @@ -267,12 +267,7 @@ describe('Bravo', () => { ); handleNewImplementation(newImplementationEvent); - assert.fieldEquals( - 'Governance', - governorBravoDelegatorAddress.toHex(), - 'implementation', - newImplementation.toHexString(), - ); + assert.fieldEquals('Governance', GOVERNANCE, 'implementation', newImplementation.toHexString()); }); test('registers new pending admin', () => { @@ -285,12 +280,7 @@ describe('Bravo', () => { ); handleNewPendingAdmin(pendingAdminEvent); - assert.fieldEquals( - 'Governance', - governorBravoDelegatorAddress.toHex(), - 'pendingAdmin', - newPendingAdmin.toHexString(), - ); + assert.fieldEquals('Governance', GOVERNANCE, 'pendingAdmin', newPendingAdmin.toHexString()); }); test('registers new admin', () => { @@ -299,13 +289,8 @@ describe('Bravo', () => { const newAdminEvent = createNewAdminEvent(governanceAddress, oldAdmin, newAdmin); handleNewAdmin(newAdminEvent); - assert.fieldEquals( - 'Governance', - governorBravoDelegatorAddress.toHex(), - 'admin', - newAdmin.toHexString(), - ); - assert.fieldEquals('Governance', governorBravoDelegatorAddress.toHex(), 'pendingAdmin', 'null'); + assert.fieldEquals('Governance', GOVERNANCE, 'admin', newAdmin.toHexString()); + assert.fieldEquals('Governance', GOVERNANCE, 'pendingAdmin', 'null'); }); test('registers new guardian', () => { @@ -314,12 +299,7 @@ describe('Bravo', () => { const newGuardianEvent = createNewGuardianEvent(governanceAddress, oldGuardian, newGuardian); handleNewGuardian(newGuardianEvent); - assert.fieldEquals( - 'Governance', - governorBravoDelegatorAddress.toHex(), - 'guardian', - newGuardian.toHexString(), - ); + assert.fieldEquals('Governance', GOVERNANCE, 'guardian', newGuardian.toHexString()); }); test('registers new proposal max operations', () => { @@ -334,7 +314,7 @@ describe('Bravo', () => { handleProposalMaxOperationsUpdated(newProposalMaxOperationsEvent); assert.fieldEquals( 'Governance', - governorBravoDelegatorAddress.toHex(), + GOVERNANCE, 'proposalMaxOperations', newProposalMaxOperations.toString(), );