From d843af3b6b8128dddf90b4b436841d710392290b Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 24 Jul 2023 17:32:36 -0400 Subject: [PATCH] update FundingVote entity --- schema.graphql | 5 ++-- src/grant-fund.ts | 22 ++++++++++++---- src/utils/grants/voter.ts | 53 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/schema.graphql b/schema.graphql index 0820059..8598f94 100644 --- a/schema.graphql +++ b/schema.graphql @@ -822,7 +822,8 @@ type DistributionPeriodVote @entity { id: Bytes! # $voterId + '|'' + $distributionId distribution: DistributionPeriod! # uint256 screeningStageVotingPower: BigDecimal! # uint256 - fundingStageVotingPower: BigDecimal! # uint256 + initialFundingStageVotingPower: BigDecimal! # uint256 + remainingFundingStageVotingPower: BigDecimal! # uint256 screeningVotes: [ScreeningVote!]! # ScreeningVote[] fundingVotes: [FundingVote!]! # FundingVote[] } @@ -842,7 +843,7 @@ type FundingVote @entity { voter: Voter! # Voter proposal: Proposal! # proposal being voted on votesCast: BigDecimal! # uint256 # TODO: can this be negative? - votingPowerUsed: BigDecimal! # uint256 + votingPowerUsed: BigDecimal! # uint256 # cost of the incremetnal funding vote to the voter's voting power blockNumber: BigInt! # block number the vote was cast } diff --git a/src/grant-fund.ts b/src/grant-fund.ts index b6e119a..1cd04f7 100644 --- a/src/grant-fund.ts +++ b/src/grant-fund.ts @@ -29,7 +29,7 @@ import { ZERO_ADDRESS, ZERO_BD } from './utils/constants' import { addressArrayToBytesArray, addressToBytes, bigIntToBytes, bytesToBigInt, wadToDecimal } from "./utils/convert" import { getProposalParamsId, getProposalsInSlate, removeProposalFromList } from './utils/grants/proposal' import { getCurrentDistributionId, getCurrentStage, loadOrCreateDistributionPeriod } from './utils/grants/distribution' -import { getFundingStageVotingPower, getFundingVoteId, getScreeningStageVotingPower, getScreeningVoteId, loadOrCreateDistributionPeriodVote, loadOrCreateVoter } from './utils/grants/voter' +import { getFundingStageVotingPower, getFundingVoteId, getFundingVotingPowerUsed, getScreeningStageVotingPower, getScreeningVoteId, loadOrCreateDistributionPeriodVote, loadOrCreateVoter } from './utils/grants/voter' import { loadOrCreateGrantFund } from './utils/grants/fund' export function handleDelegateRewardClaimed( @@ -328,19 +328,31 @@ export function handleVoteCast(event: VoteCastEvent): void { fundingVote.voter = voter.id fundingVote.proposal = proposalId fundingVote.votesCast = wadToDecimal(event.params.weight) - // fundingVote.votingPowerUsed = ZERO_BD TODO: need to calculate this fundingVote.blockNumber = voteCast.blockNumber // update voter's distributionPeriodVote entity if it hasn't been recorded yet - if (distributionPeriodVote.screeningStageVotingPower === ZERO_BD) { - distributionPeriodVote.fundingStageVotingPower = getFundingStageVotingPower(event.address, bytesToBigInt(distributionId), Address.fromBytes(voter.id)) + if (distributionPeriodVote.initialFundingStageVotingPower === ZERO_BD) { + distributionPeriodVote.initialFundingStageVotingPower = getFundingStageVotingPower(event.address, bytesToBigInt(distributionId), Address.fromBytes(voter.id)) + } + else { + distributionPeriodVote.remainingFundingStageVotingPower = getFundingStageVotingPower(event.address, bytesToBigInt(distributionId), Address.fromBytes(voter.id)) } + // add additional funding votes to voter's distributionPeriodVote entity + distributionPeriodVote.fundingVotes = distributionPeriodVote.fundingVotes.concat([fundingVote.id]) + + // calculate the voting power cost of this funding vote + fundingVote.votingPowerUsed = getFundingVotingPowerUsed(distributionPeriodVote, proposalId); + // save fundingVote to the store fundingVote.save() } - voter.distributionPeriodVotes = voter.distributionPeriodVotes.concat([distributionPeriodVote.id]) + // check if the account has already voted in this distribution period + if (!voter.distributionPeriodVotes.includes(distributionPeriodVote.id)) { + // associate the distributionPeriodVote entity with the voter + voter.distributionPeriodVotes = voter.distributionPeriodVotes.concat([distributionPeriodVote.id]) + } // save entities to the store distributionPeriod.save() diff --git a/src/utils/grants/voter.ts b/src/utils/grants/voter.ts index 3ee6570..4382ef8 100644 --- a/src/utils/grants/voter.ts +++ b/src/utils/grants/voter.ts @@ -1,6 +1,6 @@ import { Address, BigDecimal, BigInt, Bytes, dataSource } from "@graphprotocol/graph-ts" -import { DistributionPeriodVote, Voter } from "../../../generated/schema" +import { DistributionPeriodVote, FundingVote, Voter } from "../../../generated/schema" import { GrantFund } from "../../../generated/GrantFund/GrantFund" import { ZERO_BD, ZERO_BI } from "../constants" @@ -26,6 +26,54 @@ export function getScreeningVoteId(proposalId: Bytes, voterId: Bytes, logIndex: .concat(Bytes.fromUTF8(logIndex.toString())) } +export function getFundingVotesByProposalId(distributionPeriodVote: DistributionPeriodVote, proposalId: Bytes): Bytes[] { + const filteredVotes: Bytes[] = []; + const fundingVotes = distributionPeriodVote.fundingVotes; + + for (let i = 0; i < fundingVotes.length; i++) { + const proposal = loadOrCreateFundingVote(fundingVotes[i]).proposal; + if (proposal === proposalId) { + filteredVotes.push(fundingVotes[i]); + } + } + return filteredVotes; +} + +// calculate the amount of funding voting power used on an individual FundingVote +export function getFundingVotingPowerUsed(distributionPeriodVote: DistributionPeriodVote, proposalId: Bytes): BigDecimal { + const votes = getFundingVotesByProposalId(distributionPeriodVote, proposalId); + + // accumulate the squared votes from each separate vote on the proposal + const squaredAmount: BigDecimal[] = []; + for (let i = 0; i < votes.length; i++) { + const vote = loadOrCreateFundingVote(votes[i]); + squaredAmount.push(vote.votesCast.times(vote.votesCast)); + } + + // sum the squared amounts + let sum = ZERO_BD; + for (let i = 0; i < squaredAmount.length; i++) { + sum = sum.plus(squaredAmount[i]); + } + + return sum; +} + +export function loadOrCreateFundingVote(fundingVoteId: Bytes): FundingVote { + let fundingVote = FundingVote.load(fundingVoteId) + if (fundingVote == null) { + // create new fundingVote if one hasn't already been stored + fundingVote = new FundingVote(fundingVoteId) as FundingVote + fundingVote.distribution = Bytes.empty() + fundingVote.voter = Bytes.empty() + fundingVote.proposal = Bytes.empty() + fundingVote.votesCast = ZERO_BD + fundingVote.votingPowerUsed = ZERO_BD + fundingVote.blockNumber = ZERO_BI + } + return fundingVote +} + export function loadOrCreateVoter(voterId: Bytes): Voter { let voter = Voter.load(voterId) if (voter == null) { @@ -44,7 +92,8 @@ export function loadOrCreateDistributionPeriodVote(distributionPeriodId: Bytes, distributionPeriodVotes = new DistributionPeriodVote(distributionPeriodVotesId) as DistributionPeriodVote distributionPeriodVotes.distribution = distributionPeriodId distributionPeriodVotes.screeningStageVotingPower = ZERO_BD - distributionPeriodVotes.fundingStageVotingPower = ZERO_BD + distributionPeriodVotes.initialFundingStageVotingPower = ZERO_BD + distributionPeriodVotes.remainingFundingStageVotingPower = ZERO_BD distributionPeriodVotes.screeningVotes = [] distributionPeriodVotes.fundingVotes = [] }