diff --git a/schema.graphql b/schema.graphql index b7fa6df..f265128 100644 --- a/schema.graphql +++ b/schema.graphql @@ -808,7 +808,6 @@ type Proposal @entity { description: String! # proposal description hashed as part of proposalId distribution: DistributionPeriod # distributionPeriod in which the proposal was submitted if Standard, null otherwise executed: Boolean! # bool - successful: Boolean! # bool screeningVotesReceived: BigDecimal! # uint256 fundingVotesReceived: BigDecimal! # uint256 totalTokensRequested: BigDecimal! # uint256 diff --git a/src/grant-fund.ts b/src/grant-fund.ts index 0c41a9c..7089a13 100644 --- a/src/grant-fund.ts +++ b/src/grant-fund.ts @@ -1,4 +1,4 @@ -import { Address, BigInt, Bytes, ethereum } from '@graphprotocol/graph-ts' +import { Address, BigInt, Bytes, ethereum, log } from '@graphprotocol/graph-ts' import { DelegateRewardClaimed as DelegateRewardClaimedEvent, @@ -162,14 +162,8 @@ export function handleProposalCreated(event: ProposalCreatedEvent): void { // create Proposal entity const proposalId = bigIntToBytes(event.params.proposalId) - const proposal = new Proposal(proposalId) as Proposal + const proposal = loadOrCreateProposal(proposalId) proposal.description = event.params.description - proposal.distribution = Bytes.empty() - proposal.executed = false - proposal.successful = false - proposal.screeningVotesReceived = ZERO_BD - proposal.fundingVotesReceived = ZERO_BD - proposal.params = [] let totalTokensRequested = ZERO_BD @@ -182,18 +176,11 @@ export function handleProposalCreated(event: ProposalCreatedEvent): void { proposalParams.calldata = event.params.calldatas[i] // decode the calldata to get the recipient and tokens requested - const dataWithoutFunctionSelector = Bytes.fromUint8Array(proposalParams.calldata.subarray(3)) - const decoded = ethereum.decode('(address,uint256)', dataWithoutFunctionSelector) - if (decoded != null) { - proposalParams.recipient = decoded.toTuple()[0].toAddress() - const tokensRequested = decoded.toTuple()[1].toBigInt().toBigDecimal() - proposalParams.tokensRequested = tokensRequested - totalTokensRequested = totalTokensRequested.plus(tokensRequested) - } - else { - proposalParams.recipient = ZERO_ADDRESS - proposalParams.tokensRequested = ZERO_BD - } + const decoded = ethereum.decode('(address,uint256)', proposalParams.calldata)! + proposalParams.recipient = decoded.toTuple()[0].toAddress() + const tokensRequested = decoded.toTuple()[1].toBigInt().toBigDecimal() + proposalParams.tokensRequested = tokensRequested + totalTokensRequested = totalTokensRequested.plus(tokensRequested) // add proposalParams information to proposal proposal.params = proposal.params.concat([proposalParams.id]) @@ -231,14 +218,11 @@ export function handleProposalExecuted(event: ProposalExecutedEvent): void { proposalExecuted.transactionHash = event.transaction.hash // update proposal entity - const proposal = Proposal.load(bigIntToBytes(event.params.proposalId)) as Proposal - if (proposal != null) { - proposal.executed = true - proposal.successful = true + const proposal = loadOrCreateProposal(bigIntToBytes(event.params.proposalId)) + proposal.executed = true - // save entities to the store - proposal.save() - } + // save entities to the store + proposal.save() proposalExecuted.save() } @@ -356,6 +340,9 @@ export function handleVoteCast(event: VoteCastEvent): void { distributionPeriodVote.estimatedRemainingFundingStageVotingPowerForCalculatingRewards = getFundingStageVotingPower(event.address, bytesToBigInt(distributionId), Address.fromBytes(voter.id)) } + // record votes cast on the Proposal entity + proposal.fundingVotesReceived = proposal.fundingVotesReceived.plus(fundingVote.votesCast) + // save fundingVote to the store fundingVote.save() } diff --git a/src/utils/grants/proposal.ts b/src/utils/grants/proposal.ts index 72c3d2c..0dbdbcd 100644 --- a/src/utils/grants/proposal.ts +++ b/src/utils/grants/proposal.ts @@ -19,7 +19,6 @@ export function loadOrCreateProposal(proposalId: Bytes): Proposal { proposal.description = "" proposal.distribution = Bytes.empty() proposal.executed = false - proposal.successful = false proposal.screeningVotesReceived = ZERO_BD proposal.fundingVotesReceived = ZERO_BD proposal.totalTokensRequested = ZERO_BD diff --git a/src/utils/grants/voter.ts b/src/utils/grants/voter.ts index 8841d5a..2070242 100644 --- a/src/utils/grants/voter.ts +++ b/src/utils/grants/voter.ts @@ -31,8 +31,6 @@ export function getFundingVotesByProposalId(distributionPeriodVote: Distribution const filteredVotes: Bytes[] = []; const fundingVotes = distributionPeriodVote.fundingVotes; - log.info("getFundingVotesByProposalId: {} {}", [distributionPeriodVote.fundingVotes.length.toString(), proposalId.toString()]) - for (let i = 0; i < fundingVotes.length; i++) { const proposal = loadOrCreateFundingVote(fundingVotes[i]).proposal; if (proposal.equals(proposalId)) { diff --git a/tests/grant-fund.test.ts b/tests/grant-fund.test.ts index 0660d1e..cf34b54 100644 --- a/tests/grant-fund.test.ts +++ b/tests/grant-fund.test.ts @@ -7,7 +7,7 @@ import { log, logStore, } from "matchstick-as/assembly/index"; -import { Address, BigInt, Bytes, dataSource } from "@graphprotocol/graph-ts"; +import { Address, BigInt, Bytes, dataSource, ethereum } from "@graphprotocol/graph-ts"; import { handleDelegateRewardClaimed, handleFundTreasury, @@ -171,6 +171,12 @@ describe("Grant Fund assertions", () => { "treasury", `${wadToDecimal(treasuryBalance)}` ); + assert.fieldEquals( + "FundTreasury", + `0xa16081f360e3847006db660bae1c6d1b2e17ec2a01000000`, + "treasuryBalance", + `${treasuryBalance}` + ); }); test("ProposalCreated", () => { @@ -183,16 +189,26 @@ describe("Grant Fund assertions", () => { const proposer = Address.fromString( "0x0000000000000000000000000000000000000025" ); + + // encode mock calldatas const targets = [ajnaTokenAddress, ajnaTokenAddress]; const values = [ZERO_BI, ZERO_BI]; const signatures = [ "transfer(address,uint256)", "transfer(address,uint256)", ]; + const paramsArray: Array = [ + ethereum.Value.fromAddress(proposer), + ethereum.Value.fromUnsignedBigInt(ONE_BI), + ]; + const params = changetype(paramsArray) + const encodedparamsOne = ethereum.encode(ethereum.Value.fromTuple(params))!; + const encodedparamsTwo = ethereum.encode(ethereum.Value.fromTuple(params))!; const calldatas = [ - Bytes.fromHexString("0x000000"), - Bytes.fromHexString("0x000000"), + encodedparamsOne, + encodedparamsTwo, ]; + const distributionId = BigInt.fromI32(234); const startBlock = ONE_BI; const endBlock = startBlock.plus(DISTRIBUTION_PERIOD_LENGTH); @@ -227,12 +243,30 @@ describe("Grant Fund assertions", () => { // check Proposal attributes assert.entityCount("Proposal", 1); + assert.entityCount("ProposalParams", 2); // check DistributionPeriod attributes assert.entityCount("DistributionPeriod", 1); // check DistributionPeriod attributes assert.entityCount("GrantFund", 1); + + const expectedDistributionId = bigIntToBytes(distributionId).toHexString(); + + assert.fieldEquals( + "Proposal", + `${bigIntToBytes(proposalId).toHexString()}`, + "distribution", + `${expectedDistributionId}` + ); + + assert.fieldEquals( + "Proposal", + `${bigIntToBytes(proposalId).toHexString()}`, + "totalTokensRequested", + `${BigInt.fromI32(2)}` + ); + }); test("ProposalExecuted", () => { @@ -247,16 +281,26 @@ describe("Grant Fund assertions", () => { const proposer = Address.fromString( "0x0000000000000000000000000000000000000025" ); + + // encode mock calldatas const targets = [ajnaTokenAddress, ajnaTokenAddress]; const values = [ZERO_BI, ZERO_BI]; const signatures = [ "transfer(address,uint256)", "transfer(address,uint256)", ]; + const paramsArray: Array = [ + ethereum.Value.fromAddress(proposer), + ethereum.Value.fromUnsignedBigInt(ONE_BI), + ]; + const params = changetype(paramsArray) + const encodedparamsOne = ethereum.encode(ethereum.Value.fromTuple(params))!; + const encodedparamsTwo = ethereum.encode(ethereum.Value.fromTuple(params))!; const calldatas = [ - Bytes.fromHexString("0x000000"), - Bytes.fromHexString("0x000000"), + encodedparamsOne, + encodedparamsTwo, ]; + const distributionId = BigInt.fromI32(234); const startBlock = ONE_BI; const endBlock = startBlock.plus(DISTRIBUTION_PERIOD_LENGTH); @@ -307,9 +351,39 @@ describe("Grant Fund assertions", () => { // check Proposal attributes assert.entityCount("Proposal", 1); + assert.entityCount("ProposalParams", 2); // check ProposalExecuted attributes assert.entityCount("ProposalExecuted", 1); + + assert.fieldEquals( + "Proposal", + `${bigIntToBytes(proposalId).toHexString()}`, + "description", + `${description}` + ); + + assert.fieldEquals( + "Proposal", + `${bigIntToBytes(proposalId).toHexString()}`, + "totalTokensRequested", + `${BigInt.fromI32(2)}` + ); + + assert.fieldEquals( + "Proposal", + `${bigIntToBytes(proposalId).toHexString()}`, + "executed", + `${true}` + ); + + assert.fieldEquals( + "ProposalExecuted", + `0xa16081f360e3847006db660bae1c6d1b2e17ec2a01000000`, + "proposalId", + `${proposalId}` + ); + }); test("ScreeningVote", () => { @@ -324,16 +398,26 @@ describe("Grant Fund assertions", () => { const proposer = Address.fromString( "0x0000000000000000000000000000000000000025" ); + + // encode mock calldatas const targets = [ajnaTokenAddress, ajnaTokenAddress]; const values = [ZERO_BI, ZERO_BI]; const signatures = [ "transfer(address,uint256)", "transfer(address,uint256)", ]; + const paramsArray: Array = [ + ethereum.Value.fromAddress(proposer), + ethereum.Value.fromUnsignedBigInt(ONE_BI), + ]; + const params = changetype(paramsArray) + const encodedparamsOne = ethereum.encode(ethereum.Value.fromTuple(params))!; + const encodedparamsTwo = ethereum.encode(ethereum.Value.fromTuple(params))!; const calldatas = [ - Bytes.fromHexString("0x000000"), - Bytes.fromHexString("0x000000"), + encodedparamsOne, + encodedparamsTwo, ]; + const distributionId = ONE_BI; const startBlock = ONE_BI; const endBlock = startBlock.plus(DISTRIBUTION_PERIOD_LENGTH); @@ -390,6 +474,7 @@ describe("Grant Fund assertions", () => { // check Proposal attributes assert.entityCount("Proposal", 1); + assert.entityCount("ProposalParams", 2); // check Proposal attributes assert.entityCount("DistributionPeriodVote", 1); @@ -426,16 +511,26 @@ describe("Grant Fund assertions", () => { const proposer = Address.fromString( "0x0000000000000000000000000000000000000025" ); + + // encode mock calldatas const targets = [ajnaTokenAddress, ajnaTokenAddress]; const values = [ZERO_BI, ZERO_BI]; const signatures = [ "transfer(address,uint256)", "transfer(address,uint256)", ]; + const paramsArray: Array = [ + ethereum.Value.fromAddress(proposer), + ethereum.Value.fromUnsignedBigInt(ONE_BI), + ]; + const params = changetype(paramsArray) + const encodedparamsOne = ethereum.encode(ethereum.Value.fromTuple(params))!; + const encodedparamsTwo = ethereum.encode(ethereum.Value.fromTuple(params))!; const calldatas = [ - Bytes.fromHexString("0x000000"), - Bytes.fromHexString("0x000000"), + encodedparamsOne, + encodedparamsTwo, ]; + const distributionId = ONE_BI; const startBlock = ONE_BI; const endBlock = startBlock.plus(DISTRIBUTION_PERIOD_LENGTH); @@ -505,6 +600,7 @@ describe("Grant Fund assertions", () => { // check Proposal attributes assert.entityCount("Proposal", 1); + assert.entityCount("ProposalParams", 2); assert.entityCount("DistributionPeriod", 1); assert.entityCount("DistributionPeriodVote", 1); @@ -515,8 +611,24 @@ describe("Grant Fund assertions", () => { const distributionPeriodVoteId = getDistributionPeriodVoteId(bigIntToBytes(distributionId), addressToBytes(voter)); const fundingVoteId = getFundingVoteId(bigIntToBytes(proposalId), addressToBytes(voter), BigInt.fromI32(2)); const screeningVoteId = getScreeningVoteId(bigIntToBytes(proposalId), addressToBytes(voter), BigInt.fromI32(1)); + const expectedProposalId = bigIntToBytes(proposalId).toHexString(); const expectedDistributionId = bigIntToBytes(distributionId).toHexString(); const expectedVotingPowerUsed = wadToDecimal(votesCast.times(votesCast)); + const expectedScreeningVotesReceived = wadToDecimal(votesCast.times(BigInt.fromI32(-1))); + + assert.fieldEquals( + "Proposal", + `${expectedProposalId}`, + "screeningVotesReceived", + `${expectedScreeningVotesReceived}` + ); + + assert.fieldEquals( + "Proposal", + `${expectedProposalId}`, + "fundingVotesReceived", + `${wadToDecimal(votesCast)}` + ); assert.fieldEquals( "DistributionPeriodVote", @@ -530,7 +642,7 @@ describe("Grant Fund assertions", () => { "ScreeningVote", `${screeningVoteId.toHexString()}`, "votesCast", - `${wadToDecimal(votesCast.times(BigInt.fromI32(-1)))}` + `${expectedScreeningVotesReceived}` ); // check DistributionPeriodVote attributes @@ -604,15 +716,24 @@ describe("Grant Fund assertions", () => { const proposer = Address.fromString( "0x0000000000000000000000000000000000000025" ); + + // encode mock calldatas const targets = [ajnaTokenAddress, ajnaTokenAddress]; const values = [ZERO_BI, ZERO_BI]; const signatures = [ "transfer(address,uint256)", "transfer(address,uint256)", ]; + const paramsArray: Array = [ + ethereum.Value.fromAddress(proposer), + ethereum.Value.fromUnsignedBigInt(ONE_BI), + ]; + const params = changetype(paramsArray) + const encodedparamsOne = ethereum.encode(ethereum.Value.fromTuple(params))!; + const encodedparamsTwo = ethereum.encode(ethereum.Value.fromTuple(params))!; const calldatas = [ - Bytes.fromHexString("0x000000"), - Bytes.fromHexString("0x000000"), + encodedparamsOne, + encodedparamsTwo, ]; const distributionId = ONE_BI; const startBlock = ONE_BI; @@ -669,8 +790,6 @@ describe("Grant Fund assertions", () => { /********************/ const fundedProposalSlate = [proposalId] - - // TODO: need to determine how to best hash the proposalId array const fundedSlateHash = Bytes.fromHexString("0x000010") mockGetFundedProposalSlate(grantFundAddress, fundedSlateHash, fundedProposalSlate); @@ -687,19 +806,23 @@ describe("Grant Fund assertions", () => { // check Proposal attributes assert.entityCount("Proposal", 1); + assert.entityCount("ProposalParams", 2); assert.entityCount("DistributionPeriod", 1); assert.entityCount("FundedSlate", 1); - logStore(); - - // // check FundedSlate attributes - // assert.fieldEquals( - // "FundedSlate", - // `${fundedSlateHash.toHexString()}`, - // "totalFundingVotesReceived", - // `${votesCast}` - // ); - + // check FundedSlate attributes + assert.fieldEquals( + "FundedSlate", + `${fundedSlateHash.toHexString()}`, + "totalFundingVotesReceived", + `${wadToDecimal(votesCast)}` + ); + assert.fieldEquals( + "FundedSlate", + `${fundedSlateHash.toHexString()}`, + "totalTokensRequested", + `${BigInt.fromI32(2)}` + ); }); });