diff --git a/packages/subgraph/schema.graphql b/packages/subgraph/schema.graphql index 83b37393..3544e09d 100644 --- a/packages/subgraph/schema.graphql +++ b/packages/subgraph/schema.graphql @@ -1,45 +1,62 @@ -# TODO -# get total donated from correct field -# handling of generated pools from factory contract -# per collective donor/steward record -# update nft with stewards on claim - -type Steward @entity { - "{ user address} " - id: String! - " Number of actions performed " - actions: Int! - totalEarned: BigInt! - " NFT's minted to steward" - nfts: [ProvableNFT!]! @derivedFrom(field: "steward") - " Collectives the steward is apart of " - collectives: [Collective!]! @derivedFrom(field: "stewards") +type Donor @entity { + id: String! # The address of the donor + joined: BigInt! + totalDonated: BigInt! + collectives: [DonorCollective!]! } -type Donor @entity { - id: String! # This will be the contract address from which the transaction originated - supporter: Bytes! # Address of the supporter - joined: Int! +"""Represents the relationship between a Donor and a Collective""" +type DonorCollective @entity { + id: String! # donorAddress + " " + collectiveAddress + donor: Donor! @derivedFrom(field: "collectives") + collective: Collective! @derivedFrom(field: "donors") totalDonated: BigInt! + donations: [Donation!]! +} + +type Donation @entity { + id: String! # donorAddress + " " + collectiveAddress + " " + timestamp + donor: Donor! + collective: Collective! + timestamp: BigInt + originationContract: Bytes! # The contract address from which the transaction originated previousContribution: BigInt contribution: BigInt previousFlowRate: BigInt flowRate: BigInt isFlowUpdate: Boolean - collectives: [Collective!]! } -type CollectiveDonor @entity { - id: String! #collective_donor - totalDonated: BigInt! - flowRate: BigInt +type Steward @entity { + """{ user address}""" + id: String! + """Number of actions performed""" + actions: Int! + totalEarned: BigInt! + """NFT's minted to steward""" + nfts: [ProvableNFT!]! + """Collectives the steward is apart of""" + collectives: [StewardCollective!]! } -type CollectiveSteward @entity { - id: String! #collective_donor +"""Represents the relationship between a Steward and a Collective""" +type StewardCollective @entity { + id: String! # stewardAddress + " " + collectiveAddress + steward: Steward! @derivedFrom(field: "collectives") + collective: Collective! @derivedFrom(field: "stewards") actions: Int! totalEarned: BigInt! - nft: [ProvableNFT!]! + rewards: [Reward!]! +} + +type Reward @entity { + id: String! # stewardAddress + " " + collectiveAddress + " " + timestamp + steward: Steward! + collective: Collective! + timestamp: BigInt + quantity: BigInt + rewardPerContributor: BigInt + nft: ProvableNFT! } type Collective @entity { @@ -51,8 +68,10 @@ type Collective @entity { contributions: BigInt! membersValidator: Bytes uniquenessValidator: String - donors: [Donor!] @derivedFrom(field: "collectives") - stewards: [Steward!]! + donors: [DonorCollective!]! + stewards: [StewardCollective!]! + donations: [Donation!]! @derivedFrom(field: "collective") + rewards: [Reward!]! @derivedFrom(field: "collective") rewardToken: String projectId: String isVerified: Boolean @@ -82,7 +101,7 @@ type ProvableNFT @entity { id: ID! owner: String! hash: String! - steward: [Steward!]! + steward: [Steward!]! @derivedFrom(field: "nfts") collective: Collective! } @@ -95,11 +114,11 @@ type EventData @entity { rewardPerContributor: BigInt! contributors: [Steward!]! nft: ProvableNFT! - claim: Claim + claim: Claim @derivedFrom(field: "event") } type Claim @entity { id: String! totalRewards: BigInt! - events: [EventData!] @derivedFrom(field: "claim") + event: EventData! } diff --git a/packages/subgraph/src/mappings/ProvableNFT.ts b/packages/subgraph/src/mappings/ProvableNFT.ts index 3724e4a9..564e311f 100644 --- a/packages/subgraph/src/mappings/ProvableNFT.ts +++ b/packages/subgraph/src/mappings/ProvableNFT.ts @@ -1,18 +1,17 @@ import { ProvableNftMinted } from '../../generated/ProvableNFT/ProvableNFT'; -import { ProvableNFT, Steward } from '../../generated/schema'; +import { ProvableNFT } from '../../generated/schema'; +// Note that ProvableNFT.collective is set by steward reward event export function handleNftMint(event: ProvableNftMinted): void { const tokenID = event.params.tokenId.toString(); const to = event.params.to.toHexString(); const nftHash = event.params.nftDataHash.toHexString(); let provableNFT = ProvableNFT.load(tokenID); - if (provableNFT === null) { provableNFT = new ProvableNFT(tokenID); - provableNFT.id = tokenID; - provableNFT.owner = to; // Fixed this line - provableNFT.hash = nftHash; - provableNFT.save(); } + provableNFT.owner = to; + provableNFT.hash = nftHash; + provableNFT.save(); } diff --git a/packages/subgraph/src/mappings/pool.ts b/packages/subgraph/src/mappings/pool.ts index 4a6bdf96..c478e824 100644 --- a/packages/subgraph/src/mappings/pool.ts +++ b/packages/subgraph/src/mappings/pool.ts @@ -1,4 +1,4 @@ -import { BigInt, Bytes, log } from '@graphprotocol/graph-ts'; +import { BigInt, log } from '@graphprotocol/graph-ts'; import { PoolCreated, PoolDetailsChanged, @@ -10,8 +10,17 @@ import { PoolLimitsChanged, PoolSettingsChanged, } from '../../generated/DirectPaymentsPool/DirectPaymentsPool'; - -import { Claim, Collective, PoolSettings, SafetyLimits, EventData, Steward } from '../../generated/schema'; +import { + Claim, + Collective, + PoolSettings, + SafetyLimits, + EventData, + Steward, + StewardCollective, + ProvableNFT, + Reward, +} from '../../generated/schema'; export function handlePoolCreated(event: PoolCreated): void { const poolAddress = event.params.pool; @@ -39,6 +48,7 @@ export function handlePoolCreated(event: PoolCreated): void { directPaymentPool.timestamp = event.block.timestamp.toI32(); directPaymentPool.contributions = BigInt.fromI32(0); directPaymentPool.stewards = new Array(); + directPaymentPool.donors = new Array(); directPaymentPool.save(); // Pool Settings @@ -141,40 +151,100 @@ export function handleRewardClaim(event: EventRewardClaimed): void { const eventTimestamp = event.params.eventTimestamp; const eventQuantity = event.params.eventQuantity; const eventUri = event.params.eventUri; - const contributers = event.params.contributers; - const rewardPerContributer = event.params.rewardPerContributer; + const contributors = event.params.contributers; + const rewardPerContributor = event.params.rewardPerContributer; + + const nftAddress = claimId.toHexString(); + const poolAddress = event.address.toHexString(); - let pool = Collective.load(event.address.toHexString()); + let pool = Collective.load(poolAddress); if (pool === null) { log.error('Missing Payment Pool {}', [event.address.toHex()]); return; } - let eventData = EventData.load(claimId.toHexString()); + let eventData = EventData.load(nftAddress); if (eventData === null) { - eventData = new EventData(claimId.toHexString()); + eventData = new EventData(nftAddress); eventData.eventType = eventType; eventData.timestamp = eventTimestamp; - eventData.quantity = eventQuantity; eventData.uri = eventUri; - eventData.nft = event.params.tokenId.toHexString(); - eventData.claim = event.params.tokenId.toHexString(); + eventData.quantity = eventQuantity; + eventData.rewardPerContributor = rewardPerContributor; + + // handle claim + let claim = Claim.load(claimId.toHexString()); + if (claim === null) { + claim = new Claim(claimId.toHexString()); + } + claim.event = nftAddress; + claim.totalRewards = rewardPerContributor.times(eventQuantity).times(BigInt.fromI32(contributors.length)); + + // handle nft -> note that ProvableNFT.hash and ProvableNFT.owner are set by NFT mint event + eventData.nft = nftAddress; + let nft = ProvableNFT.load(nftAddress); + if (nft === null) { + nft = new ProvableNFT(nftAddress); + } + nft.collective = poolAddress; + eventData.contributors = new Array(); - for (let i = 0; i < contributers.length; i++) { - eventData.contributors.push(contributers[i].toHexString()); - if (pool.stewards.includes(contributers[i].toHexString()) === false) { - pool.stewards.push(contributers[i].toHexString()); + for (let i = 0; i < contributors.length; i++) { + const stewardAddress = contributors[i].toHexString(); + const stewardCollectiveId = `${stewardAddress} ${poolAddress}`; + const timestamp = event.block.timestamp; + const rewardId = stewardAddress + " " + poolAddress + " " + timestamp.toString(); + + // adds steward to event data + eventData.contributors.push(stewardAddress); + + // update Steward + let steward = Steward.load(contributors[i].toHexString()); + if (steward === null) { + steward = new Steward(contributors[i].toHexString()); + } + steward.nfts.push(nftAddress); + steward.actions = steward.actions + 1; + const totalReward = rewardPerContributor.times(eventQuantity); + steward.totalEarned = steward.totalEarned.plus(totalReward); + + // update StewardCollective + let stewardCollective = StewardCollective.load(stewardCollectiveId); + if (stewardCollective === null) { + stewardCollective = new StewardCollective(stewardCollectiveId); + } + stewardCollective.actions = stewardCollective.actions + 1; + stewardCollective.totalEarned = stewardCollective.totalEarned.plus(totalReward); + // Add StewardCollective to Steward and Collective + if (!steward.collectives.includes(stewardCollectiveId)) { + steward.collectives.push(stewardCollectiveId); } + if (!pool.stewards.includes(stewardCollectiveId)) { + pool.stewards.push(stewardCollectiveId); + } + + // create steward reward + let reward = new Reward(rewardId); + reward.steward = stewardAddress; + reward.collective = poolAddress; + reward.timestamp = timestamp; + reward.quantity = eventQuantity; + reward.rewardPerContributor = rewardPerContributor; + reward.nft = nftAddress; + // add Reward to StewardCollective + stewardCollective.rewards.push(rewardId); + + steward.save(); + stewardCollective.save(); } - eventData.rewardPerContributor = rewardPerContributer; + claim.save(); + nft.save(); pool.save(); eventData.save(); } } -// event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards); - export function handleClaim(event: NFTClaimed): void { const claimId = event.params.tokenId; const totalRewards = event.params.totalRewards; diff --git a/packages/subgraph/src/mappings/superApp.ts b/packages/subgraph/src/mappings/superApp.ts index 7b0aeea8..fc114b15 100644 --- a/packages/subgraph/src/mappings/superApp.ts +++ b/packages/subgraph/src/mappings/superApp.ts @@ -1,39 +1,61 @@ -import { BigInt, Bytes, log } from '@graphprotocol/graph-ts'; +import { BigInt, log } from '@graphprotocol/graph-ts'; import { SupporterUpdated } from '../../generated/DirectPaymentsPool/DirectPaymentsPool'; -import { Collective, Donor } from '../../generated/schema'; +import { Collective, Donation, Donor, DonorCollective } from '../../generated/schema'; export function handleSupport(event: SupporterUpdated): void { - // TODO: need to call contract functions to get donor/pool total donated including streams, the current method done is incorrect + const donorAddress = event.params.supporter.toHexString(); + const poolAddress = event.address.toHexString(); + const donorCollectiveId = donorAddress + " " + poolAddress; + const timestamp = event.block.timestamp; + const donationId = donorAddress + " " + poolAddress + " " + timestamp.toString() - let donorId = event.params.supporter.toHexString(); - let donor = Donor.load(donorId); - let directPaymentPool = Collective.load(event.address.toHexString()); + // update pool + const pool = Collective.load(poolAddress); + // This should never happen + if (pool === null) { + log.error('Missing Payment Pool {}', [event.address.toHex()]); + return; + } + pool.contributions = pool.contributions.plus(event.params.contribution); + // update Donor + let donor = Donor.load(donorAddress); if (donor == null) { - donor = new Donor(donorId); - donor.supporter = event.params.supporter; - donor.joined = event.block.timestamp.toI32(); - donor.totalDonated = event.params.contribution; - donor.collectives = new Array(); + donor = new Donor(donorAddress); + donor.joined = timestamp; + donor.totalDonated = BigInt.fromI32(0); } + // TODO: need to call contract functions to get donor/pool total donated including streams, the current method done is incorrect + donor.totalDonated = donor.totalDonated.plus(event.params.contribution); - if (directPaymentPool === null) { - log.error('Missing Payment Pool {}', [event.address.toHex()]); - return; + // update DonorCollective + let donorCollective = DonorCollective.load(donorCollectiveId); + if (donorCollective == null) { + donorCollective = new DonorCollective(donorCollectiveId); + donorCollective.totalDonated = BigInt.fromI32(0); } + donorCollective.totalDonated = donorCollective.totalDonated.plus(event.params.contribution); - directPaymentPool.contributions = directPaymentPool.contributions.plus(event.params.contribution); + // create Donation + const donation = new Donation(donationId); + donation.donor = donorAddress; + donation.collective = poolAddress; + donation.timestamp = timestamp; + donation.originationContract = event.address; + donation.previousContribution = event.params.previousContribution; + donation.contribution = event.params.contribution; + donation.previousFlowRate = event.params.previousFlowRate; + donation.flowRate = event.params.flowRate; + donation.isFlowUpdate = event.params.isFlowUpdate; - donor.previousContribution = event.params.previousContribution; - donor.totalDonated = donor.totalDonated.plus(event.params.contribution); // Update totalDonated based on the current total - donor.contribution = event.params.contribution; - donor.previousFlowRate = event.params.previousFlowRate; - donor.flowRate = event.params.flowRate; - donor.isFlowUpdate = event.params.isFlowUpdate; - if (donor.collectives.includes(event.address.toHexString()) == false) { - donor.collectives.push(event.address.toHexString()); - } + // add Donation to DonorCollective + donorCollective.donations.push(donationId); + + // add DonorCollective to Donor + donor.collectives.push(donorCollectiveId); - directPaymentPool.save(); // Save the updated directPaymentPool entity donor.save(); + donorCollective.save(); + donation.save(); + pool.save(); }