From a348169bf310a684e806651e291b4c93465062a6 Mon Sep 17 00:00:00 2001 From: Corey Rice Date: Tue, 12 Mar 2024 15:51:25 -0300 Subject: [PATCH] feat: add hash, blockNumber, and timestamp of proposal action transactions --- docker-compose.yaml | 1 + subgraphs/venus-governance/schema.graphql | 23 +++++++++++++-- .../venus-governance/src/operations/create.ts | 4 +-- .../venus-governance/src/operations/update.ts | 28 +++++++++++++++--- .../tests/integration/alpha.ts | 15 ++++++++-- .../tests/integration/bravo.ts | 29 +++++++++++++++---- .../queries/proposalByIdQuery.graphql | 19 ++++++++++-- .../queries/proposalsQuery.graphql | 19 ++++++++++-- .../tests/unit/Alpha/index.test.ts | 6 ++-- .../tests/unit/Bravo/index.test.ts | 6 ++-- 10 files changed, 119 insertions(+), 31 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 9f938a3c..00b7d32d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -17,6 +17,7 @@ services: condition: service_started environment: ETHEREUM_REORG_THRESHOLD: 1 + GRAPH_ALLOW_NON_DETERMINISTIC_FULLTEXT_SEARCH: "true" postgres_host: postgres postgres_user: graph-node postgres_pass: let-me-in diff --git a/subgraphs/venus-governance/schema.graphql b/subgraphs/venus-governance/schema.graphql index 8679da1c..e36952af 100644 --- a/subgraphs/venus-governance/schema.graphql +++ b/subgraphs/venus-governance/schema.graphql @@ -38,6 +38,20 @@ type _Schema_ include: [{ entity: "Proposal", fields: [{ name: "description" }] }] ) +type ProposalAction @entity { + "Transaction hash used as the ID" + id: ID! + + "Transaction hash for the proposal action" + txHash: Bytes! + + "Block number of the proposal action" + blockNumber: BigInt! + + "Timestamp of the transaction block" + timestamp: BigInt! +} + type Proposal @entity { "Internal proposal ID, in this implementation it seems to be a autoincremental id" id: ID! @@ -70,13 +84,13 @@ type Proposal @entity { executionEta: BigInt "Whether a proposal has been queued" - queued: Boolean + queued: ProposalAction "Whether a proposal has been canceled" - canceled: Boolean + canceled: ProposalAction "Whether a proposal has been executed" - executed: Boolean + executed: ProposalAction "Total of for votes on the proposal" forVotes: BigInt! @@ -87,6 +101,9 @@ type Proposal @entity { "Total of abstain votes on the proposal" abstainVotes: BigInt! + "Difference between for and against" + passing: Boolean! + "Votes associated to this proposal" votes: [Vote!]! @derivedFrom(field: "proposal") diff --git a/subgraphs/venus-governance/src/operations/create.ts b/subgraphs/venus-governance/src/operations/create.ts index 46d64b32..b6fb5505 100644 --- a/subgraphs/venus-governance/src/operations/create.ts +++ b/subgraphs/venus-governance/src/operations/create.ts @@ -27,13 +27,11 @@ export function createProposal(event: E): Proposal { proposal.startBlock = event.params.startBlock; proposal.endBlock = event.params.endBlock; proposal.description = event.params.description; - proposal.queued = false; - proposal.canceled = false; - proposal.executed = false; proposal.type = NORMAL; proposal.forVotes = BIGINT_ZERO; proposal.againstVotes = BIGINT_ZERO; proposal.abstainVotes = BIGINT_ZERO; + proposal.passing = false; proposal.save(); diff --git a/subgraphs/venus-governance/src/operations/update.ts b/subgraphs/venus-governance/src/operations/update.ts index 9fa466d9..1336cf49 100644 --- a/subgraphs/venus-governance/src/operations/update.ts +++ b/subgraphs/venus-governance/src/operations/update.ts @@ -1,7 +1,7 @@ import { BigInt } from '@graphprotocol/graph-ts'; import { GovernorBravoDelegate2 } from '../../generated/GovernorBravoDelegate2/GovernorBravoDelegate2'; -import { Governance } from '../../generated/schema'; +import { Governance, ProposalAction } from '../../generated/schema'; import { BIGINT_ONE } from '../constants'; import { governorBravoDelegatorAddress, nullAddress } from '../constants/addresses'; import { getGovernanceId } from '../utilities/ids'; @@ -12,7 +12,13 @@ export function updateProposalCanceled(event: E): void { const params = event.params; const proposal = getProposal(params.id.toString()); - proposal.canceled = true; + const canceledAction = new ProposalAction(event.transaction.hash.toHexString()); + canceledAction.blockNumber = event.block.number; + canceledAction.timestamp = event.block.timestamp; + canceledAction.txHash = event.transaction.hash; + canceledAction.save(); + + proposal.canceled = canceledAction.id; proposal.save(); } @@ -20,7 +26,13 @@ export function updateProposalQueued(event: E): void { const params = event.params; const proposal = getProposal(params.id.toString()); - proposal.queued = true; + const queuedAction = new ProposalAction(event.transaction.hash.toHexString()); + queuedAction.blockNumber = event.block.number; + queuedAction.timestamp = event.block.timestamp; + queuedAction.txHash = event.transaction.hash; + queuedAction.save(); + + proposal.queued = queuedAction.id; proposal.executionEta = params.eta; proposal.save(); } @@ -29,7 +41,13 @@ export function updateProposalExecuted(event: E): void { const params = event.params; const proposal = getProposal(params.id.toString()); - proposal.executed = true; + const executedAction = new ProposalAction(event.transaction.hash.toHexString()); + executedAction.blockNumber = event.block.number; + executedAction.timestamp = event.block.timestamp; + executedAction.txHash = event.transaction.hash; + executedAction.save(); + + proposal.executed = executedAction.id; proposal.save(); } @@ -104,6 +122,7 @@ export function updateAlphaProposalVotes(id: BigInt, votes: BigInt, support: boo } else { proposal.againstVotes = proposal.againstVotes.plus(votes); } + proposal.passing = proposal.forVotes > proposal.againstVotes; proposal.save(); } @@ -116,5 +135,6 @@ export function updateBravoProposalVotes(id: BigInt, votes: BigInt, support: i32 } else { proposal.abstainVotes = proposal.abstainVotes.plus(votes); } + proposal.passing = proposal.forVotes > proposal.againstVotes; proposal.save(); } diff --git a/subgraphs/venus-governance/tests/integration/alpha.ts b/subgraphs/venus-governance/tests/integration/alpha.ts index 83cb399b..312a39a6 100644 --- a/subgraphs/venus-governance/tests/integration/alpha.ts +++ b/subgraphs/venus-governance/tests/integration/alpha.ts @@ -86,6 +86,7 @@ describe('GovernorAlpha', function () { expect(proposal.forVotes).to.be.equal(scaleValue(1000000, 18).toFixed()); expect(proposal.againstVotes).to.be.equal(scaleValue(100000, 18).toFixed()); expect(proposal.abstainVotes).to.be.equal('0'); + expect(proposal.passing).to.be.equal(true); const { data: { delegate: delegate1 }, @@ -119,7 +120,9 @@ describe('GovernorAlpha', function () { data: { proposal }, } = await subgraphClient.getProposalById('1'); - expect(proposal.canceled).to.equal(true); + expect(typeof proposal.canceled.blockNumber).to.equal('string'); + expect(typeof proposal.canceled.txHash).to.equal('string'); + expect(typeof proposal.canceled.timestamp).to.equal('string'); }); }); @@ -165,6 +168,7 @@ describe('GovernorAlpha', function () { expect(proposal.forVotes).to.be.equal(scaleValue(800000, 18).toFixed()); expect(proposal.againstVotes).to.be.equal('0'); expect(proposal.abstainVotes).to.be.equal('0'); + expect(proposal.passing).to.be.equal(true); }); it('should transition to queued', async () => { @@ -188,7 +192,10 @@ describe('GovernorAlpha', function () { data: { proposal }, } = await subgraphClient.getProposalById('21'); - expect(proposal.queued).to.equal(true); + expect(typeof proposal.queued.blockNumber).to.equal('string'); + expect(typeof proposal.queued.txHash).to.equal('string'); + expect(typeof proposal.queued.timestamp).to.equal('string'); + expect(proposal.executionEta).to.equal(eta.toString()); await mine(1); @@ -204,7 +211,9 @@ describe('GovernorAlpha', function () { data: { proposal }, } = await subgraphClient.getProposalById('21'); - expect(proposal.executed).to.equal(true); + expect(typeof proposal.executed.blockNumber).to.equal('string'); + expect(typeof proposal.executed.txHash).to.equal('string'); + expect(typeof proposal.executed.timestamp).to.equal('string'); }); }); }); diff --git a/subgraphs/venus-governance/tests/integration/bravo.ts b/subgraphs/venus-governance/tests/integration/bravo.ts index c2133099..056740bf 100644 --- a/subgraphs/venus-governance/tests/integration/bravo.ts +++ b/subgraphs/venus-governance/tests/integration/bravo.ts @@ -105,6 +105,7 @@ describe('GovernorBravo', function () { expect(proposal.againstVotes).to.be.equal(scaleValue(700000, 18).toFixed()); expect(proposal.forVotes).to.be.equal(scaleValue(200000, 18).toFixed()); expect(proposal.abstainVotes).to.be.equal('0'); + expect(proposal.passing).to.be.equal(false); const { data: { delegate: delegate1 }, @@ -135,7 +136,9 @@ describe('GovernorBravo', function () { data: { proposal }, } = await subgraphClient.getProposalById('22'); - expect(proposal.canceled).to.equal(true); + expect(typeof proposal.canceled.blockNumber).to.equal('string'); + expect(typeof proposal.canceled.txHash).to.equal('string'); + expect(typeof proposal.canceled.timestamp).to.equal('string'); }); it('should index queued proposal event', async function () { @@ -175,12 +178,15 @@ describe('GovernorBravo', function () { data: { proposal }, } = await subgraphClient.getProposalById('23'); - expect(proposal.queued).to.equal(true); + expect(typeof proposal.queued.blockNumber).to.equal('string'); + expect(typeof proposal.queued.txHash).to.equal('string'); + expect(typeof proposal.queued.timestamp).to.equal('string'); expect(proposal.executionEta).to.equal(eta.toString()); expect(proposal.againstVotes).to.be.equal('0'); expect(proposal.forVotes).to.be.equal(scaleValue(800000, 18).toFixed()); expect(proposal.abstainVotes).to.be.equal('0'); + expect(proposal.passing).to.be.equal(true); await mine(1); await ethers.provider.send('evm_setNextBlockTimestamp', [eta]); @@ -195,7 +201,9 @@ describe('GovernorBravo', function () { data: { proposal }, } = await subgraphClient.getProposalById('23'); - expect(proposal.executed).to.equal(true); + expect(typeof proposal.executed.blockNumber).to.equal('string'); + expect(typeof proposal.executed.txHash).to.equal('string'); + expect(typeof proposal.executed.timestamp).to.equal('string'); }); }); @@ -317,6 +325,7 @@ describe('GovernorBravo', function () { expect(proposal.againstVotes).to.be.equal(scaleValue(100000, 18).toFixed()); expect(proposal.forVotes).to.be.equal(scaleValue(1000000, 18).toFixed()); expect(proposal.abstainVotes).to.be.equal('0'); + expect(proposal.passing).to.be.equal(true); const { data: { delegate: delegate1 }, @@ -352,7 +361,9 @@ describe('GovernorBravo', function () { data: { proposal }, } = await subgraphClient.getProposalById('24'); - expect(proposal.canceled).to.equal(true); + expect(typeof proposal.canceled.blockNumber).to.equal('string'); + expect(typeof proposal.canceled.txHash).to.equal('string'); + expect(typeof proposal.canceled.timestamp).to.equal('string'); }); it('should index queued proposal event', async function () { @@ -399,12 +410,16 @@ describe('GovernorBravo', function () { data: { proposal }, } = await subgraphClient.getProposalById('25'); - expect(proposal.queued).to.equal(true); + expect(typeof proposal.queued.blockNumber).to.equal('string'); + expect(typeof proposal.queued.txHash).to.equal('string'); + expect(typeof proposal.queued.timestamp).to.equal('string'); + expect(proposal.executionEta).to.equal(eta.toString()); expect(proposal.againstVotes).to.be.equal('0'); expect(proposal.forVotes).to.be.equal(scaleValue(800000, 18).toFixed()); expect(proposal.abstainVotes).to.be.equal('0'); + expect(proposal.passing).to.be.equal(true); await mine(1); await ethers.provider.send('evm_setNextBlockTimestamp', [eta]); @@ -419,7 +434,9 @@ describe('GovernorBravo', function () { data: { proposal }, } = await subgraphClient.getProposalById('25'); - expect(proposal.executed).to.equal(true); + expect(typeof proposal.executed.blockNumber).to.equal('string'); + expect(typeof proposal.executed.txHash).to.equal('string'); + expect(typeof proposal.executed.timestamp).to.equal('string'); }); }); }); diff --git a/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql b/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql index d89c8d86..7bee0e61 100644 --- a/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql +++ b/subgraphs/venus-governance/tests/integration/queries/proposalByIdQuery.graphql @@ -12,13 +12,26 @@ query ProposalById($id: ID!) { endBlock description executionEta - queued - canceled - executed + queued { + blockNumber + timestamp + txHash + } + canceled { + blockNumber + timestamp + txHash + } + executed { + blockNumber + timestamp + txHash + } type forVotes againstVotes abstainVotes + passing votes { id votes diff --git a/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql b/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql index 564be0a7..0119dd7c 100644 --- a/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql +++ b/subgraphs/venus-governance/tests/integration/queries/proposalsQuery.graphql @@ -12,13 +12,26 @@ query Proposals { endBlock description executionEta - queued - canceled - executed + queued { + blockNumber + timestamp + txHash + } + canceled { + blockNumber + timestamp + txHash + } + executed { + blockNumber + timestamp + txHash + } type forVotes againstVotes abstainVotes + passing votes { id votes diff --git a/subgraphs/venus-governance/tests/unit/Alpha/index.test.ts b/subgraphs/venus-governance/tests/unit/Alpha/index.test.ts index 38f57e0d..f7de0cac 100644 --- a/subgraphs/venus-governance/tests/unit/Alpha/index.test.ts +++ b/subgraphs/venus-governance/tests/unit/Alpha/index.test.ts @@ -106,7 +106,7 @@ describe('Alpha', () => { const assertProposalDocument = (key: string, value: string): void => { assert.fieldEquals('Proposal', '1', key, value); }; - assertProposalDocument('canceled', 'true'); + assertProposalDocument('canceled', proposalCanceledEvent.transaction.hash.toHexString()); }); test('queue proposal', () => { @@ -120,7 +120,7 @@ describe('Alpha', () => { assert.fieldEquals('Proposal', '1', key, value); }; - assertProposalDocument('queued', 'true'); + assertProposalDocument('queued', proposalQueuedEvent.transaction.hash.toHexString()); assertProposalDocument('executionEta', eta.toString()); }); @@ -138,7 +138,7 @@ describe('Alpha', () => { assert.fieldEquals('Proposal', '1', key, value); }; - assertProposalDocument('executed', 'true'); + assertProposalDocument('executed', proposalExecutedEvent.transaction.hash.toHexString()); }); test('vote cast', () => { diff --git a/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts b/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts index 52b90b37..96af1478 100644 --- a/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts +++ b/subgraphs/venus-governance/tests/unit/Bravo/index.test.ts @@ -201,7 +201,7 @@ describe('Bravo', () => { const assertProposalDocument = (key: string, value: string): void => { assert.fieldEquals('Proposal', '1', key, value); }; - assertProposalDocument('canceled', 'true'); + assertProposalDocument('canceled', proposalCanceledEvent.transaction.hash.toHexString()); }); test('queue proposal', () => { @@ -215,7 +215,7 @@ describe('Bravo', () => { assert.fieldEquals('Proposal', '1', key, value); }; - assertProposalDocument('queued', 'true'); + assertProposalDocument('queued', proposalQueuedEvent.transaction.hash.toHexString()); assertProposalDocument('executionEta', eta.toString()); }); @@ -233,7 +233,7 @@ describe('Bravo', () => { assert.fieldEquals('Proposal', '1', key, value); }; - assertProposalDocument('executed', 'true'); + assertProposalDocument('executed', proposalExecutedEvent.transaction.hash.toHexString()); }); test('vote cast', () => {