From 96f06f8f3c2e1eb789e0ea42cc0b939f24bee0c7 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:05:09 -0700 Subject: [PATCH 01/59] remove unnecessary entities --- projects/subgraph-beanstalk/schema.graphql | 226 ------------------ .../subgraph-beanstalk/src/FieldHandler.ts | 17 -- .../subgraph-beanstalk/src/SeasonHandler.ts | 55 +---- .../subgraph-beanstalk/src/SiloHandler.ts | 129 +--------- .../subgraph-beanstalk/src/YieldHandler.ts | 3 +- .../src/utils/PodTransfer.ts | 17 -- 6 files changed, 14 insertions(+), 433 deletions(-) delete mode 100644 projects/subgraph-beanstalk/src/utils/PodTransfer.ts diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index ee657640a4..4b4cd3d2a0 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -1286,50 +1286,6 @@ interface MarketplaceEvent { createdAt: BigInt! } -type PodTransfer implements FieldEvent @entity(immutable: true) { - " podtransfer-{ Transaction hash }-{ Log index } " - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Address that received the pods " - toFarmer: String! - " Address that sent the pods " - fromFarmer: String! - " Index of the pods sent" - index: BigInt! - " Total pods being sent" - pods: BigInt! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type Harvest implements FieldEvent @entity(immutable: true) { - "harvest-{ Transaction hash }-{ Log index } " - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Address harvesting beans " - farmer: String! - " Plots being harvested " - plots: [BigInt!]! - " Total beans harvested " - beans: BigInt! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - type Chop implements SiloEvent @entity(immutable: true) { "chop-{ Transaction hash }-{ Log index }" id: ID! @@ -1353,188 +1309,6 @@ type Chop implements SiloEvent @entity(immutable: true) { createdAt: BigInt! } -type Incentive implements SiloEvent @entity(immutable: true) { - "incentive-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Address incentivized " - caller: String! - " Amount minted as incentive" - amount: BigInt! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type Reward implements SiloEvent @entity(immutable: true) { - "reward-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Season of reward " - season: Int! - " Amount minted to pod line" - toField: BigInt! - " Amount minted to silo" - toSilo: BigInt! - " Amount minted to fertilizer" - toFertilizer: BigInt! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type MetapoolOracle implements SiloEvent @entity(immutable: true) { - "metapoolOracle-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Season of oracle " - season: Int! - " DeltaB for season" - deltaB: BigInt! - " Cumulative balance A" - balanceA: BigInt! - " Cumulative balance B" - balanceB: BigInt! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type WellOracle implements SiloEvent @entity(immutable: true) { - "wellOracle-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Season of oracle " - season: Int! - " DeltaB for season" - deltaB: BigInt! - " Time weighted cumulative reserves " - cumulativeReserves: Bytes! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type AddDeposit implements SiloEvent @entity(immutable: true) { - "addDeposit-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Account adding deposit" - account: String! - " Token added" - token: String! - " Season of deposit added " - season: Int! - " Stem of deposit added " - stem: BigInt - " Amount of token added " - amount: BigInt! - " BDV of the deposit " - bdv: BigInt! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type RemoveDeposit implements SiloEvent @entity(immutable: true) { - "removeDeposit-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Account removing deposit" - account: String! - " Token removed" - token: String! - " Season of deposit removed " - season: Int! - " Stem of deposit removed " - stem: BigInt - " Amount of token removed " - amount: BigInt! - " BDV of deposit removed " - bdv: BigInt - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type StalkChange implements SiloEvent @entity(immutable: true) { - "stalkChange-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Account removing deposit" - account: String! - " Token removed" - delta: BigInt! - " Season when the change happened " - season: Int! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type SeedChange implements SiloEvent @entity(immutable: true) { - "seedChange-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - " Account removing deposit" - account: String! - " Token removed" - delta: BigInt! - " Season when the change happened " - season: Int! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - type PodListingCreated implements MarketplaceEvent @entity(immutable: true) { "podListingCreated-{ Transaction hash }-{ Log index }" id: ID! diff --git a/projects/subgraph-beanstalk/src/FieldHandler.ts b/projects/subgraph-beanstalk/src/FieldHandler.ts index 4f024e9d66..4364376be7 100644 --- a/projects/subgraph-beanstalk/src/FieldHandler.ts +++ b/projects/subgraph-beanstalk/src/FieldHandler.ts @@ -9,13 +9,11 @@ import { SupplyNeutral, WeatherChange } from "../generated/Beanstalk-ABIs/PreReplant"; -import { Harvest as HarvestEntity } from "../generated/schema"; import { BEANSTALK, BEANSTALK_FARMS } from "../../subgraph-core/utils/Constants"; import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadFarmer } from "./utils/Farmer"; import { handleRateChange, loadField, loadFieldDaily, loadFieldHourly } from "./utils/Field"; import { loadPlot } from "./utils/Plot"; -import { savePodTransfer } from "./utils/PodTransfer"; import { getCurrentSeason, getHarvestableIndex, loadSeason } from "./utils/Season"; import { loadBeanstalk } from "./utils/Beanstalk"; import { expirePodListingIfExists } from "./utils/PodListing"; @@ -203,18 +201,6 @@ export function handleHarvest(event: Harvest): void { } field.plotIndexes = newIndexes; field.save(); - - // Save the low level details for the event. - let harvest = new HarvestEntity("harvest-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString()); - harvest.hash = event.transaction.hash.toHexString(); - harvest.logIndex = event.transactionLogIndex.toI32(); - harvest.protocol = event.address.toHexString(); - harvest.farmer = event.params.account.toHexString(); - harvest.plots = event.params.plots; - harvest.beans = event.params.beans; - harvest.blockNumber = event.block.number; - harvest.createdAt = event.block.timestamp; - harvest.save(); } export function handlePlotTransfer(event: PlotTransfer): void { @@ -472,9 +458,6 @@ export function handlePlotTransfer(event: PlotTransfer): void { event.block.number ); } - - // Save the raw event data - savePodTransfer(event); } export function handleSupplyIncrease(event: SupplyIncrease): void { diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index bb4efee92e..1bcca56cfe 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -2,10 +2,8 @@ import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; import { MetapoolOracle, Reward, Soil, WellOracle } from "../generated/Beanstalk-ABIs/BasinBip"; import { CurvePrice } from "../generated/Beanstalk-ABIs/CurvePrice"; import { SeasonSnapshot, Sunrise, Incentivization, PreReplant } from "../generated/Beanstalk-ABIs/PreReplant"; -import { Incentive } from "../generated/schema"; import { updateHarvestablePlots } from "./FieldHandler"; import { loadBeanstalk } from "./utils/Beanstalk"; -import { Reward as RewardEntity, MetapoolOracle as MetapoolOracleEntity, WellOracle as WellOracleEntity } from "../generated/schema"; import { BEANSTALK, BEAN_ERC20, CURVE_PRICE, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadField, loadFieldDaily, loadFieldHourly } from "./utils/Field"; @@ -88,21 +86,8 @@ export function handleSeasonSnapshot(event: SeasonSnapshot): void { } export function handleReward(event: Reward): void { - let id = "reward-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let reward = new RewardEntity(id); - reward.hash = event.transaction.hash.toHexString(); - reward.logIndex = event.transactionLogIndex.toI32(); - reward.protocol = event.address.toHexString(); - reward.season = event.params.season.toI32(); - reward.toField = event.params.toField; - reward.toSilo = event.params.toSilo; - reward.toFertilizer = event.params.toFertilizer; - reward.blockNumber = event.block.number; - reward.createdAt = event.block.timestamp; - reward.save(); - let season = loadSeason(event.address, event.params.season); - season.rewardBeans = reward.toField.plus(reward.toSilo).plus(reward.toFertilizer); + season.rewardBeans = event.params.toField.plus(event.params.toSilo).plus(event.params.toFertilizer); season.save(); // Add to total Silo Bean mints @@ -145,19 +130,6 @@ export function handleReward(event: Reward): void { } export function handleMetapoolOracle(event: MetapoolOracle): void { - let id = "metapoolOracle-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let oracle = new MetapoolOracleEntity(id); - oracle.hash = event.transaction.hash.toHexString(); - oracle.logIndex = event.transactionLogIndex.toI32(); - oracle.protocol = event.address.toHexString(); - oracle.season = event.params.season.toI32(); - oracle.deltaB = event.params.deltaB; - oracle.balanceA = event.params.balances[0]; - oracle.balanceB = event.params.balances[1]; - oracle.blockNumber = event.block.number; - oracle.createdAt = event.block.timestamp; - oracle.save(); - if (event.block.number < GAUGE_BIP45_BLOCK) { let season = loadSeason(event.address, event.params.season); // Attempt to pull from Beanstalk Price contract first @@ -174,18 +146,6 @@ export function handleMetapoolOracle(event: MetapoolOracle): void { } export function handleWellOracle(event: WellOracle): void { - let id = "wellOracle-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let oracle = new WellOracleEntity(id); - oracle.hash = event.transaction.hash.toHexString(); - oracle.logIndex = event.transactionLogIndex.toI32(); - oracle.protocol = event.address.toHexString(); - oracle.season = event.params.season.toI32(); - oracle.deltaB = event.params.deltaB; - oracle.cumulativeReserves = event.params.cumulativeReserves; - oracle.blockNumber = event.block.number; - oracle.createdAt = event.block.timestamp; - oracle.save(); - let season = loadSeason(event.address, event.params.season); season.deltaB = season.deltaB.plus(event.params.deltaB); if (event.block.number >= GAUGE_BIP45_BLOCK && season.price == ZERO_BD) { @@ -223,19 +183,8 @@ export function handleSoil(event: Soil): void { } } +// This is the final function to be called during sunrise both pre and post replant export function handleIncentive(event: Incentivization): void { - // This is the final function to be called during sunrise both pre and post replant - let id = "incentive-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let incentive = new Incentive(id); - incentive.hash = event.transaction.hash.toHexString(); - incentive.logIndex = event.transactionLogIndex.toI32(); - incentive.protocol = event.address.toHexString(); - incentive.caller = event.params.account.toHexString(); - incentive.amount = event.params.beans; - incentive.blockNumber = event.block.number; - incentive.createdAt = event.block.timestamp; - incentive.save(); - // Update market cap for season let beanstalk = loadBeanstalk(event.address); let beanstalk_contract = PreReplant.bind(BEANSTALK); diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index b41680780a..6d5fbe5e05 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -37,18 +37,13 @@ import { loadWhitelistTokenDailySnapshot, addToSiloWhitelist } from "./utils/SiloEntities"; -import { - AddDeposit as AddDepositEntity, - RemoveDeposit as RemoveDepositEntity, - WhitelistToken as WhitelistTokenEntity, - DewhitelistToken as DewhitelistTokenEntity, - SeedChange, - StalkChange -} from "../generated/schema"; +import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity } from "../generated/schema"; import { loadBeanstalk } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20 } from "../../subgraph-core/utils/Constants"; import { getCurrentSeason } from "./utils/Season"; +// TODO: extract common logic between v2, v3 handlers + /** * SILO V2 (REPLANT) HANDLERS */ @@ -107,20 +102,6 @@ export function handleAddDeposit(event: AddDeposit): void { event.block.timestamp, event.block.number ); - - let id = "addDeposit-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let add = new AddDepositEntity(id); - add.hash = event.transaction.hash.toHexString(); - add.logIndex = event.transactionLogIndex.toI32(); - add.protocol = event.address.toHexString(); - add.account = event.params.account.toHexString(); - add.token = event.params.token.toHexString(); - add.season = event.params.season.toI32(); - add.amount = event.params.amount; - add.bdv = event.params.bdv; - add.blockNumber = event.block.number; - add.createdAt = event.block.timestamp; - add.save(); } export function handleRemoveDeposit(event: RemoveDeposit): void { @@ -171,25 +152,13 @@ export function handleRemoveDeposit(event: RemoveDeposit): void { event.block.timestamp, event.block.number ); - - let id = "removeDeposit-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let removal = new RemoveDepositEntity(id); - removal.hash = event.transaction.hash.toHexString(); - removal.logIndex = event.transactionLogIndex.toI32(); - removal.protocol = event.address.toHexString(); - removal.account = event.params.account.toHexString(); - removal.token = event.params.token.toHexString(); - removal.season = event.params.season.toI32(); - removal.amount = event.params.amount; - removal.blockNumber = event.block.number; - removal.createdAt = event.block.timestamp; - removal.save(); } export function handleRemoveDeposits(event: RemoveDeposits): void { let beanstalk = loadBeanstalk(event.address); // get current season for (let i = 0; i < event.params.seasons.length; i++) { + // TODO: extract common loop logic let deposit = loadSiloDeposit(event.params.account, event.params.token, event.params.seasons[i]); let withdrawnBDV = deposit.amount == ZERO_BI ? ZERO_BI : event.params.amounts[i].times(deposit.bdv).div(deposit.amount); @@ -236,19 +205,6 @@ export function handleRemoveDeposits(event: RemoveDeposits): void { event.block.timestamp, event.block.number ); - - let id = "removeDeposit-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString() + "-" + i.toString(); - let removal = new RemoveDepositEntity(id); - removal.hash = event.transaction.hash.toHexString(); - removal.logIndex = event.transactionLogIndex.toI32(); - removal.protocol = event.address.toHexString(); - removal.account = event.params.account.toHexString(); - removal.token = event.params.token.toHexString(); - removal.season = event.params.seasons[i].toI32(); - removal.amount = event.params.amounts[i]; - removal.blockNumber = event.block.number; - removal.createdAt = event.block.timestamp; - removal.save(); } } @@ -310,21 +266,6 @@ export function handleAddDeposit_V3(event: AddDeposit_V3): void { event.block.timestamp, event.block.number ); - - let id = "addDeposit-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let add = new AddDepositEntity(id); - add.hash = event.transaction.hash.toHexString(); - add.logIndex = event.transactionLogIndex.toI32(); - add.protocol = event.address.toHexString(); - add.account = event.params.account.toHexString(); - add.token = event.params.token.toHexString(); - add.season = beanstalk.lastSeason; - add.stem = event.params.stem; - add.amount = event.params.amount; - add.bdv = event.params.bdv; - add.blockNumber = event.block.number; - add.createdAt = event.block.timestamp; - add.save(); } export function handleRemoveDeposit_V3(event: RemoveDeposit_V3): void { @@ -373,21 +314,6 @@ export function handleRemoveDeposit_V3(event: RemoveDeposit_V3): void { event.block.timestamp, event.block.number ); - - let id = "removeDeposit-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let removal = new RemoveDepositEntity(id); - removal.hash = event.transaction.hash.toHexString(); - removal.logIndex = event.transactionLogIndex.toI32(); - removal.protocol = event.address.toHexString(); - removal.account = event.params.account.toHexString(); - removal.token = event.params.token.toHexString(); - removal.season = beanstalk.lastSeason; - removal.stem = event.params.stem; - removal.amount = event.params.amount; - removal.bdv = event.params.bdv; - removal.blockNumber = event.block.number; - removal.createdAt = event.block.timestamp; - removal.save(); } export function handleRemoveDeposits_V3(event: RemoveDeposits_V3): void { @@ -438,21 +364,6 @@ export function handleRemoveDeposits_V3(event: RemoveDeposits_V3): void { event.block.timestamp, event.block.number ); - - let id = "removeDeposit-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString() + "-" + i.toString(); - let removal = new RemoveDepositEntity(id); - removal.hash = event.transaction.hash.toHexString(); - removal.logIndex = event.transactionLogIndex.toI32(); - removal.protocol = event.address.toHexString(); - removal.account = event.params.account.toHexString(); - removal.token = event.params.token.toHexString(); - removal.season = beanstalk.lastSeason; - removal.stem = event.params.stems[i]; - removal.amount = event.params.amounts[i]; - removal.bdv = event.params.bdvs[i]; - removal.blockNumber = event.block.number; - removal.createdAt = event.block.timestamp; - removal.save(); } } @@ -495,7 +406,9 @@ export function handleRemoveWithdrawals(event: RemoveWithdrawals): void { export function handleStalkBalanceChanged(event: StalkBalanceChanged): void { // Exclude BIP-24 emission of missed past events - if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") return; + if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { + return; + } let beanstalk = loadBeanstalk(event.address); // get current season updateStalkBalances( @@ -514,39 +427,17 @@ export function handleStalkBalanceChanged(event: StalkBalanceChanged): void { event.block.timestamp, event.block.number ); - - let id = "stalkChange-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let removal = new StalkChange(id); - removal.hash = event.transaction.hash.toHexString(); - removal.logIndex = event.transactionLogIndex.toI32(); - removal.protocol = event.address.toHexString(); - removal.account = event.params.account.toHexString(); - removal.delta = event.params.delta; - removal.season = beanstalk.lastSeason; - removal.blockNumber = event.block.number; - removal.createdAt = event.block.timestamp; - removal.save(); } export function handleSeedsBalanceChanged(event: SeedsBalanceChanged): void { // Exclude BIP-24 emission of missed past events - if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") return; + if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { + return; + } let beanstalk = loadBeanstalk(event.address); // get current season updateSeedsBalances(event.address, beanstalk.lastSeason, event.params.delta, event.block.timestamp, event.block.number); updateSeedsBalances(event.params.account, beanstalk.lastSeason, event.params.delta, event.block.timestamp, event.block.number); - - let id = "seedChange-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let removal = new SeedChange(id); - removal.hash = event.transaction.hash.toHexString(); - removal.logIndex = event.transactionLogIndex.toI32(); - removal.protocol = event.address.toHexString(); - removal.account = event.params.account.toHexString(); - removal.delta = event.params.delta; - removal.season = beanstalk.lastSeason; - removal.blockNumber = event.block.number; - removal.createdAt = event.block.timestamp; - removal.save(); } export function handlePlant(event: Plant): void { diff --git a/projects/subgraph-beanstalk/src/YieldHandler.ts b/projects/subgraph-beanstalk/src/YieldHandler.ts index 5ec8ca83c4..1b56733d66 100644 --- a/projects/subgraph-beanstalk/src/YieldHandler.ts +++ b/projects/subgraph-beanstalk/src/YieldHandler.ts @@ -506,7 +506,8 @@ function deltaRFromState(earnedBeans: f64): f64 { return -0.01; } -// TODO: implement the various gauge point functions and choose which one to call based on the stored selector +// (this may no longer be relevant as an api approach to vapys is preferred) +// Can implement the various gauge point functions and choose which one to call based on the stored selector // see {GaugePointFacet.defaultGaugePointFunction} for implementation. // This will become relevant once there are multiple functions implemented in the contract. function updateGaugePoints(gaugePoints: f64, currentPercent: f64, optimalPercent: f64): f64 { diff --git a/projects/subgraph-beanstalk/src/utils/PodTransfer.ts b/projects/subgraph-beanstalk/src/utils/PodTransfer.ts deleted file mode 100644 index edc24d3e0b..0000000000 --- a/projects/subgraph-beanstalk/src/utils/PodTransfer.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PlotTransfer } from "../../generated/Beanstalk-ABIs/PreReplant"; -import { PodTransfer } from "../../generated/schema"; - -export function savePodTransfer(event: PlotTransfer): void { - let id = "podtransfer" + "-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let transfer = new PodTransfer(id); - transfer.hash = event.transaction.hash.toHexString(); - transfer.logIndex = event.transactionLogIndex.toI32(); - transfer.protocol = event.address.toHexString(); - transfer.toFarmer = event.params.to.toHexString(); - transfer.fromFarmer = event.params.from.toHexString(); - transfer.index = event.params.id; - transfer.pods = event.params.pods; - transfer.blockNumber = event.block.number; - transfer.createdAt = event.block.timestamp; - transfer.save(); -} From e5938b7fb2686ef6751b4c33fec21419454b28cd Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:47:55 -0700 Subject: [PATCH 02/59] consolidate utils --- .../manifests/ethereum.yaml | 52 +++++++++---------- .../{FertilizerHandler.ts => BarnHandler.ts} | 19 ++++++- .../subgraph-beanstalk/src/BeanHandler.ts | 3 +- .../subgraph-beanstalk/src/FarmHandler.ts | 5 +- .../subgraph-beanstalk/src/FieldHandler.ts | 7 +-- .../subgraph-beanstalk/src/GaugeHandler.ts | 4 +- .../src/MarketplaceHandler.ts | 7 ++- .../subgraph-beanstalk/src/ReplantHandler.ts | 17 ------ .../subgraph-beanstalk/src/SeasonHandler.ts | 5 +- .../subgraph-beanstalk/src/SiloHandler.ts | 6 +-- .../subgraph-beanstalk/src/YieldHandler.ts | 7 ++- .../subgraph-beanstalk/src/utils/Beanstalk.ts | 52 +++++++++++++++++-- .../src/utils/BeanstalkPrice.ts | 2 +- .../subgraph-beanstalk/src/utils/Farmer.ts | 11 ---- .../src/utils/Fertilizer.ts | 29 ++++++++++- .../src/utils/FertilizerYield.ts | 27 ---------- .../subgraph-beanstalk/src/utils/Field.ts | 44 +++++++++++++--- projects/subgraph-beanstalk/src/utils/Plot.ts | 33 ------------ .../subgraph-beanstalk/src/utils/PodFill.ts | 22 -------- .../src/utils/PodMarketplace.ts | 23 +++++++- .../subgraph-beanstalk/src/utils/PodOrder.ts | 35 +------------ .../subgraph-beanstalk/src/utils/Season.ts | 47 ----------------- .../src/utils/{SiloEntities.ts => Silo.ts} | 4 +- .../src/utils/{Dates.ts => Snapshots.ts} | 0 .../subgraph-beanstalk/src/utils/Token.ts | 44 ---------------- .../src/utils/Transaction.ts | 16 ------ .../src/yield_cache/CacheLoader.ts | 2 +- .../tests/SeedGauge.test.ts | 4 +- .../tests/YieldHandler.test.ts | 2 +- 29 files changed, 204 insertions(+), 325 deletions(-) rename projects/subgraph-beanstalk/src/{FertilizerHandler.ts => BarnHandler.ts} (68%) delete mode 100644 projects/subgraph-beanstalk/src/ReplantHandler.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/Farmer.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/FertilizerYield.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/Plot.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/PodFill.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/Season.ts rename projects/subgraph-beanstalk/src/utils/{SiloEntities.ts => Silo.ts} (99%) rename projects/subgraph-beanstalk/src/utils/{Dates.ts => Snapshots.ts} (100%) delete mode 100644 projects/subgraph-beanstalk/src/utils/Token.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/Transaction.ts diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index c7e93d94d5..18aa404f4d 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -580,30 +580,6 @@ dataSources: - event: Transfer(indexed address,indexed address,uint256) handler: handleTransfer file: ../src/BeanHandler.ts - - kind: ethereum/contract - name: Replant - network: mainnet - source: - address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 - startBlock: 15277986 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Replant - abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json - eventHandlers: - - event: Chop(indexed address,indexed address,uint256,uint256) - handler: handleChop - file: ../src/ReplantHandler.ts - kind: ethereum/contract name: Season-Replanted network: mainnet @@ -639,7 +615,7 @@ dataSources: handler: handleSoil file: ../src/SeasonHandler.ts - kind: ethereum/contract - name: Fertilizer + name: Fertilizer-1155 network: mainnet source: address: "0x402c84De2Ce49aF88f5e2eF3710ff89bFED36cB6" @@ -661,7 +637,31 @@ dataSources: handler: handleTransferBatch - event: TransferSingle(indexed address,indexed address,indexed address,uint256,uint256) handler: handleTransferSingle - file: ../src/FertilizerHandler.ts + file: ../src/BarnHandler.ts + - kind: ethereum/contract + name: Fertilizer-Beanstalk + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: MarketV2 + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Replant + abis: + - name: MarketV2 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: Chop(indexed address,indexed address,uint256,uint256) + handler: handleChop + file: ../src/BarnHandler.ts - kind: ethereum/contract name: Farm network: mainnet diff --git a/projects/subgraph-beanstalk/src/FertilizerHandler.ts b/projects/subgraph-beanstalk/src/BarnHandler.ts similarity index 68% rename from projects/subgraph-beanstalk/src/FertilizerHandler.ts rename to projects/subgraph-beanstalk/src/BarnHandler.ts index 3d442411e8..e0a108db8a 100644 --- a/projects/subgraph-beanstalk/src/FertilizerHandler.ts +++ b/projects/subgraph-beanstalk/src/BarnHandler.ts @@ -1,8 +1,10 @@ +import { Chop as ChopEntity } from "../generated/schema"; +import { Chop } from "../generated/Beanstalk-ABIs/MarketV2"; import { Address, BigInt, log } from "@graphprotocol/graph-ts"; import { TransferSingle, TransferBatch } from "../generated/Beanstalk-ABIs/Fertilizer"; import { ADDRESS_ZERO, FERTILIZER } from "../../subgraph-core/utils/Constants"; import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "./utils/Fertilizer"; -import { loadFarmer } from "./utils/Farmer"; +import { loadFarmer } from "./utils/Beanstalk"; export function handleTransferSingle(event: TransferSingle): void { handleTransfer(event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); @@ -37,3 +39,18 @@ function handleTransfer(from: Address, to: Address, id: BigInt, amount: BigInt, toFertilizerBalance.amount = toFertilizerBalance.amount.plus(amount); toFertilizerBalance.save(); } + +export function handleChop(event: Chop): void { + let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); + let chop = new ChopEntity(id); + chop.hash = event.transaction.hash.toHexString(); + chop.logIndex = event.transactionLogIndex.toI32(); + chop.protocol = event.address.toHexString(); + chop.farmer = event.params.account.toHexString(); + chop.unripe = event.params.token.toHexString(); + chop.amount = event.params.amount; + chop.underlying = event.params.underlying.toHexString(); + chop.blockNumber = event.block.number; + chop.createdAt = event.block.timestamp; + chop.save(); +} diff --git a/projects/subgraph-beanstalk/src/BeanHandler.ts b/projects/subgraph-beanstalk/src/BeanHandler.ts index 7c77aa0ed8..45ca5959e2 100644 --- a/projects/subgraph-beanstalk/src/BeanHandler.ts +++ b/projects/subgraph-beanstalk/src/BeanHandler.ts @@ -2,9 +2,8 @@ import { BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; import { Transfer as LegacyTransfer } from "../generated/Beanstalk-ABIs/ERC20"; import { Transfer } from "../generated/Beanstalk-ABIs/ERC20"; import { ADDRESS_ZERO, BEANSTALK } from "../../subgraph-core/utils/Constants"; -import { loadSeason } from "./utils/Season"; import { toDecimal, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadBeanstalk } from "./utils/Beanstalk"; +import { loadBeanstalk, loadSeason } from "./utils/Beanstalk"; export function handleLegacyTransfer(event: LegacyTransfer): void { if (event.block.number > BigInt.fromI32(14603000)) { diff --git a/projects/subgraph-beanstalk/src/FarmHandler.ts b/projects/subgraph-beanstalk/src/FarmHandler.ts index 4ca457deb7..dde579c131 100644 --- a/projects/subgraph-beanstalk/src/FarmHandler.ts +++ b/projects/subgraph-beanstalk/src/FarmHandler.ts @@ -1,9 +1,8 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; import { InternalBalanceChanged } from "../generated/Beanstalk-ABIs/MarketV2"; -import { loadBeanstalk } from "./utils/Beanstalk"; +import { loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK } from "../../subgraph-core/utils/Constants"; -import { loadSiloAsset, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot } from "./utils/SiloEntities"; -import { loadFarmer } from "./utils/Farmer"; +import { loadSiloAsset, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot } from "./utils/Silo"; export function handleInternalBalanceChanged(event: InternalBalanceChanged): void { let beanstalk = loadBeanstalk(BEANSTALK); diff --git a/projects/subgraph-beanstalk/src/FieldHandler.ts b/projects/subgraph-beanstalk/src/FieldHandler.ts index 4364376be7..879973157c 100644 --- a/projects/subgraph-beanstalk/src/FieldHandler.ts +++ b/projects/subgraph-beanstalk/src/FieldHandler.ts @@ -11,11 +11,8 @@ import { } from "../generated/Beanstalk-ABIs/PreReplant"; import { BEANSTALK, BEANSTALK_FARMS } from "../../subgraph-core/utils/Constants"; import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadFarmer } from "./utils/Farmer"; -import { handleRateChange, loadField, loadFieldDaily, loadFieldHourly } from "./utils/Field"; -import { loadPlot } from "./utils/Plot"; -import { getCurrentSeason, getHarvestableIndex, loadSeason } from "./utils/Season"; -import { loadBeanstalk } from "./utils/Beanstalk"; +import { getHarvestableIndex, handleRateChange, loadField, loadFieldDaily, loadFieldHourly, loadPlot } from "./utils/Field"; +import { getCurrentSeason, loadBeanstalk, loadFarmer, loadSeason } from "./utils/Beanstalk"; import { expirePodListingIfExists } from "./utils/PodListing"; export function handleWeatherChange(event: WeatherChange): void { diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index c887572ce0..54e5177283 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -19,14 +19,14 @@ import { loadWhitelistTokenDailySnapshot, loadWhitelistTokenHourlySnapshot, addToSiloWhitelist -} from "./utils/SiloEntities"; +} from "./utils/Silo"; import { deleteGerminating, loadGerminating, loadOrCreateGerminating } from "./utils/Germinating"; import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { updateStalkBalances } from "./SiloHandler"; -import { getCurrentSeason } from "./utils/Season"; import { WhitelistToken as WhitelistTokenEntity } from "../generated/schema"; import { BEAN_WETH_CP2_WELL } from "../../subgraph-core/utils/Constants"; import { Bytes4_emptyToNull } from "../../subgraph-core/utils/Bytes"; +import { getCurrentSeason } from "./utils/Beanstalk"; export function handleTemperatureChange(event: TemperatureChange): void { handleRateChange(event.address, event.block, event.params.season, event.params.caseId, event.params.absChange); diff --git a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts b/projects/subgraph-beanstalk/src/MarketplaceHandler.ts index 05e3fdb7e5..875e46a09d 100644 --- a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts +++ b/projects/subgraph-beanstalk/src/MarketplaceHandler.ts @@ -27,10 +27,9 @@ import { PodListing } from "../generated/schema"; import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadFarmer } from "./utils/Farmer"; -import { loadPodFill } from "./utils/PodFill"; import { createHistoricalPodListing, loadPodListing } from "./utils/PodListing"; import { + loadPodFill, MarketplaceAction, updateActiveListings, updateActiveOrders, @@ -38,8 +37,8 @@ import { updateMarketOrderBalances } from "./utils/PodMarketplace"; import { createHistoricalPodOrder, loadPodOrder } from "./utils/PodOrder"; -import { getHarvestableIndex } from "./utils/Season"; -import { loadPlot } from "./utils/Plot"; +import { loadFarmer } from "./utils/Beanstalk"; +import { getHarvestableIndex, loadPlot } from "./utils/Field"; class PodListingCreatedParams { event: ethereum.Event; diff --git a/projects/subgraph-beanstalk/src/ReplantHandler.ts b/projects/subgraph-beanstalk/src/ReplantHandler.ts deleted file mode 100644 index 56f90b3393..0000000000 --- a/projects/subgraph-beanstalk/src/ReplantHandler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Chop as ChopEntity } from "../generated/schema"; -import { Chop } from "../generated/Beanstalk-ABIs/MarketV2"; - -export function handleChop(event: Chop): void { - let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let chop = new ChopEntity(id); - chop.hash = event.transaction.hash.toHexString(); - chop.logIndex = event.transactionLogIndex.toI32(); - chop.protocol = event.address.toHexString(); - chop.farmer = event.params.account.toHexString(); - chop.unripe = event.params.token.toHexString(); - chop.amount = event.params.amount; - chop.underlying = event.params.underlying.toHexString(); - chop.blockNumber = event.block.number; - chop.createdAt = event.block.timestamp; - chop.save(); -} diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index 1bcca56cfe..7187b3e0b7 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -3,7 +3,7 @@ import { MetapoolOracle, Reward, Soil, WellOracle } from "../generated/Beanstalk import { CurvePrice } from "../generated/Beanstalk-ABIs/CurvePrice"; import { SeasonSnapshot, Sunrise, Incentivization, PreReplant } from "../generated/Beanstalk-ABIs/PreReplant"; import { updateHarvestablePlots } from "./FieldHandler"; -import { loadBeanstalk } from "./utils/Beanstalk"; +import { loadBeanstalk, loadSeason } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, CURVE_PRICE, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadField, loadFieldDaily, loadFieldHourly } from "./utils/Field"; @@ -13,7 +13,6 @@ import { loadPodMarketplaceHourlySnapshot, updateExpiredPlots } from "./utils/PodMarketplace"; -import { loadSeason } from "./utils/Season"; import { addDepositToSiloAsset, updateStalkWithCalls } from "./SiloHandler"; import { updateBeanEMA } from "./YieldHandler"; import { @@ -22,7 +21,7 @@ import { loadSiloHourlySnapshot, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot -} from "./utils/SiloEntities"; +} from "./utils/Silo"; import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/BeanstalkPrice"; export function handleSunrise(event: Sunrise): void { diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 6d5fbe5e05..f34a7fbe8a 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -21,7 +21,6 @@ import { } from "../generated/Beanstalk-ABIs/SiloV3"; import { Replanted, TransferDepositCall, TransferDepositsCall } from "../generated/Beanstalk-ABIs/Replanted"; import { ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadFarmer } from "./utils/Farmer"; import { loadSilo, loadSiloDailySnapshot, @@ -36,11 +35,10 @@ import { loadWhitelistTokenHourlySnapshot, loadWhitelistTokenDailySnapshot, addToSiloWhitelist -} from "./utils/SiloEntities"; +} from "./utils/Silo"; import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity } from "../generated/schema"; -import { loadBeanstalk } from "./utils/Beanstalk"; +import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20 } from "../../subgraph-core/utils/Constants"; -import { getCurrentSeason } from "./utils/Season"; // TODO: extract common logic between v2, v3 handlers diff --git a/projects/subgraph-beanstalk/src/YieldHandler.ts b/projects/subgraph-beanstalk/src/YieldHandler.ts index 1b56733d66..96d55a87b0 100644 --- a/projects/subgraph-beanstalk/src/YieldHandler.ts +++ b/projects/subgraph-beanstalk/src/YieldHandler.ts @@ -2,8 +2,7 @@ import { Address, BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; import { BasinBip } from "../generated/Beanstalk-ABIs/BasinBip"; import { BEANSTALK, BEAN_ERC20, FERTILIZER } from "../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadFertilizer } from "./utils/Fertilizer"; -import { loadFertilizerYield } from "./utils/FertilizerYield"; +import { loadFertilizer, loadFertilizerYield } from "./utils/Fertilizer"; import { loadSilo, loadSiloAsset, @@ -12,11 +11,11 @@ import { loadTokenYield, loadWhitelistTokenSetting, SiloAsset_findIndex_token -} from "./utils/SiloEntities"; +} from "./utils/Silo"; import { BigDecimal_sum, f64_sum, f64_max } from "../../subgraph-core/utils/ArrayMath"; import { getGerminatingBdvs } from "./utils/Germinating"; -import { getCurrentSeason } from "./utils/Season"; import { SiloAsset, WhitelistTokenSetting } from "../generated/schema"; +import { getCurrentSeason } from "./utils/Beanstalk"; const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; diff --git a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts index 185ef0f0d7..a8697509df 100644 --- a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts @@ -1,6 +1,6 @@ -import { Address } from "@graphprotocol/graph-ts"; -import { Beanstalk } from "../../generated/schema"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { BigInt, Address } from "@graphprotocol/graph-ts"; +import { Beanstalk, Farmer, Season } from "../../generated/schema"; +import { ONE_BI, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; export function loadBeanstalk(protocol: Address): Beanstalk { let beanstalk = Beanstalk.load(protocol.toHexString()); @@ -19,3 +19,49 @@ export function loadBeanstalk(protocol: Address): Beanstalk { } return beanstalk as Beanstalk; } + +export function loadFarmer(account: Address): Farmer { + let farmer = Farmer.load(account.toHexString()); + if (farmer == null) { + farmer = new Farmer(account.toHexString()); + farmer.save(); + } + return farmer; +} + +export function loadSeason(diamondAddress: Address, id: BigInt): Season { + let season = Season.load(id.toString()); + if (season == null) { + season = new Season(id.toString()); + season.beanstalk = diamondAddress.toHexString(); + season.season = id.toI32(); + season.sunriseBlock = ZERO_BI; + season.createdAt = ZERO_BI; + season.price = ZERO_BD; + season.beans = ZERO_BI; + season.marketCap = ZERO_BD; + season.deltaB = ZERO_BI; + season.deltaBeans = ZERO_BI; + season.rewardBeans = ZERO_BI; + season.incentiveBeans = ZERO_BI; + season.harvestableIndex = ZERO_BI; + season.save(); + if (id > ZERO_BI) { + let lastSeason = loadSeason(diamondAddress, id.minus(ONE_BI)); + season.beans = lastSeason.beans; + season.harvestableIndex = lastSeason.harvestableIndex; + season.save(); + } + + // Update beanstalk season + let beanstalk = loadBeanstalk(diamondAddress); + beanstalk.lastSeason = season.season; + beanstalk.save(); + } + return season; +} + +export function getCurrentSeason(beanstalk: Address): i32 { + let beanstalkEntity = loadBeanstalk(beanstalk); + return beanstalkEntity.lastSeason; +} diff --git a/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts b/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts index 32c07e9ac8..c69b7036b1 100644 --- a/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts +++ b/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts @@ -7,7 +7,7 @@ import { } from "../../generated/Beanstalk-ABIs/BeanstalkPrice"; import { BEANSTALK_PRICE_1, BEANSTALK_PRICE_2, PRICE_2_BLOCK } from "../../../subgraph-core/utils/Constants"; import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { loadSilo } from "./SiloEntities"; +import { loadSilo } from "./Silo"; // Can't use the autogenerated one because the fields need to be updateable class PriceOverallStruct { diff --git a/projects/subgraph-beanstalk/src/utils/Farmer.ts b/projects/subgraph-beanstalk/src/utils/Farmer.ts deleted file mode 100644 index 3b28658a39..0000000000 --- a/projects/subgraph-beanstalk/src/utils/Farmer.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Address } from "@graphprotocol/graph-ts"; -import { Farmer } from "../../generated/schema"; - -export function loadFarmer(account: Address): Farmer { - let farmer = Farmer.load(account.toHexString()); - if (farmer == null) { - farmer = new Farmer(account.toHexString()); - farmer.save(); - } - return farmer; -} diff --git a/projects/subgraph-beanstalk/src/utils/Fertilizer.ts b/projects/subgraph-beanstalk/src/utils/Fertilizer.ts index 9e3df51e65..8ac7bba05a 100644 --- a/projects/subgraph-beanstalk/src/utils/Fertilizer.ts +++ b/projects/subgraph-beanstalk/src/utils/Fertilizer.ts @@ -1,6 +1,6 @@ import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; -import { Farmer, Fertilizer, FertilizerBalance, FertilizerToken } from "../../generated/schema"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { Farmer, Fertilizer, FertilizerBalance, FertilizerToken, FertilizerYield } from "../../generated/schema"; +import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; import { MarketV2 } from "../../generated/Beanstalk-ABIs/MarketV2"; @@ -48,3 +48,28 @@ export function loadFertilizerBalance(fertilizerToken: FertilizerToken, farmer: } return fertilizerBalance; } + +export function loadFertilizerYield(season: i32, window: i32): FertilizerYield { + let fertilizerYield = FertilizerYield.load(season.toString() + "-" + window.toString()); + if (fertilizerYield == null) { + fertilizerYield = new FertilizerYield(season.toString() + "-" + window.toString()); + fertilizerYield.season = season; + fertilizerYield.humidity = ZERO_BD; + fertilizerYield.outstandingFert = ZERO_BI; + fertilizerYield.beansPerSeasonEMA = ZERO_BD; + fertilizerYield.deltaBpf = ZERO_BD; + fertilizerYield.simpleAPY = ZERO_BD; + fertilizerYield.createdAt = ZERO_BI; + + if (window == 24) { + fertilizerYield.emaWindow = "ROLLING_24_HOUR"; + } else if (window == 168) { + fertilizerYield.emaWindow = "ROLLING_7_DAY"; + } else if (window == 720) { + fertilizerYield.emaWindow = "ROLLING_30_DAY"; + } + + fertilizerYield.save(); + } + return fertilizerYield as FertilizerYield; +} diff --git a/projects/subgraph-beanstalk/src/utils/FertilizerYield.ts b/projects/subgraph-beanstalk/src/utils/FertilizerYield.ts deleted file mode 100644 index 46e067067f..0000000000 --- a/projects/subgraph-beanstalk/src/utils/FertilizerYield.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { FertilizerYield } from "../../generated/schema"; -import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; - -export function loadFertilizerYield(season: i32, window: i32): FertilizerYield { - let fertilizerYield = FertilizerYield.load(season.toString() + "-" + window.toString()); - if (fertilizerYield == null) { - fertilizerYield = new FertilizerYield(season.toString() + "-" + window.toString()); - fertilizerYield.season = season; - fertilizerYield.humidity = ZERO_BD; - fertilizerYield.outstandingFert = ZERO_BI; - fertilizerYield.beansPerSeasonEMA = ZERO_BD; - fertilizerYield.deltaBpf = ZERO_BD; - fertilizerYield.simpleAPY = ZERO_BD; - fertilizerYield.createdAt = ZERO_BI; - - if (window == 24) { - fertilizerYield.emaWindow = "ROLLING_24_HOUR"; - } else if (window == 168) { - fertilizerYield.emaWindow = "ROLLING_7_DAY"; - } else if (window == 720) { - fertilizerYield.emaWindow = "ROLLING_30_DAY"; - } - - fertilizerYield.save(); - } - return fertilizerYield as FertilizerYield; -} diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index 5fffd2728d..1ab79e04e1 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -1,11 +1,11 @@ import { Address, BigInt, BigDecimal, ethereum } from "@graphprotocol/graph-ts"; -import { Field, FieldDailySnapshot, FieldHourlySnapshot } from "../../generated/schema"; -import { dayFromTimestamp } from "./Dates"; +import { Field, FieldDailySnapshot, FieldHourlySnapshot, Plot } from "../../generated/schema"; import { BI_MAX, ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { BEANSTALK, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; -import { loadSeason } from "./Season"; +import { ADDRESS_ZERO, BEANSTALK, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; import { CurvePrice } from "../../generated/Beanstalk-ABIs/CurvePrice"; import { BeanstalkPrice_try_price } from "./BeanstalkPrice"; +import { loadBeanstalk, loadSeason } from "./Beanstalk"; +import { dayFromTimestamp } from "./Snapshots"; // This function is for handling both the WeatherChange and TemperatureChange events. // The logic is the same for both, this is intended to accommodate the renamed event and fields. @@ -20,8 +20,6 @@ export function handleRateChange(evtAddress: Address, evtBlock: ethereum.Block, fieldHourly.caseId = caseId; - // Real Rate of Return - let seasonEntity = loadSeason(evtAddress, season); let currentPrice = ZERO_BD; @@ -73,6 +71,40 @@ export function loadField(account: Address): Field { return field; } +export function getHarvestableIndex(beanstalk: Address): BigInt { + let bs = loadBeanstalk(beanstalk); + let season = loadSeason(beanstalk, BigInt.fromI32(bs.lastSeason)); + return season.harvestableIndex; +} + +export function loadPlot(diamondAddress: Address, index: BigInt): Plot { + let plot = Plot.load(index.toString()); + if (plot == null) { + plot = new Plot(index.toString()); + plot.field = diamondAddress.toHexString(); + plot.farmer = ADDRESS_ZERO.toHexString(); + plot.source = "SOW"; // Should be overwritten in case of a transfer creating a new plot + plot.sourceHash = ""; + plot.season = 0; + plot.creationHash = ""; + plot.createdAt = ZERO_BI; + plot.updatedAt = ZERO_BI; + plot.updatedAtBlock = ZERO_BI; + plot.index = index; + plot.pods = ZERO_BI; + plot.beansPerPod = ZERO_BI; + plot.harvestablePods = ZERO_BI; + plot.harvestedPods = ZERO_BI; + plot.fullyHarvested = false; + plot.save(); + + let field = loadField(diamondAddress); + field.plotIndexes.push(plot.index); + field.save(); + } + return plot; +} + export function loadFieldHourly(account: Address, season: i32, timestamp: BigInt): FieldHourlySnapshot { // Hourly for Beanstalk is assumed to be by season. To keep other data correctly divided // by season, we elect to use the season number for the hour number. diff --git a/projects/subgraph-beanstalk/src/utils/Plot.ts b/projects/subgraph-beanstalk/src/utils/Plot.ts deleted file mode 100644 index 8e97468e9c..0000000000 --- a/projects/subgraph-beanstalk/src/utils/Plot.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Address, BigInt } from "@graphprotocol/graph-ts"; -import { Plot } from "../../generated/schema"; -import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { loadField } from "./Field"; - -export function loadPlot(diamondAddress: Address, index: BigInt): Plot { - let plot = Plot.load(index.toString()); - if (plot == null) { - plot = new Plot(index.toString()); - plot.field = diamondAddress.toHexString(); - plot.farmer = ADDRESS_ZERO.toHexString(); - plot.source = "SOW"; // Should be overwritten in case of a transfer creating a new plot - plot.sourceHash = ""; - plot.season = 0; - plot.creationHash = ""; - plot.createdAt = ZERO_BI; - plot.updatedAt = ZERO_BI; - plot.updatedAtBlock = ZERO_BI; - plot.index = index; - plot.pods = ZERO_BI; - plot.beansPerPod = ZERO_BI; - plot.harvestablePods = ZERO_BI; - plot.harvestedPods = ZERO_BI; - plot.fullyHarvested = false; - plot.save(); - - let field = loadField(diamondAddress); - field.plotIndexes.push(plot.index); - field.save(); - } - return plot; -} diff --git a/projects/subgraph-beanstalk/src/utils/PodFill.ts b/projects/subgraph-beanstalk/src/utils/PodFill.ts deleted file mode 100644 index c882ab7f57..0000000000 --- a/projects/subgraph-beanstalk/src/utils/PodFill.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Address, BigInt } from "@graphprotocol/graph-ts"; -import { PodFill } from "../../generated/schema"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; - -export function loadPodFill(diamondAddress: Address, index: BigInt, hash: String): PodFill { - let id = diamondAddress.toHexString() + "-" + index.toString() + "-" + hash; - let fill = PodFill.load(id); - if (fill == null) { - fill = new PodFill(id); - fill.podMarketplace = diamondAddress.toHexString(); - fill.createdAt = ZERO_BI; - fill.fromFarmer = ""; - fill.toFarmer = ""; - fill.placeInLine = ZERO_BI; - fill.amount = ZERO_BI; - fill.index = ZERO_BI; - fill.start = ZERO_BI; - fill.costInBeans = ZERO_BI; - fill.save(); - } - return fill; -} diff --git a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts b/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts index d039d6a02b..740d6a1507 100644 --- a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts +++ b/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts @@ -1,9 +1,9 @@ import { Address, BigInt, log } from "@graphprotocol/graph-ts"; -import { PodMarketplace, PodMarketplaceHourlySnapshot, PodMarketplaceDailySnapshot } from "../../generated/schema"; -import { dayFromTimestamp } from "./Dates"; +import { PodMarketplace, PodMarketplaceHourlySnapshot, PodMarketplaceDailySnapshot, PodFill } from "../../generated/schema"; import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { loadField } from "./Field"; import { expirePodListingIfExists } from "./PodListing"; +import { dayFromTimestamp } from "./Snapshots"; export enum MarketplaceAction { CREATED, @@ -38,6 +38,25 @@ export function loadPodMarketplace(diamondAddress: Address): PodMarketplace { return marketplace; } +export function loadPodFill(diamondAddress: Address, index: BigInt, hash: String): PodFill { + let id = diamondAddress.toHexString() + "-" + index.toString() + "-" + hash; + let fill = PodFill.load(id); + if (fill == null) { + fill = new PodFill(id); + fill.podMarketplace = diamondAddress.toHexString(); + fill.createdAt = ZERO_BI; + fill.fromFarmer = ""; + fill.toFarmer = ""; + fill.placeInLine = ZERO_BI; + fill.amount = ZERO_BI; + fill.index = ZERO_BI; + fill.start = ZERO_BI; + fill.costInBeans = ZERO_BI; + fill.save(); + } + return fill; +} + export function loadPodMarketplaceHourlySnapshot(diamondAddress: Address, season: i32, timestamp: BigInt): PodMarketplaceHourlySnapshot { // Hourly for Beanstalk is assumed to be by season. To keep other data correctly divided // by season, we elect to use the season number for the hour number. diff --git a/projects/subgraph-beanstalk/src/utils/PodOrder.ts b/projects/subgraph-beanstalk/src/utils/PodOrder.ts index 3f8cee0fe2..31c8ed8b6c 100644 --- a/projects/subgraph-beanstalk/src/utils/PodOrder.ts +++ b/projects/subgraph-beanstalk/src/utils/PodOrder.ts @@ -1,4 +1,4 @@ -import { Bytes, BigInt, Address } from "@graphprotocol/graph-ts"; +import { Bytes } from "@graphprotocol/graph-ts"; import { PodOrder } from "../../generated/schema"; import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; @@ -53,36 +53,3 @@ export function createHistoricalPodOrder(order: PodOrder): void { } } } - -// Currently there is no concept of an expired pod order, but there may be in the future -// export function expirePodOrder(diamondAddress: Address, orderId: string, timestamp: BigInt, activeOrderIndex: i32): void { -// let order = loadPodOrder(Bytes.fromHexString(orderId)); -// order.status = "EXPIRED"; -// order.save(); -// -// let market = loadPodMarketplace(diamondAddress); -// let marketHourly = loadPodMarketplaceHourlySnapshot(diamondAddress, market.season, timestamp); -// let marketDaily = loadPodMarketplaceDailySnapshot(diamondAddress, timestamp); -// -// const expiredBeans = order.beanAmount.minus(order.beanAmountFilled); -// market.expiredOrderBeans = market.expiredOrderBeans.plus(expiredBeans); -// market.availableOrderBeans = market.availableOrderBeans.minus(expiredBeans); -// let activeOrders = market.activeOrders; -// activeOrders.splice(activeOrderIndex, 1); -// market.activeOrders = activeOrders; -// market.save(); -// -// marketHourly.season = market.season; -// marketHourly.deltaExpiredOrderBeans = marketHourly.deltaExpiredOrderBeans.plus(expiredBeans); -// marketHourly.expiredOrderBeans = market.expiredListedPods; -// marketHourly.deltaAvailableOrderBeans = marketHourly.deltaAvailableOrderBeans.minus(expiredBeans); -// marketHourly.availableOrderBeans = market.availableOrderBeans; -// marketHourly.save(); -// -// marketDaily.season = market.season; -// marketDaily.deltaExpiredOrderBeans = marketDaily.deltaExpiredOrderBeans.plus(expiredBeans); -// marketDaily.expiredOrderBeans = market.expiredListedPods; -// marketDaily.deltaAvailableOrderBeans = marketDaily.deltaAvailableOrderBeans.minus(expiredBeans); -// marketDaily.availableOrderBeans = market.availableOrderBeans; -// marketDaily.save(); -// } diff --git a/projects/subgraph-beanstalk/src/utils/Season.ts b/projects/subgraph-beanstalk/src/utils/Season.ts deleted file mode 100644 index 3b0a7d5940..0000000000 --- a/projects/subgraph-beanstalk/src/utils/Season.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Address, BigInt } from "@graphprotocol/graph-ts"; -import { Season } from "../../generated/schema"; -import { loadBeanstalk } from "./Beanstalk"; -import { ONE_BI, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; - -export function loadSeason(diamondAddress: Address, id: BigInt): Season { - let season = Season.load(id.toString()); - if (season == null) { - season = new Season(id.toString()); - season.beanstalk = diamondAddress.toHexString(); - season.season = id.toI32(); - season.sunriseBlock = ZERO_BI; - season.createdAt = ZERO_BI; - season.price = ZERO_BD; - season.beans = ZERO_BI; - season.marketCap = ZERO_BD; - season.deltaB = ZERO_BI; - season.deltaBeans = ZERO_BI; - season.rewardBeans = ZERO_BI; - season.incentiveBeans = ZERO_BI; - season.harvestableIndex = ZERO_BI; - season.save(); - if (id > ZERO_BI) { - let lastSeason = loadSeason(diamondAddress, id.minus(ONE_BI)); - season.beans = lastSeason.beans; - season.harvestableIndex = lastSeason.harvestableIndex; - season.save(); - } - - // Update beanstalk season - let beanstalk = loadBeanstalk(diamondAddress); - beanstalk.lastSeason = season.season; - beanstalk.save(); - } - return season; -} - -export function getCurrentSeason(beanstalk: Address): i32 { - let beanstalkEntity = loadBeanstalk(beanstalk); - return beanstalkEntity.lastSeason; -} - -export function getHarvestableIndex(beanstalk: Address): BigInt { - let bs = loadBeanstalk(beanstalk); - let season = loadSeason(beanstalk, BigInt.fromI32(bs.lastSeason)); - return season.harvestableIndex; -} diff --git a/projects/subgraph-beanstalk/src/utils/SiloEntities.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts similarity index 99% rename from projects/subgraph-beanstalk/src/utils/SiloEntities.ts rename to projects/subgraph-beanstalk/src/utils/Silo.ts index f3178e1f7e..ca0750d1dc 100644 --- a/projects/subgraph-beanstalk/src/utils/SiloEntities.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -15,9 +15,9 @@ import { TokenYield } from "../../generated/schema"; import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; -import { dayFromTimestamp, hourFromTimestamp } from "./Dates"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { loadBeanstalk } from "./Beanstalk"; +import { dayFromTimestamp, hourFromTimestamp } from "./Snapshots"; /* ===== Base Silo Entities ===== */ @@ -119,7 +119,6 @@ export function loadSiloAsset(account: Address, token: Address): SiloAsset { let asset = SiloAsset.load(id); if (asset == null) { - //let tokenEntity = loadToken(token) asset = new SiloAsset(id); asset.silo = account.toHexString(); asset.token = token.toHexString(); @@ -264,6 +263,7 @@ export function loadWhitelistTokenDailySnapshot(token: Address, timestamp: BigIn /* ===== Deposit Entities ===== */ +// TODO: consolidate the 2 load methods export function loadSiloDeposit(account: Address, token: Address, season: BigInt): SiloDeposit { let id = account.toHexString() + "-" + token.toHexString() + "-" + season.toString(); let deposit = SiloDeposit.load(id); diff --git a/projects/subgraph-beanstalk/src/utils/Dates.ts b/projects/subgraph-beanstalk/src/utils/Snapshots.ts similarity index 100% rename from projects/subgraph-beanstalk/src/utils/Dates.ts rename to projects/subgraph-beanstalk/src/utils/Snapshots.ts diff --git a/projects/subgraph-beanstalk/src/utils/Token.ts b/projects/subgraph-beanstalk/src/utils/Token.ts deleted file mode 100644 index d85f3fb315..0000000000 --- a/projects/subgraph-beanstalk/src/utils/Token.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Address } from "@graphprotocol/graph-ts"; -import { ERC20 } from "../../generated/Beanstalk-ABIs/ERC20"; -import { Token } from "../../generated/schema"; -import { ZERO_BD, ZERO_BI } from "./Decimals"; - -export function loadToken(token: Address): Token { - let tokenEntity = Token.load(token.toHexString()); - if (tokenEntity == null) { - let tokenERC20 = ERC20.bind(token); - tokenEntity = new Token(token.toHexString()); - - // Assign replant token info manually since deposits are emitted prior to token deployment - if (token.toHexString() == "0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449") { - // Unripe Bean - tokenEntity.name = "Unripe Bean"; - tokenEntity.symbol = "urBEAN"; - tokenEntity.decimals = 6; - } else if (token.toHexString() == "0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D") { - // Unripe Bean:3CRV - tokenEntity.name = "Unripe BEAN3CRV"; - tokenEntity.symbol = "urBEAN3CRV"; - tokenEntity.decimals = 6; - } else if (token.toHexString() == "0xBEA0000029AD1c77D3d5D23Ba2D8893dB9d1Efab") { - // Unripe Bean:3CRV - tokenEntity.name = "BEAN"; - tokenEntity.symbol = "BEAN"; - tokenEntity.decimals = 6; - } else if (token.toHexString() == "0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D") { - // Unripe Bean:3CRV - tokenEntity.name = "BEAN3CRV"; - tokenEntity.symbol = "BEAN3CRV"; - tokenEntity.decimals = 18; - } else { - tokenEntity.name = "Unknown"; - tokenEntity.symbol = "Unknown"; - tokenEntity.decimals = 18; - } - - tokenEntity.lastPriceUSD = ZERO_BD; - tokenEntity.lastPriceBlockNumber = ZERO_BI; - tokenEntity.save(); - } - return tokenEntity as Token; -} diff --git a/projects/subgraph-beanstalk/src/utils/Transaction.ts b/projects/subgraph-beanstalk/src/utils/Transaction.ts deleted file mode 100644 index 60cf7334e4..0000000000 --- a/projects/subgraph-beanstalk/src/utils/Transaction.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ethereum } from "@graphprotocol/graph-ts"; -// schema imports -import { Transaction } from "../../generated/schema"; - -export function loadTransaction(eth_transaction: ethereum.Transaction, eth_block: ethereum.Block): Transaction { - let transaction = Transaction.load(eth_transaction.hash.toHex()); - if (transaction == null) { - transaction = new Transaction(eth_transaction.hash.toHex()); - transaction.timestamp = eth_block.timestamp; - transaction.blockNumber = eth_block.number; - transaction.from = eth_transaction.from; - transaction.to = eth_transaction.to; - transaction.save(); - } - return transaction as Transaction; -} diff --git a/projects/subgraph-beanstalk/src/yield_cache/CacheLoader.ts b/projects/subgraph-beanstalk/src/yield_cache/CacheLoader.ts index 2788e0dd03..723e86718c 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/CacheLoader.ts +++ b/projects/subgraph-beanstalk/src/yield_cache/CacheLoader.ts @@ -1,5 +1,5 @@ import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; -import { loadSiloYield, loadTokenYield } from "../utils/SiloEntities"; +import { loadSiloYield, loadTokenYield } from "../utils/Silo"; export function loadSiloCache(SILO_YIELD: string[][]): void { for (let i = 0; i < SILO_YIELD.length; i++) { diff --git a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts index 5035dde5fa..e263393972 100644 --- a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts +++ b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts @@ -29,10 +29,10 @@ import { import { createWhitelistTokenV4Event } from "./event-mocking/Whitelist"; import { createTemperatureChangeEvent } from "./event-mocking/Field"; import { simpleMockPrice } from "../../subgraph-core/tests/event-mocking/Price"; -import { loadSilo } from "../src/utils/SiloEntities"; +import { loadSilo } from "../src/utils/Silo"; import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block"; -import { dayFromTimestamp } from "../src/utils/Dates"; import { setSeason } from "./utils/Season"; +import { dayFromTimestamp } from "../src/utils/Snapshots"; const ANVIL_ADDR_1 = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".toLowerCase(); diff --git a/projects/subgraph-beanstalk/tests/YieldHandler.test.ts b/projects/subgraph-beanstalk/tests/YieldHandler.test.ts index 17273f331c..55595bcdae 100644 --- a/projects/subgraph-beanstalk/tests/YieldHandler.test.ts +++ b/projects/subgraph-beanstalk/tests/YieldHandler.test.ts @@ -2,7 +2,7 @@ import { BigInt, BigDecimal, log, Bytes } from "@graphprotocol/graph-ts"; import { afterEach, assert, clearStore, describe, test } from "matchstick-as/assembly/index"; import * as YieldHandler from "../src/YieldHandler"; import { BI_10, BigDecimal_isClose, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadSilo, loadSiloAsset, loadSiloYield, loadTokenYield, loadWhitelistTokenSetting } from "../src/utils/SiloEntities"; +import { loadSilo, loadSiloAsset, loadSiloYield, loadTokenYield, loadWhitelistTokenSetting } from "../src/utils/Silo"; import { BEAN_3CRV, BEAN_ERC20, From 0a0ad0170322a9247483346df25ffb27918c7413 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:53:46 -0700 Subject: [PATCH 03/59] refactor add/remove deposit --- .../subgraph-beanstalk/manifests/no-apy.yaml | 483 +++++++++++++++++ projects/subgraph-beanstalk/schema.graphql | 30 +- .../src/MarketplaceHandler.ts | 1 - .../subgraph-beanstalk/src/SiloHandler.ts | 498 +++++++----------- projects/subgraph-beanstalk/src/utils/Silo.ts | 66 ++- .../tests/Silo-Replanted.test.ts | 8 +- 6 files changed, 725 insertions(+), 361 deletions(-) create mode 100644 projects/subgraph-beanstalk/manifests/no-apy.yaml diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml new file mode 100644 index 0000000000..8aee7a6396 --- /dev/null +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -0,0 +1,483 @@ +# Use this file for faster testing of whether the subgraph build works +specVersion: 0.0.4 +schema: + file: ../schema.graphql +dataSources: + # Silo V3 + - kind: ethereum/contract + name: Silo-V3 + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SiloV3 + startBlock: 17636279 # Placeholder + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Silo-V3 + abis: + - name: SiloV3 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP36.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: AddDeposit(indexed address,indexed address,int96,uint256,uint256) + handler: handleAddDeposit_V3 + - event: RemoveDeposit(indexed address,indexed address,int96,uint256,uint256) + handler: handleRemoveDeposit_V3 + - event: RemoveDeposits(indexed address,indexed address,int96[],uint256[],uint256,uint256[]) + handler: handleRemoveDeposits_V3 + - event: WhitelistToken(indexed address,bytes4,uint32,uint256) + handler: handleWhitelistToken_V3 + - event: UpdatedStalkPerBdvPerSeason(indexed address,uint32,uint32) + handler: handleUpdatedStalkPerBdvPerSeason + file: ../src/SiloHandler.ts + # Silo V2 / Replanted + - kind: ethereum/contract + name: Silo-Replanted + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: MarketV2 + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Silo-Replanted + abis: + - name: MarketV2 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: AddDeposit(indexed address,indexed address,uint32,uint256,uint256) + handler: handleAddDeposit + - event: RemoveDeposit(indexed address,indexed address,uint32,uint256) + handler: handleRemoveDeposit + - event: RemoveDeposits(indexed address,indexed address,uint32[],uint256[],uint256) + handler: handleRemoveDeposits + - event: AddWithdrawal(indexed address,indexed address,uint32,uint256) + handler: handleAddWithdrawal + - event: RemoveWithdrawal(indexed address,indexed address,uint32,uint256) + handler: handleRemoveWithdrawal + - event: RemoveWithdrawals(indexed address,indexed address,uint32[],uint256) + handler: handleRemoveWithdrawals + - event: SeedsBalanceChanged(indexed address,int256) + handler: handleSeedsBalanceChanged + - event: StalkBalanceChanged(indexed address,int256,int256) + handler: handleStalkBalanceChanged + - event: Plant(indexed address,uint256) + handler: handlePlant + - event: WhitelistToken(indexed address,bytes4,uint256,uint256) + handler: handleWhitelistToken + - event: DewhitelistToken(indexed address) + handler: handleDewhitelistToken + file: ../src/SiloHandler.ts + # Field - Original + - kind: ethereum/contract + name: Field + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Field + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + - name: CurvePrice + file: ../../subgraph-core/abis/CurvePrice.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json + eventHandlers: + - event: WeatherChange(indexed uint256,uint256,int8) + handler: handleWeatherChange + - event: Sow(indexed address,uint256,uint256,uint256) + handler: handleSow + - event: Harvest(indexed address,uint256[],uint256) + handler: handleHarvest + - event: PlotTransfer(indexed address,indexed address,indexed uint256,uint256) + handler: handlePlotTransfer + - event: SupplyIncrease(indexed uint256,uint256,uint256,uint256,int256) + handler: handleSupplyIncrease + - event: SupplyDecrease(indexed uint256,uint256,int256) + handler: handleSupplyDecrease + - event: SupplyNeutral(indexed uint256,int256) + handler: handleSupplyNeutral + - event: FundFundraiser(indexed address,indexed uint32,uint256) + handler: handleFundFundraiser + file: ../src/FieldHandler.ts + - kind: ethereum/contract + name: Season + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleSunrise + - event: SeasonSnapshot(indexed uint32,uint256,uint256,uint256,uint256,uint256,uint256) + handler: handleSeasonSnapshot + - event: Incentivization(indexed address,uint256) + handler: handleIncentive + file: ../src/SeasonHandler.ts + - kind: ethereum/contract + name: Marketplace + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,bool) + handler: handlePodListingCreated + - event: PodListingCancelled(indexed address,uint256) + handler: handlePodListingCancelled + - event: PodListingCancelled(indexed address,indexed uint256) + handler: handlePodListingCancelled + - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256) + handler: handlePodListingFilled + - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256) + handler: handlePodOrderCreated + - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256) + handler: handlePodOrderFilled + - event: PodOrderCancelled(indexed address,bytes32) + handler: handlePodOrderCancelled + file: ../src/MarketplaceHandler.ts + - kind: ethereum/contract + name: Marketplace-Replanted + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: Replanted + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Marketplace-Replanted + abis: + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint8) + handler: handlePodListingCreated_v1_1 + file: ../src/MarketplaceHandler.ts + - kind: ethereum/contract + name: Diamond + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Diamond + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + eventHandlers: + - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) + handler: handleDiamondCut + file: ../src/DiamondHandler.ts + - kind: ethereum/contract + name: Bean + network: mainnet + source: + address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" + abi: ERC20 + startBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Bean + abis: + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + eventHandlers: + - event: Transfer(indexed address,indexed address,uint256) + handler: handleLegacyTransfer + file: ../src/BeanHandler.ts + - kind: ethereum/contract + name: Bean-Replanted + network: mainnet + source: + address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" + abi: ERC20 + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Bean + abis: + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + eventHandlers: + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + file: ../src/BeanHandler.ts + - kind: ethereum/contract + name: Season-Replanted + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: BasinBip + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season-Replanted + abis: + - name: BasinBip + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP37.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + - name: CurvePrice + file: ../../subgraph-core/abis/CurvePrice.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json + eventHandlers: + - event: Reward(indexed uint32,uint256,uint256,uint256) + handler: handleReward + - event: MetapoolOracle(indexed uint32,int256,uint256[2]) + handler: handleMetapoolOracle + - event: WellOracle(indexed uint32,address,int256,bytes) + handler: handleWellOracle + - event: Soil(indexed uint32,uint256) + handler: handleSoil + file: ../src/SeasonHandler.ts + - kind: ethereum/contract + name: Fertilizer-1155 + network: mainnet + source: + address: "0x402c84De2Ce49aF88f5e2eF3710ff89bFED36cB6" + abi: Fertilizer + startBlock: 14910573 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Fertilizer + abis: + - name: Fertilizer + file: ../../subgraph-core/abis/Fertilizer.json + - name: MarketV2 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + eventHandlers: + - event: TransferBatch(indexed address,indexed address,indexed address,uint256[],uint256[]) + handler: handleTransferBatch + - event: TransferSingle(indexed address,indexed address,indexed address,uint256,uint256) + handler: handleTransferSingle + file: ../src/BarnHandler.ts + - kind: ethereum/contract + name: Fertilizer-Beanstalk + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: MarketV2 + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Replant + abis: + - name: MarketV2 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: Chop(indexed address,indexed address,uint256,uint256) + handler: handleChop + file: ../src/BarnHandler.ts + - kind: ethereum/contract + name: Farm + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: MarketV2 + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Farm + abis: + - name: MarketV2 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: InternalBalanceChanged(indexed address,indexed address,int256) + handler: handleInternalBalanceChanged + file: ../src/FarmHandler.ts + - kind: ethereum/contract + name: Silo-Calls + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: Replanted + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Silo + abis: + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + callHandlers: + - function: transferDeposit(address,address,uint32,uint256) + handler: handleTransferDepositCall + - function: transferDeposits(address,address,uint32[],uint256[]) + handler: handleTransferDepositsCall + file: ../src/SiloHandler.ts + - kind: ethereum/contract + name: BIP29-PodMarketplace + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: MarketV2 + startBlock: 15277986 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - PodMarketplaceV2 + abis: + - name: MarketV2 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + - name: UniswapV2Pair + file: ../../subgraph-core/abis/UniswapV2Pair.json + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + eventHandlers: + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint256,bytes,uint8,uint8) + handler: handlePodListingCreated_v2 + - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256,uint256) + handler: handlePodListingFilled_v2 + - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256,uint256,bytes,uint8) + handler: handlePodOrderCreated_v2 + - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256,uint256) + handler: handlePodOrderFilled_v2 + file: ../src/MarketplaceHandler.ts + - kind: ethereum/contract + name: BIP45-SeedGauge + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SeedGauge + startBlock: 19628074 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - SeedGauge + abis: + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json + eventHandlers: + - event: TemperatureChange(indexed uint256,uint256,int8) + handler: handleTemperatureChange + - event: BeanToMaxLpGpPerBdvRatioChange(indexed uint256,uint256,int80) + handler: handleBeanToMaxLpGpPerBdvRatioChange + - event: GaugePointChange(indexed uint256,indexed address,uint256) + handler: handleGaugePointChange + - event: UpdateAverageStalkPerBdvPerSeason(uint256) + handler: handleUpdateAverageStalkPerBdvPerSeason + - event: FarmerGerminatingStalkBalanceChanged(indexed address,int256,uint8) + handler: handleFarmerGerminatingStalkBalanceChanged + - event: TotalGerminatingBalanceChanged(uint256,indexed address,int256,int256) + handler: handleTotalGerminatingBalanceChanged + - event: TotalGerminatingStalkChanged(uint256,int256) + handler: handleTotalGerminatingStalkChanged + - event: TotalStalkChangedFromGermination(int256,int256) + handler: handleTotalStalkChangedFromGermination + - event: WhitelistToken(indexed address,bytes4,uint32,uint256,bytes4,bytes4,uint128,uint64) + handler: handleWhitelistToken_BIP45 + - event: UpdateGaugeSettings(indexed address,bytes4,bytes4,uint64) + handler: handleUpdateGaugeSettings + file: ../src/GaugeHandler.ts +# features: +# - grafting +# graft: +# base: QmcZq7RVCbzixsh7PoHCVKXHsXnpigNo7JWvzj6rUsuvPd +# block: 19393254 diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 4b4cd3d2a0..0e182c5314 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -606,35 +606,29 @@ type Farmer @entity { type SiloDeposit @entity { """ - Pre Silo V3: - Account - Token Address - Season - - Post Silo-V3: - Account - Token Address - Stem + Account - Token Address - Deposit Version - (Season|Stem) """ id: ID! "Farmer address" farmer: Farmer! "Token Address" token: String! + "Version of deposit. Options are season, v3, v3.1. `season` type includes those deposits which are calculated according to their silo v1 deposits pre-explout" + depositVersion: String! "Season of deposit" - season: Int! - "Stem of deposit - Introduced in Silo V3" + season: BigInt + "Stem of deposit. If this is a season deposit type, stem will be filled according to `LibLegacyTokenSilo.seasonToStem`" stem: BigInt - "Current token amount deposited" - amount: BigInt! - "Original token amount deposited" + "Token amount deposited" depositedAmount: BigInt! - "Token amount withdrawn" - withdrawnAmount: BigInt! - "Current BDV of the deposit" - bdv: BigInt! "Original deposited BDV" depositedBDV: BigInt! - "Withdrawn BDV" - withdrawnBDV: BigInt! - "Transaction hashes for multiple deposits in one season" + "Transaction hashes pertaining to this deposit" hashes: [String!]! + "Block of first deposit" + createdBlock: BigInt! + "Block when last updated" + updatedBlock: BigInt! "Timestamp of first deposit" createdAt: BigInt! "Timestamp when last updated" @@ -656,8 +650,6 @@ type SiloWithdraw @entity { claimed: Boolean! "Token amount withdrawn" amount: BigInt! - "Transaction hash of withdrawal" - hashes: [String!]! "Timestamp created" createdAt: BigInt! } diff --git a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts b/projects/subgraph-beanstalk/src/MarketplaceHandler.ts index 875e46a09d..6a1141b79c 100644 --- a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts +++ b/projects/subgraph-beanstalk/src/MarketplaceHandler.ts @@ -14,7 +14,6 @@ import { PodOrderCreated as PodOrderCreated_v2, PodOrderFilled as PodOrderFilled_v2 } from "../generated/Beanstalk-ABIs/MarketV2"; - import { Plot, PodListingCreated as PodListingCreatedEvent, diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index f34a7fbe8a..b2c38f84b7 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -1,4 +1,4 @@ -import { Address, BigInt, log } from "@graphprotocol/graph-ts"; +import { Address, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; import { AddDeposit, StalkBalanceChanged, @@ -30,347 +30,197 @@ import { loadSiloAssetHourlySnapshot, loadSiloWithdraw, loadSiloDeposit, - loadSiloDepositV3, loadWhitelistTokenSetting, loadWhitelistTokenHourlySnapshot, loadWhitelistTokenDailySnapshot, - addToSiloWhitelist + addToSiloWhitelist, + updateDeposit } from "./utils/Silo"; -import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity } from "../generated/schema"; +import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit } from "../generated/schema"; import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; -import { BEANSTALK, BEAN_ERC20 } from "../../subgraph-core/utils/Constants"; - -// TODO: extract common logic between v2, v3 handlers - -/** - * SILO V2 (REPLANT) HANDLERS - */ - -export function handleAddDeposit(event: AddDeposit): void { - let deposit = loadSiloDeposit(event.params.account, event.params.token, event.params.season); - deposit.amount = deposit.amount.plus(event.params.amount); - deposit.depositedAmount = deposit.depositedAmount.plus(event.params.amount); - deposit.bdv = deposit.bdv.plus(event.params.bdv); - deposit.depositedBDV = deposit.depositedBDV.plus(event.params.bdv); - let depositHashes = deposit.hashes; - depositHashes.push(event.transaction.hash.toHexString()); - deposit.hashes = depositHashes; - deposit.createdAt = deposit.createdAt == ZERO_BI ? event.block.timestamp : deposit.createdAt; - deposit.updatedAt = event.block.timestamp; - deposit.save(); - - // Use the current season of beanstalk for updating silo and farmer totals - let beanstalk = loadBeanstalk(event.address); - - // Update overall silo totals - addDepositToSilo( - event.address, - beanstalk.lastSeason, - event.params.bdv, - addDepositToSiloAsset( - event.address, - event.params.token, - beanstalk.lastSeason, - event.params.bdv, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); - - // Ensure that a Farmer entity is set up for this account. - loadFarmer(event.params.account); - - // Update farmer silo totals - addDepositToSilo( - event.params.account, - beanstalk.lastSeason, - event.params.bdv, - addDepositToSiloAsset( - event.params.account, - event.params.token, - beanstalk.lastSeason, - event.params.bdv, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); +import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; + +class AddRemoveDepositsParams { + event: ethereum.Event; + account: Address; + token: Address; + seasons: BigInt[] | null; // Seasons not present in v3+ + stems: BigInt[] | null; // Stems not present in v2 + amounts: BigInt[]; + bdvs: BigInt[] | null; // bdv not present in v2 + depositVersion: String; } -export function handleRemoveDeposit(event: RemoveDeposit): void { - let beanstalk = loadBeanstalk(event.address); // get current season - let deposit = loadSiloDeposit(event.params.account, event.params.token, event.params.season); - - let withdrawnBDV = deposit.amount == ZERO_BI ? ZERO_BI : event.params.amount.times(deposit.bdv).div(deposit.amount); +function addDeposits(params: AddRemoveDepositsParams): void { + let currentSeason = getCurrentSeason(params.event.address); + for (let i = 0; i < params.amounts.length; ++i) { + let deposit = loadSiloDeposit({ + account: params.account, + token: params.token, + depositVersion: params.depositVersion, + season: params.seasons != null ? params.seasons![i] : null, + stem: params.stems != null ? params.stems![i] : null + }); + + // Set granular deposit version type + if (params.depositVersion == "season") { + deposit.depositVersion = "season"; + // TODO: fill stem according to seasonToStem + } else { + deposit.depositVersion = params.event.block.number > GAUGE_BIP45_BLOCK ? "v3.1" : "v3"; + } - // Update deposit - deposit.withdrawnBDV = deposit.withdrawnBDV.plus(withdrawnBDV); - deposit.bdv = deposit.bdv.minus(withdrawnBDV); - deposit.withdrawnAmount = deposit.withdrawnAmount.plus(event.params.amount); - deposit.amount = deposit.amount.minus(event.params.amount); - deposit.save(); + updateDeposit(deposit, params.amounts[i], params.bdvs![i], params.event); + deposit.save(); - // Update protocol totals - removeDepositFromSilo( - event.address, - beanstalk.lastSeason, - withdrawnBDV, - removeDepositFromSiloAsset( - event.address, - event.params.token, - beanstalk.lastSeason, - withdrawnBDV, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); + // TODO: these add/remove deposit to silo methods should be refactored such that it only needs to be called + // at the farmer level, and that will recur on the system level (only when called for farmer). + // In that case, the addDepositToSiloAsset method should not need to be called here, it can be called in the + // underlying method. I believe it needs to be refactored also + + // Ensure that a Farmer entity is set up for this account. + loadFarmer(params.account); + + // Update overall silo totals + addDepositToSilo( + params.event.address, + currentSeason, + params.bdvs![i], + addDepositToSiloAsset( + params.event.address, + params.token, + currentSeason, + params.bdvs![i], + params.amounts[i], + params.event.block.timestamp, + params.event.block.number + ), + params.event.block.timestamp, + params.event.block.number + ); - // Update farmer totals - removeDepositFromSilo( - event.params.account, - beanstalk.lastSeason, - withdrawnBDV, - removeDepositFromSiloAsset( - event.params.account, - event.params.token, - beanstalk.lastSeason, - withdrawnBDV, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); + // Update farmer silo totals + addDepositToSilo( + params.account, + currentSeason, + params.bdvs![i], + addDepositToSiloAsset( + params.account, + params.token, + currentSeason, + params.bdvs![i], + params.amounts[i], + params.event.block.timestamp, + params.event.block.number + ), + params.event.block.timestamp, + params.event.block.number + ); + } } -export function handleRemoveDeposits(event: RemoveDeposits): void { - let beanstalk = loadBeanstalk(event.address); // get current season - - for (let i = 0; i < event.params.seasons.length; i++) { - // TODO: extract common loop logic - let deposit = loadSiloDeposit(event.params.account, event.params.token, event.params.seasons[i]); - - let withdrawnBDV = deposit.amount == ZERO_BI ? ZERO_BI : event.params.amounts[i].times(deposit.bdv).div(deposit.amount); - - // Update deposit - deposit.withdrawnBDV = deposit.withdrawnBDV.plus(withdrawnBDV); - deposit.bdv = deposit.bdv.minus(withdrawnBDV); - deposit.withdrawnAmount = deposit.withdrawnAmount.plus(event.params.amounts[i]); - deposit.amount = deposit.amount.minus(event.params.amounts[i]); +function removeDeposits(params: AddRemoveDepositsParams): void { + let currentSeason = getCurrentSeason(params.event.address); + for (let i = 0; i < params.amounts.length; ++i) { + let deposit = loadSiloDeposit({ + account: params.account, + token: params.token, + depositVersion: params.depositVersion, + season: params.seasons != null ? params.seasons![i] : null, + stem: params.stems != null ? params.stems![i] : null + }); + + // Use bdv if it was provided (v2 events dont provide bdv), otherwise infer + let removedBdv = params.bdvs != null ? params.bdvs![i] : params.amounts[i].times(deposit.depositedBDV).div(deposit.depositedAmount); + + // TODO: if amount goes to zero, instead delete the deposit entirely. + updateDeposit(deposit, params.amounts[i].neg(), removedBdv.neg(), params.event); deposit.save(); // Update protocol totals removeDepositFromSilo( - event.address, - beanstalk.lastSeason, - withdrawnBDV, + params.event.address, + currentSeason, + removedBdv, removeDepositFromSiloAsset( - event.address, - event.params.token, - beanstalk.lastSeason, - withdrawnBDV, - event.params.amounts[i], - event.block.timestamp, - event.block.number + params.event.address, + params.token, + currentSeason, + removedBdv, + params.amounts[i], + params.event.block.timestamp, + params.event.block.number ), - event.block.timestamp, - event.block.number + params.event.block.timestamp, + params.event.block.number ); // Update farmer totals removeDepositFromSilo( - event.params.account, - beanstalk.lastSeason, - withdrawnBDV, + params.account, + currentSeason, + removedBdv, removeDepositFromSiloAsset( - event.params.account, - event.params.token, - beanstalk.lastSeason, - withdrawnBDV, - event.params.amounts[i], - event.block.timestamp, - event.block.number + params.account, + params.token, + currentSeason, + removedBdv, + params.amounts[i], + params.event.block.timestamp, + params.event.block.number ), - event.block.timestamp, - event.block.number + params.event.block.timestamp, + params.event.block.number ); } } /** - * SILO V3 HANDLERS + * SILO V2 (REPLANT) HANDLERS */ -export function handleAddDeposit_V3(event: AddDeposit_V3): void { - let deposit = loadSiloDepositV3(event.params.account, event.params.token, event.params.stem); - deposit.amount = deposit.amount.plus(event.params.amount); - deposit.depositedAmount = deposit.depositedAmount.plus(event.params.amount); - deposit.bdv = deposit.bdv.plus(event.params.bdv); - deposit.depositedBDV = deposit.depositedBDV.plus(event.params.bdv); - let depositHashes = deposit.hashes; - depositHashes.push(event.transaction.hash.toHexString()); - deposit.hashes = depositHashes; - deposit.createdAt = deposit.createdAt == ZERO_BI ? event.block.timestamp : deposit.createdAt; - deposit.updatedAt = event.block.timestamp; - deposit.save(); - - // Use the current season of beanstalk for updating silo and farmer totals - let beanstalk = loadBeanstalk(event.address); - - // Update overall silo totals - addDepositToSilo( - event.address, - beanstalk.lastSeason, - event.params.bdv, - addDepositToSiloAsset( - event.address, - event.params.token, - beanstalk.lastSeason, - event.params.bdv, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); - - // Ensure that a Farmer entity is set up for this account. - loadFarmer(event.params.account); - - // Update farmer silo totals - addDepositToSilo( - event.params.account, - beanstalk.lastSeason, - event.params.bdv, - addDepositToSiloAsset( - event.params.account, - event.params.token, - beanstalk.lastSeason, - event.params.bdv, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); +export function handleAddDeposit(event: AddDeposit): void { + addDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: [event.params.season], + stems: null, + amounts: [event.params.amount], + bdvs: [event.params.bdv], + depositVersion: "season" + }); } -export function handleRemoveDeposit_V3(event: RemoveDeposit_V3): void { - let beanstalk = loadBeanstalk(event.address); // get current season - let deposit = loadSiloDepositV3(event.params.account, event.params.token, event.params.stem); - - // Update deposit - deposit.withdrawnBDV = deposit.withdrawnBDV.plus(event.params.bdv); - deposit.bdv = deposit.bdv.minus(event.params.bdv); - deposit.withdrawnAmount = deposit.withdrawnAmount.plus(event.params.amount); - deposit.amount = deposit.amount.minus(event.params.amount); - deposit.save(); - - // Update protocol totals - removeDepositFromSilo( - event.address, - beanstalk.lastSeason, - event.params.bdv, - removeDepositFromSiloAsset( - event.address, - event.params.token, - beanstalk.lastSeason, - event.params.bdv, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); - - // Update farmer totals - removeDepositFromSilo( - event.params.account, - beanstalk.lastSeason, - event.params.bdv, - removeDepositFromSiloAsset( - event.params.account, - event.params.token, - beanstalk.lastSeason, - event.params.bdv, - event.params.amount, - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); +export function handleRemoveDeposit(event: RemoveDeposit): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: [event.params.season], + stems: null, + amounts: [event.params.amount], + bdvs: null, + depositVersion: "season" + }); } -export function handleRemoveDeposits_V3(event: RemoveDeposits_V3): void { - let beanstalk = loadBeanstalk(event.address); // get current season - - for (let i = 0; i < event.params.stems.length; i++) { - let deposit = loadSiloDepositV3(event.params.account, event.params.token, event.params.stems[i]); - - // Update deposit - deposit.withdrawnBDV = deposit.withdrawnBDV.plus(event.params.bdvs[i]); - deposit.bdv = deposit.bdv.minus(event.params.bdvs[i]); - deposit.withdrawnAmount = deposit.withdrawnAmount.plus(event.params.amounts[i]); - deposit.amount = deposit.amount.minus(event.params.amounts[i]); - deposit.save(); - - // Update protocol totals - removeDepositFromSilo( - event.address, - beanstalk.lastSeason, - event.params.bdvs[i], - removeDepositFromSiloAsset( - event.address, - event.params.token, - beanstalk.lastSeason, - event.params.bdvs[i], - event.params.amounts[i], - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); - - // Update farmer totals - removeDepositFromSilo( - event.params.account, - beanstalk.lastSeason, - event.params.bdvs[i], - removeDepositFromSiloAsset( - event.params.account, - event.params.token, - beanstalk.lastSeason, - event.params.bdvs[i], - event.params.amounts[i], - event.block.timestamp, - event.block.number - ), - event.block.timestamp, - event.block.number - ); - } +export function handleRemoveDeposits(event: RemoveDeposits): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: event.params.seasons, + stems: null, + amounts: event.params.amounts, + bdvs: null, + depositVersion: "season" + }); } export function handleAddWithdrawal(event: AddWithdrawal): void { let withdraw = loadSiloWithdraw(event.params.account, event.params.token, event.params.season.toI32()); withdraw.amount = withdraw.amount.plus(event.params.amount); - let withdrawHashes = withdraw.hashes; - withdrawHashes.push(event.transaction.hash.toHexString()); - withdraw.hashes = withdrawHashes; withdraw.createdAt = withdraw.createdAt == ZERO_BI ? event.block.timestamp : withdraw.createdAt; withdraw.save(); @@ -402,6 +252,49 @@ export function handleRemoveWithdrawals(event: RemoveWithdrawals): void { } } +/** + * SILO V3 HANDLERS + */ + +export function handleAddDeposit_V3(event: AddDeposit_V3): void { + addDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: null, + stems: [event.params.stem], + amounts: [event.params.amount], + bdvs: [event.params.bdv], + depositVersion: "stem" + }); +} + +export function handleRemoveDeposit_V3(event: RemoveDeposit_V3): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: null, + stems: [event.params.stem], + amounts: [event.params.amount], + bdvs: [event.params.bdv], + depositVersion: "stem" + }); +} + +export function handleRemoveDeposits_V3(event: RemoveDeposits_V3): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: null, + stems: event.params.stems, + amounts: event.params.amounts, + bdvs: event.params.bdvs, + depositVersion: "stem" + }); +} + export function handleStalkBalanceChanged(event: StalkBalanceChanged): void { // Exclude BIP-24 emission of missed past events if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { @@ -497,6 +390,7 @@ export function handleTransferDepositsCall(call: TransferDepositsCall): void { beanstalk.save(); } +// TODO: consider consolidating both add/remove deposit methods here function addDepositToSilo( account: Address, season: i32, diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index ca0750d1dc..94afb82189 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -1,4 +1,4 @@ -import { Address, BigInt, Bytes } from "@graphprotocol/graph-ts"; +import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; import { Silo, SiloHourlySnapshot, @@ -16,7 +16,6 @@ import { } from "../../generated/schema"; import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { loadBeanstalk } from "./Beanstalk"; import { dayFromTimestamp, hourFromTimestamp } from "./Snapshots"; /* ===== Base Silo Entities ===== */ @@ -263,46 +262,32 @@ export function loadWhitelistTokenDailySnapshot(token: Address, timestamp: BigIn /* ===== Deposit Entities ===== */ -// TODO: consolidate the 2 load methods -export function loadSiloDeposit(account: Address, token: Address, season: BigInt): SiloDeposit { - let id = account.toHexString() + "-" + token.toHexString() + "-" + season.toString(); - let deposit = SiloDeposit.load(id); - if (deposit == null) { - deposit = new SiloDeposit(id); - deposit.farmer = account.toHexString(); - deposit.token = token.toHexString(); - deposit.season = season.toI32(); - deposit.amount = ZERO_BI; - deposit.depositedAmount = ZERO_BI; - deposit.withdrawnAmount = ZERO_BI; - deposit.bdv = ZERO_BI; - deposit.depositedBDV = ZERO_BI; - deposit.withdrawnBDV = ZERO_BI; - deposit.hashes = []; - deposit.createdAt = ZERO_BI; - deposit.updatedAt = ZERO_BI; - deposit.save(); - } - return deposit; +class SiloDepositID { + account: Address; + token: Address; + depositVersion: String; + season: BigInt | null; + stem: BigInt | null; } -export function loadSiloDepositV3(account: Address, token: Address, stem: BigInt): SiloDeposit { - let id = account.toHexString() + "-" + token.toHexString() + "-" + stem.toString(); +export function loadSiloDeposit(depositId: SiloDepositID): SiloDeposit { + // id: Account - Token Address - Deposit Version - (Season|Stem) + const seasonOrStem = depositId.depositVersion == "season" ? depositId.season! : depositId.stem!; + const id = + depositId.account.toHexString() + "-" + depositId.token.toHexString() + "-" + depositId.depositVersion + "-" + seasonOrStem.toString(); let deposit = SiloDeposit.load(id); if (deposit == null) { - let beanstalk = loadBeanstalk(BEANSTALK); deposit = new SiloDeposit(id); - deposit.farmer = account.toHexString(); - deposit.token = token.toHexString(); - deposit.season = beanstalk.lastSeason; - deposit.stem = stem; - deposit.amount = ZERO_BI; + deposit.farmer = depositId.account.toHexString(); + deposit.token = depositId.token.toHexString(); + deposit.depositVersion = depositId.depositVersion.toString(); + deposit.season = depositId.season; + deposit.stem = depositId.stem; deposit.depositedAmount = ZERO_BI; - deposit.withdrawnAmount = ZERO_BI; - deposit.bdv = ZERO_BI; deposit.depositedBDV = ZERO_BI; - deposit.withdrawnBDV = ZERO_BI; deposit.hashes = []; + deposit.createdBlock = ZERO_BI; + deposit.updatedBlock = ZERO_BI; deposit.createdAt = ZERO_BI; deposit.updatedAt = ZERO_BI; deposit.save(); @@ -310,6 +295,18 @@ export function loadSiloDepositV3(account: Address, token: Address, stem: BigInt return deposit; } +export function updateDeposit(deposit: SiloDeposit, amount: BigInt, bdv: BigInt, event: ethereum.Event): void { + deposit.depositedAmount = deposit.depositedAmount.plus(amount); + deposit.depositedBDV = deposit.depositedBDV.plus(bdv); + let depositHashes = deposit.hashes; + depositHashes.push(event.transaction.hash.toHexString()); + deposit.hashes = depositHashes; + deposit.createdBlock = deposit.createdBlock == ZERO_BI ? event.block.number : deposit.createdBlock; + deposit.createdAt = deposit.createdAt == ZERO_BI ? event.block.timestamp : deposit.createdAt; + deposit.updatedBlock = event.block.number; + deposit.updatedAt = event.block.timestamp; +} + /* ===== Withdraw Entities ===== */ export function loadSiloWithdraw(account: Address, token: Address, season: i32): SiloWithdraw { @@ -323,7 +320,6 @@ export function loadSiloWithdraw(account: Address, token: Address, season: i32): withdraw.claimableSeason = season + 1; withdraw.claimed = false; withdraw.amount = ZERO_BI; - withdraw.hashes = []; withdraw.createdAt = ZERO_BI; withdraw.save(); } diff --git a/projects/subgraph-beanstalk/tests/Silo-Replanted.test.ts b/projects/subgraph-beanstalk/tests/Silo-Replanted.test.ts index d3059b4e96..4bf2b87982 100644 --- a/projects/subgraph-beanstalk/tests/Silo-Replanted.test.ts +++ b/projects/subgraph-beanstalk/tests/Silo-Replanted.test.ts @@ -44,8 +44,8 @@ describe("Mocked Events", () => { handleRemoveDeposit(newRemoveDepositEvent); assert.fieldEquals("Silo", account, "depositedBDV", "500000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-6100", "withdrawnAmount", "500000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-6100", "withdrawnBDV", "500000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "500000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedBDV", "500000000"); assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "500000000"); assert.fieldEquals("SiloAsset", account + "-" + token, "depositedAmount", "500000000"); }); @@ -67,8 +67,8 @@ describe("Mocked Events", () => { handleRemoveDeposit(secondRemoveDepositEvent); assert.fieldEquals("Silo", account, "depositedBDV", "250000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-6100", "withdrawnAmount", "750000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-6100", "withdrawnBDV", "750000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "250000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedBDV", "250000000"); assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "250000000"); assert.fieldEquals("SiloAsset", account + "-" + token, "depositedAmount", "250000000"); }); From 49a000375b86a854e289cefda38a5b4e84d431e9 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:52:28 -0700 Subject: [PATCH 04/59] generalized silo snapshot --- projects/subgraph-beanstalk/schema.graphql | 6 +- .../subgraph-beanstalk/src/SiloHandler.ts | 25 +++--- projects/subgraph-beanstalk/src/utils/Silo.ts | 4 +- .../subgraph-beanstalk/src/utils/Snapshots.ts | 81 ++++++++++++++++++- 4 files changed, 97 insertions(+), 19 deletions(-) diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 0e182c5314..208fc6bdf5 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -137,6 +137,10 @@ type Silo @entity { beanMints: BigInt! "Current number of active farmers deposited in the silo" activeFarmers: Int! + "Season when the previous hourly snapshot was taken/updated" + lastHourlySnapshotSeason: Int + "Day of when the previous daily snapshot was taken/updated" + lastDailySnapshotDay: BigInt "Link to hourly snapshot data" hourlySnapshots: [SiloHourlySnapshot!]! @derivedFrom(field: "silo") "Link to daily snapshot data" @@ -616,7 +620,7 @@ type SiloDeposit @entity { "Version of deposit. Options are season, v3, v3.1. `season` type includes those deposits which are calculated according to their silo v1 deposits pre-explout" depositVersion: String! "Season of deposit" - season: BigInt + season: Int "Stem of deposit. If this is a season deposit type, stem will be filled according to `LibLegacyTokenSilo.seasonToStem`" stem: BigInt "Token amount deposited" diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index b2c38f84b7..81b2275daf 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -39,6 +39,7 @@ import { import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit } from "../generated/schema"; import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; +import { takeSiloSnapshots } from "./utils/Snapshots"; class AddRemoveDepositsParams { event: ethereum.Event; @@ -335,9 +336,9 @@ export function handlePlant(event: Plant): void { // This removes the plantable stalk for planted beans. // Actual stalk credit for the farmer will be handled under the StalkBalanceChanged event. - let beanstalk = loadBeanstalk(event.address); + const currentSeason = getCurrentSeason(event.address); let silo = loadSilo(event.address); - let siloHourly = loadSiloHourlySnapshot(event.address, beanstalk.lastSeason, event.block.timestamp); + let siloHourly = loadSiloHourlySnapshot(event.address, currentSeason, event.block.timestamp); let siloDaily = loadSiloDailySnapshot(event.address, event.block.timestamp); let newPlantableStalk = event.params.beans.times(BigInt.fromI32(10000)); @@ -359,10 +360,12 @@ export function handlePlant(event: Plant): void { siloDaily.updatedAt = event.block.timestamp; siloDaily.save(); + // Remove the asset-only amount that got added in Reward event handler. + // Will be immediately re-credited to the user/system in AddDeposit removeDepositFromSiloAsset( event.address, BEAN_ERC20, - beanstalk.lastSeason, + currentSeason, event.params.beans, event.params.beans, event.block.timestamp, @@ -438,23 +441,12 @@ function removeDepositFromSilo( silo.depositedBDV = silo.depositedBDV.minus(bdv); // Individual farmer seeds cannot be directly tracked due to seed gauge + // TODO: event originator in method signature (required for recursion also) if (account == BEANSTALK) { silo.grownStalkPerSeason = silo.grownStalkPerSeason.minus(grownStalkPerBDV); } + takeSiloSnapshots(silo, BEANSTALK, timestamp); silo.save(); - - siloHourly.deltaDepositedBDV = siloHourly.deltaDepositedBDV.minus(bdv); - siloHourly.depositedBDV = silo.depositedBDV; - siloHourly.grownStalkPerSeason = silo.grownStalkPerSeason; - siloHourly.updatedAt = timestamp; - siloHourly.save(); - - siloDaily.season = season; - siloDaily.deltaDepositedBDV = siloDaily.deltaDepositedBDV.minus(bdv); - siloDaily.depositedBDV = silo.depositedBDV; - siloDaily.grownStalkPerSeason = silo.grownStalkPerSeason; - siloDaily.updatedAt = timestamp; - siloDaily.save(); } export function addDepositToSiloAsset( @@ -738,6 +730,7 @@ export function handleWhitelistToken_V3(event: WhitelistToken_V3): void { rawEvent.createdAt = event.block.timestamp; rawEvent.save(); } +// V4 whitelist for seed gauge is in GaugeHandler export function handleDewhitelistToken(event: DewhitelistToken): void { let silo = loadSilo(event.address); diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 94afb82189..2a596533a9 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -281,7 +281,9 @@ export function loadSiloDeposit(depositId: SiloDepositID): SiloDeposit { deposit.farmer = depositId.account.toHexString(); deposit.token = depositId.token.toHexString(); deposit.depositVersion = depositId.depositVersion.toString(); - deposit.season = depositId.season; + if (depositId.season !== null) { + deposit.season = depositId.season!.toU32(); + } deposit.stem = depositId.stem; deposit.depositedAmount = ZERO_BI; deposit.depositedBDV = ZERO_BI; diff --git a/projects/subgraph-beanstalk/src/utils/Snapshots.ts b/projects/subgraph-beanstalk/src/utils/Snapshots.ts index 220eab8fee..0ca4e92431 100644 --- a/projects/subgraph-beanstalk/src/utils/Snapshots.ts +++ b/projects/subgraph-beanstalk/src/utils/Snapshots.ts @@ -1,4 +1,6 @@ -import { BigInt } from "@graphprotocol/graph-ts"; +import { BigInt, Address } from "@graphprotocol/graph-ts"; +import { Silo, SiloDailySnapshot, SiloHourlySnapshot } from "../../generated/schema"; +import { getCurrentSeason } from "./Beanstalk"; export function dayFromTimestamp(timestamp: BigInt): string { let day_ts = timestamp.toI32() - (timestamp.toI32() % 86400); @@ -9,3 +11,80 @@ export function hourFromTimestamp(timestamp: BigInt): string { let day_ts = timestamp.toI32() - (timestamp.toI32() % 3600); return day_ts.toString(); } + +// Entities could store a lastSnapshotAt field which can be used to derive both the date and hour. +// This would then become the base for comparison of deltas + +export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: BigInt): void { + const currentSeason = getCurrentSeason(beanstalk); + + const hour = BigInt.fromString(hourFromTimestamp(timestamp)); + const day = BigInt.fromString(dayFromTimestamp(timestamp)); + + // Load the snapshot for this season/day + const hourlyId = silo.id + "-" + currentSeason.toString(); + const dailyId = silo.id + "-" + day.toString(); + let baseHourly = SiloHourlySnapshot.load(hourlyId); + let baseDaily = SiloDailySnapshot.load(dailyId); + if (baseHourly == null && silo.lastHourlySnapshotSeason !== 0) { + baseHourly = SiloHourlySnapshot.load(silo.id + "-" + silo.lastHourlySnapshotSeason.toString()); + } + if (baseDaily == null && silo.lastDailySnapshotDay !== null) { + baseDaily = SiloDailySnapshot.load(silo.id + "-" + silo.lastDailySnapshotDay!.toString()); + } + const hourly = new SiloHourlySnapshot(hourlyId); + const daily = new SiloDailySnapshot(dailyId); + + hourly.season = currentSeason; + hourly.silo = silo.id; + hourly.depositedBDV = silo.depositedBDV; + hourly.stalk = silo.stalk; + hourly.plantableStalk = silo.plantableStalk; + hourly.seeds = silo.seeds; + hourly.grownStalkPerSeason = silo.grownStalkPerSeason; + hourly.roots = silo.roots; + hourly.germinatingStalk = silo.germinatingStalk; + hourly.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; + hourly.beanMints = silo.beanMints; + hourly.activeFarmers = silo.activeFarmers; + if (baseHourly !== null) { + hourly.deltaDepositedBDV = hourly.depositedBDV.minus(baseHourly.depositedBDV); + hourly.deltaStalk = hourly.stalk.minus(baseHourly.stalk); + hourly.deltaPlantableStalk = hourly.plantableStalk.minus(baseHourly.plantableStalk); + hourly.deltaSeeds = hourly.seeds.minus(baseHourly.seeds); + hourly.deltaRoots = hourly.roots.minus(baseHourly.roots); + hourly.deltaGerminatingStalk = hourly.germinatingStalk.minus(baseHourly.germinatingStalk); + // NOTE: missing beanToMaxLpGpPerBdvRatio + hourly.deltaBeanMints = hourly.beanMints.minus(baseHourly.beanMints); + hourly.deltaActiveFarmers = hourly.activeFarmers - baseHourly.activeFarmers; + if (hourly.id == baseHourly.id) { + // Add existing deltas + hourly.deltaDepositedBDV = hourly.deltaDepositedBDV.plus(baseHourly.deltaDepositedBDV); + hourly.deltaStalk = hourly.deltaStalk.plus(baseHourly.deltaDepositedBDV); + hourly.deltaPlantableStalk = hourly.deltaPlantableStalk.plus(baseHourly.deltaPlantableStalk); + hourly.deltaSeeds = hourly.deltaSeeds.plus(baseHourly.deltaSeeds); + hourly.deltaRoots = hourly.deltaRoots.plus(baseHourly.deltaRoots); + hourly.deltaGerminatingStalk = hourly.deltaGerminatingStalk.plus(baseHourly.deltaGerminatingStalk); + // NOTE: missing beanToMaxLpGpPerBdvRatio + hourly.deltaBeanMints = hourly.deltaBeanMints.plus(baseHourly.deltaBeanMints); + hourly.deltaActiveFarmers = hourly.deltaActiveFarmers + baseHourly.deltaActiveFarmers; + } + } else { + hourly.deltaDepositedBDV = hourly.depositedBDV; + hourly.deltaStalk = hourly.stalk; + hourly.deltaPlantableStalk = hourly.plantableStalk; + hourly.deltaSeeds = hourly.seeds; + hourly.deltaRoots = hourly.roots; + hourly.deltaGerminatingStalk = hourly.germinatingStalk; + // NOTE: missing beanToMaxLpGpPerBdvRatio + hourly.deltaBeanMints = hourly.beanMints; + hourly.deltaActiveFarmers = hourly.activeFarmers; + } + hourly.createdAt = hour; + hourly.updatedAt = timestamp; + hourly.save(); + + silo.lastHourlySnapshotSeason = currentSeason; + silo.lastDailySnapshotDay = day; + // Caller must call save on silo. (document this somewhere) +} From 8aa55b1cc034afae8cdf15893c7d3dd57773a6a3 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:12:55 -0700 Subject: [PATCH 05/59] refactor snapshot usages --- .../subgraph-beanstalk/src/GaugeHandler.ts | 29 +----- .../subgraph-beanstalk/src/SeasonHandler.ts | 33 ++----- .../subgraph-beanstalk/src/SiloHandler.ts | 98 +++---------------- .../subgraph-beanstalk/src/YieldHandler.ts | 2 + projects/subgraph-beanstalk/src/utils/Silo.ts | 2 +- .../src/utils/snapshots/DateUtil.ts | 11 +++ .../utils/{Snapshots.ts => snapshots/Silo.ts} | 74 +++++++++++--- 7 files changed, 96 insertions(+), 153 deletions(-) create mode 100644 projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts rename projects/subgraph-beanstalk/src/utils/{Snapshots.ts => snapshots/Silo.ts} (57%) diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index 54e5177283..4c6d07d1f0 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -27,6 +27,7 @@ import { WhitelistToken as WhitelistTokenEntity } from "../generated/schema"; import { BEAN_WETH_CP2_WELL } from "../../subgraph-core/utils/Constants"; import { Bytes4_emptyToNull } from "../../subgraph-core/utils/Bytes"; import { getCurrentSeason } from "./utils/Beanstalk"; +import { takeSiloSnapshots } from "./utils/snapshots/Silo"; export function handleTemperatureChange(event: TemperatureChange): void { handleRateChange(event.address, event.block, event.params.season, event.params.caseId, event.params.absChange); @@ -44,6 +45,7 @@ export function handleBeanToMaxLpGpPerBdvRatioChange(event: BeanToMaxLpGpPerBdvR } silo.save(); + // TODO: solution for caseId. let siloHourly = loadSiloHourlySnapshot(event.address, event.params.season.toI32(), event.block.timestamp); let siloDaily = loadSiloDailySnapshot(event.address, event.block.timestamp); siloHourly.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; @@ -71,13 +73,8 @@ export function handleUpdateAverageStalkPerBdvPerSeason(event: UpdateAverageStal let silo = loadSilo(event.address); silo.grownStalkPerSeason = silo.depositedBDV.times(event.params.newStalkPerBdvPerSeason); + takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); - let siloHourly = loadSiloHourlySnapshot(event.address, getCurrentSeason(event.address), event.block.timestamp); - let siloDaily = loadSiloDailySnapshot(event.address, event.block.timestamp); - siloHourly.grownStalkPerSeason = silo.grownStalkPerSeason; - siloDaily.grownStalkPerSeason = silo.grownStalkPerSeason; - siloHourly.save(); - siloDaily.save(); // Individual asset grown stalk is set by the UpdatedStalkPerBdvPerSeason event in SiloHandler } @@ -110,16 +107,8 @@ export function handleFarmerGerminatingStalkBalanceChanged(event: FarmerGerminat let farmerSilo = loadSilo(event.params.account); farmerSilo.germinatingStalk = farmerSilo.germinatingStalk.plus(event.params.deltaGerminatingStalk); + takeSiloSnapshots(farmerSilo, event.address, event.block.timestamp); farmerSilo.save(); - - let siloHourly = loadSiloHourlySnapshot(event.params.account, currentSeason, event.block.timestamp); - let siloDaily = loadSiloDailySnapshot(event.params.account, event.block.timestamp); - siloHourly.germinatingStalk = farmerSilo.germinatingStalk; - siloHourly.deltaGerminatingStalk = siloHourly.deltaGerminatingStalk.plus(event.params.deltaGerminatingStalk); - siloDaily.germinatingStalk = farmerSilo.germinatingStalk; - siloDaily.deltaGerminatingStalk = siloDaily.deltaGerminatingStalk.plus(event.params.deltaGerminatingStalk); - siloHourly.save(); - siloDaily.save(); } // Tracks the germinating balance on a token level @@ -153,16 +142,8 @@ export function handleTotalGerminatingStalkChanged(event: TotalGerminatingStalkC let silo = loadSilo(event.address); silo.germinatingStalk = silo.germinatingStalk.plus(event.params.deltaGerminatingStalk); + takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); - - let siloHourly = loadSiloHourlySnapshot(event.address, getCurrentSeason(event.address), event.block.timestamp); - let siloDaily = loadSiloDailySnapshot(event.address, event.block.timestamp); - siloHourly.germinatingStalk = silo.germinatingStalk; - siloHourly.deltaGerminatingStalk = siloHourly.deltaGerminatingStalk.plus(event.params.deltaGerminatingStalk); - siloDaily.germinatingStalk = silo.germinatingStalk; - siloDaily.deltaGerminatingStalk = siloDaily.deltaGerminatingStalk.plus(event.params.deltaGerminatingStalk); - siloHourly.save(); - siloDaily.save(); } // Germination completes, germinating stalk turns into stalk. diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index 7187b3e0b7..12f9326238 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -15,14 +15,9 @@ import { } from "./utils/PodMarketplace"; import { addDepositToSiloAsset, updateStalkWithCalls } from "./SiloHandler"; import { updateBeanEMA } from "./YieldHandler"; -import { - loadSilo, - loadSiloDailySnapshot, - loadSiloHourlySnapshot, - loadSiloAssetDailySnapshot, - loadSiloAssetHourlySnapshot -} from "./utils/Silo"; +import { loadSilo, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot } from "./utils/Silo"; import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/BeanstalkPrice"; +import { takeSiloSnapshots } from "./utils/snapshots/Silo"; export function handleSunrise(event: Sunrise): void { let currentSeason = event.params.season.toI32(); @@ -70,12 +65,12 @@ export function handleSunrise(event: Sunrise): void { // Create silo entities for the protocol let silo = loadSilo(event.address); - loadSiloHourlySnapshot(event.address, currentSeason, event.block.timestamp); - loadSiloDailySnapshot(event.address, event.block.timestamp); + takeSiloSnapshots(silo, event.address, event.block.timestamp); for (let i = 0; i < silo.whitelistedTokens.length; i++) { loadSiloAssetHourlySnapshot(event.address, Address.fromString(silo.whitelistedTokens[i]), currentSeason, event.block.timestamp); loadSiloAssetDailySnapshot(event.address, Address.fromString(silo.whitelistedTokens[i]), event.block.timestamp); } + silo.save(); } export function handleSeasonSnapshot(event: SeasonSnapshot): void { @@ -92,30 +87,14 @@ export function handleReward(event: Reward): void { // Add to total Silo Bean mints let silo = loadSilo(event.address); - let siloHourly = loadSiloHourlySnapshot(event.address, season.season, event.block.timestamp); - let siloDaily = loadSiloDailySnapshot(event.address, event.block.timestamp); let newPlantableStalk = event.params.toSilo.times(BigInt.fromI32(10000)); // Stalk has 10 decimals silo.beanMints = silo.beanMints.plus(event.params.toSilo); silo.plantableStalk = silo.plantableStalk.plus(newPlantableStalk); silo.depositedBDV = silo.depositedBDV.plus(event.params.toSilo); - silo.save(); - siloHourly.beanMints = silo.beanMints; - siloHourly.plantableStalk = silo.plantableStalk; - siloHourly.depositedBDV = silo.depositedBDV; - siloHourly.deltaBeanMints = siloHourly.deltaBeanMints.plus(event.params.toSilo); - siloHourly.deltaPlantableStalk = siloHourly.deltaPlantableStalk.plus(newPlantableStalk); - siloHourly.deltaDepositedBDV = siloHourly.deltaDepositedBDV.plus(event.params.toSilo); - siloHourly.save(); - - siloDaily.beanMints = silo.beanMints; - siloDaily.plantableStalk = silo.plantableStalk; - siloDaily.depositedBDV = silo.depositedBDV; - siloDaily.deltaBeanMints = siloDaily.deltaBeanMints.plus(event.params.toSilo); - siloDaily.deltaPlantableStalk = siloDaily.deltaPlantableStalk.plus(newPlantableStalk); - siloDaily.deltaDepositedBDV = siloDaily.deltaDepositedBDV.plus(event.params.toSilo); - siloDaily.save(); + takeSiloSnapshots(silo, event.address, event.block.timestamp); + silo.save(); addDepositToSiloAsset( event.address, diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 81b2275daf..c06efeb4db 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -23,8 +23,6 @@ import { Replanted, TransferDepositCall, TransferDepositsCall } from "../generat import { ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadSilo, - loadSiloDailySnapshot, - loadSiloHourlySnapshot, loadSiloAsset, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot, @@ -39,7 +37,7 @@ import { import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit } from "../generated/schema"; import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; -import { takeSiloSnapshots } from "./utils/Snapshots"; +import { takeSiloSnapshots } from "./utils/snapshots/Silo"; class AddRemoveDepositsParams { event: ethereum.Event; @@ -338,27 +336,13 @@ export function handlePlant(event: Plant): void { const currentSeason = getCurrentSeason(event.address); let silo = loadSilo(event.address); - let siloHourly = loadSiloHourlySnapshot(event.address, currentSeason, event.block.timestamp); - let siloDaily = loadSiloDailySnapshot(event.address, event.block.timestamp); let newPlantableStalk = event.params.beans.times(BigInt.fromI32(10000)); silo.plantableStalk = silo.plantableStalk.minus(newPlantableStalk); silo.depositedBDV = silo.depositedBDV.minus(event.params.beans); - silo.save(); - - siloHourly.plantableStalk = silo.plantableStalk; - siloHourly.depositedBDV = silo.depositedBDV; - siloHourly.deltaPlantableStalk = siloHourly.deltaPlantableStalk.minus(newPlantableStalk); - siloHourly.deltaDepositedBDV = siloHourly.deltaDepositedBDV.minus(event.params.beans); - siloHourly.updatedAt = event.block.timestamp; - siloHourly.save(); - siloDaily.plantableStalk = silo.plantableStalk; - siloDaily.depositedBDV = silo.depositedBDV; - siloDaily.deltaPlantableStalk = siloDaily.deltaPlantableStalk.minus(newPlantableStalk); - siloDaily.deltaDepositedBDV = siloDaily.deltaDepositedBDV.minus(event.params.beans); - siloDaily.updatedAt = event.block.timestamp; - siloDaily.save(); + takeSiloSnapshots(silo, event.address, event.block.timestamp); + silo.save(); // Remove the asset-only amount that got added in Reward event handler. // Will be immediately re-credited to the user/system in AddDeposit @@ -403,28 +387,14 @@ function addDepositToSilo( blockNumber: BigInt ): void { let silo = loadSilo(account); - let siloHourly = loadSiloHourlySnapshot(account, season, timestamp); - let siloDaily = loadSiloDailySnapshot(account, timestamp); silo.depositedBDV = silo.depositedBDV.plus(bdv); // Individual farmer seeds cannot be directly tracked due to seed gauge if (account == BEANSTALK) { silo.grownStalkPerSeason = silo.grownStalkPerSeason.plus(grownStalkPerBDV); } + takeSiloSnapshots(silo, BEANSTALK, timestamp); silo.save(); - - siloHourly.deltaDepositedBDV = siloHourly.deltaDepositedBDV.plus(bdv); - siloHourly.depositedBDV = silo.depositedBDV; - siloHourly.grownStalkPerSeason = silo.grownStalkPerSeason; - siloHourly.updatedAt = timestamp; - siloHourly.save(); - - siloDaily.season = season; - siloDaily.deltaDepositedBDV = siloDaily.deltaDepositedBDV.plus(bdv); - siloDaily.depositedBDV = silo.depositedBDV; - siloDaily.grownStalkPerSeason = silo.grownStalkPerSeason; - siloDaily.updatedAt = timestamp; - siloDaily.save(); } function removeDepositFromSilo( @@ -436,8 +406,6 @@ function removeDepositFromSilo( blockNumber: BigInt ): void { let silo = loadSilo(account); - let siloHourly = loadSiloHourlySnapshot(account, season, timestamp); - let siloDaily = loadSiloDailySnapshot(account, timestamp); silo.depositedBDV = silo.depositedBDV.minus(bdv); // Individual farmer seeds cannot be directly tracked due to seed gauge @@ -555,27 +523,13 @@ export function updateStalkBalances( blockNumber: BigInt ): void { let silo = loadSilo(account); - let siloHourly = loadSiloHourlySnapshot(account, season, timestamp); - let siloDaily = loadSiloDailySnapshot(account, timestamp); silo.stalk = silo.stalk.plus(stalk); silo.roots = silo.roots.plus(roots); - silo.save(); - siloHourly.stalk = silo.stalk; - siloHourly.roots = silo.roots; - siloHourly.deltaStalk = siloHourly.deltaStalk.plus(stalk); - siloHourly.deltaRoots = siloHourly.deltaRoots.plus(roots); - siloHourly.updatedAt = timestamp; - siloHourly.save(); - - siloDaily.season = season; - siloDaily.stalk = silo.stalk; - siloDaily.roots = silo.roots; - siloDaily.deltaStalk = siloDaily.deltaStalk.plus(stalk); - siloDaily.deltaRoots = siloDaily.deltaRoots.plus(roots); - siloDaily.updatedAt = timestamp; - siloDaily.save(); + // TODO: protocol in param + takeSiloSnapshots(silo, BEANSTALK, timestamp); + silo.save(); // Add account to active list if needed if (account !== BEANSTALK) { @@ -600,22 +554,10 @@ export function updateStalkBalances( function updateSeedsBalances(account: Address, season: i32, seeds: BigInt, timestamp: BigInt, blockNumber: BigInt): void { let silo = loadSilo(account); - let siloHourly = loadSiloHourlySnapshot(account, season, timestamp); - let siloDaily = loadSiloDailySnapshot(account, timestamp); - silo.seeds = silo.seeds.plus(seeds); + // TODO: protocol in param? + takeSiloSnapshots(silo, BEANSTALK, timestamp); silo.save(); - - siloHourly.seeds = silo.seeds; - siloHourly.deltaSeeds = siloHourly.deltaSeeds.plus(seeds); - siloHourly.updatedAt = timestamp; - siloHourly.save(); - - siloDaily.season = season; - siloDaily.seeds = silo.seeds; - siloDaily.deltaSeeds = siloDaily.deltaSeeds.plus(seeds); - siloDaily.updatedAt = timestamp; - siloDaily.save(); } function updateClaimedWithdraw(account: Address, token: Address, season: BigInt): void { @@ -626,32 +568,18 @@ function updateClaimedWithdraw(account: Address, token: Address, season: BigInt) function incrementProtocolFarmers(season: i32, timestamp: BigInt): void { let silo = loadSilo(BEANSTALK); - let siloHourly = loadSiloHourlySnapshot(BEANSTALK, season, timestamp); - let siloDaily = loadSiloDailySnapshot(BEANSTALK, timestamp); - silo.activeFarmers += 1; - siloHourly.activeFarmers += 1; - siloHourly.deltaActiveFarmers += 1; - siloDaily.activeFarmers += 1; - siloDaily.deltaActiveFarmers += 1; + // TODO: protocol in param? + takeSiloSnapshots(silo, BEANSTALK, timestamp); silo.save(); - siloHourly.save(); - siloDaily.save(); } function decrementProtocolFarmers(season: i32, timestamp: BigInt): void { let silo = loadSilo(BEANSTALK); - let siloHourly = loadSiloHourlySnapshot(BEANSTALK, season, timestamp); - let siloDaily = loadSiloDailySnapshot(BEANSTALK, timestamp); - silo.activeFarmers -= 1; - siloHourly.activeFarmers -= 1; - siloHourly.deltaActiveFarmers -= 1; - siloDaily.activeFarmers -= 1; - siloDaily.deltaActiveFarmers -= 1; + // TODO: protocol in param? + takeSiloSnapshots(silo, BEANSTALK, timestamp); silo.save(); - siloHourly.save(); - siloDaily.save(); } export function updateStalkWithCalls(season: i32, timestamp: BigInt, blockNumber: BigInt): void { diff --git a/projects/subgraph-beanstalk/src/YieldHandler.ts b/projects/subgraph-beanstalk/src/YieldHandler.ts index 96d55a87b0..a3ff1756cc 100644 --- a/projects/subgraph-beanstalk/src/YieldHandler.ts +++ b/projects/subgraph-beanstalk/src/YieldHandler.ts @@ -64,6 +64,7 @@ function updateWindowEMA(t: i32, timestamp: BigInt, window: i32): void { if (siloYield.u < window) { // Recalculate EMA from initial season since beta has changed for (let i = 6075; i <= t; i++) { + // TODO: solution for this let season = loadSiloHourlySnapshot(BEANSTALK, i, timestamp); currentEMA = toDecimal(season.deltaBeanMints).minus(priorEMA).times(siloYield.beta).plus(priorEMA); priorEMA = currentEMA; @@ -71,6 +72,7 @@ function updateWindowEMA(t: i32, timestamp: BigInt, window: i32): void { } else { // Calculate EMA for the prior 720 seasons for (let i = t - window + 1; i <= t; i++) { + // TODO: solution for this let season = loadSiloHourlySnapshot(BEANSTALK, i, timestamp); currentEMA = toDecimal(season.deltaBeanMints).minus(priorEMA).times(siloYield.beta).plus(priorEMA); priorEMA = currentEMA; diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 2a596533a9..95fa117fdc 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -16,7 +16,7 @@ import { } from "../../generated/schema"; import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { dayFromTimestamp, hourFromTimestamp } from "./Snapshots"; +import { dayFromTimestamp, hourFromTimestamp } from "./snapshots/DateUtil"; /* ===== Base Silo Entities ===== */ diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts b/projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts new file mode 100644 index 0000000000..220eab8fee --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts @@ -0,0 +1,11 @@ +import { BigInt } from "@graphprotocol/graph-ts"; + +export function dayFromTimestamp(timestamp: BigInt): string { + let day_ts = timestamp.toI32() - (timestamp.toI32() % 86400); + return day_ts.toString(); +} + +export function hourFromTimestamp(timestamp: BigInt): string { + let day_ts = timestamp.toI32() - (timestamp.toI32() % 3600); + return day_ts.toString(); +} diff --git a/projects/subgraph-beanstalk/src/utils/Snapshots.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts similarity index 57% rename from projects/subgraph-beanstalk/src/utils/Snapshots.ts rename to projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts index 0ca4e92431..1cd3e3a981 100644 --- a/projects/subgraph-beanstalk/src/utils/Snapshots.ts +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts @@ -1,19 +1,7 @@ import { BigInt, Address } from "@graphprotocol/graph-ts"; -import { Silo, SiloDailySnapshot, SiloHourlySnapshot } from "../../generated/schema"; -import { getCurrentSeason } from "./Beanstalk"; - -export function dayFromTimestamp(timestamp: BigInt): string { - let day_ts = timestamp.toI32() - (timestamp.toI32() % 86400); - return day_ts.toString(); -} - -export function hourFromTimestamp(timestamp: BigInt): string { - let day_ts = timestamp.toI32() - (timestamp.toI32() % 3600); - return day_ts.toString(); -} - -// Entities could store a lastSnapshotAt field which can be used to derive both the date and hour. -// This would then become the base for comparison of deltas +import { Silo, SiloDailySnapshot, SiloHourlySnapshot } from "../../../generated/schema"; +import { getCurrentSeason } from "../Beanstalk"; +import { dayFromTimestamp, hourFromTimestamp } from "./DateUtil"; export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: BigInt): void { const currentSeason = getCurrentSeason(beanstalk); @@ -35,6 +23,7 @@ export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: Big const hourly = new SiloHourlySnapshot(hourlyId); const daily = new SiloDailySnapshot(dailyId); + // Set current values hourly.season = currentSeason; hourly.silo = silo.id; hourly.depositedBDV = silo.depositedBDV; @@ -47,6 +36,8 @@ export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: Big hourly.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; hourly.beanMints = silo.beanMints; hourly.activeFarmers = silo.activeFarmers; + + // Set deltas if (baseHourly !== null) { hourly.deltaDepositedBDV = hourly.depositedBDV.minus(baseHourly.depositedBDV); hourly.deltaStalk = hourly.stalk.minus(baseHourly.stalk); @@ -84,7 +75,58 @@ export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: Big hourly.updatedAt = timestamp; hourly.save(); + // Repeat for daily snapshot. + // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + + daily.season = currentSeason; + daily.silo = silo.id; + daily.depositedBDV = silo.depositedBDV; + daily.stalk = silo.stalk; + daily.plantableStalk = silo.plantableStalk; + daily.seeds = silo.seeds; + daily.grownStalkPerSeason = silo.grownStalkPerSeason; + daily.roots = silo.roots; + daily.germinatingStalk = silo.germinatingStalk; + daily.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; + daily.beanMints = silo.beanMints; + daily.activeFarmers = silo.activeFarmers; + if (baseDaily !== null) { + daily.deltaDepositedBDV = daily.depositedBDV.minus(baseDaily.depositedBDV); + daily.deltaStalk = daily.stalk.minus(baseDaily.stalk); + daily.deltaPlantableStalk = daily.plantableStalk.minus(baseDaily.plantableStalk); + daily.deltaSeeds = daily.seeds.minus(baseDaily.seeds); + daily.deltaRoots = daily.roots.minus(baseDaily.roots); + daily.deltaGerminatingStalk = daily.germinatingStalk.minus(baseDaily.germinatingStalk); + // NOTE: missing beanToMaxLpGpPerBdvRatio + daily.deltaBeanMints = daily.beanMints.minus(baseDaily.beanMints); + daily.deltaActiveFarmers = daily.activeFarmers - baseDaily.activeFarmers; + if (daily.id == baseDaily.id) { + // Add existing deltas + daily.deltaDepositedBDV = daily.deltaDepositedBDV.plus(baseDaily.deltaDepositedBDV); + daily.deltaStalk = daily.deltaStalk.plus(baseDaily.deltaDepositedBDV); + daily.deltaPlantableStalk = daily.deltaPlantableStalk.plus(baseDaily.deltaPlantableStalk); + daily.deltaSeeds = daily.deltaSeeds.plus(baseDaily.deltaSeeds); + daily.deltaRoots = daily.deltaRoots.plus(baseDaily.deltaRoots); + daily.deltaGerminatingStalk = daily.deltaGerminatingStalk.plus(baseDaily.deltaGerminatingStalk); + // NOTE: missing beanToMaxLpGpPerBdvRatio + daily.deltaBeanMints = daily.deltaBeanMints.plus(baseDaily.deltaBeanMints); + daily.deltaActiveFarmers = daily.deltaActiveFarmers + baseDaily.deltaActiveFarmers; + } + } else { + daily.deltaDepositedBDV = daily.depositedBDV; + daily.deltaStalk = daily.stalk; + daily.deltaPlantableStalk = daily.plantableStalk; + daily.deltaSeeds = daily.seeds; + daily.deltaRoots = daily.roots; + daily.deltaGerminatingStalk = daily.germinatingStalk; + // NOTE: missing beanToMaxLpGpPerBdvRatio + daily.deltaBeanMints = daily.beanMints; + daily.deltaActiveFarmers = daily.activeFarmers; + } + daily.createdAt = hour; + daily.updatedAt = timestamp; + daily.save(); + silo.lastHourlySnapshotSeason = currentSeason; silo.lastDailySnapshotDay = day; - // Caller must call save on silo. (document this somewhere) } From a9eaa79eacbeeb8a124b9dc9c94ef8ed4110c109 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 13:48:18 -0700 Subject: [PATCH 06/59] test fixes --- .../subgraph-beanstalk/src/GaugeHandler.ts | 15 +--- .../subgraph-beanstalk/src/YieldHandler.ts | 22 ++---- .../subgraph-beanstalk/src/utils/Beanstalk.ts | 9 +++ .../subgraph-beanstalk/src/utils/Field.ts | 2 +- .../src/utils/PodMarketplace.ts | 2 +- projects/subgraph-beanstalk/src/utils/Silo.ts | 79 ++----------------- .../src/utils/snapshots/DateUtil.ts | 11 --- .../src/utils/snapshots/Silo.ts | 18 +++-- .../tests/SeedGauge.test.ts | 7 +- 9 files changed, 42 insertions(+), 123 deletions(-) delete mode 100644 projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index 4c6d07d1f0..574ca67db4 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -13,8 +13,6 @@ import { import { handleRateChange } from "./utils/Field"; import { loadSilo, - loadSiloHourlySnapshot, - loadSiloDailySnapshot, loadWhitelistTokenSetting, loadWhitelistTokenDailySnapshot, loadWhitelistTokenHourlySnapshot, @@ -27,7 +25,7 @@ import { WhitelistToken as WhitelistTokenEntity } from "../generated/schema"; import { BEAN_WETH_CP2_WELL } from "../../subgraph-core/utils/Constants"; import { Bytes4_emptyToNull } from "../../subgraph-core/utils/Bytes"; import { getCurrentSeason } from "./utils/Beanstalk"; -import { takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { setHourlyCaseId, takeSiloSnapshots } from "./utils/snapshots/Silo"; export function handleTemperatureChange(event: TemperatureChange): void { handleRateChange(event.address, event.block, event.params.season, event.params.caseId, event.params.absChange); @@ -43,16 +41,9 @@ export function handleBeanToMaxLpGpPerBdvRatioChange(event: BeanToMaxLpGpPerBdvR } else { silo.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio!.plus(event.params.absChange); } + takeSiloSnapshots(silo, event.address, event.block.timestamp); + setHourlyCaseId(event.params.caseId, silo, event.address); silo.save(); - - // TODO: solution for caseId. - let siloHourly = loadSiloHourlySnapshot(event.address, event.params.season.toI32(), event.block.timestamp); - let siloDaily = loadSiloDailySnapshot(event.address, event.block.timestamp); - siloHourly.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; - siloHourly.caseId = event.params.caseId; - siloDaily.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; - siloHourly.save(); - siloDaily.save(); } export function handleGaugePointChange(event: GaugePointChange): void { diff --git a/projects/subgraph-beanstalk/src/YieldHandler.ts b/projects/subgraph-beanstalk/src/YieldHandler.ts index a3ff1756cc..6af1fb648b 100644 --- a/projects/subgraph-beanstalk/src/YieldHandler.ts +++ b/projects/subgraph-beanstalk/src/YieldHandler.ts @@ -3,19 +3,11 @@ import { BasinBip } from "../generated/Beanstalk-ABIs/BasinBip"; import { BEANSTALK, BEAN_ERC20, FERTILIZER } from "../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadFertilizer, loadFertilizerYield } from "./utils/Fertilizer"; -import { - loadSilo, - loadSiloAsset, - loadSiloHourlySnapshot, - loadSiloYield, - loadTokenYield, - loadWhitelistTokenSetting, - SiloAsset_findIndex_token -} from "./utils/Silo"; +import { loadSilo, loadSiloAsset, loadSiloYield, loadTokenYield, loadWhitelistTokenSetting, SiloAsset_findIndex_token } from "./utils/Silo"; import { BigDecimal_sum, f64_sum, f64_max } from "../../subgraph-core/utils/ArrayMath"; import { getGerminatingBdvs } from "./utils/Germinating"; import { SiloAsset, WhitelistTokenSetting } from "../generated/schema"; -import { getCurrentSeason } from "./utils/Beanstalk"; +import { getCurrentSeason, getRewardMinted } from "./utils/Beanstalk"; const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; @@ -64,17 +56,15 @@ function updateWindowEMA(t: i32, timestamp: BigInt, window: i32): void { if (siloYield.u < window) { // Recalculate EMA from initial season since beta has changed for (let i = 6075; i <= t; i++) { - // TODO: solution for this - let season = loadSiloHourlySnapshot(BEANSTALK, i, timestamp); - currentEMA = toDecimal(season.deltaBeanMints).minus(priorEMA).times(siloYield.beta).plus(priorEMA); + let rewardMint = getRewardMinted(i); + currentEMA = toDecimal(rewardMint).minus(priorEMA).times(siloYield.beta).plus(priorEMA); priorEMA = currentEMA; } } else { // Calculate EMA for the prior 720 seasons for (let i = t - window + 1; i <= t; i++) { - // TODO: solution for this - let season = loadSiloHourlySnapshot(BEANSTALK, i, timestamp); - currentEMA = toDecimal(season.deltaBeanMints).minus(priorEMA).times(siloYield.beta).plus(priorEMA); + let rewardMint = getRewardMinted(i); + currentEMA = toDecimal(rewardMint).minus(priorEMA).times(siloYield.beta).plus(priorEMA); priorEMA = currentEMA; } } diff --git a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts index a8697509df..0ef2e4bc4b 100644 --- a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts @@ -65,3 +65,12 @@ export function getCurrentSeason(beanstalk: Address): i32 { let beanstalkEntity = loadBeanstalk(beanstalk); return beanstalkEntity.lastSeason; } + +// Returns the number of reward beans minted for the requested season +export function getRewardMinted(season: i32): BigInt { + const snapshot = Season.load(season.toString()); + if (snapshot == null) { + return ZERO_BI; + } + return snapshot.rewardBeans; +} diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index 1ab79e04e1..a096049b20 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -5,7 +5,7 @@ import { ADDRESS_ZERO, BEANSTALK, CURVE_PRICE } from "../../../subgraph-core/uti import { CurvePrice } from "../../generated/Beanstalk-ABIs/CurvePrice"; import { BeanstalkPrice_try_price } from "./BeanstalkPrice"; import { loadBeanstalk, loadSeason } from "./Beanstalk"; -import { dayFromTimestamp } from "./Snapshots"; +import { dayFromTimestamp } from "../../../subgraph-core/utils/Dates"; // This function is for handling both the WeatherChange and TemperatureChange events. // The logic is the same for both, this is intended to accommodate the renamed event and fields. diff --git a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts b/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts index 740d6a1507..717528be54 100644 --- a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts +++ b/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts @@ -3,7 +3,7 @@ import { PodMarketplace, PodMarketplaceHourlySnapshot, PodMarketplaceDailySnapsh import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { loadField } from "./Field"; import { expirePodListingIfExists } from "./PodListing"; -import { dayFromTimestamp } from "./Snapshots"; +import { dayFromTimestamp } from "../../../subgraph-core/utils/Dates"; export enum MarketplaceAction { CREATED, diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 95fa117fdc..82dfb93d34 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -1,8 +1,6 @@ import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; import { Silo, - SiloHourlySnapshot, - SiloDailySnapshot, SiloDeposit, SiloWithdraw, SiloYield, @@ -16,7 +14,7 @@ import { } from "../../generated/schema"; import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { dayFromTimestamp, hourFromTimestamp } from "./snapshots/DateUtil"; +import { dayFromTimestamp, hourFromTimestamp } from "../../../subgraph-core/utils/Dates"; /* ===== Base Silo Entities ===== */ @@ -44,73 +42,6 @@ export function loadSilo(account: Address): Silo { return silo as Silo; } -export function loadSiloHourlySnapshot(account: Address, season: i32, timestamp: BigInt): SiloHourlySnapshot { - let id = account.toHexString() + "-" + season.toString(); - let snapshot = SiloHourlySnapshot.load(id); - if (snapshot == null) { - snapshot = new SiloHourlySnapshot(id); - let silo = loadSilo(account); - snapshot.season = season; - snapshot.silo = account.toHexString(); - snapshot.depositedBDV = silo.depositedBDV; - snapshot.stalk = silo.stalk; - snapshot.plantableStalk = silo.plantableStalk; - snapshot.seeds = silo.seeds; - snapshot.grownStalkPerSeason = silo.grownStalkPerSeason; - snapshot.roots = silo.roots; - snapshot.germinatingStalk = silo.germinatingStalk; - snapshot.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; - snapshot.beanMints = silo.beanMints; - snapshot.activeFarmers = silo.activeFarmers; - snapshot.deltaDepositedBDV = ZERO_BI; - snapshot.deltaStalk = ZERO_BI; - snapshot.deltaPlantableStalk = ZERO_BI; - snapshot.deltaSeeds = ZERO_BI; - snapshot.deltaRoots = ZERO_BI; - snapshot.deltaGerminatingStalk = ZERO_BI; - snapshot.deltaBeanMints = ZERO_BI; - snapshot.deltaActiveFarmers = 0; - snapshot.createdAt = BigInt.fromString(hourFromTimestamp(timestamp)); - snapshot.updatedAt = timestamp; - snapshot.save(); - } - return snapshot as SiloHourlySnapshot; -} - -export function loadSiloDailySnapshot(account: Address, timestamp: BigInt): SiloDailySnapshot { - let day = dayFromTimestamp(timestamp); - let id = account.toHexString() + "-" + day.toString(); - let snapshot = SiloDailySnapshot.load(id); - if (snapshot == null) { - snapshot = new SiloDailySnapshot(id); - let silo = loadSilo(account); - snapshot.season = 0; - snapshot.silo = account.toHexString(); - snapshot.depositedBDV = silo.depositedBDV; - snapshot.stalk = silo.stalk; - snapshot.plantableStalk = silo.plantableStalk; - snapshot.seeds = silo.seeds; - snapshot.grownStalkPerSeason = silo.grownStalkPerSeason; - snapshot.roots = silo.roots; - snapshot.germinatingStalk = silo.germinatingStalk; - snapshot.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio; - snapshot.beanMints = silo.beanMints; - snapshot.activeFarmers = silo.activeFarmers; - snapshot.deltaDepositedBDV = ZERO_BI; - snapshot.deltaStalk = ZERO_BI; - snapshot.deltaPlantableStalk = ZERO_BI; - snapshot.deltaSeeds = ZERO_BI; - snapshot.deltaRoots = ZERO_BI; - snapshot.deltaGerminatingStalk = ZERO_BI; - snapshot.deltaBeanMints = ZERO_BI; - snapshot.deltaActiveFarmers = 0; - snapshot.createdAt = BigInt.fromString(day); - snapshot.updatedAt = timestamp; - snapshot.save(); - } - return snapshot as SiloDailySnapshot; -} - /* ===== Asset Entities ===== */ export function loadSiloAsset(account: Address, token: Address): SiloAsset { @@ -147,7 +78,7 @@ export function loadSiloAssetHourlySnapshot(account: Address, token: Address, se snapshot.deltaDepositedAmount = ZERO_BI; snapshot.deltaWithdrawnAmount = ZERO_BI; snapshot.deltaFarmAmount = ZERO_BI; - snapshot.createdAt = BigInt.fromString(hour); + snapshot.createdAt = BigInt.fromI32(hour); snapshot.updatedAt = ZERO_BI; snapshot.save(); } @@ -171,7 +102,7 @@ export function loadSiloAssetDailySnapshot(account: Address, token: Address, tim snapshot.deltaDepositedAmount = ZERO_BI; snapshot.deltaWithdrawnAmount = ZERO_BI; snapshot.deltaFarmAmount = ZERO_BI; - snapshot.createdAt = BigInt.fromString(day); + snapshot.createdAt = BigInt.fromI32(day); snapshot.updatedAt = ZERO_BI; snapshot.save(); } @@ -230,7 +161,7 @@ export function loadWhitelistTokenHourlySnapshot(token: Address, season: i32, ti snapshot.milestoneSeason = setting.milestoneSeason; snapshot.gaugePoints = setting.gaugePoints; snapshot.optimalPercentDepositedBdv = setting.optimalPercentDepositedBdv; - snapshot.createdAt = BigInt.fromString(hour); + snapshot.createdAt = BigInt.fromI32(hour); snapshot.updatedAt = ZERO_BI; snapshot.save(); } @@ -253,7 +184,7 @@ export function loadWhitelistTokenDailySnapshot(token: Address, timestamp: BigIn snapshot.milestoneSeason = setting.milestoneSeason; snapshot.gaugePoints = setting.gaugePoints; snapshot.optimalPercentDepositedBdv = setting.optimalPercentDepositedBdv; - snapshot.createdAt = BigInt.fromString(day); + snapshot.createdAt = BigInt.fromI32(day); snapshot.updatedAt = ZERO_BI; snapshot.save(); } diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts b/projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts deleted file mode 100644 index 220eab8fee..0000000000 --- a/projects/subgraph-beanstalk/src/utils/snapshots/DateUtil.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BigInt } from "@graphprotocol/graph-ts"; - -export function dayFromTimestamp(timestamp: BigInt): string { - let day_ts = timestamp.toI32() - (timestamp.toI32() % 86400); - return day_ts.toString(); -} - -export function hourFromTimestamp(timestamp: BigInt): string { - let day_ts = timestamp.toI32() - (timestamp.toI32() % 3600); - return day_ts.toString(); -} diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts index 1cd3e3a981..68e1b3048c 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts @@ -1,13 +1,13 @@ -import { BigInt, Address } from "@graphprotocol/graph-ts"; +import { BigInt, Address, log } from "@graphprotocol/graph-ts"; import { Silo, SiloDailySnapshot, SiloHourlySnapshot } from "../../../generated/schema"; import { getCurrentSeason } from "../Beanstalk"; -import { dayFromTimestamp, hourFromTimestamp } from "./DateUtil"; +import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: BigInt): void { const currentSeason = getCurrentSeason(beanstalk); - const hour = BigInt.fromString(hourFromTimestamp(timestamp)); - const day = BigInt.fromString(dayFromTimestamp(timestamp)); + const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); + const day = BigInt.fromI32(dayFromTimestamp(timestamp)); // Load the snapshot for this season/day const hourlyId = silo.id + "-" + currentSeason.toString(); @@ -123,10 +123,18 @@ export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: Big daily.deltaBeanMints = daily.beanMints; daily.deltaActiveFarmers = daily.activeFarmers; } - daily.createdAt = hour; + daily.createdAt = day; daily.updatedAt = timestamp; daily.save(); silo.lastHourlySnapshotSeason = currentSeason; silo.lastDailySnapshotDay = day; } + +// Set case id on hourly snapshot. assumption is that the snapshot was already created +export function setHourlyCaseId(caseId: BigInt, silo: Silo, beanstalk: Address): void { + const currentSeason = getCurrentSeason(beanstalk); + const hourly = SiloHourlySnapshot.load(silo.id + "-" + currentSeason.toString())!; + hourly.caseId = caseId; + hourly.save(); +} diff --git a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts index e263393972..f19d26cbd4 100644 --- a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts +++ b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts @@ -32,7 +32,7 @@ import { simpleMockPrice } from "../../subgraph-core/tests/event-mocking/Price"; import { loadSilo } from "../src/utils/Silo"; import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block"; import { setSeason } from "./utils/Season"; -import { dayFromTimestamp } from "../src/utils/Snapshots"; +import { dayFromTimestamp } from "../../subgraph-core/utils/Dates"; const ANVIL_ADDR_1 = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".toLowerCase(); @@ -61,6 +61,7 @@ describe("Seed Gauge", () => { describe("Seasonal Adjustments", () => { test("event: BeanToMaxLpGpPerBdvRatioChange (initialization)", () => { const initialRatio = BigInt.fromI32(66).times(ratioDecimals); + setSeason(20000); handleBeanToMaxLpGpPerBdvRatioChange( createBeanToMaxLpGpPerBdvRatioChangeEvent(BigInt.fromU32(20000), BigInt.fromU32(10), initialRatio) ); @@ -224,7 +225,7 @@ describe("Seed Gauge", () => { const timestamp = BigInt.fromU32(1712793374); const day = dayFromTimestamp(timestamp); assert.notInStore("WhitelistTokenHourlySnapshot", BEAN_ERC20.toHexString() + "-1"); - assert.notInStore("WhitelistTokenDailySnapshot", BEAN_ERC20.toHexString() + "-" + day); + assert.notInStore("WhitelistTokenDailySnapshot", BEAN_ERC20.toHexString() + "-" + day.toString()); let event = createUpdateGaugeSettingsEvent( BEAN_ERC20.toHexString(), @@ -236,7 +237,7 @@ describe("Seed Gauge", () => { handleUpdateGaugeSettings(event); assert.fieldEquals("WhitelistTokenHourlySnapshot", BEAN_ERC20.toHexString() + "-1", "gpSelector", "0x12341234"); - assert.fieldEquals("WhitelistTokenDailySnapshot", BEAN_ERC20.toHexString() + "-" + day, "gpSelector", "0x12341234"); + assert.fieldEquals("WhitelistTokenDailySnapshot", BEAN_ERC20.toHexString() + "-" + day.toString(), "gpSelector", "0x12341234"); }); }); }); From c460e2853eaec2635b284bf6a6f515a47bcd1870 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:00:55 -0700 Subject: [PATCH 07/59] recursive seed update --- .../subgraph-beanstalk/src/SiloHandler.ts | 47 ++++++------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index c06efeb4db..507a22f7dd 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -34,7 +34,7 @@ import { addToSiloWhitelist, updateDeposit } from "./utils/Silo"; -import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit } from "../generated/schema"; +import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit, Silo } from "../generated/schema"; import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; import { takeSiloSnapshots } from "./utils/snapshots/Silo"; @@ -325,9 +325,7 @@ export function handleSeedsBalanceChanged(event: SeedsBalanceChanged): void { return; } - let beanstalk = loadBeanstalk(event.address); // get current season - updateSeedsBalances(event.address, beanstalk.lastSeason, event.params.delta, event.block.timestamp, event.block.number); - updateSeedsBalances(event.params.account, beanstalk.lastSeason, event.params.delta, event.block.timestamp, event.block.number); + updateSeedsBalances(event.address, event.params.account, event.params.delta, event.block.timestamp); } export function handlePlant(event: Plant): void { @@ -529,7 +527,6 @@ export function updateStalkBalances( // TODO: protocol in param takeSiloSnapshots(silo, BEANSTALK, timestamp); - silo.save(); // Add account to active list if needed if (account !== BEANSTALK) { @@ -540,23 +537,25 @@ export function updateStalkBalances( newFarmers.push(account.toHexString()); beanstalk.activeFarmers = newFarmers; beanstalk.save(); - - incrementProtocolFarmers(season, timestamp); + silo.activeFarmers += 1; } else if (silo.stalk == ZERO_BI) { let newFarmers = beanstalk.activeFarmers; newFarmers.splice(farmerIndex, 1); beanstalk.activeFarmers = newFarmers; - - decrementProtocolFarmers(season, timestamp); + beanstalk.save(); + silo.activeFarmers -= 1; } } + silo.save(); } -function updateSeedsBalances(account: Address, season: i32, seeds: BigInt, timestamp: BigInt, blockNumber: BigInt): void { +function updateSeedsBalances(beanstalk: Address, account: Address, seeds: BigInt, timestamp: BigInt, recurs: Boolean = true): void { + if (recurs && account != beanstalk) { + updateSeedsBalances(beanstalk, beanstalk, seeds, timestamp); + } let silo = loadSilo(account); silo.seeds = silo.seeds.plus(seeds); - // TODO: protocol in param? - takeSiloSnapshots(silo, BEANSTALK, timestamp); + takeSiloSnapshots(silo, beanstalk, timestamp); silo.save(); } @@ -566,27 +565,11 @@ function updateClaimedWithdraw(account: Address, token: Address, season: BigInt) withdraw.save(); } -function incrementProtocolFarmers(season: i32, timestamp: BigInt): void { - let silo = loadSilo(BEANSTALK); - silo.activeFarmers += 1; - // TODO: protocol in param? - takeSiloSnapshots(silo, BEANSTALK, timestamp); - silo.save(); -} - -function decrementProtocolFarmers(season: i32, timestamp: BigInt): void { - let silo = loadSilo(BEANSTALK); - silo.activeFarmers -= 1; - // TODO: protocol in param? - takeSiloSnapshots(silo, BEANSTALK, timestamp); - silo.save(); -} - -export function updateStalkWithCalls(season: i32, timestamp: BigInt, blockNumber: BigInt): void { +export function updateStalkWithCalls(beanstalkAddress: Address, season: i32, timestamp: BigInt, blockNumber: BigInt): void { // This should be run at sunrise for the previous season to update any farmers stalk/seed/roots balances from silo transfers. - let beanstalk = loadBeanstalk(BEANSTALK); - let beanstalk_call = Replanted.bind(BEANSTALK); + let beanstalk = loadBeanstalk(beanstalkAddress); + let beanstalk_call = Replanted.bind(beanstalkAddress); for (let i = 0; i < beanstalk.farmersToUpdate.length; i++) { let account = Address.fromString(beanstalk.farmersToUpdate[i]); @@ -600,7 +583,7 @@ export function updateStalkWithCalls(season: i32, timestamp: BigInt, blockNumber blockNumber ); // balanceOfSeeds function was removed in silov2 - updateSeedsBalances(account, season, beanstalk_call.balanceOfSeeds(account).minus(silo.seeds), timestamp, blockNumber); + updateSeedsBalances(beanstalkAddress, account, beanstalk_call.balanceOfSeeds(account).minus(silo.seeds), timestamp, false); } beanstalk.farmersToUpdate = []; beanstalk.save(); From 5dae9471c9f8cb4da5dce659498d2af30879dbc8 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:15:23 -0700 Subject: [PATCH 08/59] recursive stalk update --- .../subgraph-beanstalk/src/GaugeHandler.ts | 9 +-- .../subgraph-beanstalk/src/SeasonHandler.ts | 7 ++- .../subgraph-beanstalk/src/SiloHandler.ts | 61 +++++++------------ .../subgraph-beanstalk/src/utils/Beanstalk.ts | 4 +- .../subgraph-beanstalk/src/utils/Field.ts | 6 +- .../src/utils/snapshots/Silo.ts | 8 +-- 6 files changed, 37 insertions(+), 58 deletions(-) diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index 574ca67db4..a4dea1072a 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -140,14 +140,7 @@ export function handleTotalGerminatingStalkChanged(event: TotalGerminatingStalkC // Germination completes, germinating stalk turns into stalk. // The removal of Germinating stalk would have already been handled from a separate emission export function handleTotalStalkChangedFromGermination(event: TotalStalkChangedFromGermination): void { - updateStalkBalances( - event.address, - getCurrentSeason(event.address), - event.params.deltaStalk, - event.params.deltaRoots, - event.block.timestamp, - event.block.number - ); + updateStalkBalances(event.address, event.address, event.params.deltaStalk, event.params.deltaRoots, event.block.timestamp); } // WHITELIST / GAUGE CONFIGURATION SETTINGS // diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index 12f9326238..32ddcd3f78 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -20,12 +20,13 @@ import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/BeanstalkPr import { takeSiloSnapshots } from "./utils/snapshots/Silo"; export function handleSunrise(event: Sunrise): void { + // Update any farmers that had silo transfers from the prior season. + // This is intentionally done before beanstalk.lastSeason gets updated + updateStalkWithCalls(event.address, event.block.timestamp); + let currentSeason = event.params.season.toI32(); let season = loadSeason(event.address, event.params.season); - // Update any farmers that had silo transfers from the prior season - updateStalkWithCalls(currentSeason - 1, event.block.timestamp, event.block.number); - // Update season metrics if (event.params.season == BigInt.fromI32(6075)) { // Replant oracle initialization diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 507a22f7dd..36b191e0d2 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -300,23 +300,7 @@ export function handleStalkBalanceChanged(event: StalkBalanceChanged): void { return; } - let beanstalk = loadBeanstalk(event.address); // get current season - updateStalkBalances( - event.address, - beanstalk.lastSeason, - event.params.delta, - event.params.deltaRoots, - event.block.timestamp, - event.block.number - ); - updateStalkBalances( - event.params.account, - beanstalk.lastSeason, - event.params.delta, - event.params.deltaRoots, - event.block.timestamp, - event.block.number - ); + updateStalkBalances(event.address, event.params.account, event.params.delta, event.params.deltaRoots, event.block.timestamp); } export function handleSeedsBalanceChanged(event: SeedsBalanceChanged): void { @@ -513,24 +497,25 @@ function addWithdrawToSiloAsset( } export function updateStalkBalances( + protocol: Address, account: Address, - season: i32, - stalk: BigInt, - roots: BigInt, + deltaStalk: BigInt, + deltaRoots: BigInt, timestamp: BigInt, - blockNumber: BigInt + recurs: boolean = true ): void { + if (recurs && account != protocol) { + updateStalkBalances(protocol, protocol, deltaStalk, deltaRoots, timestamp); + } let silo = loadSilo(account); + silo.stalk = silo.stalk.plus(deltaStalk); + silo.roots = silo.roots.plus(deltaRoots); - silo.stalk = silo.stalk.plus(stalk); - silo.roots = silo.roots.plus(roots); - - // TODO: protocol in param - takeSiloSnapshots(silo, BEANSTALK, timestamp); + takeSiloSnapshots(silo, protocol, timestamp); // Add account to active list if needed - if (account !== BEANSTALK) { - let beanstalk = loadBeanstalk(BEANSTALK); + if (account !== protocol) { + let beanstalk = loadBeanstalk(protocol); let farmerIndex = beanstalk.activeFarmers.indexOf(account.toHexString()); if (farmerIndex == -1) { let newFarmers = beanstalk.activeFarmers; @@ -549,13 +534,13 @@ export function updateStalkBalances( silo.save(); } -function updateSeedsBalances(beanstalk: Address, account: Address, seeds: BigInt, timestamp: BigInt, recurs: Boolean = true): void { - if (recurs && account != beanstalk) { - updateSeedsBalances(beanstalk, beanstalk, seeds, timestamp); +function updateSeedsBalances(protocol: Address, account: Address, seeds: BigInt, timestamp: BigInt, recurs: boolean = true): void { + if (recurs && account != protocol) { + updateSeedsBalances(protocol, protocol, seeds, timestamp); } let silo = loadSilo(account); silo.seeds = silo.seeds.plus(seeds); - takeSiloSnapshots(silo, beanstalk, timestamp); + takeSiloSnapshots(silo, protocol, timestamp); silo.save(); } @@ -565,25 +550,25 @@ function updateClaimedWithdraw(account: Address, token: Address, season: BigInt) withdraw.save(); } -export function updateStalkWithCalls(beanstalkAddress: Address, season: i32, timestamp: BigInt, blockNumber: BigInt): void { +export function updateStalkWithCalls(protocol: Address, timestamp: BigInt): void { // This should be run at sunrise for the previous season to update any farmers stalk/seed/roots balances from silo transfers. - let beanstalk = loadBeanstalk(beanstalkAddress); - let beanstalk_call = Replanted.bind(beanstalkAddress); + let beanstalk = loadBeanstalk(protocol); + let beanstalk_call = Replanted.bind(protocol); for (let i = 0; i < beanstalk.farmersToUpdate.length; i++) { let account = Address.fromString(beanstalk.farmersToUpdate[i]); let silo = loadSilo(account); updateStalkBalances( + protocol, account, - season, beanstalk_call.balanceOfStalk(account).minus(silo.stalk), beanstalk_call.balanceOfRoots(account).minus(silo.roots), timestamp, - blockNumber + false ); // balanceOfSeeds function was removed in silov2 - updateSeedsBalances(beanstalkAddress, account, beanstalk_call.balanceOfSeeds(account).minus(silo.seeds), timestamp, false); + updateSeedsBalances(protocol, account, beanstalk_call.balanceOfSeeds(account).minus(silo.seeds), timestamp, false); } beanstalk.farmersToUpdate = []; beanstalk.save(); diff --git a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts index 0ef2e4bc4b..f93c3c2a0d 100644 --- a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts @@ -61,8 +61,8 @@ export function loadSeason(diamondAddress: Address, id: BigInt): Season { return season; } -export function getCurrentSeason(beanstalk: Address): i32 { - let beanstalkEntity = loadBeanstalk(beanstalk); +export function getCurrentSeason(protocol: Address): i32 { + let beanstalkEntity = loadBeanstalk(protocol); return beanstalkEntity.lastSeason; } diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index a096049b20..f173d1ba02 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -71,9 +71,9 @@ export function loadField(account: Address): Field { return field; } -export function getHarvestableIndex(beanstalk: Address): BigInt { - let bs = loadBeanstalk(beanstalk); - let season = loadSeason(beanstalk, BigInt.fromI32(bs.lastSeason)); +export function getHarvestableIndex(protocol: Address): BigInt { + let bs = loadBeanstalk(protocol); + let season = loadSeason(protocol, BigInt.fromI32(bs.lastSeason)); return season.harvestableIndex; } diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts index 68e1b3048c..a3dedd222b 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts @@ -3,8 +3,8 @@ import { Silo, SiloDailySnapshot, SiloHourlySnapshot } from "../../../generated/ import { getCurrentSeason } from "../Beanstalk"; import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; -export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: BigInt): void { - const currentSeason = getCurrentSeason(beanstalk); +export function takeSiloSnapshots(silo: Silo, protocol: Address, timestamp: BigInt): void { + const currentSeason = getCurrentSeason(protocol); const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); const day = BigInt.fromI32(dayFromTimestamp(timestamp)); @@ -132,8 +132,8 @@ export function takeSiloSnapshots(silo: Silo, beanstalk: Address, timestamp: Big } // Set case id on hourly snapshot. assumption is that the snapshot was already created -export function setHourlyCaseId(caseId: BigInt, silo: Silo, beanstalk: Address): void { - const currentSeason = getCurrentSeason(beanstalk); +export function setHourlyCaseId(caseId: BigInt, silo: Silo, protocol: Address): void { + const currentSeason = getCurrentSeason(protocol); const hourly = SiloHourlySnapshot.load(silo.id + "-" + currentSeason.toString())!; hourly.caseId = caseId; hourly.save(); From 743b14350b84df9e667df612f983bc959206c6f4 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:35:48 -0700 Subject: [PATCH 09/59] recursive deposit update --- .../subgraph-beanstalk/src/SeasonHandler.ts | 8 +- .../subgraph-beanstalk/src/SiloHandler.ts | 203 +++++------------- 2 files changed, 55 insertions(+), 156 deletions(-) diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index 32ddcd3f78..cebb293188 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -13,7 +13,7 @@ import { loadPodMarketplaceHourlySnapshot, updateExpiredPlots } from "./utils/PodMarketplace"; -import { addDepositToSiloAsset, updateStalkWithCalls } from "./SiloHandler"; +import { updateDepositInSiloAsset, updateStalkWithCalls } from "./SiloHandler"; import { updateBeanEMA } from "./YieldHandler"; import { loadSilo, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot } from "./utils/Silo"; import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/BeanstalkPrice"; @@ -97,14 +97,14 @@ export function handleReward(event: Reward): void { takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); - addDepositToSiloAsset( + updateDepositInSiloAsset( + event.address, event.address, BEAN_ERC20, event.params.season.toI32(), event.params.toSilo, event.params.toSilo, - event.block.timestamp, - event.block.number + event.block.timestamp ); } diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 36b191e0d2..d06dc8c3a2 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -51,7 +51,6 @@ class AddRemoveDepositsParams { } function addDeposits(params: AddRemoveDepositsParams): void { - let currentSeason = getCurrentSeason(params.event.address); for (let i = 0; i < params.amounts.length; ++i) { let deposit = loadSiloDeposit({ account: params.account, @@ -72,54 +71,21 @@ function addDeposits(params: AddRemoveDepositsParams): void { updateDeposit(deposit, params.amounts[i], params.bdvs![i], params.event); deposit.save(); - // TODO: these add/remove deposit to silo methods should be refactored such that it only needs to be called - // at the farmer level, and that will recur on the system level (only when called for farmer). - // In that case, the addDepositToSiloAsset method should not need to be called here, it can be called in the - // underlying method. I believe it needs to be refactored also - // Ensure that a Farmer entity is set up for this account. loadFarmer(params.account); - // Update overall silo totals - addDepositToSilo( + updateDepositInSilo( params.event.address, - currentSeason, - params.bdvs![i], - addDepositToSiloAsset( - params.event.address, - params.token, - currentSeason, - params.bdvs![i], - params.amounts[i], - params.event.block.timestamp, - params.event.block.number - ), - params.event.block.timestamp, - params.event.block.number - ); - - // Update farmer silo totals - addDepositToSilo( params.account, - currentSeason, + params.token, + params.amounts[i], params.bdvs![i], - addDepositToSiloAsset( - params.account, - params.token, - currentSeason, - params.bdvs![i], - params.amounts[i], - params.event.block.timestamp, - params.event.block.number - ), - params.event.block.timestamp, - params.event.block.number + params.event.block.timestamp ); } } function removeDeposits(params: AddRemoveDepositsParams): void { - let currentSeason = getCurrentSeason(params.event.address); for (let i = 0; i < params.amounts.length; ++i) { let deposit = loadSiloDeposit({ account: params.account, @@ -137,39 +103,13 @@ function removeDeposits(params: AddRemoveDepositsParams): void { deposit.save(); // Update protocol totals - removeDepositFromSilo( + updateDepositInSilo( params.event.address, - currentSeason, - removedBdv, - removeDepositFromSiloAsset( - params.event.address, - params.token, - currentSeason, - removedBdv, - params.amounts[i], - params.event.block.timestamp, - params.event.block.number - ), - params.event.block.timestamp, - params.event.block.number - ); - - // Update farmer totals - removeDepositFromSilo( params.account, - currentSeason, - removedBdv, - removeDepositFromSiloAsset( - params.account, - params.token, - currentSeason, - removedBdv, - params.amounts[i], - params.event.block.timestamp, - params.event.block.number - ), - params.event.block.timestamp, - params.event.block.number + params.token, + params.amounts[i].neg(), + removedBdv.neg(), + params.event.block.timestamp ); } } @@ -328,14 +268,14 @@ export function handlePlant(event: Plant): void { // Remove the asset-only amount that got added in Reward event handler. // Will be immediately re-credited to the user/system in AddDeposit - removeDepositFromSiloAsset( + updateDepositInSiloAsset( + event.address, event.address, BEAN_ERC20, currentSeason, event.params.beans, event.params.beans, - event.block.timestamp, - event.block.number + event.block.timestamp ); } @@ -359,77 +299,74 @@ export function handleTransferDepositsCall(call: TransferDepositsCall): void { beanstalk.save(); } -// TODO: consider consolidating both add/remove deposit methods here -function addDepositToSilo( +function updateDepositInSilo( + protocol: Address, account: Address, - season: i32, - bdv: BigInt, - grownStalkPerBDV: BigInt, + token: Address, + deltaAmount: BigInt, + deltaBdv: BigInt, timestamp: BigInt, - blockNumber: BigInt + recurs: boolean = true ): void { - let silo = loadSilo(account); - - silo.depositedBDV = silo.depositedBDV.plus(bdv); - // Individual farmer seeds cannot be directly tracked due to seed gauge - if (account == BEANSTALK) { - silo.grownStalkPerSeason = silo.grownStalkPerSeason.plus(grownStalkPerBDV); + if (recurs && account != protocol) { + updateDepositInSilo(protocol, protocol, token, deltaAmount, deltaBdv, timestamp); } - takeSiloSnapshots(silo, BEANSTALK, timestamp); - silo.save(); -} - -function removeDepositFromSilo( - account: Address, - season: i32, - bdv: BigInt, - grownStalkPerBDV: BigInt, - timestamp: BigInt, - blockNumber: BigInt -): void { let silo = loadSilo(account); - - silo.depositedBDV = silo.depositedBDV.minus(bdv); + silo.depositedBDV = silo.depositedBDV.plus(deltaBdv); + + const newSeedStalk = updateDepositInSiloAsset( + protocol, + account, + token, + getCurrentSeason(protocol), + deltaAmount, + deltaBdv, + timestamp, + false + ); // Individual farmer seeds cannot be directly tracked due to seed gauge - // TODO: event originator in method signature (required for recursion also) - if (account == BEANSTALK) { - silo.grownStalkPerSeason = silo.grownStalkPerSeason.minus(grownStalkPerBDV); + if (account == protocol) { + silo.grownStalkPerSeason = silo.grownStalkPerSeason.plus(newSeedStalk); } - takeSiloSnapshots(silo, BEANSTALK, timestamp); + takeSiloSnapshots(silo, protocol, timestamp); silo.save(); } -export function addDepositToSiloAsset( +export function updateDepositInSiloAsset( + protocol: Address, account: Address, token: Address, - season: i32, - bdv: BigInt, - amount: BigInt, + season: i32, // season will be removed upon snapshot refactor + deltaAmount: BigInt, + deltaBdv: BigInt, timestamp: BigInt, - blockNumber: BigInt + recurs: boolean = true ): BigInt { + if (recurs && account != protocol) { + updateDepositInSiloAsset(protocol, protocol, token, season, deltaAmount, deltaBdv, timestamp); + } let asset = loadSiloAsset(account, token); let assetHourly = loadSiloAssetHourlySnapshot(account, token, season, timestamp); let assetDaily = loadSiloAssetDailySnapshot(account, token, timestamp); let tokenSettings = loadWhitelistTokenSetting(token); - let newGrownStalk = bdv.times(tokenSettings.stalkEarnedPerSeason).div(BigInt.fromI32(1000000)); + let newGrownStalk = deltaBdv.times(tokenSettings.stalkEarnedPerSeason).div(BigInt.fromI32(1000000)); - asset.depositedBDV = asset.depositedBDV.plus(bdv); - asset.depositedAmount = asset.depositedAmount.plus(amount); + asset.depositedBDV = asset.depositedBDV.plus(deltaBdv); + asset.depositedAmount = asset.depositedAmount.plus(deltaAmount); asset.save(); - assetHourly.deltaDepositedBDV = assetHourly.deltaDepositedBDV.plus(bdv); + assetHourly.deltaDepositedBDV = assetHourly.deltaDepositedBDV.plus(deltaBdv); assetHourly.depositedBDV = asset.depositedBDV; - assetHourly.deltaDepositedAmount = assetHourly.deltaDepositedAmount.plus(amount); + assetHourly.deltaDepositedAmount = assetHourly.deltaDepositedAmount.plus(deltaAmount); assetHourly.depositedAmount = asset.depositedAmount; assetHourly.updatedAt = timestamp; assetHourly.save(); assetDaily.season = season; - assetDaily.deltaDepositedBDV = assetDaily.deltaDepositedBDV.plus(bdv); + assetDaily.deltaDepositedBDV = assetDaily.deltaDepositedBDV.plus(deltaBdv); assetDaily.depositedBDV = asset.depositedBDV; - assetDaily.deltaDepositedAmount = assetDaily.deltaDepositedAmount.plus(amount); + assetDaily.deltaDepositedAmount = assetDaily.deltaDepositedAmount.plus(deltaAmount); assetDaily.depositedAmount = asset.depositedAmount; assetDaily.updatedAt = timestamp; assetDaily.save(); @@ -437,44 +374,6 @@ export function addDepositToSiloAsset( return newGrownStalk; } -function removeDepositFromSiloAsset( - account: Address, - token: Address, - season: i32, - bdv: BigInt, - amount: BigInt, - timestamp: BigInt, - blockNumber: BigInt -): BigInt { - let asset = loadSiloAsset(account, token); - let assetHourly = loadSiloAssetHourlySnapshot(account, token, season, timestamp); - let assetDaily = loadSiloAssetDailySnapshot(account, token, timestamp); - - let tokenSettings = loadWhitelistTokenSetting(token); - let removedGrownStalk = bdv.times(tokenSettings.stalkEarnedPerSeason).div(BigInt.fromI32(1000000)); - - asset.depositedBDV = asset.depositedBDV.minus(bdv); - asset.depositedAmount = asset.depositedAmount.minus(amount); - asset.save(); - - assetHourly.deltaDepositedBDV = assetHourly.deltaDepositedBDV.minus(bdv); - assetHourly.depositedBDV = asset.depositedBDV; - assetHourly.deltaDepositedAmount = assetHourly.deltaDepositedAmount.minus(amount); - assetHourly.depositedAmount = asset.depositedAmount; - assetHourly.updatedAt = timestamp; - assetHourly.save(); - - assetDaily.season = season; - assetDaily.deltaDepositedBDV = assetDaily.deltaDepositedBDV.minus(bdv); - assetDaily.depositedBDV = asset.depositedBDV; - assetDaily.deltaDepositedAmount = assetDaily.deltaDepositedAmount.minus(amount); - assetDaily.depositedAmount = asset.depositedAmount; - assetDaily.updatedAt = timestamp; - assetDaily.save(); - - return removedGrownStalk; -} - function addWithdrawToSiloAsset( account: Address, token: Address, From 3bd5024b84b11296703da06993d3a1fa59dbe366 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 16:24:29 -0700 Subject: [PATCH 10/59] legacy stem conversion --- .../subgraph-beanstalk/src/SeasonHandler.ts | 2 +- .../subgraph-beanstalk/src/SiloHandler.ts | 14 ++++++---- .../subgraph-beanstalk/src/utils/Field.ts | 2 +- projects/subgraph-beanstalk/src/utils/Silo.ts | 14 +++++++--- .../utils/{ => contracts}/BeanstalkPrice.ts | 8 +++--- .../src/utils/contracts/SiloCalculations.ts | 28 +++++++++++++++++++ .../{Silo-Replanted.test.ts => Silo.test.ts} | 0 7 files changed, 53 insertions(+), 15 deletions(-) rename projects/subgraph-beanstalk/src/utils/{ => contracts}/BeanstalkPrice.ts (96%) create mode 100644 projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts rename projects/subgraph-beanstalk/tests/{Silo-Replanted.test.ts => Silo.test.ts} (100%) diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index cebb293188..18e5726bee 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -16,7 +16,7 @@ import { import { updateDepositInSiloAsset, updateStalkWithCalls } from "./SiloHandler"; import { updateBeanEMA } from "./YieldHandler"; import { loadSilo, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot } from "./utils/Silo"; -import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/BeanstalkPrice"; +import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/contracts/BeanstalkPrice"; import { takeSiloSnapshots } from "./utils/snapshots/Silo"; export function handleSunrise(event: Sunrise): void { diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index d06dc8c3a2..b8c861a29f 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -38,6 +38,7 @@ import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as Dewhitelist import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; import { takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { stemFromSeason } from "./utils/contracts/SiloCalculations"; class AddRemoveDepositsParams { event: ethereum.Event; @@ -63,12 +64,13 @@ function addDeposits(params: AddRemoveDepositsParams): void { // Set granular deposit version type if (params.depositVersion == "season") { deposit.depositVersion = "season"; - // TODO: fill stem according to seasonToStem + // Fill stem according to legacy conversion + deposit.stem = stemFromSeason(params.seasons![i].toI32(), params.token); } else { deposit.depositVersion = params.event.block.number > GAUGE_BIP45_BLOCK ? "v3.1" : "v3"; } - updateDeposit(deposit, params.amounts[i], params.bdvs![i], params.event); + deposit = updateDeposit(deposit, params.amounts[i], params.bdvs![i], params.event)!; deposit.save(); // Ensure that a Farmer entity is set up for this account. @@ -98,9 +100,11 @@ function removeDeposits(params: AddRemoveDepositsParams): void { // Use bdv if it was provided (v2 events dont provide bdv), otherwise infer let removedBdv = params.bdvs != null ? params.bdvs![i] : params.amounts[i].times(deposit.depositedBDV).div(deposit.depositedAmount); - // TODO: if amount goes to zero, instead delete the deposit entirely. - updateDeposit(deposit, params.amounts[i].neg(), removedBdv.neg(), params.event); - deposit.save(); + // If the amount goes to zero, the deposit is deleted and not returned + const updatedDeposit = updateDeposit(deposit, params.amounts[i].neg(), removedBdv.neg(), params.event); + if (updatedDeposit !== null) { + updatedDeposit.save(); + } // Update protocol totals updateDepositInSilo( diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index f173d1ba02..23a43388db 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -3,7 +3,7 @@ import { Field, FieldDailySnapshot, FieldHourlySnapshot, Plot } from "../../gene import { BI_MAX, ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { ADDRESS_ZERO, BEANSTALK, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; import { CurvePrice } from "../../generated/Beanstalk-ABIs/CurvePrice"; -import { BeanstalkPrice_try_price } from "./BeanstalkPrice"; +import { BeanstalkPrice_try_price } from "./contracts/BeanstalkPrice"; import { loadBeanstalk, loadSeason } from "./Beanstalk"; import { dayFromTimestamp } from "../../../subgraph-core/utils/Dates"; diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 82dfb93d34..34e1567212 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -1,4 +1,4 @@ -import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; +import { Address, BigInt, Bytes, ethereum, store } from "@graphprotocol/graph-ts"; import { Silo, SiloDeposit, @@ -228,9 +228,14 @@ export function loadSiloDeposit(depositId: SiloDepositID): SiloDeposit { return deposit; } -export function updateDeposit(deposit: SiloDeposit, amount: BigInt, bdv: BigInt, event: ethereum.Event): void { - deposit.depositedAmount = deposit.depositedAmount.plus(amount); - deposit.depositedBDV = deposit.depositedBDV.plus(bdv); +// Updates the given SiloDeposit with new amounts/bdv. If the deposit was fully withdrawn, delete the SiloDeposit. +export function updateDeposit(deposit: SiloDeposit, deltaAmount: BigInt, deltaBdv: BigInt, event: ethereum.Event): SiloDeposit | null { + deposit.depositedAmount = deposit.depositedAmount.plus(deltaAmount); + if (deposit.depositedAmount <= ZERO_BI) { + store.remove("SiloDeposit", deposit.id); + return null; + } + deposit.depositedBDV = deposit.depositedBDV.plus(deltaBdv); let depositHashes = deposit.hashes; depositHashes.push(event.transaction.hash.toHexString()); deposit.hashes = depositHashes; @@ -238,6 +243,7 @@ export function updateDeposit(deposit: SiloDeposit, amount: BigInt, bdv: BigInt, deposit.createdAt = deposit.createdAt == ZERO_BI ? event.block.timestamp : deposit.createdAt; deposit.updatedBlock = event.block.number; deposit.updatedAt = event.block.timestamp; + return deposit; } /* ===== Withdraw Entities ===== */ diff --git a/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts b/projects/subgraph-beanstalk/src/utils/contracts/BeanstalkPrice.ts similarity index 96% rename from projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts rename to projects/subgraph-beanstalk/src/utils/contracts/BeanstalkPrice.ts index c69b7036b1..bc751fd313 100644 --- a/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts +++ b/projects/subgraph-beanstalk/src/utils/contracts/BeanstalkPrice.ts @@ -4,10 +4,10 @@ import { BeanstalkPrice, BeanstalkPrice__priceResultPPsStruct, BeanstalkPrice__priceResultPStruct -} from "../../generated/Beanstalk-ABIs/BeanstalkPrice"; -import { BEANSTALK_PRICE_1, BEANSTALK_PRICE_2, PRICE_2_BLOCK } from "../../../subgraph-core/utils/Constants"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { loadSilo } from "./Silo"; +} from "../../../generated/Beanstalk-ABIs/BeanstalkPrice"; +import { BEANSTALK_PRICE_1, BEANSTALK_PRICE_2, PRICE_2_BLOCK } from "../../../../subgraph-core/utils/Constants"; +import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; +import { loadSilo } from "../Silo"; // Can't use the autogenerated one because the fields need to be updateable class PriceOverallStruct { diff --git a/projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts b/projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts new file mode 100644 index 0000000000..106effc3bf --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts @@ -0,0 +1,28 @@ +import { Address, BigInt } from "@graphprotocol/graph-ts"; +import { BEAN_3CRV, BEAN_ERC20, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../../subgraph-core/utils/Constants"; +import { BI_10 } from "../../../../subgraph-core/utils/Decimals"; + +const STEM_START_SEASON = 14210; + +export function stemFromSeason(season: i32, token: Address): BigInt { + return seasonToV3Stem(season, STEM_START_SEASON, getLegacySeedsPerToken(token)); +} + +// Equivalent to LibLegacyTokenSilo.seasonToStem +function seasonToV3Stem(season: i32, stemStartSeason: i32, seedsPerBdv: i32): BigInt { + return BigInt.fromI32(season - stemStartSeason).times(BigInt.fromI32(seedsPerBdv).times(BI_10.pow(6))); +} + +// Equivalent to LibLegacyTokenSilo.getLegacySeedsPerToken +function getLegacySeedsPerToken(token: Address): i32 { + if (token == BEAN_ERC20) { + return 2; + } else if (token == UNRIPE_BEAN) { + return 2; + } else if (token == UNRIPE_BEAN_3CRV) { + return 4; + } else if (token == BEAN_3CRV) { + return 4; + } + return 0; +} diff --git a/projects/subgraph-beanstalk/tests/Silo-Replanted.test.ts b/projects/subgraph-beanstalk/tests/Silo.test.ts similarity index 100% rename from projects/subgraph-beanstalk/tests/Silo-Replanted.test.ts rename to projects/subgraph-beanstalk/tests/Silo.test.ts From 04a3c46cd59193735784e006c9d4c6a153e7184b Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:36:05 -0700 Subject: [PATCH 11/59] silo deposit tests --- projects/subgraph-beanstalk/schema.graphql | 4 +- .../subgraph-beanstalk/src/SiloHandler.ts | 5 +- projects/subgraph-beanstalk/src/utils/Silo.ts | 1 + .../subgraph-beanstalk/tests/Silo.test.ts | 165 ++++++++++++++--- .../tests/event-mocking/Silo.ts | 174 ++++++++++++++---- 5 files changed, 283 insertions(+), 66 deletions(-) diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 208fc6bdf5..a436f64341 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -621,8 +621,10 @@ type SiloDeposit @entity { depositVersion: String! "Season of deposit" season: Int - "Stem of deposit. If this is a season deposit type, stem will be filled according to `LibLegacyTokenSilo.seasonToStem`" + "Stem of deposit" stem: BigInt + "Silo v3.1 equivalent stem. This value will always be assigned regardless of the deposit version." + stemV31: BigInt! "Token amount deposited" depositedAmount: BigInt! "Original deposited BDV" diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index b8c861a29f..c4a3adb6bd 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -20,7 +20,7 @@ import { WhitelistToken as WhitelistToken_V3 } from "../generated/Beanstalk-ABIs/SiloV3"; import { Replanted, TransferDepositCall, TransferDepositsCall } from "../generated/Beanstalk-ABIs/Replanted"; -import { ZERO_BI } from "../../subgraph-core/utils/Decimals"; +import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadSilo, loadSiloAsset, @@ -65,9 +65,10 @@ function addDeposits(params: AddRemoveDepositsParams): void { if (params.depositVersion == "season") { deposit.depositVersion = "season"; // Fill stem according to legacy conversion - deposit.stem = stemFromSeason(params.seasons![i].toI32(), params.token); + deposit.stemV31 = stemFromSeason(params.seasons![i].toI32(), params.token); } else { deposit.depositVersion = params.event.block.number > GAUGE_BIP45_BLOCK ? "v3.1" : "v3"; + deposit.stemV31 = params.event.block.number > GAUGE_BIP45_BLOCK ? deposit.stem! : deposit.stem!.times(BI_10.pow(6)); } deposit = updateDeposit(deposit, params.amounts[i], params.bdvs![i], params.event)!; diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 34e1567212..69f31a4210 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -216,6 +216,7 @@ export function loadSiloDeposit(depositId: SiloDepositID): SiloDeposit { deposit.season = depositId.season!.toU32(); } deposit.stem = depositId.stem; + deposit.stemV31 = ZERO_BI; deposit.depositedAmount = ZERO_BI; deposit.depositedBDV = ZERO_BI; deposit.hashes = []; diff --git a/projects/subgraph-beanstalk/tests/Silo.test.ts b/projects/subgraph-beanstalk/tests/Silo.test.ts index 4bf2b87982..3c7a4b098e 100644 --- a/projects/subgraph-beanstalk/tests/Silo.test.ts +++ b/projects/subgraph-beanstalk/tests/Silo.test.ts @@ -2,75 +2,175 @@ import { BigInt } from "@graphprotocol/graph-ts"; import { afterEach, assert, clearStore, describe, test } from "matchstick-as/assembly/index"; import { handleAddDeposit, + handleAddDeposit_V3, handleDewhitelistToken, handleRemoveDeposit, + handleRemoveDeposit_V3, + handleRemoveDeposits, handleWhitelistToken, handleWhitelistToken_V3 } from "../src/SiloHandler"; -import { BEAN_ERC20, BEAN_WETH_CP2_WELL, BEANSTALK, LUSD_3POOL } from "../../subgraph-core/utils/Constants"; -import { createAddDepositEvent, createRemoveDepositEvent } from "./event-mocking/Silo"; +import { + BEAN_3CRV, + BEAN_ERC20, + BEAN_WETH_CP2_WELL, + BEANSTALK, + GAUGE_BIP45_BLOCK, + LUSD_3POOL, + UNRIPE_BEAN, + UNRIPE_BEAN_3CRV +} from "../../subgraph-core/utils/Constants"; +import { + createAddDepositV2Event, + createAddDepositV3Event, + createRemoveDepositsV2Event, + createRemoveDepositsV3Event, + createRemoveDepositV2Event, + createRemoveDepositV3Event +} from "./event-mocking/Silo"; import { createDewhitelistTokenEvent, createWhitelistTokenV2Event, createWhitelistTokenV3Event } from "./event-mocking/Whitelist"; import { ONE_BI } from "../../subgraph-core/utils/Decimals"; +import { stemFromSeason } from "../src/utils/contracts/SiloCalculations"; +import { setSeason } from "./utils/Season"; +import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block"; -describe("Mocked Events", () => { +describe("Silo Events", () => { afterEach(() => { clearStore(); }); - describe("Bean", () => { - test("AddDeposit - Silo and Assets updated", () => { + describe("Deposit/Withdraw", () => { + test("AddDeposit - Silo v2", () => { let account = "0x1234567890abcdef1234567890abcdef12345678".toLowerCase(); let token = BEAN_ERC20.toHexString().toLowerCase(); - let newAddDepositEvent = createAddDepositEvent(account, token, 6100, 1000, 6, 1000); - + let newAddDepositEvent = createAddDepositV2Event(account, token, 6100, 1000, 6, 1000); handleAddDeposit(newAddDepositEvent); assert.fieldEquals("Silo", account, "depositedBDV", "1000000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "season", "6100"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositVersion", "season"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "stem", "null"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "stemV31", "-16220000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "1000000000"); assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "1000000000"); - assert.fieldEquals("SiloAsset", account + "-" + token, "depositedAmount", "1000000000"); }); - test("RemoveDeposit - Farmer Silo Amounts 50% Initial", () => { + test("AddDeposit - Silo v3", () => { let account = "0x1234567890abcdef1234567890abcdef12345678".toLowerCase(); let token = BEAN_ERC20.toHexString().toLowerCase(); - let newAddDepositEvent = createAddDepositEvent(account, token, 6100, 1000, 6, 1000); + let newAddDepositEvent = createAddDepositV3Event(account, token, BigInt.fromU32(1500), 1000, 6, 1000); + handleAddDeposit_V3(newAddDepositEvent); - handleAddDeposit(newAddDepositEvent); + assert.fieldEquals("Silo", account, "depositedBDV", "1000000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-1500", "stem", "1500"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-1500", "depositVersion", "v3"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-1500", "stemV31", "1500000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-1500", "depositedAmount", "1000000000"); + assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "1000000000"); + + // with V3.1 stem + let addDeposit31 = createAddDepositV3Event(account, token, BigInt.fromI64(5700000000), 2500, 6, 2500); + addDeposit31.block = mockBlock(GAUGE_BIP45_BLOCK.plus(ONE_BI)); + handleAddDeposit_V3(addDeposit31); + + assert.fieldEquals("Silo", account, "depositedBDV", "3500000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-5700000000", "stem", "5700000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-5700000000", "depositVersion", "v3.1"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-5700000000", "stemV31", "5700000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-5700000000", "depositedAmount", "2500000000"); + assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "3500000000"); + }); - let newRemoveDepositEvent = createRemoveDepositEvent(account, token, 6100, BigInt.fromString("500000000")); + test("RemoveDeposit - 80% removed", () => { + let account = "0x1234567890abcdef1234567890abcdef12345678".toLowerCase(); + let token = BEAN_ERC20.toHexString().toLowerCase(); + let newAddDepositEvent = createAddDepositV2Event(account, token, 6100, 1000, 6, 1000); + handleAddDeposit(newAddDepositEvent); + + let newRemoveDepositEvent = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("800000000")); handleRemoveDeposit(newRemoveDepositEvent); - assert.fieldEquals("Silo", account, "depositedBDV", "500000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "500000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedBDV", "500000000"); - assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "500000000"); - assert.fieldEquals("SiloAsset", account + "-" + token, "depositedAmount", "500000000"); + assert.fieldEquals("Silo", account, "depositedBDV", "200000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "200000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedBDV", "200000000"); + assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "200000000"); + assert.fieldEquals("SiloAsset", account + "-" + token, "depositedAmount", "200000000"); }); - test("RemoveDeposit - Farmer Silo Amounts 50% Remaining", () => { + test("RemoveDeposit - Multiple removals", () => { let account = "0x1234567890abcdef1234567890abcdef12345678".toLowerCase(); let token = BEAN_ERC20.toHexString().toLowerCase(); - let newAddDepositEvent = createAddDepositEvent(account, token, 6100, 1000, 6, 1000); - + let newAddDepositEvent = createAddDepositV2Event(account, token, 6100, 1000, 6, 1000); handleAddDeposit(newAddDepositEvent); - let newRemoveDepositEvent = createRemoveDepositEvent(account, token, 6100, BigInt.fromString("500000000")); + let removeEvent = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("500000000")); + handleRemoveDeposit(removeEvent); - handleRemoveDeposit(newRemoveDepositEvent); + let removeEvent2 = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("200000000")); + handleRemoveDeposit(removeEvent2); - let secondRemoveDepositEvent = createRemoveDepositEvent(account, token, 6100, BigInt.fromString("250000000")); + assert.fieldEquals("Silo", account, "depositedBDV", "300000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "300000000"); + assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedBDV", "300000000"); + assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "300000000"); + assert.fieldEquals("SiloAsset", account + "-" + token, "depositedAmount", "300000000"); - handleRemoveDeposit(secondRemoveDepositEvent); + // Remove the deposit completely + let removeEvent3 = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("300000000")); + handleRemoveDeposit(removeEvent3); - assert.fieldEquals("Silo", account, "depositedBDV", "250000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "250000000"); - assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedBDV", "250000000"); - assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "250000000"); - assert.fieldEquals("SiloAsset", account + "-" + token, "depositedAmount", "250000000"); + assert.fieldEquals("Silo", account, "depositedBDV", "0"); + assert.notInStore("SiloDeposit", account + "-" + token + "-season-6100"); + assert.fieldEquals("SiloAsset", account + "-" + token, "depositedBDV", "0"); + }); + + test("Adding/Removing multiple tokens/types - Silo/Asset balance totals", () => { + let account1 = "0x1234567890abcdef1234567890abcdef12345678".toLowerCase(); + let account2 = "0x1234567890abcdef1234567890abcdef12345679".toLowerCase(); + let token1 = BEAN_ERC20.toHexString().toLowerCase(); + let token2 = BEAN_3CRV.toHexString().toLowerCase(); + + let addV2_1 = createAddDepositV2Event(account1, token1, 6100, 1000, 6, 1000); + handleAddDeposit(addV2_1); + let addV3_1 = createAddDepositV3Event(account1, token1, BigInt.fromU32(70), 2000, 6, 2000); + handleAddDeposit_V3(addV3_1); + let addV3_2 = createAddDepositV3Event(account1, token2, BigInt.fromU32(50), 1000, 6, 1000); + handleAddDeposit_V3(addV3_2); + let addV3_3 = createAddDepositV3Event(account2, token2, BigInt.fromU32(90), 5000, 6, 4000); + handleAddDeposit_V3(addV3_3); + + assert.fieldEquals("Silo", BEANSTALK.toHexString(), "depositedBDV", "8000000000"); + assert.fieldEquals("Silo", account1, "depositedBDV", "4000000000"); + assert.fieldEquals("Silo", account2, "depositedBDV", "4000000000"); + assert.fieldEquals("SiloAsset", BEANSTALK.toHexString() + "-" + token1, "depositedBDV", "3000000000"); + assert.fieldEquals("SiloAsset", BEANSTALK.toHexString() + "-" + token2, "depositedBDV", "5000000000"); + assert.fieldEquals("SiloAsset", account1 + "-" + token1, "depositedBDV", "3000000000"); + assert.fieldEquals("SiloAsset", account1 + "-" + token2, "depositedBDV", "1000000000"); + assert.fieldEquals("SiloAsset", account2 + "-" + token2, "depositedBDV", "4000000000"); + + let removeV2_1 = createRemoveDepositsV2Event(account1, token1, [6100], [BigInt.fromU32(1000000000)], BigInt.fromU32(1000000000)); + handleRemoveDeposits(removeV2_1); + let removeV3_1 = createRemoveDepositV3Event( + account2, + token2, + BigInt.fromU32(90), + BigInt.fromU32(1500000000), + BigInt.fromU32(1500000000) + ); + handleRemoveDeposit_V3(removeV3_1); + + assert.fieldEquals("Silo", BEANSTALK.toHexString(), "depositedBDV", "5500000000"); + assert.fieldEquals("Silo", account1, "depositedBDV", "3000000000"); + assert.fieldEquals("Silo", account2, "depositedBDV", "2500000000"); + assert.fieldEquals("SiloAsset", BEANSTALK.toHexString() + "-" + token1, "depositedBDV", "2000000000"); + assert.fieldEquals("SiloAsset", BEANSTALK.toHexString() + "-" + token2, "depositedBDV", "3500000000"); + assert.fieldEquals("SiloAsset", account1 + "-" + token1, "depositedBDV", "2000000000"); + assert.fieldEquals("SiloAsset", account1 + "-" + token2, "depositedBDV", "1000000000"); + assert.fieldEquals("SiloAsset", account2 + "-" + token2, "depositedBDV", "2500000000"); }); }); @@ -126,3 +226,10 @@ describe("Mocked Events", () => { }); }); }); + +test("Legacy stem calculation", () => { + assert.bigIntEquals(BigInt.fromI64(-5528000000), stemFromSeason(11446, BEAN_ERC20)); + assert.bigIntEquals(BigInt.fromI64(-31556000000), stemFromSeason(6321, BEAN_3CRV)); + assert.bigIntEquals(BigInt.fromI64(-16272000000), stemFromSeason(6074, UNRIPE_BEAN)); + assert.bigIntEquals(BigInt.fromI64(-32684000000), stemFromSeason(6039, UNRIPE_BEAN_3CRV)); +}); diff --git a/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts b/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts index 1364d8bbf0..3c4b04c643 100644 --- a/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts +++ b/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts @@ -1,10 +1,8 @@ import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; -import { newMockEvent } from "matchstick-as/assembly/index"; - import { - AddDeposit, - RemoveDeposit, - RemoveDeposits, + AddDeposit as AddDepositV2, + RemoveDeposit as RemoveDepositV2, + RemoveDeposits as RemoveDepositsV2, AddWithdrawal, RemoveWithdrawal, RemoveWithdrawals, @@ -12,17 +10,23 @@ import { StalkBalanceChanged, Plant } from "../../generated/Beanstalk-ABIs/MarketV2"; -import { handleAddDeposit } from "../../src/SiloHandler"; import { BEAN_DECIMALS } from "../../../subgraph-core/utils/Constants"; +import { mockBeanstalkEvent } from "../../../subgraph-core/tests/event-mocking/Util"; +import { + AddDeposit as AddDepositV3, + RemoveDeposits as RemoveDepositsV3, + RemoveDeposit as RemoveDepositV3 +} from "../../generated/Beanstalk-ABIs/SiloV3"; -export function handleAddDeposits(events: AddDeposit[]): void { - events.forEach((event) => { - handleAddDeposit(event); - }); -} - -export function createAddDepositEvent(account: string, token: string, season: i32, amount: i32, tokenDecimals: i32, bdv: i32): AddDeposit { - let addDepositEvent = changetype(newMockEvent()); +export function createAddDepositV2Event( + account: string, + token: string, + season: i32, + amount: i32, + tokenDecimals: i32, + bdv: i32 +): AddDepositV2 { + let addDepositEvent = changetype(mockBeanstalkEvent()); addDepositEvent.parameters = new Array(); let accountParam = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); let tokenParam = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); @@ -42,11 +46,42 @@ export function createAddDepositEvent(account: string, token: string, season: i3 addDepositEvent.parameters.push(amountParam); addDepositEvent.parameters.push(bdvParam); - return addDepositEvent as AddDeposit; + return addDepositEvent as AddDepositV2; } -export function createRemoveDepositEvent(account: string, token: string, season: i32, amount: BigInt): RemoveDeposit { - let removeDepositEvent = changetype(newMockEvent()); +export function createAddDepositV3Event( + account: string, + token: string, + stem: BigInt, + amount: i32, + tokenDecimals: i32, + bdv: i32 +): AddDepositV3 { + let addDepositEvent = changetype(mockBeanstalkEvent()); + addDepositEvent.parameters = new Array(); + let accountParam = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); + let tokenParam = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); + let stemParam = new ethereum.EventParam("stem", ethereum.Value.fromSignedBigInt(stem)); + let amountParam = new ethereum.EventParam( + "amount", + ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(amount).times(BigInt.fromI32(10 ** tokenDecimals))) + ); + let bdvParam = new ethereum.EventParam( + "bdv", + ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(bdv).times(BigInt.fromI32(10 ** BEAN_DECIMALS))) + ); + + addDepositEvent.parameters.push(accountParam); + addDepositEvent.parameters.push(tokenParam); + addDepositEvent.parameters.push(stemParam); + addDepositEvent.parameters.push(amountParam); + addDepositEvent.parameters.push(bdvParam); + + return addDepositEvent as AddDepositV3; +} + +export function createRemoveDepositV2Event(account: string, token: string, season: i32, amount: BigInt): RemoveDepositV2 { + let removeDepositEvent = changetype(mockBeanstalkEvent()); removeDepositEvent.parameters = new Array(); let accountParam = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); let tokenParam = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); @@ -58,78 +93,149 @@ export function createRemoveDepositEvent(account: string, token: string, season: removeDepositEvent.parameters.push(seasonParam); removeDepositEvent.parameters.push(amountParam); - return removeDepositEvent as RemoveDeposit; + return removeDepositEvent as RemoveDepositV2; +} + +export function createRemoveDepositV3Event(account: string, token: string, stem: BigInt, amount: BigInt, bdv: BigInt): RemoveDepositV3 { + let removeDepositEvent = changetype(mockBeanstalkEvent()); + removeDepositEvent.parameters = new Array(); + let accountParam = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); + let tokenParam = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); + let stemParam = new ethereum.EventParam("stem", ethereum.Value.fromSignedBigInt(stem)); + let amountParam = new ethereum.EventParam("amount", ethereum.Value.fromUnsignedBigInt(amount)); + let bdvParam = new ethereum.EventParam("bdv", ethereum.Value.fromUnsignedBigInt(bdv)); + + removeDepositEvent.parameters.push(accountParam); + removeDepositEvent.parameters.push(tokenParam); + removeDepositEvent.parameters.push(stemParam); + removeDepositEvent.parameters.push(amountParam); + removeDepositEvent.parameters.push(bdvParam); + + return removeDepositEvent as RemoveDepositV3; } -export function createRemoveDepositsEvent( +export function createRemoveDepositsV2Event( account: string, token: string, seasons: i32[], amounts: BigInt[], amount: BigInt -): RemoveDeposits { - let event = changetype(newMockEvent()); +): RemoveDepositsV2 { + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); + let seasonsArray: ethereum.Value[] = []; + for (let i = 0; i < seasons.length; ++i) { + seasonsArray.push(ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(seasons[i]))); + } + + let amountsArray: ethereum.Value[] = []; + for (let i = 0; i < amounts.length; ++i) { + amountsArray.push(ethereum.Value.fromUnsignedBigInt(amounts[i])); + } + + let param1 = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); + let param2 = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); + let param3 = new ethereum.EventParam("seasons", ethereum.Value.fromArray(seasonsArray)); + let param4 = new ethereum.EventParam("amounts", ethereum.Value.fromArray(amountsArray)); + let param5 = new ethereum.EventParam("amount", ethereum.Value.fromUnsignedBigInt(amount)); + + event.parameters.push(param1); + event.parameters.push(param2); + event.parameters.push(param3); + event.parameters.push(param4); + event.parameters.push(param5); + + return event as RemoveDepositsV2; +} + +export function createRemoveDepositsV3Event( + account: string, + token: string, + stems: BigInt[], + amounts: BigInt[], + amount: BigInt, + bdvs: BigInt[] +): RemoveDepositsV3 { + let event = changetype(mockBeanstalkEvent()); + event.parameters = new Array(); + + let stemsArray: ethereum.Value[] = []; + for (let i = 0; i < stems.length; ++i) { + stemsArray.push(ethereum.Value.fromSignedBigInt(stems[i])); + } + + let amountsArray: ethereum.Value[] = []; + for (let i = 0; i < amounts.length; ++i) { + amountsArray.push(ethereum.Value.fromUnsignedBigInt(amounts[i])); + } + + let bdvsArray: ethereum.Value[] = []; + for (let i = 0; i < bdvs.length; ++i) { + bdvsArray.push(ethereum.Value.fromUnsignedBigInt(bdvs[i])); + } + let param1 = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); - let param2 = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(account))); - let param3 = new ethereum.EventParam("seasons", ethereum.Value.fromAddress(Address.fromString(account))); - let param4 = new ethereum.EventParam("amounts", ethereum.Value.fromAddress(Address.fromString(account))); - let param5 = new ethereum.EventParam("amount", ethereum.Value.fromAddress(Address.fromString(account))); + let param2 = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); + let param3 = new ethereum.EventParam("stems", ethereum.Value.fromArray(stemsArray)); + let param4 = new ethereum.EventParam("amounts", ethereum.Value.fromArray(amountsArray)); + let param5 = new ethereum.EventParam("amount", ethereum.Value.fromUnsignedBigInt(amount)); + let param6 = new ethereum.EventParam("bdvs", ethereum.Value.fromArray(bdvsArray)); event.parameters.push(param1); event.parameters.push(param2); event.parameters.push(param3); event.parameters.push(param4); event.parameters.push(param5); + event.parameters.push(param6); - return event as RemoveDeposits; + return event as RemoveDepositsV3; } export function createAddWithdrawalEvent(account: string, token: string, season: i32, amount: BigInt): AddWithdrawal { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); return event as AddWithdrawal; } export function createRemoveWithdrawalEvent(account: string, token: string, season: i32, amount: BigInt): RemoveWithdrawal { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); return event as RemoveWithdrawal; } export function createRemoveWithdrawalsEvent(account: string, token: string, seasons: i32[], amount: BigInt): RemoveWithdrawals { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); return event as RemoveWithdrawals; } export function createSeedsBalanceChangedEvent(account: string, delta: BigInt): SeedsBalanceChanged { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); return event as SeedsBalanceChanged; } export function createStalkBalanceChangedEvent(account: string, delta: BigInt, rootDelta: BigInt): StalkBalanceChanged { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); return event as StalkBalanceChanged; } export function createPlantEvent(account: string, amount: BigInt): Plant { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); return event as Plant; } export function createWhitelistTokenEvent(token: string, selector: Bytes, seeds: BigInt, stalk: BigInt): WhitelistToken { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); return event as WhitelistToken; } export function createDewhitelistTokenEvent(token: string): DewhitelistToken { - let event = changetype(newMockEvent()); + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); let param1 = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); event.parameters.push(param1); From 330dc484bd314937bca6aa4070893dc39142ec9f Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:03:37 -0700 Subject: [PATCH 12/59] hourly snapshot tests --- .../subgraph-beanstalk/tests/Silo.test.ts | 74 ++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/projects/subgraph-beanstalk/tests/Silo.test.ts b/projects/subgraph-beanstalk/tests/Silo.test.ts index 3c7a4b098e..b97e0762e4 100644 --- a/projects/subgraph-beanstalk/tests/Silo.test.ts +++ b/projects/subgraph-beanstalk/tests/Silo.test.ts @@ -24,15 +24,15 @@ import { createAddDepositV2Event, createAddDepositV3Event, createRemoveDepositsV2Event, - createRemoveDepositsV3Event, createRemoveDepositV2Event, createRemoveDepositV3Event } from "./event-mocking/Silo"; import { createDewhitelistTokenEvent, createWhitelistTokenV2Event, createWhitelistTokenV3Event } from "./event-mocking/Whitelist"; -import { ONE_BI } from "../../subgraph-core/utils/Decimals"; +import { ONE_BI, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { stemFromSeason } from "../src/utils/contracts/SiloCalculations"; -import { setSeason } from "./utils/Season"; import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block"; +import { dayFromTimestamp } from "../../subgraph-core/utils/Dates"; +import { setSeason } from "./utils/Season"; describe("Silo Events", () => { afterEach(() => { @@ -172,6 +172,74 @@ describe("Silo Events", () => { assert.fieldEquals("SiloAsset", account1 + "-" + token2, "depositedBDV", "1000000000"); assert.fieldEquals("SiloAsset", account2 + "-" + token2, "depositedBDV", "2500000000"); }); + + // It is assumed sufficient to test a few fields updating properly + test("Hourly/Daily snapshots update appropriately", () => { + const baseTimestamp = BigInt.fromU32(1712732400); + const hours15 = BigInt.fromU64(15 * 60 * 60); + let account = "0x1234567890abcdef1234567890abcdef12345678".toLowerCase(); + let token = BEAN_ERC20.toHexString().toLowerCase(); + + let addV3_1 = createAddDepositV3Event(account, token, BigInt.fromU32(70), 2000, 6, 2000); + addV3_1.block = mockBlock(ZERO_BI, baseTimestamp); + setSeason(20000); + handleAddDeposit_V3(addV3_1); + + assert.fieldEquals("SiloHourlySnapshot", account + "-20000", "depositedBDV", "2000000000"); + assert.fieldEquals("SiloHourlySnapshot", account + "-20000", "deltaDepositedBDV", "2000000000"); + assert.fieldEquals( + "SiloDailySnapshot", + account + "-" + dayFromTimestamp(addV3_1.block.timestamp).toString(), + "depositedBDV", + "2000000000" + ); + assert.fieldEquals( + "SiloDailySnapshot", + account + "-" + dayFromTimestamp(addV3_1.block.timestamp).toString(), + "deltaDepositedBDV", + "2000000000" + ); + + let addV3_2 = createAddDepositV3Event(account, token, BigInt.fromU32(50), 1000, 6, 1000); + addV3_2.block = mockBlock(ZERO_BI, baseTimestamp.plus(hours15)); + setSeason(20015); + handleAddDeposit_V3(addV3_2); + + assert.fieldEquals("SiloHourlySnapshot", account + "-20015", "depositedBDV", "3000000000"); + assert.fieldEquals("SiloHourlySnapshot", account + "-20015", "deltaDepositedBDV", "1000000000"); + assert.fieldEquals( + "SiloDailySnapshot", + account + "-" + dayFromTimestamp(addV3_2.block.timestamp).toString(), + "depositedBDV", + "3000000000" + ); + assert.fieldEquals( + "SiloDailySnapshot", + account + "-" + dayFromTimestamp(addV3_2.block.timestamp).toString(), + "deltaDepositedBDV", + "3000000000" + ); + + let addV3_3 = createAddDepositV3Event(account, token, BigInt.fromU32(90), 5000, 6, 4000); + addV3_3.block = mockBlock(ZERO_BI, baseTimestamp.plus(hours15).plus(hours15)); + setSeason(20030); + handleAddDeposit_V3(addV3_3); + + assert.fieldEquals("SiloHourlySnapshot", account + "-20030", "depositedBDV", "7000000000"); + assert.fieldEquals("SiloHourlySnapshot", account + "-20030", "deltaDepositedBDV", "4000000000"); + assert.fieldEquals( + "SiloDailySnapshot", + account + "-" + dayFromTimestamp(addV3_3.block.timestamp).toString(), + "depositedBDV", + "7000000000" + ); + assert.fieldEquals( + "SiloDailySnapshot", + account + "-" + dayFromTimestamp(addV3_3.block.timestamp).toString(), + "deltaDepositedBDV", + "4000000000" + ); + }); }); describe("Whitelist", () => { From 57a4787a820057ae011d3eddab1b61e3c065fcf4 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:25:27 -0700 Subject: [PATCH 13/59] generalized silo asset snapshot --- projects/subgraph-beanstalk/schema.graphql | 8 +- .../src/utils/snapshots/Silo.ts | 95 ++++++++++++++++++- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index a436f64341..c84fc70465 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -254,14 +254,18 @@ type SiloAsset @entity { silo: Silo! "Token address for this asset" token: String! - "Current BDV of deposits" - depositedBDV: BigInt! "Current Token amount of deposits" depositedAmount: BigInt! + "Current BDV of deposits" + depositedBDV: BigInt! "Current Token amount of silo withdrawals" withdrawnAmount: BigInt! "Current internal (farm) balance of the asset" farmAmount: BigInt! + "Season when the previous hourly snapshot was taken/updated" + lastHourlySnapshotSeason: Int + "Day of when the previous daily snapshot was taken/updated" + lastDailySnapshotDay: BigInt "Link to hourly snapshot data" hourlySnapshots: [SiloAssetHourlySnapshot!]! @derivedFrom(field: "siloAsset") "Link to daily snapshot data" diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts index a3dedd222b..db5888daae 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts @@ -1,5 +1,12 @@ import { BigInt, Address, log } from "@graphprotocol/graph-ts"; -import { Silo, SiloDailySnapshot, SiloHourlySnapshot } from "../../../generated/schema"; +import { + Silo, + SiloAsset, + SiloAssetDailySnapshot, + SiloAssetHourlySnapshot, + SiloDailySnapshot, + SiloHourlySnapshot +} from "../../../generated/schema"; import { getCurrentSeason } from "../Beanstalk"; import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; @@ -51,7 +58,7 @@ export function takeSiloSnapshots(silo: Silo, protocol: Address, timestamp: BigI if (hourly.id == baseHourly.id) { // Add existing deltas hourly.deltaDepositedBDV = hourly.deltaDepositedBDV.plus(baseHourly.deltaDepositedBDV); - hourly.deltaStalk = hourly.deltaStalk.plus(baseHourly.deltaDepositedBDV); + hourly.deltaStalk = hourly.deltaStalk.plus(baseHourly.deltaStalk); hourly.deltaPlantableStalk = hourly.deltaPlantableStalk.plus(baseHourly.deltaPlantableStalk); hourly.deltaSeeds = hourly.deltaSeeds.plus(baseHourly.deltaSeeds); hourly.deltaRoots = hourly.deltaRoots.plus(baseHourly.deltaRoots); @@ -103,7 +110,7 @@ export function takeSiloSnapshots(silo: Silo, protocol: Address, timestamp: BigI if (daily.id == baseDaily.id) { // Add existing deltas daily.deltaDepositedBDV = daily.deltaDepositedBDV.plus(baseDaily.deltaDepositedBDV); - daily.deltaStalk = daily.deltaStalk.plus(baseDaily.deltaDepositedBDV); + daily.deltaStalk = daily.deltaStalk.plus(baseDaily.deltaStalk); daily.deltaPlantableStalk = daily.deltaPlantableStalk.plus(baseDaily.deltaPlantableStalk); daily.deltaSeeds = daily.deltaSeeds.plus(baseDaily.deltaSeeds); daily.deltaRoots = daily.deltaRoots.plus(baseDaily.deltaRoots); @@ -138,3 +145,85 @@ export function setHourlyCaseId(caseId: BigInt, silo: Silo, protocol: Address): hourly.caseId = caseId; hourly.save(); } + +export function takeSiloAssetSnapshots(siloAsset: SiloAsset, protocol: Address, timestamp: BigInt): void { + const currentSeason = getCurrentSeason(protocol); + + const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); + const day = BigInt.fromI32(dayFromTimestamp(timestamp)); + + // Load the snapshot for this season/day + const hourlyId = siloAsset.id + "-" + currentSeason.toString(); + const dailyId = siloAsset.id + "-" + day.toString(); + let baseHourly = SiloAssetHourlySnapshot.load(hourlyId); + let baseDaily = SiloAssetDailySnapshot.load(dailyId); + if (baseHourly == null && siloAsset.lastHourlySnapshotSeason !== 0) { + baseHourly = SiloAssetHourlySnapshot.load(siloAsset.id + "-" + siloAsset.lastHourlySnapshotSeason.toString()); + } + if (baseDaily == null && siloAsset.lastDailySnapshotDay !== null) { + baseDaily = SiloAssetDailySnapshot.load(siloAsset.id + "-" + siloAsset.lastDailySnapshotDay!.toString()); + } + const hourly = new SiloAssetHourlySnapshot(hourlyId); + const daily = new SiloAssetDailySnapshot(dailyId); + + // Set current values + hourly.season = currentSeason; + hourly.siloAsset = siloAsset.id; + hourly.depositedAmount = siloAsset.depositedAmount; + hourly.depositedBDV = siloAsset.depositedBDV; + hourly.withdrawnAmount = siloAsset.withdrawnAmount; + hourly.farmAmount = siloAsset.farmAmount; + + // Set deltas + if (baseHourly !== null) { + hourly.deltaDepositedAmount = hourly.depositedAmount.minus(baseHourly.depositedAmount); + hourly.deltaDepositedBDV = hourly.depositedBDV.minus(baseHourly.depositedBDV); + hourly.deltaWithdrawnAmount = hourly.withdrawnAmount.minus(baseHourly.withdrawnAmount); + hourly.deltaFarmAmount = hourly.farmAmount.minus(baseHourly.farmAmount); + + if (hourly.id == baseHourly.id) { + // Add existing deltas + hourly.deltaDepositedAmount = hourly.deltaDepositedAmount.plus(baseHourly.deltaDepositedAmount); + hourly.deltaDepositedBDV = hourly.deltaDepositedBDV.plus(baseHourly.deltaDepositedBDV); + hourly.deltaWithdrawnAmount = hourly.deltaWithdrawnAmount.plus(baseHourly.deltaWithdrawnAmount); + hourly.deltaFarmAmount = hourly.deltaFarmAmount.plus(baseHourly.deltaFarmAmount); + } + } else { + hourly.deltaDepositedAmount = hourly.depositedAmount; + hourly.deltaDepositedBDV = hourly.depositedBDV; + hourly.deltaWithdrawnAmount = hourly.withdrawnAmount; + hourly.deltaFarmAmount = hourly.farmAmount; + } + hourly.createdAt = hour; + hourly.updatedAt = timestamp; + hourly.save(); + + // Repeat for daily snapshot. + // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + + if (baseDaily !== null) { + daily.deltaDepositedAmount = daily.depositedAmount.minus(baseDaily.depositedAmount); + daily.deltaDepositedBDV = daily.depositedBDV.minus(baseDaily.depositedBDV); + daily.deltaWithdrawnAmount = daily.withdrawnAmount.minus(baseDaily.withdrawnAmount); + daily.deltaFarmAmount = daily.farmAmount.minus(baseDaily.farmAmount); + + if (daily.id == baseDaily.id) { + // Add existing deltas + daily.deltaDepositedAmount = daily.deltaDepositedAmount.plus(baseDaily.deltaDepositedAmount); + daily.deltaDepositedBDV = daily.deltaDepositedBDV.plus(baseDaily.deltaDepositedBDV); + daily.deltaWithdrawnAmount = daily.deltaWithdrawnAmount.plus(baseDaily.deltaWithdrawnAmount); + daily.deltaFarmAmount = daily.deltaFarmAmount.plus(baseDaily.deltaFarmAmount); + } + } else { + daily.deltaDepositedAmount = daily.depositedAmount; + daily.deltaDepositedBDV = daily.depositedBDV; + daily.deltaWithdrawnAmount = daily.withdrawnAmount; + daily.deltaFarmAmount = daily.farmAmount; + } + daily.createdAt = day; + daily.updatedAt = timestamp; + daily.save(); + + siloAsset.lastHourlySnapshotSeason = currentSeason; + siloAsset.lastDailySnapshotDay = day; +} From 52d5d8a0f321b13e43ca7cb38760f1da22f234c8 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:51:46 -0700 Subject: [PATCH 14/59] silo asset snapshot refactor --- .../subgraph-beanstalk/src/FarmHandler.ts | 41 +++---- .../subgraph-beanstalk/src/SeasonHandler.ts | 19 ++-- .../subgraph-beanstalk/src/SiloHandler.ts | 101 +++++------------- projects/subgraph-beanstalk/src/utils/Silo.ts | 50 --------- .../src/utils/snapshots/Silo.ts | 6 ++ 5 files changed, 55 insertions(+), 162 deletions(-) diff --git a/projects/subgraph-beanstalk/src/FarmHandler.ts b/projects/subgraph-beanstalk/src/FarmHandler.ts index dde579c131..363909302e 100644 --- a/projects/subgraph-beanstalk/src/FarmHandler.ts +++ b/projects/subgraph-beanstalk/src/FarmHandler.ts @@ -1,34 +1,27 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; import { InternalBalanceChanged } from "../generated/Beanstalk-ABIs/MarketV2"; -import { loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; -import { BEANSTALK } from "../../subgraph-core/utils/Constants"; -import { loadSiloAsset, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot } from "./utils/Silo"; +import { loadFarmer } from "./utils/Beanstalk"; +import { loadSiloAsset } from "./utils/Silo"; +import { takeSiloAssetSnapshots } from "./utils/snapshots/Silo"; export function handleInternalBalanceChanged(event: InternalBalanceChanged): void { - let beanstalk = loadBeanstalk(BEANSTALK); - loadFarmer(event.params.user); - - updateFarmTotals(BEANSTALK, event.params.token, beanstalk.lastSeason, event.params.delta, event.block.timestamp); - updateFarmTotals(event.params.user, event.params.token, beanstalk.lastSeason, event.params.delta, event.block.timestamp); + updateFarmTotals(event.address, event.params.user, event.params.token, event.params.delta, event.block.timestamp); } -function updateFarmTotals(account: Address, token: Address, season: i32, delta: BigInt, timestamp: BigInt): void { +function updateFarmTotals( + protocol: Address, + account: Address, + token: Address, + deltaAmount: BigInt, + timestamp: BigInt, + recursive: boolean = true +): void { + if (recursive && account != protocol) { + updateFarmTotals(protocol, account, token, deltaAmount, timestamp); + } let asset = loadSiloAsset(account, token); - let assetHourly = loadSiloAssetHourlySnapshot(account, token, season, timestamp); - let assetDaily = loadSiloAssetDailySnapshot(account, token, timestamp); - - asset.farmAmount = asset.farmAmount.plus(delta); + asset.farmAmount = asset.farmAmount.plus(deltaAmount); + takeSiloAssetSnapshots(asset, protocol, timestamp); asset.save(); - - assetHourly.farmAmount = asset.farmAmount; - assetHourly.deltaFarmAmount = assetHourly.deltaFarmAmount.plus(delta); - assetHourly.updatedAt = timestamp; - assetHourly.save(); - - assetDaily.season = season; - assetDaily.farmAmount = asset.farmAmount; - assetDaily.deltaFarmAmount = assetDaily.deltaFarmAmount.plus(delta); - assetDaily.updatedAt = timestamp; - assetDaily.save(); } diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index 18e5726bee..2737c99cfd 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -15,9 +15,9 @@ import { } from "./utils/PodMarketplace"; import { updateDepositInSiloAsset, updateStalkWithCalls } from "./SiloHandler"; import { updateBeanEMA } from "./YieldHandler"; -import { loadSilo, loadSiloAssetDailySnapshot, loadSiloAssetHourlySnapshot } from "./utils/Silo"; +import { loadSilo, loadSiloAsset } from "./utils/Silo"; import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/contracts/BeanstalkPrice"; -import { takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { takeSiloAssetSnapshots, takeSiloSnapshots } from "./utils/snapshots/Silo"; export function handleSunrise(event: Sunrise): void { // Update any farmers that had silo transfers from the prior season. @@ -68,8 +68,9 @@ export function handleSunrise(event: Sunrise): void { let silo = loadSilo(event.address); takeSiloSnapshots(silo, event.address, event.block.timestamp); for (let i = 0; i < silo.whitelistedTokens.length; i++) { - loadSiloAssetHourlySnapshot(event.address, Address.fromString(silo.whitelistedTokens[i]), currentSeason, event.block.timestamp); - loadSiloAssetDailySnapshot(event.address, Address.fromString(silo.whitelistedTokens[i]), event.block.timestamp); + let siloAsset = loadSiloAsset(event.address, Address.fromString(silo.whitelistedTokens[i])); + takeSiloAssetSnapshots(siloAsset, event.address, event.block.timestamp); + siloAsset.save(); } silo.save(); } @@ -97,15 +98,7 @@ export function handleReward(event: Reward): void { takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); - updateDepositInSiloAsset( - event.address, - event.address, - BEAN_ERC20, - event.params.season.toI32(), - event.params.toSilo, - event.params.toSilo, - event.block.timestamp - ); + updateDepositInSiloAsset(event.address, event.address, BEAN_ERC20, event.params.toSilo, event.params.toSilo, event.block.timestamp); } export function handleMetapoolOracle(event: MetapoolOracle): void { diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index c4a3adb6bd..9cf81326ab 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -24,8 +24,6 @@ import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadSilo, loadSiloAsset, - loadSiloAssetDailySnapshot, - loadSiloAssetHourlySnapshot, loadSiloWithdraw, loadSiloDeposit, loadWhitelistTokenSetting, @@ -37,7 +35,7 @@ import { import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit, Silo } from "../generated/schema"; import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; -import { takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { takeSiloAssetSnapshots, takeSiloSnapshots } from "./utils/snapshots/Silo"; import { stemFromSeason } from "./utils/contracts/SiloCalculations"; class AddRemoveDepositsParams { @@ -168,31 +166,16 @@ export function handleAddWithdrawal(event: AddWithdrawal): void { withdraw.createdAt = withdraw.createdAt == ZERO_BI ? event.block.timestamp : withdraw.createdAt; withdraw.save(); - addWithdrawToSiloAsset( - event.address, - event.params.token, - event.params.season.toI32(), - event.params.amount, - event.block.timestamp, - event.block.number - ); - addWithdrawToSiloAsset( - event.params.account, - event.params.token, - event.params.season.toI32(), - event.params.amount, - event.block.timestamp, - event.block.number - ); + addWithdrawToSiloAsset(event.address, event.params.account, event.params.token, event.params.amount, event.block.timestamp); } export function handleRemoveWithdrawal(event: RemoveWithdrawal): void { - updateClaimedWithdraw(event.params.account, event.params.token, event.params.season); + updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.season, event.block.timestamp); } export function handleRemoveWithdrawals(event: RemoveWithdrawals): void { for (let i = 0; i < event.params.seasons.length; i++) { - updateClaimedWithdraw(event.params.account, event.params.token, event.params.seasons[i]); + updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.seasons[i], event.block.timestamp); } } @@ -273,15 +256,7 @@ export function handlePlant(event: Plant): void { // Remove the asset-only amount that got added in Reward event handler. // Will be immediately re-credited to the user/system in AddDeposit - updateDepositInSiloAsset( - event.address, - event.address, - BEAN_ERC20, - currentSeason, - event.params.beans, - event.params.beans, - event.block.timestamp - ); + updateDepositInSiloAsset(event.address, event.address, BEAN_ERC20, event.params.beans, event.params.beans, event.block.timestamp); } // These two calls are according to the Replant abi, before stems were included. @@ -319,16 +294,7 @@ function updateDepositInSilo( let silo = loadSilo(account); silo.depositedBDV = silo.depositedBDV.plus(deltaBdv); - const newSeedStalk = updateDepositInSiloAsset( - protocol, - account, - token, - getCurrentSeason(protocol), - deltaAmount, - deltaBdv, - timestamp, - false - ); + const newSeedStalk = updateDepositInSiloAsset(protocol, account, token, deltaAmount, deltaBdv, timestamp, false); // Individual farmer seeds cannot be directly tracked due to seed gauge if (account == protocol) { silo.grownStalkPerSeason = silo.grownStalkPerSeason.plus(newSeedStalk); @@ -341,63 +307,43 @@ export function updateDepositInSiloAsset( protocol: Address, account: Address, token: Address, - season: i32, // season will be removed upon snapshot refactor deltaAmount: BigInt, deltaBdv: BigInt, timestamp: BigInt, recurs: boolean = true ): BigInt { if (recurs && account != protocol) { - updateDepositInSiloAsset(protocol, protocol, token, season, deltaAmount, deltaBdv, timestamp); + updateDepositInSiloAsset(protocol, protocol, token, deltaAmount, deltaBdv, timestamp); } let asset = loadSiloAsset(account, token); - let assetHourly = loadSiloAssetHourlySnapshot(account, token, season, timestamp); - let assetDaily = loadSiloAssetDailySnapshot(account, token, timestamp); let tokenSettings = loadWhitelistTokenSetting(token); let newGrownStalk = deltaBdv.times(tokenSettings.stalkEarnedPerSeason).div(BigInt.fromI32(1000000)); asset.depositedBDV = asset.depositedBDV.plus(deltaBdv); asset.depositedAmount = asset.depositedAmount.plus(deltaAmount); - asset.save(); - assetHourly.deltaDepositedBDV = assetHourly.deltaDepositedBDV.plus(deltaBdv); - assetHourly.depositedBDV = asset.depositedBDV; - assetHourly.deltaDepositedAmount = assetHourly.deltaDepositedAmount.plus(deltaAmount); - assetHourly.depositedAmount = asset.depositedAmount; - assetHourly.updatedAt = timestamp; - assetHourly.save(); - - assetDaily.season = season; - assetDaily.deltaDepositedBDV = assetDaily.deltaDepositedBDV.plus(deltaBdv); - assetDaily.depositedBDV = asset.depositedBDV; - assetDaily.deltaDepositedAmount = assetDaily.deltaDepositedAmount.plus(deltaAmount); - assetDaily.depositedAmount = asset.depositedAmount; - assetDaily.updatedAt = timestamp; - assetDaily.save(); + takeSiloAssetSnapshots(asset, protocol, timestamp); + asset.save(); return newGrownStalk; } function addWithdrawToSiloAsset( + protocol: Address, account: Address, token: Address, - season: i32, - amount: BigInt, + deltaAmount: BigInt, timestamp: BigInt, - blockNumber: BigInt + recurs: boolean = true ): void { - let assetHourly = loadSiloAssetHourlySnapshot(account, token, season, timestamp); - let assetDaily = loadSiloAssetDailySnapshot(account, token, timestamp); - - assetHourly.deltaWithdrawnAmount = assetHourly.deltaWithdrawnAmount.plus(amount); - assetHourly.updatedAt = timestamp; - assetHourly.save(); - - assetDaily.season = season; - assetDaily.deltaWithdrawnAmount = assetDaily.deltaWithdrawnAmount.plus(amount); - assetDaily.updatedAt = timestamp; - assetDaily.save(); + if (recurs && account != protocol) { + addWithdrawToSiloAsset(protocol, protocol, token, deltaAmount, timestamp); + } + let asset = loadSiloAsset(account, token); + asset.withdrawnAmount = asset.withdrawnAmount.plus(deltaAmount); + takeSiloAssetSnapshots(asset, protocol, timestamp); + asset.save(); } export function updateStalkBalances( @@ -448,10 +394,15 @@ function updateSeedsBalances(protocol: Address, account: Address, seeds: BigInt, silo.save(); } -function updateClaimedWithdraw(account: Address, token: Address, season: BigInt): void { - let withdraw = loadSiloWithdraw(account, token, season.toI32()); +function updateClaimedWithdraw(protocol: Address, account: Address, token: Address, withdrawSeason: BigInt, timestamp: BigInt): void { + let withdraw = loadSiloWithdraw(account, token, withdrawSeason.toI32()); withdraw.claimed = true; withdraw.save(); + + let asset = loadSiloAsset(account, token); + asset.withdrawnAmount = asset.withdrawnAmount.minus(withdraw.amount); + takeSiloAssetSnapshots(asset, protocol, timestamp); + asset.save(); } export function updateStalkWithCalls(protocol: Address, timestamp: BigInt): void { diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 69f31a4210..e7059da935 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -4,8 +4,6 @@ import { SiloDeposit, SiloWithdraw, SiloYield, - SiloAssetDailySnapshot, - SiloAssetHourlySnapshot, SiloAsset, WhitelistTokenSetting, WhitelistTokenHourlySnapshot, @@ -61,54 +59,6 @@ export function loadSiloAsset(account: Address, token: Address): SiloAsset { return asset as SiloAsset; } -export function loadSiloAssetHourlySnapshot(account: Address, token: Address, season: i32, timestamp: BigInt): SiloAssetHourlySnapshot { - let hour = hourFromTimestamp(timestamp); - let id = account.toHexString() + "-" + token.toHexString() + "-" + season.toString(); - let snapshot = SiloAssetHourlySnapshot.load(id); - if (snapshot == null) { - let asset = loadSiloAsset(account, token); - snapshot = new SiloAssetHourlySnapshot(id); - snapshot.season = season; - snapshot.siloAsset = asset.id; - snapshot.depositedBDV = asset.depositedBDV; - snapshot.depositedAmount = asset.depositedAmount; - snapshot.withdrawnAmount = asset.withdrawnAmount; - snapshot.farmAmount = asset.farmAmount; - snapshot.deltaDepositedBDV = ZERO_BI; - snapshot.deltaDepositedAmount = ZERO_BI; - snapshot.deltaWithdrawnAmount = ZERO_BI; - snapshot.deltaFarmAmount = ZERO_BI; - snapshot.createdAt = BigInt.fromI32(hour); - snapshot.updatedAt = ZERO_BI; - snapshot.save(); - } - return snapshot as SiloAssetHourlySnapshot; -} - -export function loadSiloAssetDailySnapshot(account: Address, token: Address, timestamp: BigInt): SiloAssetDailySnapshot { - let day = dayFromTimestamp(timestamp); - let id = account.toHexString() + "-" + token.toHexString() + "-" + day.toString(); - let snapshot = SiloAssetDailySnapshot.load(id); - if (snapshot == null) { - let asset = loadSiloAsset(account, token); - snapshot = new SiloAssetDailySnapshot(id); - snapshot.season = 0; - snapshot.siloAsset = asset.id; - snapshot.depositedBDV = asset.depositedBDV; - snapshot.depositedAmount = asset.depositedAmount; - snapshot.withdrawnAmount = asset.withdrawnAmount; - snapshot.farmAmount = asset.farmAmount; - snapshot.deltaDepositedBDV = ZERO_BI; - snapshot.deltaDepositedAmount = ZERO_BI; - snapshot.deltaWithdrawnAmount = ZERO_BI; - snapshot.deltaFarmAmount = ZERO_BI; - snapshot.createdAt = BigInt.fromI32(day); - snapshot.updatedAt = ZERO_BI; - snapshot.save(); - } - return snapshot as SiloAssetDailySnapshot; -} - /* ===== Whitelist Token Settings Entities ===== */ export function addToSiloWhitelist(siloAddress: Address, token: Address): void { diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts index db5888daae..321cba60a5 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts @@ -201,6 +201,12 @@ export function takeSiloAssetSnapshots(siloAsset: SiloAsset, protocol: Address, // Repeat for daily snapshot. // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + daily.season = currentSeason; + daily.siloAsset = siloAsset.id; + daily.depositedAmount = siloAsset.depositedAmount; + daily.depositedBDV = siloAsset.depositedBDV; + daily.withdrawnAmount = siloAsset.withdrawnAmount; + daily.farmAmount = siloAsset.farmAmount; if (baseDaily !== null) { daily.deltaDepositedAmount = daily.depositedAmount.minus(baseDaily.depositedAmount); daily.deltaDepositedBDV = daily.depositedBDV.minus(baseDaily.depositedBDV); From 35223cc44abb719cae88a65d38b7eb4fb32483f9 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:03:40 -0700 Subject: [PATCH 15/59] refactor other snapshots --- projects/subgraph-beanstalk/schema.graphql | 148 ++++++------- .../subgraph-beanstalk/src/FarmHandler.ts | 2 +- .../subgraph-beanstalk/src/FieldHandler.ts | 196 ++++++----------- .../subgraph-beanstalk/src/GaugeHandler.ts | 41 +--- .../src/MarketplaceHandler.ts | 43 +++- .../subgraph-beanstalk/src/SeasonHandler.ts | 48 ++--- .../subgraph-beanstalk/src/SiloHandler.ts | 28 +-- .../subgraph-beanstalk/src/utils/Field.ts | 103 +-------- .../src/utils/PodListing.ts | 26 +-- .../src/utils/PodMarketplace.ts | 171 ++------------- projects/subgraph-beanstalk/src/utils/Silo.ts | 47 ---- .../src/utils/snapshots/Field.ts | 200 ++++++++++++++++++ .../src/utils/snapshots/Marketplace.ts | 156 ++++++++++++++ .../src/utils/snapshots/Silo.ts | 101 +-------- .../src/utils/snapshots/SiloAsset.ts | 92 ++++++++ .../utils/snapshots/WhitelistTokenSetting.ts | 146 +++++++++++++ 16 files changed, 832 insertions(+), 716 deletions(-) create mode 100644 projects/subgraph-beanstalk/src/utils/snapshots/Field.ts create mode 100644 projects/subgraph-beanstalk/src/utils/snapshots/Marketplace.ts create mode 100644 projects/subgraph-beanstalk/src/utils/snapshots/SiloAsset.ts create mode 100644 projects/subgraph-beanstalk/src/utils/snapshots/WhitelistTokenSetting.ts diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index c84fc70465..b0a00ebfa4 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -174,28 +174,24 @@ type SiloHourlySnapshot @entity { beanMints: BigInt! "Point in time current number of active farmers deposited in the silo" activeFarmers: Int! - "Point in time delta BDV of all deposited assets" + deltaDepositedBDV: BigInt! - "Point in time delta stalk balance" deltaStalk: BigInt! - "Point in time current plantable stalk for bean seigniorage not yet claimed" deltaPlantableStalk: BigInt! - "Point in time delta seeds balance" deltaSeeds: BigInt! - "Point in time delta roots balance" deltaRoots: BigInt! - "Point in time germinating stalk balance" deltaGerminatingStalk: BigInt! - "Point in time delta total for bean mints sent to the silo" deltaBeanMints: BigInt! - "Point in time delta number of active farmers deposited in the silo" deltaActiveFarmers: Int! - "[Seed Gauge] The caseId used in the seasonal adjustment of beanToMaxLpGpPerBdvRatio" - caseId: BigInt + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" updatedAt: BigInt! + + # caseId is unique to hourly snapshot + "[Seed Gauge] The caseId used in the seasonal adjustment of beanToMaxLpGpPerBdvRatio" + caseId: BigInt } type SiloDailySnapshot @entity { @@ -225,22 +221,16 @@ type SiloDailySnapshot @entity { beanMints: BigInt! "Point in time current number of active farmers deposited in the silo" activeFarmers: Int! - "Point in time delta BDV of all deposited assets" + deltaDepositedBDV: BigInt! - "Point in time delta stalk balance" deltaStalk: BigInt! - "Point in time current plantable stalk for bean seigniorage not yet claimed" deltaPlantableStalk: BigInt! - "Point in time delta seeds balance" deltaSeeds: BigInt! - "Point in time delta roots balance" deltaRoots: BigInt! - "Point in time germinating stalk balance" deltaGerminatingStalk: BigInt! - "Point in time delta total for bean mints sent to the silo" deltaBeanMints: BigInt! - "Point in time delta number of active farmers deposited in the silo" deltaActiveFarmers: Int! + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" @@ -287,14 +277,12 @@ type SiloAssetHourlySnapshot @entity { withdrawnAmount: BigInt! "Point in time current internal (farm) balance of the asset" farmAmount: BigInt! - "Point in time delta BDV of deposits" + deltaDepositedBDV: BigInt! - "Point in time delta Token amount of deposits" deltaDepositedAmount: BigInt! - "Point in time delta Token amount of silo withdrawals" deltaWithdrawnAmount: BigInt! - "Point in time delta internal (farm) balance of the asset" deltaFarmAmount: BigInt! + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" @@ -316,14 +304,12 @@ type SiloAssetDailySnapshot @entity { withdrawnAmount: BigInt! "Point in time current internal (farm) balance of the asset" farmAmount: BigInt! - "Point in time delta BDV of deposits" + deltaDepositedBDV: BigInt! - "Point in time delta Token amount of deposits" deltaDepositedAmount: BigInt! - "Point in time delta Token amount of silo withdrawals" deltaWithdrawnAmount: BigInt! - "Point in time delta internal (farm) balance of the asset" deltaFarmAmount: BigInt! + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" @@ -389,6 +375,10 @@ type WhitelistTokenSetting @entity { optimalPercentDepositedBdv: BigInt "Last timestamp entity was updated" updatedAt: BigInt! + "Season when the previous hourly snapshot was taken/updated" + lastHourlySnapshotSeason: Int + "Day of when the previous daily snapshot was taken/updated" + lastDailySnapshotDay: BigInt "Link to hourly snapshot data" hourlySnapshots: [WhitelistTokenHourlySnapshot!]! @derivedFrom(field: "token") "Link to daily snapshot data" @@ -418,6 +408,13 @@ type WhitelistTokenHourlySnapshot @entity { gaugePoints: BigInt "[Seed Gauge] The current optimal targeted distribution of BDV for this whitelisted asset" optimalPercentDepositedBdv: BigInt + + deltaStalkEarnedPerSeason: BigInt! + deltaStalkIssuedPerBdv: BigInt! + deltaMilestoneSeason: Int! + deltaGaugePoints: BigInt + deltaOptimalPercentDepositedBdv: BigInt + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" @@ -427,6 +424,8 @@ type WhitelistTokenHourlySnapshot @entity { type WhitelistTokenDailySnapshot @entity { "Token address - Unix Timestamp" id: ID! + "The season for this snapshot" + season: Int! "WhitelistTokenSetting associated with this snapshot" token: WhitelistTokenSetting! "Encoded BDV selector" @@ -445,6 +444,13 @@ type WhitelistTokenDailySnapshot @entity { gaugePoints: BigInt "[Seed Gauge] The current optimal targeted distribution of BDV for this whitelisted asset" optimalPercentDepositedBdv: BigInt + + deltaStalkEarnedPerSeason: BigInt! + deltaStalkIssuedPerBdv: BigInt! + deltaMilestoneSeason: Int! + deltaGaugePoints: BigInt + deltaOptimalPercentDepositedBdv: BigInt + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" @@ -484,6 +490,10 @@ type Field @entity { podIndex: BigInt! "Current pod rate: Total unharvestable pods / bean supply" podRate: BigDecimal! + "Season when the previous hourly snapshot was taken/updated" + lastHourlySnapshotSeason: Int + "Day of when the previous daily snapshot was taken/updated" + lastDailySnapshotDay: BigInt "Link to hourly snapshot data" hourlySnapshots: [FieldHourlySnapshot!]! @derivedFrom(field: "field") "Link to daily snapshot data" @@ -515,36 +525,40 @@ type FieldHourlySnapshot @entity { harvestedPods: BigInt! "Point in time amount of soil remaining" soil: BigInt! + "Point in time amount of soil issued" + issuedSoil: BigInt! "Point in time pod index" podIndex: BigInt! "Point in time pod rate: Total unharvestable pods / bean supply" podRate: BigDecimal! - "Point in time delta number of unique sowers" + + deltaTemperature: Int! + deltaRealRateOfReturn: BigDecimal! deltaNumberOfSowers: Int! - "Point in time delta number of sows" deltaNumberOfSows: Int! - "Point in time delta total of sown beans" deltaSownBeans: BigInt! - "Point in time delta non-harvestable pods" deltaUnharvestablePods: BigInt! - "Point in time delta harvestable pods" deltaHarvestablePods: BigInt! - "Point in time delta harvested pods" deltaHarvestedPods: BigInt! - "Point in time amount of soil issued" - issuedSoil: BigInt! - "Number of blocks between sunrise and soil being sold out" - blocksToSoldOutSoil: BigInt! - "Bool flag if soil sold out for the season" - soilSoldOut: Boolean! - "The caseId used in the seasonal adjustment of temperature" - caseId: BigInt! - "Creation Block Number" - blockNumber: BigInt! + deltaSoil: BigInt! + deltaIssuedSoil: BigInt! + deltaPodIndex: BigInt! + deltaPodRate: BigDecimal! + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" updatedAt: BigInt! + + # These are unique to hourly snapshot + "The caseId used in the seasonal adjustment of temperature" + caseId: BigInt + "Block that started this season/at time of snapshot creation" + seasonBlock: BigInt! + "Number of blocks between sunrise and soil being sold out" + blocksToSoldOutSoil: BigInt + "Bool flag if soil sold out for the season" + soilSoldOut: Boolean! } type FieldDailySnapshot @entity { @@ -572,24 +586,26 @@ type FieldDailySnapshot @entity { harvestedPods: BigInt! "Point in time amount of soil remaining" soil: BigInt! + "Point in time amount of soil issued" + issuedSoil: BigInt! "Point in time pod index" podIndex: BigInt! "Point in time pod rate: Total unharvestable pods / bean supply" podRate: BigDecimal! - "Point in time delta number of unique sowers" + + deltaTemperature: Int! + deltaRealRateOfReturn: BigDecimal! deltaNumberOfSowers: Int! - "Point in time delta number of sows" deltaNumberOfSows: Int! - "Point in time delta total of sown beans" deltaSownBeans: BigInt! - "Point in time delta non-harvestable pods" deltaUnharvestablePods: BigInt! - "Point in time delta harvestable pods" deltaHarvestablePods: BigInt! - "Point in time delta harvested pods" deltaHarvestedPods: BigInt! - "Point in time amount of soil issued" - issuedSoil: BigInt! + deltaSoil: BigInt! + deltaIssuedSoil: BigInt! + deltaPodIndex: BigInt! + deltaPodRate: BigDecimal! + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" @@ -740,6 +756,10 @@ type PodMarketplace @entity { podVolume: BigInt! "Cumulative bean volume between listings and orders" beanVolume: BigInt! + "Season when the previous hourly snapshot was taken/updated" + lastHourlySnapshotSeason: Int + "Day of when the previous daily snapshot was taken/updated" + lastDailySnapshotDay: BigInt "Link to hourly snapshot data" hourlySnapshots: [PodMarketplaceHourlySnapshot!]! @derivedFrom(field: "podMarketplace") "Link to daily snapshot data" @@ -777,30 +797,20 @@ type PodMarketplaceHourlySnapshot @entity { podVolume: BigInt! "Point in time current cumulative bean volume between listings and orders" beanVolume: BigInt! - "Point in time current delta pods listed for sale" + deltaListedPods: BigInt! - "Point in time current delta of total pods listed" deltaAvailableListedPods: BigInt! - "Point in time current delta pod listings filled" deltaFilledListedPods: BigInt! - "Point in time current delta pod listings that expired" deltaExpiredListedPods: BigInt! - "Point in time current delta pod listings that were cancelled" deltaCancelledListedPods: BigInt! - "Point in time current delta ordered beans in pod orders created" deltaOrderBeans: BigInt! - "Point in time current delta available ordered beans in pod orders" deltaAvailableOrderBeans: BigInt! - "Point in time current delta filled ordered beans in pod orders" deltaFilledOrderBeans: BigInt! - "Point in time current delta pod orders filled" deltaFilledOrderedPods: BigInt! - "Point in time current delta cancelled ordered beans in pod orders" deltaCancelledOrderBeans: BigInt! - "Point in time current delta pod volume between listings and orders" deltaPodVolume: BigInt! - "Point in time current delta bean volume between listings and orders" deltaBeanVolume: BigInt! + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" @@ -838,30 +848,20 @@ type PodMarketplaceDailySnapshot @entity { podVolume: BigInt! "Point in time current cumulative bean volume between listings and orders" beanVolume: BigInt! - "Point in time current delta pods listed for sale" + deltaListedPods: BigInt! - "Point in time current delta of total pods listed" deltaAvailableListedPods: BigInt! - "Point in time current delta pod listings filled" deltaFilledListedPods: BigInt! - "Point in time current delta pod listings that expired" deltaExpiredListedPods: BigInt! - "Point in time current delta pod listings that were cancelled" deltaCancelledListedPods: BigInt! - "Point in time current delta ordered beans in pod orders created" deltaOrderBeans: BigInt! - "Point in time current delta available ordered beans in pod orders" deltaAvailableOrderBeans: BigInt! - "Point in time current delta filled ordered beans in pod orders" deltaFilledOrderBeans: BigInt! - "Point in time current delta pod orders filled" deltaFilledOrderedPods: BigInt! - "Point in time current delta cancelled ordered beans in pod orders" deltaCancelledOrderBeans: BigInt! - "Point in time current delta pod volume between listings and orders" deltaPodVolume: BigInt! - "Point in time current delta bean volume between listings and orders" deltaBeanVolume: BigInt! + "Timestamp of initial snapshot creation" createdAt: BigInt! "Timestamp of last entity update" diff --git a/projects/subgraph-beanstalk/src/FarmHandler.ts b/projects/subgraph-beanstalk/src/FarmHandler.ts index 363909302e..eafbb8412e 100644 --- a/projects/subgraph-beanstalk/src/FarmHandler.ts +++ b/projects/subgraph-beanstalk/src/FarmHandler.ts @@ -2,7 +2,7 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; import { InternalBalanceChanged } from "../generated/Beanstalk-ABIs/MarketV2"; import { loadFarmer } from "./utils/Beanstalk"; import { loadSiloAsset } from "./utils/Silo"; -import { takeSiloAssetSnapshots } from "./utils/snapshots/Silo"; +import { takeSiloAssetSnapshots } from "./utils/snapshots/SiloAsset"; export function handleInternalBalanceChanged(event: InternalBalanceChanged): void { loadFarmer(event.params.user); diff --git a/projects/subgraph-beanstalk/src/FieldHandler.ts b/projects/subgraph-beanstalk/src/FieldHandler.ts index 879973157c..9612d05618 100644 --- a/projects/subgraph-beanstalk/src/FieldHandler.ts +++ b/projects/subgraph-beanstalk/src/FieldHandler.ts @@ -11,42 +11,26 @@ import { } from "../generated/Beanstalk-ABIs/PreReplant"; import { BEANSTALK, BEANSTALK_FARMS } from "../../subgraph-core/utils/Constants"; import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { getHarvestableIndex, handleRateChange, loadField, loadFieldDaily, loadFieldHourly, loadPlot } from "./utils/Field"; +import { getHarvestableIndex, handleRateChange, loadField, loadPlot } from "./utils/Field"; import { getCurrentSeason, loadBeanstalk, loadFarmer, loadSeason } from "./utils/Beanstalk"; import { expirePodListingIfExists } from "./utils/PodListing"; +import { setHourlySoilSoldOut, takeFieldSnapshots } from "./utils/snapshots/Field"; export function handleWeatherChange(event: WeatherChange): void { handleRateChange(event.address, event.block, event.params.season, event.params.caseId, event.params.change); } export function handleSow(event: Sow): void { - let beanstalk = loadBeanstalk(event.address); - let sownBeans = event.params.beans; if (event.params.account == BEANSTALK_FARMS) { let startingField = loadField(event.address); sownBeans = startingField.soil; } - - // Update Beanstalk Totals - updateFieldTotals( - event.address, - beanstalk.lastSeason, - ZERO_BI, - sownBeans, - event.params.pods, - ZERO_BI, - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number - ); - // Update Farmer Totals updateFieldTotals( + event.address, event.params.account, - beanstalk.lastSeason, ZERO_BI, sownBeans, event.params.pods, @@ -78,11 +62,7 @@ export function handleSow(event: Sow): void { plot.beansPerPod = event.params.beans.times(BI_10.pow(6)).div(plot.pods); plot.save(); - // Increment protocol amounts - incrementSows(event.address, field.season, event.block.timestamp); - - // Increment farmer amounts - incrementSows(event.params.account, field.season, event.block.timestamp); + incrementSows(event.address, event.params.account, event.block.timestamp, event.block.number); } export function handleHarvest(event: Harvest): void { @@ -107,19 +87,7 @@ export function handleHarvest(event: Harvest): void { // Plot fully harvests updateFieldTotals( event.address, - beanstalk.lastSeason, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - plot.pods, - event.block.timestamp, - event.block.number - ); - updateFieldTotals( event.params.account, - beanstalk.lastSeason, ZERO_BI, ZERO_BI, ZERO_BI, @@ -135,22 +103,9 @@ export function handleHarvest(event: Harvest): void { plot.save(); } else { // Plot partially harvests - updateFieldTotals( event.address, - beanstalk.lastSeason, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - harvestablePods, - event.block.timestamp, - event.block.number - ); - updateFieldTotals( event.params.account, - beanstalk.lastSeason, ZERO_BI, ZERO_BI, ZERO_BI, @@ -201,7 +156,6 @@ export function handleHarvest(event: Harvest): void { } export function handlePlotTransfer(event: PlotTransfer): void { - const currentSeason = getCurrentSeason(event.address); const currentHarvestable = getHarvestableIndex(event.address); // Ensure both farmer entites exist @@ -210,8 +164,8 @@ export function handlePlotTransfer(event: PlotTransfer): void { // Update farmer field data updateFieldTotals( + event.address, event.params.from, - currentSeason, ZERO_BI, ZERO_BI, ZERO_BI, @@ -219,11 +173,12 @@ export function handlePlotTransfer(event: PlotTransfer): void { ZERO_BI, ZERO_BI, event.block.timestamp, - event.block.number + event.block.number, + false ); updateFieldTotals( + event.address, event.params.to, - currentSeason, ZERO_BI, ZERO_BI, ZERO_BI, @@ -231,7 +186,8 @@ export function handlePlotTransfer(event: PlotTransfer): void { ZERO_BI, ZERO_BI, event.block.timestamp, - event.block.number + event.block.number, + false ); let field = loadField(BEANSTALK); @@ -431,8 +387,8 @@ export function handlePlotTransfer(event: PlotTransfer): void { // No need to shift beanstalk field, only the farmer fields. if (transferredHarvestable != ZERO_BI) { updateFieldTotals( + event.address, event.params.from, - currentSeason, ZERO_BI, ZERO_BI, ZERO_BI, @@ -440,11 +396,12 @@ export function handlePlotTransfer(event: PlotTransfer): void { ZERO_BI.minus(transferredHarvestable), ZERO_BI, event.block.timestamp, - event.block.number + event.block.number, + false ); updateFieldTotals( + event.address, event.params.to, - currentSeason, ZERO_BI, ZERO_BI, ZERO_BI, @@ -452,7 +409,8 @@ export function handlePlotTransfer(event: PlotTransfer): void { transferredHarvestable, ZERO_BI, event.block.timestamp, - event.block.number + event.block.number, + false ); } } @@ -460,7 +418,7 @@ export function handlePlotTransfer(event: PlotTransfer): void { export function handleSupplyIncrease(event: SupplyIncrease): void { updateFieldTotals( event.address, - event.params.season.toI32(), + event.address, event.params.newSoil, ZERO_BI, ZERO_BI, @@ -475,7 +433,7 @@ export function handleSupplyIncrease(event: SupplyIncrease): void { export function handleSupplyDecrease(event: SupplyDecrease): void { updateFieldTotals( event.address, - event.params.season.toI32(), + event.address, event.params.newSoil, ZERO_BI, ZERO_BI, @@ -490,7 +448,7 @@ export function handleSupplyDecrease(event: SupplyDecrease): void { export function handleSupplyNeutral(event: SupplyNeutral): void { updateFieldTotals( event.address, - event.params.season.toI32(), + event.address, event.params.newSoil, ZERO_BI, ZERO_BI, @@ -503,11 +461,10 @@ export function handleSupplyNeutral(event: SupplyNeutral): void { } export function handleFundFundraiser(event: FundFundraiser): void { - // Account for the fact thta fundraiser sow using no soil. - let beanstalk = loadBeanstalk(event.address); + // Account for the fact that fundraiser sow using no soil. updateFieldTotals( event.address, - beanstalk.lastSeason, + event.address, ZERO_BI, ZERO_BI.minus(event.params.amount), ZERO_BI, @@ -520,8 +477,8 @@ export function handleFundFundraiser(event: FundFundraiser): void { } function updateFieldTotals( + protocol: Address, account: Address, - season: i32, soil: BigInt, sownBeans: BigInt, sownPods: BigInt, @@ -529,64 +486,51 @@ function updateFieldTotals( harvestablePods: BigInt, harvestedPods: BigInt, timestamp: BigInt, - blockNumber: BigInt + blockNumber: BigInt, + recurs: boolean = true ): void { + if (recurs && account != protocol) { + updateFieldTotals( + protocol, + protocol, + soil, + sownBeans, + sownPods, + transferredPods, + harvestablePods, + harvestedPods, + timestamp, + blockNumber + ); + } let field = loadField(account); - let fieldHourly = loadFieldHourly(account, season, timestamp); - let fieldDaily = loadFieldDaily(account, timestamp); - field.season = season; + field.season = getCurrentSeason(protocol); field.soil = field.soil.plus(soil).minus(sownBeans); field.sownBeans = field.sownBeans.plus(sownBeans); field.unharvestablePods = field.unharvestablePods.plus(sownPods).minus(harvestablePods).plus(transferredPods); field.harvestablePods = field.harvestablePods.plus(harvestablePods); field.harvestedPods = field.harvestedPods.plus(harvestedPods); field.podIndex = field.podIndex.plus(sownPods); + + takeFieldSnapshots(field, protocol, timestamp, blockNumber); field.save(); - fieldHourly.soil = field.soil; - fieldHourly.sownBeans = field.sownBeans; - fieldHourly.unharvestablePods = field.unharvestablePods; - fieldHourly.harvestablePods = field.harvestablePods; - fieldHourly.harvestedPods = field.harvestedPods; - fieldHourly.podIndex = field.podIndex; - fieldHourly.issuedSoil = fieldHourly.issuedSoil.plus(soil); - fieldHourly.deltaSownBeans = fieldHourly.deltaSownBeans.plus(sownBeans); - fieldHourly.deltaUnharvestablePods = fieldHourly.deltaUnharvestablePods.plus(sownPods).minus(harvestablePods).plus(transferredPods); - fieldHourly.deltaHarvestablePods = fieldHourly.deltaHarvestablePods.plus(harvestablePods); - fieldHourly.deltaHarvestedPods = fieldHourly.deltaHarvestedPods.plus(harvestedPods); - fieldHourly.blockNumber = fieldHourly.blockNumber == ZERO_BI ? blockNumber : fieldHourly.blockNumber; - fieldHourly.updatedAt = timestamp; + // Set extra info on the hourly snapshot if (field.soil == ZERO_BI) { - fieldHourly.blocksToSoldOutSoil = blockNumber.minus(fieldHourly.blockNumber); - fieldHourly.soilSoldOut = true; + setHourlySoilSoldOut(blockNumber, field, protocol); } - fieldHourly.save(); - - fieldDaily.soil = field.soil; - fieldDaily.sownBeans = field.sownBeans; - fieldDaily.unharvestablePods = field.unharvestablePods; - fieldDaily.harvestablePods = field.harvestablePods; - fieldDaily.harvestedPods = field.harvestedPods; - fieldDaily.podIndex = field.podIndex; - fieldDaily.issuedSoil = fieldDaily.issuedSoil.plus(soil); - fieldDaily.deltaSownBeans = fieldDaily.deltaSownBeans.plus(sownBeans); - fieldDaily.deltaUnharvestablePods = fieldDaily.deltaUnharvestablePods.plus(sownPods).minus(harvestablePods).plus(transferredPods); - fieldDaily.deltaHarvestablePods = fieldDaily.deltaHarvestablePods.plus(harvestablePods); - fieldDaily.deltaHarvestedPods = fieldDaily.deltaHarvestedPods.plus(harvestedPods); - fieldDaily.updatedAt = timestamp; - fieldDaily.save(); } -export function updateHarvestablePlots(harvestableIndex: BigInt, timestamp: BigInt, blockNumber: BigInt): void { - let field = loadField(BEANSTALK); +export function updateHarvestablePlots(protocol: Address, harvestableIndex: BigInt, timestamp: BigInt, blockNumber: BigInt): void { + let field = loadField(protocol); let sortedIndexes = field.plotIndexes.sort(); for (let i = 0; i < sortedIndexes.length; i++) { if (sortedIndexes[i] > harvestableIndex) { break; } - let plot = loadPlot(BEANSTALK, sortedIndexes[i]); + let plot = loadPlot(protocol, sortedIndexes[i]); // Plot is fully harvestable, but hasn't been harvested yet if (plot.harvestablePods == plot.pods) { @@ -600,10 +544,9 @@ export function updateHarvestablePlots(harvestableIndex: BigInt, timestamp: BigI let deltaHarvestablePods = oldHarvestablePods == ZERO_BI ? plot.harvestablePods : plot.harvestablePods.minus(oldHarvestablePods); - updateFieldTotals(BEANSTALK, field.season, ZERO_BI, ZERO_BI, ZERO_BI, ZERO_BI, deltaHarvestablePods, ZERO_BI, timestamp, blockNumber); updateFieldTotals( + protocol, Address.fromString(plot.farmer), - field.season, ZERO_BI, ZERO_BI, ZERO_BI, @@ -616,42 +559,27 @@ export function updateHarvestablePlots(harvestableIndex: BigInt, timestamp: BigI } } -function incrementSowers(account: Address, season: i32, timestamp: BigInt): void { - // Increment total number of sowers by one - let field = loadField(account); - let fieldHourly = loadFieldHourly(account, season, timestamp); - let fieldDaily = loadFieldDaily(account, timestamp); - +// Increment number of unique sowers (protocol only) +function incrementSowers(protocol: Address, timestamp: BigInt, blockNumber: BigInt): void { + let field = loadField(protocol); field.numberOfSowers += 1; + takeFieldSnapshots(field, protocol, timestamp, blockNumber); field.save(); - - fieldHourly.numberOfSowers = field.numberOfSowers; - fieldHourly.deltaNumberOfSowers += 1; - fieldHourly.save(); - - fieldDaily.numberOfSowers = field.numberOfSowers; - fieldDaily.deltaNumberOfSowers += 1; - fieldDaily.save(); } -function incrementSows(account: Address, season: i32, timestamp: BigInt): void { - // Increment total sows by one - let field = loadField(account); - let fieldHourly = loadFieldHourly(account, season, timestamp); - let fieldDaily = loadFieldDaily(account, timestamp); - - // Add to protocol numberOfSowers if needed - if (account != BEANSTALK && field.numberOfSows == 0) incrementSowers(BEANSTALK, season, timestamp); +// Increment total number of sows for either an account or the protocol +function incrementSows(protocol: Address, account: Address, timestamp: BigInt, blockNumber: BigInt, recurs: boolean = true): void { + if (recurs && account != protocol) { + incrementSows(protocol, protocol, timestamp, blockNumber); + } - // Update sower counts + let field = loadField(account); field.numberOfSows += 1; + takeFieldSnapshots(field, protocol, timestamp, blockNumber); field.save(); - fieldHourly.numberOfSows = field.numberOfSows; - fieldHourly.deltaNumberOfSows += 1; - fieldHourly.save(); - - fieldDaily.numberOfSows = field.numberOfSows; - fieldDaily.deltaNumberOfSows += 1; - fieldDaily.save(); + // Add to protocol numberOfSowers if this is the first time this account has sown + if (account != protocol && field.numberOfSows == 0) { + incrementSowers(protocol, timestamp, blockNumber); + } } diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index a4dea1072a..3a91e4c5c1 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -11,13 +11,7 @@ import { TotalStalkChangedFromGermination } from "../generated/Beanstalk-ABIs/SeedGauge"; import { handleRateChange } from "./utils/Field"; -import { - loadSilo, - loadWhitelistTokenSetting, - loadWhitelistTokenDailySnapshot, - loadWhitelistTokenHourlySnapshot, - addToSiloWhitelist -} from "./utils/Silo"; +import { loadSilo, loadWhitelistTokenSetting, addToSiloWhitelist } from "./utils/Silo"; import { deleteGerminating, loadGerminating, loadOrCreateGerminating } from "./utils/Germinating"; import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { updateStalkBalances } from "./SiloHandler"; @@ -26,6 +20,7 @@ import { BEAN_WETH_CP2_WELL } from "../../subgraph-core/utils/Constants"; import { Bytes4_emptyToNull } from "../../subgraph-core/utils/Bytes"; import { getCurrentSeason } from "./utils/Beanstalk"; import { setHourlyCaseId, takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { takeWhitelistTokenSettingSnapshots } from "./utils/snapshots/WhitelistTokenSetting"; export function handleTemperatureChange(event: TemperatureChange): void { handleRateChange(event.address, event.block, event.params.season, event.params.caseId, event.params.absChange); @@ -50,14 +45,9 @@ export function handleGaugePointChange(event: GaugePointChange): void { let siloSettings = loadWhitelistTokenSetting(event.params.token); siloSettings.gaugePoints = event.params.gaugePoints; siloSettings.updatedAt = event.block.timestamp; - siloSettings.save(); - let whitelistHourly = loadWhitelistTokenHourlySnapshot(event.params.token, event.params.season.toI32(), event.block.timestamp); - let whitelistDaily = loadWhitelistTokenDailySnapshot(event.params.token, event.block.timestamp); - whitelistHourly.gaugePoints = event.params.gaugePoints; - whitelistDaily.gaugePoints = event.params.gaugePoints; - whitelistHourly.save(); - whitelistDaily.save(); + takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); + siloSettings.save(); } export function handleUpdateAverageStalkPerBdvPerSeason(event: UpdateAverageStalkPerBdvPerSeason): void { @@ -158,10 +148,9 @@ export function handleWhitelistToken_BIP45(event: WhitelistToken): void { siloSettings.lwSelector = Bytes4_emptyToNull(event.params.lwSelector); siloSettings.optimalPercentDepositedBdv = event.params.optimalPercentDepositedBdv; siloSettings.updatedAt = event.block.timestamp; - siloSettings.save(); - loadWhitelistTokenHourlySnapshot(event.params.token, getCurrentSeason(event.address), event.block.timestamp); - loadWhitelistTokenDailySnapshot(event.params.token, event.block.timestamp); + takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); + siloSettings.save(); let id = "whitelistToken-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); let rawEvent = new WhitelistTokenEntity(id); @@ -181,28 +170,14 @@ export function handleUpdateGaugeSettings(event: UpdateGaugeSettings): void { siloSettings.optimalPercentDepositedBdv = event.params.optimalPercentDepositedBdv; siloSettings.updatedAt = event.block.timestamp; - let hourly = loadWhitelistTokenHourlySnapshot(event.params.token, getCurrentSeason(event.address), event.block.timestamp); - hourly.gpSelector = siloSettings.gpSelector; - hourly.lwSelector = siloSettings.lwSelector; - hourly.optimalPercentDepositedBdv = siloSettings.optimalPercentDepositedBdv; - hourly.updatedAt = siloSettings.updatedAt; - - let daily = loadWhitelistTokenDailySnapshot(event.params.token, event.block.timestamp); - daily.gpSelector = siloSettings.gpSelector; - daily.lwSelector = siloSettings.lwSelector; - daily.optimalPercentDepositedBdv = siloSettings.optimalPercentDepositedBdv; - daily.updatedAt = siloSettings.updatedAt; - // On initial gauge deployment, there was no GaugePointChange event emitted. Need to initialize BEANETH here if ( event.params.token == BEAN_WETH_CP2_WELL && event.transaction.hash.toHexString().toLowerCase() == "0x299a4b93b8d19f8587b648ce04e3f5e618ea461426bb2b2337993b5d6677f6a7" ) { siloSettings.gaugePoints = BI_10.pow(20); - hourly.gaugePoints = BI_10.pow(20); - daily.gaugePoints = BI_10.pow(20); } + + takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); siloSettings.save(); - hourly.save(); - daily.save(); } diff --git a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts b/projects/subgraph-beanstalk/src/MarketplaceHandler.ts index 6a1141b79c..26b3f7eda3 100644 --- a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts +++ b/projects/subgraph-beanstalk/src/MarketplaceHandler.ts @@ -115,7 +115,7 @@ export function handlePodListingCancelled(event: PodListingCancelled): void { listing.index, listing.maxHarvestableIndex ); - updateMarketListingBalances(event.address, ZERO_BI, listing.remainingAmount, ZERO_BI, ZERO_BI, event.block.timestamp); + updateMarketListingBalances(event.address, event.address, ZERO_BI, listing.remainingAmount, ZERO_BI, ZERO_BI, event.block.timestamp); listing.status = listing.filled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; listing.updatedAt = event.block.timestamp; @@ -193,6 +193,7 @@ export function handlePodOrderCancelled(event: PodOrderCancelled): void { updateActiveOrders(event.address, MarketplaceAction.CANCELLED, order.id, order.maxPlaceInLine); updateMarketOrderBalances( + event.address, event.address, ZERO_BI, order.beanAmount.minus(order.beanAmountFilled), @@ -366,7 +367,15 @@ function podListingCreated(params: PodListingCreatedParams): void { listing.index, listing.maxHarvestableIndex ); - updateMarketListingBalances(params.event.address, params.amount, ZERO_BI, ZERO_BI, ZERO_BI, params.event.block.timestamp); + updateMarketListingBalances( + params.event.address, + params.event.address, + params.amount, + ZERO_BI, + ZERO_BI, + ZERO_BI, + params.event.block.timestamp + ); /// Save raw event data let id = "podListingCreated-" + params.event.transaction.hash.toHexString() + "-" + params.event.logIndex.toString(); @@ -394,7 +403,15 @@ function podListingCreated(params: PodListingCreatedParams): void { function podListingFilled(params: MarketFillParams): void { let listing = loadPodListing(params.from, params.index); - updateMarketListingBalances(params.event.address, ZERO_BI, ZERO_BI, params.amount, params.costInBeans, params.event.block.timestamp); + updateMarketListingBalances( + params.event.address, + params.event.address, + ZERO_BI, + ZERO_BI, + params.amount, + params.costInBeans, + params.event.block.timestamp + ); listing.filledAmount = params.amount; listing.remainingAmount = listing.remainingAmount.minus(params.amount); @@ -512,7 +529,15 @@ function podOrderCreated(params: PodOrderCreatedParams): void { order.save(); updateActiveOrders(params.event.address, MarketplaceAction.CREATED, order.id, order.maxPlaceInLine); - updateMarketOrderBalances(params.event.address, params.beanAmount, ZERO_BI, ZERO_BI, ZERO_BI, params.event.block.timestamp); + updateMarketOrderBalances( + params.event.address, + params.event.address, + params.beanAmount, + ZERO_BI, + ZERO_BI, + ZERO_BI, + params.event.block.timestamp + ); // Save the raw event data let id = "podOrderCreated-" + params.event.transaction.hash.toHexString() + "-" + params.event.logIndex.toString(); @@ -563,7 +588,15 @@ function podOrderFilled(params: MarketFillParams): void { updateActiveOrders(params.event.address, MarketplaceAction.FILLED_FULL, order.id, order.maxPlaceInLine); } - updateMarketOrderBalances(params.event.address, ZERO_BI, ZERO_BI, params.amount, params.costInBeans, params.event.block.timestamp); + updateMarketOrderBalances( + params.event.address, + params.event.address, + ZERO_BI, + ZERO_BI, + params.amount, + params.costInBeans, + params.event.block.timestamp + ); // Save the raw event data let id = "podOrderFilled-" + params.event.transaction.hash.toHexString() + "-" + params.event.logIndex.toString(); diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index 2737c99cfd..dec40df2a5 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -6,18 +6,16 @@ import { updateHarvestablePlots } from "./FieldHandler"; import { loadBeanstalk, loadSeason } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, CURVE_PRICE, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadField, loadFieldDaily, loadFieldHourly } from "./utils/Field"; -import { - loadPodMarketplace, - loadPodMarketplaceDailySnapshot, - loadPodMarketplaceHourlySnapshot, - updateExpiredPlots -} from "./utils/PodMarketplace"; +import { loadField } from "./utils/Field"; +import { loadPodMarketplace, updateExpiredPlots } from "./utils/PodMarketplace"; import { updateDepositInSiloAsset, updateStalkWithCalls } from "./SiloHandler"; import { updateBeanEMA } from "./YieldHandler"; import { loadSilo, loadSiloAsset } from "./utils/Silo"; import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/contracts/BeanstalkPrice"; -import { takeSiloAssetSnapshots, takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { takeSiloAssetSnapshots } from "./utils/snapshots/SiloAsset"; +import { takeMarketSnapshots } from "./utils/snapshots/Marketplace"; +import { takeFieldSnapshots } from "./utils/snapshots/Field"; export function handleSunrise(event: Sunrise): void { // Update any farmers that had silo transfers from the prior season. @@ -38,31 +36,20 @@ export function handleSunrise(event: Sunrise): void { // Update field metrics let field = loadField(event.address); - let fieldHourly = loadFieldHourly(event.address, field.season, event.block.timestamp); - let fieldDaily = loadFieldDaily(event.address, event.block.timestamp); // -- Field level totals field.season = currentSeason; field.podRate = season.beans == ZERO_BI ? ZERO_BD : toDecimal(field.unharvestablePods, 6).div(toDecimal(season.beans, 6)); - fieldHourly.podRate = field.podRate; - fieldDaily.season = currentSeason; - fieldDaily.podRate = field.podRate; + takeFieldSnapshots(field, event.address, event.block.timestamp, event.block.number); field.save(); - fieldHourly.save(); - fieldDaily.save(); // Marketplace Season Update let market = loadPodMarketplace(event.address); - let marketHourly = loadPodMarketplaceHourlySnapshot(event.address, market.season, event.block.timestamp); - let marketDaily = loadPodMarketplaceDailySnapshot(event.address, event.block.timestamp); market.season = currentSeason; - marketHourly.season = currentSeason; - marketDaily.season = currentSeason; + takeMarketSnapshots(market, event.address, event.block.timestamp); market.save(); - marketHourly.save(); - marketDaily.save(); // Create silo entities for the protocol let silo = loadSilo(event.address); @@ -133,22 +120,11 @@ export function handleSoil(event: Soil): void { // to an existing amount. let field = loadField(event.address); - let fieldHourly = loadFieldHourly(event.address, event.params.season.toI32(), event.block.timestamp); - let fieldDaily = loadFieldDaily(event.address, event.block.timestamp); - field.season = event.params.season.toI32(); field.soil = event.params.soil; - field.save(); - fieldHourly.soil = field.soil; - fieldHourly.issuedSoil = fieldHourly.issuedSoil.plus(event.params.soil); - fieldHourly.updatedAt = event.block.timestamp; - fieldHourly.save(); - - fieldDaily.soil = field.soil; - fieldDaily.issuedSoil = fieldDaily.issuedSoil.plus(event.params.soil); - fieldDaily.updatedAt = event.block.timestamp; - fieldDaily.save(); + takeFieldSnapshots(field, event.address, event.block.timestamp, event.block.number); + field.save(); if (event.params.season.toI32() >= 6075) { updateBeanEMA(event.params.season.toI32(), event.block.timestamp); @@ -167,6 +143,6 @@ export function handleIncentive(event: Incentivization): void { season.harvestableIndex = beanstalk_contract.harvestableIndex(); season.save(); - updateExpiredPlots(season.harvestableIndex, event.address, event.block.timestamp); - updateHarvestablePlots(season.harvestableIndex, event.block.timestamp, event.block.number); + updateExpiredPlots(event.address, season.harvestableIndex, event.block.timestamp); + updateHarvestablePlots(event.address, season.harvestableIndex, event.block.timestamp, event.block.number); } diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 9cf81326ab..380a83add0 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -27,16 +27,16 @@ import { loadSiloWithdraw, loadSiloDeposit, loadWhitelistTokenSetting, - loadWhitelistTokenHourlySnapshot, - loadWhitelistTokenDailySnapshot, addToSiloWhitelist, updateDeposit } from "./utils/Silo"; import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit, Silo } from "../generated/schema"; import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; -import { takeSiloAssetSnapshots, takeSiloSnapshots } from "./utils/snapshots/Silo"; +import { takeSiloSnapshots } from "./utils/snapshots/Silo"; import { stemFromSeason } from "./utils/contracts/SiloCalculations"; +import { takeSiloAssetSnapshots } from "./utils/snapshots/SiloAsset"; +import { takeWhitelistTokenSettingSnapshots } from "./utils/snapshots/WhitelistTokenSetting"; class AddRemoveDepositsParams { event: ethereum.Event; @@ -436,10 +436,9 @@ export function handleWhitelistToken(event: WhitelistToken): void { setting.selector = event.params.selector; setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); setting.stalkEarnedPerSeason = event.params.stalk.times(BigInt.fromI32(1000000)); - setting.save(); - loadWhitelistTokenHourlySnapshot(event.params.token, getCurrentSeason(event.address), event.block.timestamp); - loadWhitelistTokenDailySnapshot(event.params.token, event.block.timestamp); + takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); + setting.save(); let id = "whitelistToken-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); let rawEvent = new WhitelistTokenEntity(id); @@ -462,10 +461,9 @@ export function handleWhitelistToken_V3(event: WhitelistToken_V3): void { setting.selector = event.params.selector; setting.stalkIssuedPerBdv = event.params.stalk.times(BigInt.fromI32(1_000_000)); setting.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; - setting.save(); - loadWhitelistTokenHourlySnapshot(event.params.token, getCurrentSeason(event.address), event.block.timestamp); - loadWhitelistTokenDailySnapshot(event.params.token, event.block.timestamp); + takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); + setting.save(); let id = "whitelistToken-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); let rawEvent = new WhitelistTokenEntity(id); @@ -511,15 +509,7 @@ export function handleUpdatedStalkPerBdvPerSeason(event: UpdatedStalkPerBdvPerSe siloSettings.milestoneSeason = event.params.season.toI32(); siloSettings.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; siloSettings.updatedAt = event.block.timestamp; - siloSettings.save(); - - let hourly = loadWhitelistTokenHourlySnapshot(event.params.token, event.params.season.toI32(), event.block.timestamp); - hourly.milestoneSeason = siloSettings.milestoneSeason; - hourly.stalkEarnedPerSeason = siloSettings.stalkEarnedPerSeason; - hourly.save(); - let daily = loadWhitelistTokenDailySnapshot(event.params.token, event.block.timestamp); - daily.milestoneSeason = siloSettings.milestoneSeason; - daily.stalkEarnedPerSeason = siloSettings.stalkEarnedPerSeason; - daily.save(); + takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); + siloSettings.save(); } diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index 23a43388db..f2210860b3 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -1,33 +1,25 @@ import { Address, BigInt, BigDecimal, ethereum } from "@graphprotocol/graph-ts"; -import { Field, FieldDailySnapshot, FieldHourlySnapshot, Plot } from "../../generated/schema"; -import { BI_MAX, ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { Field, Plot } from "../../generated/schema"; +import { ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { ADDRESS_ZERO, BEANSTALK, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; import { CurvePrice } from "../../generated/Beanstalk-ABIs/CurvePrice"; import { BeanstalkPrice_try_price } from "./contracts/BeanstalkPrice"; import { loadBeanstalk, loadSeason } from "./Beanstalk"; -import { dayFromTimestamp } from "../../../subgraph-core/utils/Dates"; +import { setHourlyCaseId, takeFieldSnapshots } from "./snapshots/Field"; // This function is for handling both the WeatherChange and TemperatureChange events. // The logic is the same for both, this is intended to accommodate the renamed event and fields. -export function handleRateChange(evtAddress: Address, evtBlock: ethereum.Block, season: BigInt, caseId: BigInt, absChange: i32): void { - let field = loadField(evtAddress); - let fieldHourly = loadFieldHourly(evtAddress, season.toI32(), evtBlock.timestamp); - let fieldDaily = loadFieldDaily(evtAddress, evtBlock.timestamp); - +export function handleRateChange(protocol: Address, evtBlock: ethereum.Block, season: BigInt, caseId: BigInt, absChange: i32): void { + let field = loadField(protocol); field.temperature += absChange; - fieldHourly.temperature += absChange; - fieldDaily.temperature += absChange; - - fieldHourly.caseId = caseId; - - let seasonEntity = loadSeason(evtAddress, season); + let seasonEntity = loadSeason(protocol, season); let currentPrice = ZERO_BD; if (seasonEntity.price != ZERO_BD) { currentPrice = seasonEntity.price; } else { // Attempt to pull from Beanstalk Price contract first - let beanstalkQuery = BeanstalkPrice_try_price(evtAddress, evtBlock.number); + let beanstalkQuery = BeanstalkPrice_try_price(protocol, evtBlock.number); if (beanstalkQuery.reverted) { let curvePrice = CurvePrice.bind(CURVE_PRICE); currentPrice = toDecimal(curvePrice.getCurve().price); @@ -37,12 +29,12 @@ export function handleRateChange(evtAddress: Address, evtBlock: ethereum.Block, } field.realRateOfReturn = ONE_BD.plus(BigDecimal.fromString((field.temperature / 100).toString())).div(currentPrice); - fieldHourly.realRateOfReturn = field.realRateOfReturn; - fieldHourly.realRateOfReturn = field.realRateOfReturn; + takeFieldSnapshots(field, protocol, evtBlock.timestamp, evtBlock.number); field.save(); - fieldHourly.save(); - fieldDaily.save(); + + // Set caseId on the hourly snapshot + setHourlyCaseId(caseId, field, protocol); } export function loadField(account: Address): Field { @@ -104,76 +96,3 @@ export function loadPlot(diamondAddress: Address, index: BigInt): Plot { } return plot; } - -export function loadFieldHourly(account: Address, season: i32, timestamp: BigInt): FieldHourlySnapshot { - // Hourly for Beanstalk is assumed to be by season. To keep other data correctly divided - // by season, we elect to use the season number for the hour number. - let id = account.toHexString() + "-" + season.toString(); - let hourly = FieldHourlySnapshot.load(id); - if (hourly == null) { - let field = loadField(account); - hourly = new FieldHourlySnapshot(id); - hourly.field = field.id; - hourly.season = season; - hourly.temperature = field.temperature; - hourly.realRateOfReturn = ZERO_BD; - hourly.podIndex = field.podIndex; - hourly.deltaNumberOfSowers = 0; - hourly.numberOfSowers = field.numberOfSowers; - hourly.deltaNumberOfSows = 0; - hourly.numberOfSows = field.numberOfSows; - hourly.deltaSownBeans = ZERO_BI; - hourly.sownBeans = field.sownBeans; - hourly.deltaUnharvestablePods = ZERO_BI; - hourly.unharvestablePods = field.unharvestablePods; - hourly.deltaHarvestablePods = ZERO_BI; - hourly.harvestablePods = field.harvestablePods; - hourly.deltaHarvestedPods = ZERO_BI; - hourly.harvestedPods = field.harvestedPods; - hourly.issuedSoil = ZERO_BI; - hourly.soil = ZERO_BI; - hourly.podRate = field.podRate; - hourly.blocksToSoldOutSoil = ZERO_BI; - hourly.soilSoldOut = false; - hourly.caseId = BI_MAX; - hourly.blockNumber = ZERO_BI; - hourly.createdAt = timestamp; - hourly.updatedAt = timestamp; - hourly.save(); - } - return hourly; -} - -export function loadFieldDaily(account: Address, timestamp: BigInt): FieldDailySnapshot { - let hour = dayFromTimestamp(timestamp); - let id = account.toHexString() + "-" + hour.toString(); - let daily = FieldDailySnapshot.load(id); - if (daily == null) { - let field = loadField(account); - daily = new FieldDailySnapshot(id); - daily.field = field.id; - daily.season = field.season; - daily.temperature = field.temperature; - daily.realRateOfReturn = ZERO_BD; - daily.podIndex = field.podIndex; - daily.deltaNumberOfSowers = 0; - daily.numberOfSowers = field.numberOfSowers; - daily.deltaNumberOfSows = 0; - daily.numberOfSows = field.numberOfSows; - daily.deltaSownBeans = ZERO_BI; - daily.sownBeans = field.sownBeans; - daily.deltaUnharvestablePods = ZERO_BI; - daily.unharvestablePods = field.unharvestablePods; - daily.deltaHarvestablePods = ZERO_BI; - daily.harvestablePods = field.harvestablePods; - daily.deltaHarvestedPods = ZERO_BI; - daily.harvestedPods = field.harvestedPods; - daily.issuedSoil = ZERO_BI; - daily.soil = ZERO_BI; - daily.podRate = field.podRate; - daily.createdAt = timestamp; - daily.updatedAt = timestamp; - daily.save(); - } - return daily; -} diff --git a/projects/subgraph-beanstalk/src/utils/PodListing.ts b/projects/subgraph-beanstalk/src/utils/PodListing.ts index ee94cec930..d1ede5e444 100644 --- a/projects/subgraph-beanstalk/src/utils/PodListing.ts +++ b/projects/subgraph-beanstalk/src/utils/PodListing.ts @@ -2,7 +2,8 @@ import { Address, BigInt, log } from "@graphprotocol/graph-ts"; import { PodListing } from "../../generated/schema"; import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { loadPodMarketplace, loadPodMarketplaceDailySnapshot, loadPodMarketplaceHourlySnapshot } from "./PodMarketplace"; +import { loadPodMarketplace } from "./PodMarketplace"; +import { takeMarketSnapshots } from "./snapshots/Marketplace"; export function loadPodListing(account: Address, index: BigInt): PodListing { let id = account.toHexString() + "-" + index.toString(); @@ -44,7 +45,7 @@ export function loadPodListing(account: Address, index: BigInt): PodListing { } export function expirePodListingIfExists( - diamondAddress: Address, + protocol: Address, farmer: string, listedPlotIndex: BigInt, timestamp: BigInt, @@ -57,7 +58,7 @@ export function expirePodListingIfExists( listing.status = "EXPIRED"; listing.save(); - let market = loadPodMarketplace(diamondAddress); + let market = loadPodMarketplace(protocol); if (activeListingIndex == -1) { // There should always be a matching entry in this list because it is verified that the listing is ACTIVE @@ -71,29 +72,14 @@ export function expirePodListingIfExists( } } - let marketHourly = loadPodMarketplaceHourlySnapshot(diamondAddress, market.season, timestamp); - let marketDaily = loadPodMarketplaceDailySnapshot(diamondAddress, timestamp); - market.expiredListedPods = market.expiredListedPods.plus(listing.remainingAmount); market.availableListedPods = market.availableListedPods.minus(listing.remainingAmount); let activeListings = market.activeListings; activeListings.splice(activeListingIndex, 1); market.activeListings = activeListings; - market.save(); - marketHourly.season = market.season; - marketHourly.deltaExpiredListedPods = marketHourly.deltaExpiredListedPods.plus(listing.remainingAmount); - marketHourly.expiredListedPods = market.expiredListedPods; - marketHourly.deltaAvailableListedPods = marketHourly.deltaAvailableListedPods.minus(listing.remainingAmount); - marketHourly.availableListedPods = market.availableListedPods; - marketHourly.save(); - - marketDaily.season = market.season; - marketDaily.deltaExpiredListedPods = marketDaily.deltaExpiredListedPods.plus(listing.remainingAmount); - marketDaily.expiredListedPods = market.expiredListedPods; - marketDaily.deltaAvailableListedPods = marketDaily.deltaAvailableListedPods.minus(listing.remainingAmount); - marketDaily.availableListedPods = market.availableListedPods; - marketDaily.save(); + takeMarketSnapshots(market, protocol, timestamp); + market.save(); } export function createHistoricalPodListing(listing: PodListing): void { diff --git a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts b/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts index 717528be54..deadc82333 100644 --- a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts +++ b/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts @@ -1,9 +1,9 @@ import { Address, BigInt, log } from "@graphprotocol/graph-ts"; -import { PodMarketplace, PodMarketplaceHourlySnapshot, PodMarketplaceDailySnapshot, PodFill } from "../../generated/schema"; +import { PodMarketplace, PodFill } from "../../generated/schema"; import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { loadField } from "./Field"; import { expirePodListingIfExists } from "./PodListing"; -import { dayFromTimestamp } from "../../../subgraph-core/utils/Dates"; +import { takeMarketSnapshots } from "./snapshots/Marketplace"; export enum MarketplaceAction { CREATED, @@ -57,88 +57,8 @@ export function loadPodFill(diamondAddress: Address, index: BigInt, hash: String return fill; } -export function loadPodMarketplaceHourlySnapshot(diamondAddress: Address, season: i32, timestamp: BigInt): PodMarketplaceHourlySnapshot { - // Hourly for Beanstalk is assumed to be by season. To keep other data correctly divided - // by season, we elect to use the season number for the hour number. - let id = diamondAddress.toHexString() + "-" + season.toString(); - let marketplace = loadPodMarketplace(diamondAddress); - let snapshot = PodMarketplaceHourlySnapshot.load(id); - if (snapshot == null) { - snapshot = new PodMarketplaceHourlySnapshot(id); - snapshot.season = marketplace.season; - snapshot.podMarketplace = diamondAddress.toHexString(); - snapshot.deltaListedPods = ZERO_BI; - snapshot.listedPods = marketplace.listedPods; - snapshot.deltaAvailableListedPods = ZERO_BI; - snapshot.availableListedPods = marketplace.availableListedPods; - snapshot.deltaFilledListedPods = ZERO_BI; - snapshot.filledListedPods = marketplace.filledListedPods; - snapshot.deltaExpiredListedPods = ZERO_BI; - snapshot.expiredListedPods = marketplace.expiredListedPods; - snapshot.deltaCancelledListedPods = ZERO_BI; - snapshot.cancelledListedPods = marketplace.cancelledListedPods; - snapshot.deltaOrderBeans = ZERO_BI; - snapshot.orderBeans = marketplace.orderBeans; - snapshot.deltaAvailableOrderBeans = ZERO_BI; - snapshot.availableOrderBeans = marketplace.availableOrderBeans; - snapshot.deltaFilledOrderedPods = ZERO_BI; - snapshot.filledOrderedPods = marketplace.filledOrderedPods; - snapshot.deltaFilledOrderBeans = ZERO_BI; - snapshot.filledOrderBeans = marketplace.filledOrderBeans; - snapshot.deltaCancelledOrderBeans = ZERO_BI; - snapshot.cancelledOrderBeans = marketplace.cancelledOrderBeans; - snapshot.deltaPodVolume = ZERO_BI; - snapshot.podVolume = marketplace.podVolume; - snapshot.deltaBeanVolume = ZERO_BI; - snapshot.beanVolume = marketplace.beanVolume; - snapshot.createdAt = timestamp; - snapshot.updatedAt = timestamp; - snapshot.save(); - } - return snapshot; -} - -export function loadPodMarketplaceDailySnapshot(diamondAddress: Address, timestamp: BigInt): PodMarketplaceDailySnapshot { - let day = dayFromTimestamp(timestamp); - let id = diamondAddress.toHexString() + "-" + day.toString(); - let marketplace = loadPodMarketplace(diamondAddress); - let snapshot = PodMarketplaceDailySnapshot.load(id); - if (snapshot == null) { - snapshot = new PodMarketplaceDailySnapshot(id); - snapshot.season = marketplace.season; - snapshot.podMarketplace = diamondAddress.toHexString(); - snapshot.deltaListedPods = ZERO_BI; - snapshot.listedPods = marketplace.listedPods; - snapshot.deltaAvailableListedPods = ZERO_BI; - snapshot.availableListedPods = marketplace.availableListedPods; - snapshot.deltaFilledListedPods = ZERO_BI; - snapshot.filledListedPods = marketplace.filledListedPods; - snapshot.deltaExpiredListedPods = ZERO_BI; - snapshot.expiredListedPods = marketplace.expiredListedPods; - snapshot.deltaCancelledListedPods = ZERO_BI; - snapshot.cancelledListedPods = marketplace.cancelledListedPods; - snapshot.deltaOrderBeans = ZERO_BI; - snapshot.orderBeans = marketplace.orderBeans; - snapshot.deltaAvailableOrderBeans = ZERO_BI; - snapshot.availableOrderBeans = marketplace.availableOrderBeans; - snapshot.deltaFilledOrderedPods = ZERO_BI; - snapshot.filledOrderedPods = marketplace.filledOrderedPods; - snapshot.deltaFilledOrderBeans = ZERO_BI; - snapshot.filledOrderBeans = marketplace.filledOrderBeans; - snapshot.deltaCancelledOrderBeans = ZERO_BI; - snapshot.cancelledOrderBeans = marketplace.cancelledOrderBeans; - snapshot.deltaPodVolume = ZERO_BI; - snapshot.podVolume = marketplace.podVolume; - snapshot.deltaBeanVolume = ZERO_BI; - snapshot.beanVolume = marketplace.beanVolume; - snapshot.createdAt = timestamp; - snapshot.updatedAt = timestamp; - snapshot.save(); - } - return snapshot; -} - export function updateMarketListingBalances( + protocol: Address, marketAddress: Address, newPodAmount: BigInt, cancelledPodAmount: BigInt, @@ -147,8 +67,6 @@ export function updateMarketListingBalances( timestamp: BigInt ): void { let market = loadPodMarketplace(marketAddress); - let marketHourly = loadPodMarketplaceHourlySnapshot(marketAddress, market.season, timestamp); - let marketDaily = loadPodMarketplaceDailySnapshot(marketAddress, timestamp); const netListingChange = newPodAmount.minus(cancelledPodAmount).minus(filledPodAmount); @@ -158,42 +76,13 @@ export function updateMarketListingBalances( market.filledListedPods = market.filledListedPods.plus(filledPodAmount); market.podVolume = market.podVolume.plus(filledPodAmount); market.beanVolume = market.beanVolume.plus(filledBeanAmount); - market.save(); - marketHourly.season = market.season; - marketHourly.deltaListedPods = marketHourly.deltaListedPods.plus(newPodAmount); - marketHourly.listedPods = market.listedPods; - marketHourly.deltaAvailableListedPods = marketHourly.deltaAvailableListedPods.plus(netListingChange); - marketHourly.availableListedPods = market.availableListedPods; - marketHourly.deltaCancelledListedPods = marketHourly.deltaCancelledListedPods.plus(cancelledPodAmount); - marketHourly.cancelledListedPods = market.cancelledListedPods; - marketHourly.deltaFilledListedPods = marketHourly.deltaFilledListedPods.plus(filledPodAmount); - marketHourly.filledListedPods = market.filledListedPods; - marketHourly.deltaPodVolume = marketHourly.deltaPodVolume.plus(filledPodAmount); - marketHourly.podVolume = market.podVolume; - marketHourly.deltaBeanVolume = marketHourly.deltaBeanVolume.plus(filledBeanAmount); - marketHourly.beanVolume = market.beanVolume; - marketHourly.updatedAt = timestamp; - marketHourly.save(); - - marketDaily.season = market.season; - marketDaily.deltaListedPods = marketDaily.deltaListedPods.plus(newPodAmount); - marketDaily.listedPods = market.listedPods; - marketDaily.deltaAvailableListedPods = marketDaily.deltaAvailableListedPods.plus(netListingChange); - marketDaily.availableListedPods = market.availableListedPods; - marketDaily.deltaCancelledListedPods = marketDaily.deltaCancelledListedPods.plus(cancelledPodAmount); - marketDaily.cancelledListedPods = market.cancelledListedPods; - marketDaily.deltaFilledListedPods = marketDaily.deltaFilledListedPods.plus(filledPodAmount); - marketDaily.filledListedPods = market.filledListedPods; - marketDaily.deltaPodVolume = marketDaily.deltaPodVolume.plus(filledPodAmount); - marketDaily.podVolume = market.podVolume; - marketDaily.deltaBeanVolume = marketDaily.deltaBeanVolume.plus(filledBeanAmount); - marketDaily.beanVolume = market.beanVolume; - marketDaily.updatedAt = timestamp; - marketDaily.save(); + takeMarketSnapshots(market, protocol, timestamp); + market.save(); } export function updateMarketOrderBalances( + protocol: Address, marketAddress: Address, newBeanAmount: BigInt, cancelledBeanAmount: BigInt, @@ -202,8 +91,6 @@ export function updateMarketOrderBalances( timestamp: BigInt ): void { let market = loadPodMarketplace(marketAddress); - let marketHourly = loadPodMarketplaceHourlySnapshot(marketAddress, market.season, timestamp); - let marketDaily = loadPodMarketplaceDailySnapshot(marketAddress, timestamp); const netOrderChange = newBeanAmount.minus(cancelledBeanAmount).minus(filledBeanAmount); @@ -214,45 +101,13 @@ export function updateMarketOrderBalances( market.podVolume = market.podVolume.plus(filledPodAmount); market.beanVolume = market.beanVolume.plus(filledBeanAmount); market.cancelledOrderBeans = market.cancelledOrderBeans.plus(cancelledBeanAmount); - market.save(); - - marketHourly.deltaOrderBeans = marketHourly.deltaOrderBeans.plus(newBeanAmount); - marketHourly.orderBeans = market.orderBeans; - marketHourly.deltaAvailableOrderBeans = marketHourly.deltaAvailableOrderBeans.plus(netOrderChange); - marketHourly.availableOrderBeans = market.availableOrderBeans; - marketHourly.deltaFilledOrderedPods = marketHourly.deltaFilledOrderedPods.plus(filledPodAmount); - marketHourly.filledOrderedPods = market.filledOrderedPods; - marketHourly.deltaFilledOrderBeans = marketHourly.deltaFilledOrderBeans.plus(filledBeanAmount); - marketHourly.filledOrderBeans = market.filledOrderBeans; - marketHourly.deltaPodVolume = marketHourly.deltaPodVolume.plus(filledPodAmount); - marketHourly.podVolume = market.podVolume; - marketHourly.deltaBeanVolume = marketHourly.deltaBeanVolume.plus(filledBeanAmount); - marketHourly.beanVolume = market.beanVolume; - marketHourly.deltaCancelledOrderBeans = marketHourly.deltaCancelledOrderBeans.plus(cancelledBeanAmount); - marketHourly.cancelledOrderBeans = market.cancelledOrderBeans; - marketHourly.updatedAt = timestamp; - marketHourly.save(); - marketDaily.deltaOrderBeans = marketDaily.deltaOrderBeans.plus(newBeanAmount); - marketDaily.orderBeans = market.orderBeans; - marketDaily.deltaAvailableOrderBeans = marketHourly.deltaAvailableOrderBeans.plus(netOrderChange); - marketDaily.availableOrderBeans = market.availableOrderBeans; - marketDaily.deltaFilledOrderedPods = marketDaily.deltaFilledOrderedPods.plus(filledPodAmount); - marketDaily.filledOrderedPods = market.filledOrderedPods; - marketDaily.deltaFilledOrderBeans = marketHourly.deltaFilledOrderBeans.plus(filledBeanAmount); - marketDaily.filledOrderBeans = market.filledOrderBeans; - marketDaily.deltaPodVolume = marketDaily.deltaPodVolume.plus(filledPodAmount); - marketDaily.podVolume = market.podVolume; - marketDaily.deltaBeanVolume = marketDaily.deltaBeanVolume.plus(filledBeanAmount); - marketDaily.beanVolume = market.beanVolume; - marketDaily.deltaCancelledOrderBeans = marketDaily.deltaCancelledOrderBeans.plus(cancelledBeanAmount); - marketDaily.cancelledOrderBeans = market.cancelledOrderBeans; - marketDaily.updatedAt = timestamp; - marketDaily.save(); + takeMarketSnapshots(market, protocol, timestamp); + market.save(); } -export function updateExpiredPlots(harvestableIndex: BigInt, diamondAddress: Address, timestamp: BigInt): void { - let market = loadPodMarketplace(diamondAddress); +export function updateExpiredPlots(protocol: Address, harvestableIndex: BigInt, timestamp: BigInt): void { + let market = loadPodMarketplace(protocol); let remainingListings = market.activeListings; // Cancel any pod marketplace listings beyond the index @@ -261,7 +116,7 @@ export function updateExpiredPlots(harvestableIndex: BigInt, diamondAddress: Add const maxHarvestableIndex = BigInt.fromString(destructured[2]); if (harvestableIndex > maxHarvestableIndex) { // This method updates the marketplace entity, so it will perform the splice. - expirePodListingIfExists(diamondAddress, destructured[0], BigInt.fromString(destructured[1]), timestamp, i); + expirePodListingIfExists(protocol, destructured[0], BigInt.fromString(destructured[1]), timestamp, i); // A similar splice is done here also to track the updated index on the underlying array. remainingListings.splice(i--, 1); } @@ -269,13 +124,13 @@ export function updateExpiredPlots(harvestableIndex: BigInt, diamondAddress: Add } export function updateActiveListings( - diamondAddress: Address, + protocol: Address, action: MarketplaceAction, farmer: string, plotIndex: BigInt, expiryIndex: BigInt ): void { - let market = loadPodMarketplace(diamondAddress); + let market = loadPodMarketplace(protocol); let listings = market.activeListings; if (action == MarketplaceAction.CREATED) { diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index e7059da935..dfe135431f 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -94,53 +94,6 @@ export function loadWhitelistTokenSetting(token: Address): WhitelistTokenSetting return setting as WhitelistTokenSetting; } -export function loadWhitelistTokenHourlySnapshot(token: Address, season: i32, timestamp: BigInt): WhitelistTokenHourlySnapshot { - let hour = hourFromTimestamp(timestamp); - let id = token.toHexString() + "-" + season.toString(); - let snapshot = WhitelistTokenHourlySnapshot.load(id); - if (snapshot == null) { - let setting = loadWhitelistTokenSetting(token); - snapshot = new WhitelistTokenHourlySnapshot(id); - snapshot.season = season; - snapshot.token = setting.id; - snapshot.selector = setting.selector; - snapshot.gpSelector = setting.gpSelector; - snapshot.lwSelector = setting.lwSelector; - snapshot.stalkEarnedPerSeason = setting.stalkEarnedPerSeason; - snapshot.stalkIssuedPerBdv = setting.stalkIssuedPerBdv; - snapshot.milestoneSeason = setting.milestoneSeason; - snapshot.gaugePoints = setting.gaugePoints; - snapshot.optimalPercentDepositedBdv = setting.optimalPercentDepositedBdv; - snapshot.createdAt = BigInt.fromI32(hour); - snapshot.updatedAt = ZERO_BI; - snapshot.save(); - } - return snapshot as WhitelistTokenHourlySnapshot; -} - -export function loadWhitelistTokenDailySnapshot(token: Address, timestamp: BigInt): WhitelistTokenDailySnapshot { - let day = dayFromTimestamp(timestamp); - let id = token.toHexString() + "-" + day.toString(); - let snapshot = WhitelistTokenDailySnapshot.load(id); - if (snapshot == null) { - let setting = loadWhitelistTokenSetting(token); - snapshot = new WhitelistTokenDailySnapshot(id); - snapshot.token = setting.id; - snapshot.selector = setting.selector; - snapshot.gpSelector = setting.gpSelector; - snapshot.lwSelector = setting.lwSelector; - snapshot.stalkEarnedPerSeason = setting.stalkEarnedPerSeason; - snapshot.stalkIssuedPerBdv = setting.stalkIssuedPerBdv; - snapshot.milestoneSeason = setting.milestoneSeason; - snapshot.gaugePoints = setting.gaugePoints; - snapshot.optimalPercentDepositedBdv = setting.optimalPercentDepositedBdv; - snapshot.createdAt = BigInt.fromI32(day); - snapshot.updatedAt = ZERO_BI; - snapshot.save(); - } - return snapshot as WhitelistTokenDailySnapshot; -} - /* ===== Deposit Entities ===== */ class SiloDepositID { diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Field.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Field.ts new file mode 100644 index 0000000000..cd56e52d68 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Field.ts @@ -0,0 +1,200 @@ +import { BigInt, Address, log } from "@graphprotocol/graph-ts"; +import { Field, FieldDailySnapshot, FieldHourlySnapshot } from "../../../generated/schema"; +import { getCurrentSeason } from "../Beanstalk"; +import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; +import { BI_MAX, ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; + +export function takeFieldSnapshots(field: Field, protocol: Address, timestamp: BigInt, blockNumber: BigInt): void { + const currentSeason = getCurrentSeason(protocol); + + const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); + const day = BigInt.fromI32(dayFromTimestamp(timestamp)); + + // Load the snapshot for this season/day + const hourlyId = field.id + "-" + currentSeason.toString(); + const dailyId = field.id + "-" + day.toString(); + let baseHourly = FieldHourlySnapshot.load(hourlyId); + let baseDaily = FieldDailySnapshot.load(dailyId); + if (baseHourly == null && field.lastHourlySnapshotSeason !== 0) { + baseHourly = FieldHourlySnapshot.load(field.id + "-" + field.lastHourlySnapshotSeason.toString()); + } + if (baseDaily == null && field.lastDailySnapshotDay !== null) { + baseDaily = FieldDailySnapshot.load(field.id + "-" + field.lastDailySnapshotDay!.toString()); + } + const hourly = new FieldHourlySnapshot(hourlyId); + const daily = new FieldDailySnapshot(dailyId); + + // Set current values + hourly.season = currentSeason; + hourly.field = field.id; + hourly.temperature = field.temperature; + hourly.realRateOfReturn = field.realRateOfReturn; + hourly.numberOfSowers = field.numberOfSowers; + hourly.numberOfSows = field.numberOfSows; + hourly.sownBeans = field.sownBeans; + hourly.unharvestablePods = field.unharvestablePods; + hourly.harvestablePods = field.harvestablePods; + hourly.harvestedPods = field.harvestedPods; + hourly.soil = field.soil; + // issuedSoil set below, on initial snapshot + hourly.podIndex = field.podIndex; + hourly.podRate = field.podRate; + + // Set deltas + if (baseHourly !== null) { + hourly.deltaTemperature = hourly.temperature - baseHourly.temperature; + hourly.deltaRealRateOfReturn = hourly.realRateOfReturn.minus(baseHourly.realRateOfReturn); + hourly.deltaNumberOfSowers = hourly.numberOfSowers - baseHourly.numberOfSowers; + hourly.deltaNumberOfSows = hourly.numberOfSows - baseHourly.numberOfSows; + hourly.deltaSownBeans = hourly.sownBeans.minus(baseHourly.sownBeans); + hourly.deltaUnharvestablePods = hourly.unharvestablePods.minus(baseHourly.unharvestablePods); + hourly.deltaHarvestablePods = hourly.harvestablePods.minus(baseHourly.harvestablePods); + hourly.deltaHarvestedPods = hourly.harvestedPods.minus(baseHourly.harvestedPods); + hourly.deltaSoil = hourly.soil.minus(baseHourly.soil); + // deltaIssuedSoil set below, on initial snapshot + hourly.deltaPodIndex = hourly.podIndex.minus(baseHourly.podIndex); + hourly.deltaPodRate = hourly.podRate.minus(baseHourly.podRate); + + if (hourly.id == baseHourly.id) { + // Add existing deltas + hourly.deltaTemperature = hourly.deltaTemperature + baseHourly.deltaTemperature; + hourly.deltaRealRateOfReturn = hourly.deltaRealRateOfReturn.plus(baseHourly.deltaRealRateOfReturn); + hourly.deltaNumberOfSowers = hourly.deltaNumberOfSowers + baseHourly.deltaNumberOfSowers; + hourly.deltaNumberOfSows = hourly.deltaNumberOfSows + baseHourly.deltaNumberOfSows; + hourly.deltaSownBeans = hourly.deltaSownBeans.plus(baseHourly.deltaSownBeans); + hourly.deltaUnharvestablePods = hourly.deltaUnharvestablePods.plus(baseHourly.deltaUnharvestablePods); + hourly.deltaHarvestablePods = hourly.deltaHarvestablePods.plus(baseHourly.deltaHarvestablePods); + hourly.deltaHarvestedPods = hourly.deltaHarvestedPods.plus(baseHourly.deltaHarvestedPods); + hourly.deltaSoil = hourly.deltaSoil.plus(baseHourly.deltaSoil); + hourly.deltaPodIndex = hourly.deltaPodIndex.plus(baseHourly.deltaPodIndex); + hourly.deltaPodRate = hourly.deltaPodRate.plus(baseHourly.deltaPodRate); + // Carry over unset values that would otherwise get erased + hourly.issuedSoil = baseHourly.issuedSoil; + hourly.deltaIssuedSoil = baseHourly.deltaIssuedSoil; + hourly.seasonBlock = baseHourly.seasonBlock; + hourly.caseId = baseHourly.caseId; + hourly.soilSoldOut = baseHourly.soilSoldOut; + hourly.blocksToSoldOutSoil = baseHourly.blocksToSoldOutSoil; + } else { + // Sets initial creation values + hourly.issuedSoil = field.soil; + hourly.deltaIssuedSoil = field.soil.minus(baseHourly.issuedSoil); + hourly.seasonBlock = blockNumber; + hourly.soilSoldOut = false; + } + } else { + hourly.deltaTemperature = hourly.temperature; + hourly.deltaRealRateOfReturn = hourly.realRateOfReturn; + hourly.deltaNumberOfSowers = hourly.numberOfSowers; + hourly.deltaNumberOfSows = hourly.numberOfSows; + hourly.deltaSownBeans = hourly.sownBeans; + hourly.deltaUnharvestablePods = hourly.unharvestablePods; + hourly.deltaHarvestablePods = hourly.harvestablePods; + hourly.deltaHarvestedPods = hourly.harvestedPods; + hourly.deltaSoil = hourly.soil; + hourly.deltaPodIndex = hourly.podIndex; + hourly.deltaPodRate = hourly.podRate; + + // Sets initial creation values + hourly.issuedSoil = field.soil; + hourly.deltaIssuedSoil = field.soil; + hourly.seasonBlock = blockNumber; + hourly.soilSoldOut = false; + } + hourly.createdAt = hour; + hourly.updatedAt = timestamp; + hourly.save(); + + // Repeat for daily snapshot. + // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + + daily.season = currentSeason; + daily.field = field.id; + daily.temperature = field.temperature; + daily.realRateOfReturn = field.realRateOfReturn; + daily.numberOfSowers = field.numberOfSowers; + daily.numberOfSows = field.numberOfSows; + daily.sownBeans = field.sownBeans; + daily.unharvestablePods = field.unharvestablePods; + daily.harvestablePods = field.harvestablePods; + daily.harvestedPods = field.harvestedPods; + daily.soil = field.soil; + // issuedSoil set below, on initial snapshot + daily.podIndex = field.podIndex; + daily.podRate = field.podRate; + if (baseDaily !== null) { + daily.deltaTemperature = daily.temperature - baseDaily.temperature; + daily.deltaRealRateOfReturn = daily.realRateOfReturn.minus(baseDaily.realRateOfReturn); + daily.deltaNumberOfSowers = daily.numberOfSowers - baseDaily.numberOfSowers; + daily.deltaNumberOfSows = daily.numberOfSows - baseDaily.numberOfSows; + daily.deltaSownBeans = daily.sownBeans.minus(baseDaily.sownBeans); + daily.deltaUnharvestablePods = daily.unharvestablePods.minus(baseDaily.unharvestablePods); + daily.deltaHarvestablePods = daily.harvestablePods.minus(baseDaily.harvestablePods); + daily.deltaHarvestedPods = daily.harvestedPods.minus(baseDaily.harvestedPods); + daily.deltaSoil = daily.soil.minus(baseDaily.soil); + // deltaIssuedSoil set below, on initial snapshot + daily.deltaPodIndex = daily.podIndex.minus(baseDaily.podIndex); + daily.deltaPodRate = daily.podRate.minus(baseDaily.podRate); + + if (daily.id == baseDaily.id) { + // Add existing deltas + daily.deltaTemperature = daily.deltaTemperature + baseDaily.deltaTemperature; + daily.deltaRealRateOfReturn = daily.deltaRealRateOfReturn.plus(baseDaily.deltaRealRateOfReturn); + daily.deltaNumberOfSowers = daily.deltaNumberOfSowers + baseDaily.deltaNumberOfSowers; + daily.deltaNumberOfSows = daily.deltaNumberOfSows + baseDaily.deltaNumberOfSows; + daily.deltaSownBeans = daily.deltaSownBeans.plus(baseDaily.deltaSownBeans); + daily.deltaUnharvestablePods = daily.deltaUnharvestablePods.plus(baseDaily.deltaUnharvestablePods); + daily.deltaHarvestablePods = daily.deltaHarvestablePods.plus(baseDaily.deltaHarvestablePods); + daily.deltaHarvestedPods = daily.deltaHarvestedPods.plus(baseDaily.deltaHarvestedPods); + daily.deltaSoil = daily.deltaSoil.plus(baseDaily.deltaSoil); + daily.deltaPodIndex = daily.deltaPodIndex.plus(baseDaily.deltaPodIndex); + daily.deltaPodRate = daily.deltaPodRate.plus(baseDaily.deltaPodRate); + // Carry over existing values + daily.issuedSoil = baseDaily.issuedSoil; + daily.deltaIssuedSoil = baseDaily.deltaIssuedSoil; + } else { + // Sets issued soil here since this is the initial creation + daily.issuedSoil = field.soil; + daily.deltaIssuedSoil = field.soil.minus(baseDaily.issuedSoil); + } + } else { + daily.deltaTemperature = daily.temperature; + daily.deltaRealRateOfReturn = daily.realRateOfReturn; + daily.deltaNumberOfSowers = daily.numberOfSowers; + daily.deltaNumberOfSows = daily.numberOfSows; + daily.deltaSownBeans = daily.sownBeans; + daily.deltaUnharvestablePods = daily.unharvestablePods; + daily.deltaHarvestablePods = daily.harvestablePods; + daily.deltaHarvestedPods = daily.harvestedPods; + daily.deltaSoil = daily.soil; + daily.deltaPodIndex = daily.podIndex; + daily.deltaPodRate = daily.podRate; + + // Sets issued soil here since this is the initial creation + daily.issuedSoil = field.soil; + daily.deltaIssuedSoil = field.soil; + } + daily.createdAt = day; + daily.updatedAt = timestamp; + daily.save(); + + field.lastHourlySnapshotSeason = currentSeason; + field.lastDailySnapshotDay = day; +} + +// Set case id on hourly. Snapshot must have already been created. +export function setHourlyCaseId(caseId: BigInt, field: Field, protocol: Address): void { + const currentSeason = getCurrentSeason(protocol); + const hourly = FieldHourlySnapshot.load(field.id + "-" + currentSeason.toString())!; + hourly.caseId = caseId; + hourly.save(); +} + +// Set soil sold out info on the hourly. Snapshot must have already been created. +export function setHourlySoilSoldOut(soldOutBlock: BigInt, field: Field, protocol: Address): void { + const currentSeason = getCurrentSeason(protocol); + const hourly = FieldHourlySnapshot.load(field.id + "-" + currentSeason.toString())!; + hourly.blocksToSoldOutSoil = soldOutBlock.minus(hourly.seasonBlock); + hourly.soilSoldOut = true; + hourly.save(); +} diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Marketplace.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Marketplace.ts new file mode 100644 index 0000000000..d3203079f3 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Marketplace.ts @@ -0,0 +1,156 @@ +import { BigInt, Address, log } from "@graphprotocol/graph-ts"; +import { PodMarketplace, PodMarketplaceDailySnapshot, PodMarketplaceHourlySnapshot } from "../../../generated/schema"; +import { getCurrentSeason } from "../Beanstalk"; +import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; + +export function takeMarketSnapshots(market: PodMarketplace, protocol: Address, timestamp: BigInt): void { + const currentSeason = getCurrentSeason(protocol); + + const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); + const day = BigInt.fromI32(dayFromTimestamp(timestamp)); + + // Load the snapshot for this season/day + const hourlyId = market.id + "-" + currentSeason.toString(); + const dailyId = market.id + "-" + day.toString(); + let baseHourly = PodMarketplaceHourlySnapshot.load(hourlyId); + let baseDaily = PodMarketplaceDailySnapshot.load(dailyId); + if (baseHourly == null && market.lastHourlySnapshotSeason !== 0) { + baseHourly = PodMarketplaceHourlySnapshot.load(market.id + "-" + market.lastHourlySnapshotSeason.toString()); + } + if (baseDaily == null && market.lastDailySnapshotDay !== null) { + baseDaily = PodMarketplaceDailySnapshot.load(market.id + "-" + market.lastDailySnapshotDay!.toString()); + } + const hourly = new PodMarketplaceHourlySnapshot(hourlyId); + const daily = new PodMarketplaceDailySnapshot(dailyId); + + // Set current values + hourly.season = currentSeason; + hourly.podMarketplace = market.id; + hourly.listedPods = market.listedPods; + hourly.availableListedPods = market.availableListedPods; + hourly.filledListedPods = market.filledListedPods; + hourly.expiredListedPods = market.expiredListedPods; + hourly.cancelledListedPods = market.cancelledListedPods; + hourly.orderBeans = market.orderBeans; + hourly.availableOrderBeans = market.availableOrderBeans; + hourly.filledOrderBeans = market.filledOrderBeans; + hourly.filledOrderedPods = market.filledOrderedPods; + hourly.cancelledOrderBeans = market.cancelledOrderBeans; + hourly.podVolume = market.podVolume; + hourly.beanVolume = market.beanVolume; + + // Set deltas + if (baseHourly !== null) { + hourly.deltaListedPods = hourly.listedPods.minus(baseHourly.listedPods); + hourly.deltaAvailableListedPods = hourly.availableListedPods.minus(baseHourly.availableListedPods); + hourly.deltaFilledListedPods = hourly.filledListedPods.minus(baseHourly.filledListedPods); + hourly.deltaExpiredListedPods = hourly.expiredListedPods.minus(baseHourly.expiredListedPods); + hourly.deltaCancelledListedPods = hourly.cancelledListedPods.minus(baseHourly.cancelledListedPods); + hourly.deltaOrderBeans = hourly.orderBeans.minus(baseHourly.orderBeans); + hourly.deltaAvailableOrderBeans = hourly.availableOrderBeans.minus(baseHourly.availableOrderBeans); + hourly.deltaFilledOrderBeans = hourly.filledOrderBeans.minus(baseHourly.filledOrderBeans); + hourly.deltaFilledOrderedPods = hourly.filledOrderedPods.minus(baseHourly.filledOrderedPods); + hourly.deltaCancelledOrderBeans = hourly.cancelledOrderBeans.minus(baseHourly.cancelledOrderBeans); + hourly.deltaPodVolume = hourly.podVolume.minus(baseHourly.podVolume); + hourly.deltaBeanVolume = hourly.beanVolume.minus(baseHourly.beanVolume); + + if (hourly.id == baseHourly.id) { + // Add existing deltas + hourly.deltaListedPods = hourly.deltaListedPods.plus(baseHourly.deltaListedPods); + hourly.deltaAvailableListedPods = hourly.deltaAvailableListedPods.plus(baseHourly.deltaAvailableListedPods); + hourly.deltaFilledListedPods = hourly.deltaFilledListedPods.plus(baseHourly.deltaFilledListedPods); + hourly.deltaExpiredListedPods = hourly.deltaExpiredListedPods.plus(baseHourly.deltaExpiredListedPods); + hourly.deltaCancelledListedPods = hourly.deltaCancelledListedPods.plus(baseHourly.deltaCancelledListedPods); + hourly.deltaOrderBeans = hourly.deltaOrderBeans.plus(baseHourly.deltaOrderBeans); + hourly.deltaAvailableOrderBeans = hourly.deltaAvailableOrderBeans.plus(baseHourly.deltaAvailableOrderBeans); + hourly.deltaFilledOrderBeans = hourly.deltaFilledOrderBeans.plus(baseHourly.deltaFilledOrderBeans); + hourly.deltaFilledOrderedPods = hourly.deltaFilledOrderedPods.plus(baseHourly.deltaFilledOrderedPods); + hourly.deltaCancelledOrderBeans = hourly.deltaCancelledOrderBeans.plus(baseHourly.deltaCancelledOrderBeans); + hourly.deltaPodVolume = hourly.deltaPodVolume.plus(baseHourly.deltaPodVolume); + hourly.deltaBeanVolume = hourly.deltaBeanVolume.plus(baseHourly.deltaBeanVolume); + } + } else { + hourly.deltaListedPods = hourly.listedPods; + hourly.deltaAvailableListedPods = hourly.availableListedPods; + hourly.deltaFilledListedPods = hourly.filledListedPods; + hourly.deltaExpiredListedPods = hourly.expiredListedPods; + hourly.deltaCancelledListedPods = hourly.cancelledListedPods; + hourly.deltaOrderBeans = hourly.orderBeans; + hourly.deltaAvailableOrderBeans = hourly.availableOrderBeans; + hourly.deltaFilledOrderBeans = hourly.filledOrderBeans; + hourly.deltaFilledOrderedPods = hourly.filledOrderedPods; + hourly.deltaCancelledOrderBeans = hourly.cancelledOrderBeans; + hourly.deltaPodVolume = hourly.podVolume; + hourly.deltaBeanVolume = hourly.beanVolume; + } + hourly.createdAt = hour; + hourly.updatedAt = timestamp; + hourly.save(); + + // Repeat for daily snapshot. + // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + + daily.season = currentSeason; + daily.podMarketplace = market.id; + daily.listedPods = market.listedPods; + daily.availableListedPods = market.availableListedPods; + daily.filledListedPods = market.filledListedPods; + daily.expiredListedPods = market.expiredListedPods; + daily.cancelledListedPods = market.cancelledListedPods; + daily.orderBeans = market.orderBeans; + daily.availableOrderBeans = market.availableOrderBeans; + daily.filledOrderBeans = market.filledOrderBeans; + daily.filledOrderedPods = market.filledOrderedPods; + daily.cancelledOrderBeans = market.cancelledOrderBeans; + daily.podVolume = market.podVolume; + daily.beanVolume = market.beanVolume; + if (baseDaily !== null) { + daily.deltaListedPods = daily.listedPods.minus(baseDaily.listedPods); + daily.deltaAvailableListedPods = daily.availableListedPods.minus(baseDaily.availableListedPods); + daily.deltaFilledListedPods = daily.filledListedPods.minus(baseDaily.filledListedPods); + daily.deltaExpiredListedPods = daily.expiredListedPods.minus(baseDaily.expiredListedPods); + daily.deltaCancelledListedPods = daily.cancelledListedPods.minus(baseDaily.cancelledListedPods); + daily.deltaOrderBeans = daily.orderBeans.minus(baseDaily.orderBeans); + daily.deltaAvailableOrderBeans = daily.availableOrderBeans.minus(baseDaily.availableOrderBeans); + daily.deltaFilledOrderBeans = daily.filledOrderBeans.minus(baseDaily.filledOrderBeans); + daily.deltaFilledOrderedPods = daily.filledOrderedPods.minus(baseDaily.filledOrderedPods); + daily.deltaCancelledOrderBeans = daily.cancelledOrderBeans.minus(baseDaily.cancelledOrderBeans); + daily.deltaPodVolume = daily.podVolume.minus(baseDaily.podVolume); + daily.deltaBeanVolume = daily.beanVolume.minus(baseDaily.beanVolume); + + if (daily.id == baseDaily.id) { + // Add existing deltas + daily.deltaListedPods = daily.deltaListedPods.plus(baseDaily.deltaListedPods); + daily.deltaAvailableListedPods = daily.deltaAvailableListedPods.plus(baseDaily.deltaAvailableListedPods); + daily.deltaFilledListedPods = daily.deltaFilledListedPods.plus(baseDaily.deltaFilledListedPods); + daily.deltaExpiredListedPods = daily.deltaExpiredListedPods.plus(baseDaily.deltaExpiredListedPods); + daily.deltaCancelledListedPods = daily.deltaCancelledListedPods.plus(baseDaily.deltaCancelledListedPods); + daily.deltaOrderBeans = daily.deltaOrderBeans.plus(baseDaily.deltaOrderBeans); + daily.deltaAvailableOrderBeans = daily.deltaAvailableOrderBeans.plus(baseDaily.deltaAvailableOrderBeans); + daily.deltaFilledOrderBeans = daily.deltaFilledOrderBeans.plus(baseDaily.deltaFilledOrderBeans); + daily.deltaFilledOrderedPods = daily.deltaFilledOrderedPods.plus(baseDaily.deltaFilledOrderedPods); + daily.deltaCancelledOrderBeans = daily.deltaCancelledOrderBeans.plus(baseDaily.deltaCancelledOrderBeans); + daily.deltaPodVolume = daily.deltaPodVolume.plus(baseDaily.deltaPodVolume); + daily.deltaBeanVolume = daily.deltaBeanVolume.plus(baseDaily.deltaBeanVolume); + } + } else { + daily.deltaListedPods = daily.listedPods; + daily.deltaAvailableListedPods = daily.availableListedPods; + daily.deltaFilledListedPods = daily.filledListedPods; + daily.deltaExpiredListedPods = daily.expiredListedPods; + daily.deltaCancelledListedPods = daily.cancelledListedPods; + daily.deltaOrderBeans = daily.orderBeans; + daily.deltaAvailableOrderBeans = daily.availableOrderBeans; + daily.deltaFilledOrderBeans = daily.filledOrderBeans; + daily.deltaFilledOrderedPods = daily.filledOrderedPods; + daily.deltaCancelledOrderBeans = daily.cancelledOrderBeans; + daily.deltaPodVolume = daily.podVolume; + daily.deltaBeanVolume = daily.beanVolume; + } + daily.createdAt = day; + daily.updatedAt = timestamp; + daily.save(); + + market.lastHourlySnapshotSeason = currentSeason; + market.lastDailySnapshotDay = day; +} diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts index 321cba60a5..8ebcb4f1fd 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts @@ -1,12 +1,5 @@ import { BigInt, Address, log } from "@graphprotocol/graph-ts"; -import { - Silo, - SiloAsset, - SiloAssetDailySnapshot, - SiloAssetHourlySnapshot, - SiloDailySnapshot, - SiloHourlySnapshot -} from "../../../generated/schema"; +import { Silo, SiloDailySnapshot, SiloHourlySnapshot } from "../../../generated/schema"; import { getCurrentSeason } from "../Beanstalk"; import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; @@ -66,6 +59,8 @@ export function takeSiloSnapshots(silo: Silo, protocol: Address, timestamp: BigI // NOTE: missing beanToMaxLpGpPerBdvRatio hourly.deltaBeanMints = hourly.deltaBeanMints.plus(baseHourly.deltaBeanMints); hourly.deltaActiveFarmers = hourly.deltaActiveFarmers + baseHourly.deltaActiveFarmers; + // Carry over unset values that would otherwise get erased + hourly.caseId = baseHourly.caseId; } } else { hourly.deltaDepositedBDV = hourly.depositedBDV; @@ -138,98 +133,10 @@ export function takeSiloSnapshots(silo: Silo, protocol: Address, timestamp: BigI silo.lastDailySnapshotDay = day; } -// Set case id on hourly snapshot. assumption is that the snapshot was already created +// Set case id on hourly snapshot. Snapshot must have already been created. export function setHourlyCaseId(caseId: BigInt, silo: Silo, protocol: Address): void { const currentSeason = getCurrentSeason(protocol); const hourly = SiloHourlySnapshot.load(silo.id + "-" + currentSeason.toString())!; hourly.caseId = caseId; hourly.save(); } - -export function takeSiloAssetSnapshots(siloAsset: SiloAsset, protocol: Address, timestamp: BigInt): void { - const currentSeason = getCurrentSeason(protocol); - - const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); - const day = BigInt.fromI32(dayFromTimestamp(timestamp)); - - // Load the snapshot for this season/day - const hourlyId = siloAsset.id + "-" + currentSeason.toString(); - const dailyId = siloAsset.id + "-" + day.toString(); - let baseHourly = SiloAssetHourlySnapshot.load(hourlyId); - let baseDaily = SiloAssetDailySnapshot.load(dailyId); - if (baseHourly == null && siloAsset.lastHourlySnapshotSeason !== 0) { - baseHourly = SiloAssetHourlySnapshot.load(siloAsset.id + "-" + siloAsset.lastHourlySnapshotSeason.toString()); - } - if (baseDaily == null && siloAsset.lastDailySnapshotDay !== null) { - baseDaily = SiloAssetDailySnapshot.load(siloAsset.id + "-" + siloAsset.lastDailySnapshotDay!.toString()); - } - const hourly = new SiloAssetHourlySnapshot(hourlyId); - const daily = new SiloAssetDailySnapshot(dailyId); - - // Set current values - hourly.season = currentSeason; - hourly.siloAsset = siloAsset.id; - hourly.depositedAmount = siloAsset.depositedAmount; - hourly.depositedBDV = siloAsset.depositedBDV; - hourly.withdrawnAmount = siloAsset.withdrawnAmount; - hourly.farmAmount = siloAsset.farmAmount; - - // Set deltas - if (baseHourly !== null) { - hourly.deltaDepositedAmount = hourly.depositedAmount.minus(baseHourly.depositedAmount); - hourly.deltaDepositedBDV = hourly.depositedBDV.minus(baseHourly.depositedBDV); - hourly.deltaWithdrawnAmount = hourly.withdrawnAmount.minus(baseHourly.withdrawnAmount); - hourly.deltaFarmAmount = hourly.farmAmount.minus(baseHourly.farmAmount); - - if (hourly.id == baseHourly.id) { - // Add existing deltas - hourly.deltaDepositedAmount = hourly.deltaDepositedAmount.plus(baseHourly.deltaDepositedAmount); - hourly.deltaDepositedBDV = hourly.deltaDepositedBDV.plus(baseHourly.deltaDepositedBDV); - hourly.deltaWithdrawnAmount = hourly.deltaWithdrawnAmount.plus(baseHourly.deltaWithdrawnAmount); - hourly.deltaFarmAmount = hourly.deltaFarmAmount.plus(baseHourly.deltaFarmAmount); - } - } else { - hourly.deltaDepositedAmount = hourly.depositedAmount; - hourly.deltaDepositedBDV = hourly.depositedBDV; - hourly.deltaWithdrawnAmount = hourly.withdrawnAmount; - hourly.deltaFarmAmount = hourly.farmAmount; - } - hourly.createdAt = hour; - hourly.updatedAt = timestamp; - hourly.save(); - - // Repeat for daily snapshot. - // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. - - daily.season = currentSeason; - daily.siloAsset = siloAsset.id; - daily.depositedAmount = siloAsset.depositedAmount; - daily.depositedBDV = siloAsset.depositedBDV; - daily.withdrawnAmount = siloAsset.withdrawnAmount; - daily.farmAmount = siloAsset.farmAmount; - if (baseDaily !== null) { - daily.deltaDepositedAmount = daily.depositedAmount.minus(baseDaily.depositedAmount); - daily.deltaDepositedBDV = daily.depositedBDV.minus(baseDaily.depositedBDV); - daily.deltaWithdrawnAmount = daily.withdrawnAmount.minus(baseDaily.withdrawnAmount); - daily.deltaFarmAmount = daily.farmAmount.minus(baseDaily.farmAmount); - - if (daily.id == baseDaily.id) { - // Add existing deltas - daily.deltaDepositedAmount = daily.deltaDepositedAmount.plus(baseDaily.deltaDepositedAmount); - daily.deltaDepositedBDV = daily.deltaDepositedBDV.plus(baseDaily.deltaDepositedBDV); - daily.deltaWithdrawnAmount = daily.deltaWithdrawnAmount.plus(baseDaily.deltaWithdrawnAmount); - daily.deltaFarmAmount = daily.deltaFarmAmount.plus(baseDaily.deltaFarmAmount); - } - } else { - daily.deltaDepositedAmount = daily.depositedAmount; - daily.deltaDepositedBDV = daily.depositedBDV; - daily.deltaWithdrawnAmount = daily.withdrawnAmount; - daily.deltaFarmAmount = daily.farmAmount; - } - daily.createdAt = day; - daily.updatedAt = timestamp; - daily.save(); - - siloAsset.lastHourlySnapshotSeason = currentSeason; - siloAsset.lastDailySnapshotDay = day; -} diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/SiloAsset.ts b/projects/subgraph-beanstalk/src/utils/snapshots/SiloAsset.ts new file mode 100644 index 0000000000..ff66a7cd8d --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/snapshots/SiloAsset.ts @@ -0,0 +1,92 @@ +import { BigInt, Address, log } from "@graphprotocol/graph-ts"; +import { SiloAsset, SiloAssetDailySnapshot, SiloAssetHourlySnapshot } from "../../../generated/schema"; +import { getCurrentSeason } from "../Beanstalk"; +import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; + +export function takeSiloAssetSnapshots(siloAsset: SiloAsset, protocol: Address, timestamp: BigInt): void { + const currentSeason = getCurrentSeason(protocol); + + const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); + const day = BigInt.fromI32(dayFromTimestamp(timestamp)); + + // Load the snapshot for this season/day + const hourlyId = siloAsset.id + "-" + currentSeason.toString(); + const dailyId = siloAsset.id + "-" + day.toString(); + let baseHourly = SiloAssetHourlySnapshot.load(hourlyId); + let baseDaily = SiloAssetDailySnapshot.load(dailyId); + if (baseHourly == null && siloAsset.lastHourlySnapshotSeason !== 0) { + baseHourly = SiloAssetHourlySnapshot.load(siloAsset.id + "-" + siloAsset.lastHourlySnapshotSeason.toString()); + } + if (baseDaily == null && siloAsset.lastDailySnapshotDay !== null) { + baseDaily = SiloAssetDailySnapshot.load(siloAsset.id + "-" + siloAsset.lastDailySnapshotDay!.toString()); + } + const hourly = new SiloAssetHourlySnapshot(hourlyId); + const daily = new SiloAssetDailySnapshot(dailyId); + + // Set current values + hourly.season = currentSeason; + hourly.siloAsset = siloAsset.id; + hourly.depositedAmount = siloAsset.depositedAmount; + hourly.depositedBDV = siloAsset.depositedBDV; + hourly.withdrawnAmount = siloAsset.withdrawnAmount; + hourly.farmAmount = siloAsset.farmAmount; + + // Set deltas + if (baseHourly !== null) { + hourly.deltaDepositedAmount = hourly.depositedAmount.minus(baseHourly.depositedAmount); + hourly.deltaDepositedBDV = hourly.depositedBDV.minus(baseHourly.depositedBDV); + hourly.deltaWithdrawnAmount = hourly.withdrawnAmount.minus(baseHourly.withdrawnAmount); + hourly.deltaFarmAmount = hourly.farmAmount.minus(baseHourly.farmAmount); + + if (hourly.id == baseHourly.id) { + // Add existing deltas + hourly.deltaDepositedAmount = hourly.deltaDepositedAmount.plus(baseHourly.deltaDepositedAmount); + hourly.deltaDepositedBDV = hourly.deltaDepositedBDV.plus(baseHourly.deltaDepositedBDV); + hourly.deltaWithdrawnAmount = hourly.deltaWithdrawnAmount.plus(baseHourly.deltaWithdrawnAmount); + hourly.deltaFarmAmount = hourly.deltaFarmAmount.plus(baseHourly.deltaFarmAmount); + } + } else { + hourly.deltaDepositedAmount = hourly.depositedAmount; + hourly.deltaDepositedBDV = hourly.depositedBDV; + hourly.deltaWithdrawnAmount = hourly.withdrawnAmount; + hourly.deltaFarmAmount = hourly.farmAmount; + } + hourly.createdAt = hour; + hourly.updatedAt = timestamp; + hourly.save(); + + // Repeat for daily snapshot. + // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + + daily.season = currentSeason; + daily.siloAsset = siloAsset.id; + daily.depositedAmount = siloAsset.depositedAmount; + daily.depositedBDV = siloAsset.depositedBDV; + daily.withdrawnAmount = siloAsset.withdrawnAmount; + daily.farmAmount = siloAsset.farmAmount; + if (baseDaily !== null) { + daily.deltaDepositedAmount = daily.depositedAmount.minus(baseDaily.depositedAmount); + daily.deltaDepositedBDV = daily.depositedBDV.minus(baseDaily.depositedBDV); + daily.deltaWithdrawnAmount = daily.withdrawnAmount.minus(baseDaily.withdrawnAmount); + daily.deltaFarmAmount = daily.farmAmount.minus(baseDaily.farmAmount); + + if (daily.id == baseDaily.id) { + // Add existing deltas + daily.deltaDepositedAmount = daily.deltaDepositedAmount.plus(baseDaily.deltaDepositedAmount); + daily.deltaDepositedBDV = daily.deltaDepositedBDV.plus(baseDaily.deltaDepositedBDV); + daily.deltaWithdrawnAmount = daily.deltaWithdrawnAmount.plus(baseDaily.deltaWithdrawnAmount); + daily.deltaFarmAmount = daily.deltaFarmAmount.plus(baseDaily.deltaFarmAmount); + } + } else { + daily.deltaDepositedAmount = daily.depositedAmount; + daily.deltaDepositedBDV = daily.depositedBDV; + daily.deltaWithdrawnAmount = daily.withdrawnAmount; + daily.deltaFarmAmount = daily.farmAmount; + } + daily.createdAt = day; + daily.updatedAt = timestamp; + daily.save(); + + siloAsset.lastHourlySnapshotSeason = currentSeason; + siloAsset.lastDailySnapshotDay = day; +} diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/WhitelistTokenSetting.ts b/projects/subgraph-beanstalk/src/utils/snapshots/WhitelistTokenSetting.ts new file mode 100644 index 0000000000..e28a0ef88d --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/snapshots/WhitelistTokenSetting.ts @@ -0,0 +1,146 @@ +import { BigInt, Address, log } from "@graphprotocol/graph-ts"; +import { WhitelistTokenSetting, WhitelistTokenHourlySnapshot, WhitelistTokenDailySnapshot } from "../../../generated/schema"; +import { getCurrentSeason } from "../Beanstalk"; +import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; + +export function takeWhitelistTokenSettingSnapshots( + whitelistTokenSetting: WhitelistTokenSetting, + protocol: Address, + timestamp: BigInt +): void { + const currentSeason = getCurrentSeason(protocol); + + const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); + const day = BigInt.fromI32(dayFromTimestamp(timestamp)); + + // Load the snapshot for this season/day + const hourlyId = whitelistTokenSetting.id.toHexString() + "-" + currentSeason.toString(); + const dailyId = whitelistTokenSetting.id.toHexString() + "-" + day.toString(); + let baseHourly = WhitelistTokenHourlySnapshot.load(hourlyId); + let baseDaily = WhitelistTokenDailySnapshot.load(dailyId); + if (baseHourly == null && whitelistTokenSetting.lastHourlySnapshotSeason !== 0) { + baseHourly = WhitelistTokenHourlySnapshot.load( + whitelistTokenSetting.id.toHexString() + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() + ); + } + if (baseDaily == null && whitelistTokenSetting.lastDailySnapshotDay !== null) { + baseDaily = WhitelistTokenDailySnapshot.load( + whitelistTokenSetting.id.toHexString() + "-" + whitelistTokenSetting.lastDailySnapshotDay!.toString() + ); + } + const hourly = new WhitelistTokenHourlySnapshot(hourlyId); + const daily = new WhitelistTokenDailySnapshot(dailyId); + + // Set current values + hourly.season = currentSeason; + hourly.token = whitelistTokenSetting.id; + hourly.selector = whitelistTokenSetting.selector; + hourly.gpSelector = whitelistTokenSetting.gpSelector; + hourly.lwSelector = whitelistTokenSetting.lwSelector; + hourly.stalkEarnedPerSeason = whitelistTokenSetting.stalkEarnedPerSeason; + hourly.stalkIssuedPerBdv = whitelistTokenSetting.stalkIssuedPerBdv; + hourly.milestoneSeason = whitelistTokenSetting.milestoneSeason; + hourly.gaugePoints = whitelistTokenSetting.gaugePoints; + hourly.optimalPercentDepositedBdv = whitelistTokenSetting.optimalPercentDepositedBdv; + + // Set deltas + if (baseHourly !== null) { + hourly.deltaStalkEarnedPerSeason = hourly.stalkEarnedPerSeason.minus(baseHourly.stalkEarnedPerSeason); + hourly.deltaStalkIssuedPerBdv = hourly.stalkIssuedPerBdv.minus(baseHourly.stalkIssuedPerBdv); + hourly.deltaMilestoneSeason = hourly.milestoneSeason - baseHourly.milestoneSeason; + if (hourly.gaugePoints !== null) { + if (baseHourly.gaugePoints !== null) { + hourly.deltaGaugePoints = hourly.gaugePoints!.minus(baseHourly.gaugePoints!); + } else { + hourly.deltaGaugePoints = hourly.gaugePoints; + } + } + if (hourly.optimalPercentDepositedBdv !== null) { + if (baseHourly.optimalPercentDepositedBdv !== null) { + hourly.deltaOptimalPercentDepositedBdv = hourly.optimalPercentDepositedBdv!.minus(baseHourly.optimalPercentDepositedBdv!); + } else { + hourly.deltaOptimalPercentDepositedBdv = hourly.optimalPercentDepositedBdv; + } + } + + if (hourly.id == baseHourly.id) { + // Add existing deltas + hourly.deltaStalkEarnedPerSeason = hourly.deltaStalkEarnedPerSeason.plus(baseHourly.deltaStalkEarnedPerSeason); + hourly.deltaStalkIssuedPerBdv = hourly.deltaStalkIssuedPerBdv.plus(baseHourly.deltaStalkIssuedPerBdv); + hourly.deltaMilestoneSeason = hourly.deltaMilestoneSeason + baseHourly.deltaMilestoneSeason; + if (hourly.deltaGaugePoints !== null && baseHourly.deltaGaugePoints !== null) { + hourly.deltaGaugePoints = hourly.deltaGaugePoints!.plus(baseHourly.deltaGaugePoints!); + } + if (hourly.deltaOptimalPercentDepositedBdv !== null && baseHourly.deltaOptimalPercentDepositedBdv !== null) { + hourly.deltaOptimalPercentDepositedBdv = hourly.deltaOptimalPercentDepositedBdv!.plus(baseHourly.deltaOptimalPercentDepositedBdv!); + } + } + } else { + hourly.deltaStalkEarnedPerSeason = hourly.stalkEarnedPerSeason; + hourly.deltaStalkIssuedPerBdv = hourly.stalkIssuedPerBdv; + hourly.deltaMilestoneSeason = hourly.milestoneSeason; + hourly.deltaGaugePoints = hourly.gaugePoints; + hourly.deltaOptimalPercentDepositedBdv = hourly.optimalPercentDepositedBdv; + } + hourly.createdAt = hour; + hourly.updatedAt = timestamp; + hourly.save(); + + // Repeat for daily snapshot. + // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + + daily.season = currentSeason; + daily.token = whitelistTokenSetting.id; + daily.selector = whitelistTokenSetting.selector; + daily.gpSelector = whitelistTokenSetting.gpSelector; + daily.lwSelector = whitelistTokenSetting.lwSelector; + daily.stalkEarnedPerSeason = whitelistTokenSetting.stalkEarnedPerSeason; + daily.stalkIssuedPerBdv = whitelistTokenSetting.stalkIssuedPerBdv; + daily.milestoneSeason = whitelistTokenSetting.milestoneSeason; + daily.gaugePoints = whitelistTokenSetting.gaugePoints; + daily.optimalPercentDepositedBdv = whitelistTokenSetting.optimalPercentDepositedBdv; + if (baseDaily !== null) { + daily.deltaStalkEarnedPerSeason = daily.stalkEarnedPerSeason.minus(baseDaily.stalkEarnedPerSeason); + daily.deltaStalkIssuedPerBdv = daily.stalkIssuedPerBdv.minus(baseDaily.stalkIssuedPerBdv); + daily.deltaMilestoneSeason = daily.milestoneSeason - baseDaily.milestoneSeason; + if (daily.gaugePoints !== null) { + if (baseDaily.gaugePoints !== null) { + daily.deltaGaugePoints = daily.gaugePoints!.minus(baseDaily.gaugePoints!); + } else { + daily.deltaGaugePoints = daily.gaugePoints; + } + } + if (daily.optimalPercentDepositedBdv !== null) { + if (baseDaily.optimalPercentDepositedBdv !== null) { + daily.deltaOptimalPercentDepositedBdv = daily.optimalPercentDepositedBdv!.minus(baseDaily.optimalPercentDepositedBdv!); + } else { + daily.deltaOptimalPercentDepositedBdv = daily.optimalPercentDepositedBdv; + } + } + + if (daily.id == baseDaily.id) { + // Add existing deltas + daily.deltaStalkEarnedPerSeason = daily.deltaStalkEarnedPerSeason.plus(baseDaily.deltaStalkEarnedPerSeason); + daily.deltaStalkIssuedPerBdv = daily.deltaStalkIssuedPerBdv.plus(baseDaily.deltaStalkIssuedPerBdv); + daily.deltaMilestoneSeason = daily.deltaMilestoneSeason + baseDaily.deltaMilestoneSeason; + if (daily.deltaGaugePoints !== null && baseDaily.deltaGaugePoints !== null) { + daily.deltaGaugePoints = daily.deltaGaugePoints!.plus(baseDaily.deltaGaugePoints!); + } + if (daily.deltaOptimalPercentDepositedBdv !== null && baseDaily.deltaOptimalPercentDepositedBdv !== null) { + daily.deltaOptimalPercentDepositedBdv = daily.deltaOptimalPercentDepositedBdv!.plus(baseDaily.deltaOptimalPercentDepositedBdv!); + } + } + } else { + daily.deltaStalkEarnedPerSeason = daily.stalkEarnedPerSeason; + daily.deltaStalkIssuedPerBdv = daily.stalkIssuedPerBdv; + daily.deltaMilestoneSeason = daily.milestoneSeason; + daily.deltaGaugePoints = daily.gaugePoints; + daily.deltaOptimalPercentDepositedBdv = daily.optimalPercentDepositedBdv; + } + daily.createdAt = day; + daily.updatedAt = timestamp; + daily.save(); + + whitelistTokenSetting.lastHourlySnapshotSeason = currentSeason; + whitelistTokenSetting.lastDailySnapshotDay = day; +} From 41ce4b19bd5c066d698d72ecdf1b3c2adf88c651 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:20:22 -0700 Subject: [PATCH 16/59] fix stalk mismatch from plantable/germinating --- projects/subgraph-beanstalk/src/GaugeHandler.ts | 7 +++++++ projects/subgraph-beanstalk/src/SeasonHandler.ts | 1 + projects/subgraph-beanstalk/src/SiloHandler.ts | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index 3a91e4c5c1..74f1f155fa 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -84,6 +84,13 @@ export function handleFarmerGerminatingStalkBalanceChanged(event: FarmerGerminat } else { farmerGerminating.save(); } + + // Need to subtract stalk from system silo. The finished germinating stalk was already added + // into system stalk, and there are subsequent StalkBalanceChanged events for this transaction. + let systemSilo = loadSilo(event.address); + systemSilo.stalk = systemSilo.stalk.plus(event.params.deltaGerminatingStalk); + takeSiloSnapshots(systemSilo, event.address, event.block.timestamp); + systemSilo.save(); } let farmerSilo = loadSilo(event.params.account); diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index dec40df2a5..4e6a1336e2 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -79,6 +79,7 @@ export function handleReward(event: Reward): void { let newPlantableStalk = event.params.toSilo.times(BigInt.fromI32(10000)); // Stalk has 10 decimals silo.beanMints = silo.beanMints.plus(event.params.toSilo); + silo.stalk = silo.stalk.plus(newPlantableStalk); silo.plantableStalk = silo.plantableStalk.plus(newPlantableStalk); silo.depositedBDV = silo.depositedBDV.plus(event.params.toSilo); diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 380a83add0..3e6f2efcdf 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -244,10 +244,11 @@ export function handlePlant(event: Plant): void { // This removes the plantable stalk for planted beans. // Actual stalk credit for the farmer will be handled under the StalkBalanceChanged event. - const currentSeason = getCurrentSeason(event.address); let silo = loadSilo(event.address); let newPlantableStalk = event.params.beans.times(BigInt.fromI32(10000)); + // Subtract stalk since it was already added in Reward, and is about to get re-added in StalkBalanceChanged. + silo.stalk = silo.stalk.minus(newPlantableStalk); silo.plantableStalk = silo.plantableStalk.minus(newPlantableStalk); silo.depositedBDV = silo.depositedBDV.minus(event.params.beans); From df29c40b9a897652b53e99ca393fad1db40a7de4 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:23:00 -0700 Subject: [PATCH 17/59] bump version --- projects/subgraph-beanstalk/src/utils/Beanstalk.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts index f93c3c2a0d..c33345eb48 100644 --- a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts @@ -8,9 +8,9 @@ export function loadBeanstalk(protocol: Address): Beanstalk { beanstalk = new Beanstalk(protocol.toHexString()); beanstalk.name = "Beanstalk"; beanstalk.slug = "beanstalk"; - beanstalk.schemaVersion = "2.3.1"; - beanstalk.subgraphVersion = "2.3.1"; - beanstalk.methodologyVersion = "2.3.1"; + beanstalk.schemaVersion = "2.4.0"; + beanstalk.subgraphVersion = "2.4.0"; + beanstalk.methodologyVersion = "2.4.0"; beanstalk.lastUpgrade = ZERO_BI; beanstalk.lastSeason = 1; beanstalk.activeFarmers = []; From 1ce10ca6b9e745a3586fea6958950941ebfae417 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:06:55 -0700 Subject: [PATCH 18/59] runtime fixes --- .../subgraph-beanstalk/manifests/ethereum.yaml | 4 ++-- projects/subgraph-beanstalk/src/FarmHandler.ts | 2 +- projects/subgraph-beanstalk/src/SiloHandler.ts | 6 +++++- projects/subgraph-beanstalk/src/utils/Silo.ts | 15 ++------------- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 18aa404f4d..9b28f1ffec 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -781,5 +781,5 @@ dataSources: # features: # - grafting # graft: -# base: QmcZq7RVCbzixsh7PoHCVKXHsXnpigNo7JWvzj6rUsuvPd -# block: 19393254 +# base: QmQCyzt2SH1dnGyPDaWUCWCxAhdaYwxHa1MgMEJLLizw1L +# block: 15278000 diff --git a/projects/subgraph-beanstalk/src/FarmHandler.ts b/projects/subgraph-beanstalk/src/FarmHandler.ts index eafbb8412e..8ca6767065 100644 --- a/projects/subgraph-beanstalk/src/FarmHandler.ts +++ b/projects/subgraph-beanstalk/src/FarmHandler.ts @@ -18,7 +18,7 @@ function updateFarmTotals( recursive: boolean = true ): void { if (recursive && account != protocol) { - updateFarmTotals(protocol, account, token, deltaAmount, timestamp); + updateFarmTotals(protocol, protocol, token, deltaAmount, timestamp); } let asset = loadSiloAsset(account, token); asset.farmAmount = asset.farmAmount.plus(deltaAmount); diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 3e6f2efcdf..741154a8d9 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -45,7 +45,7 @@ class AddRemoveDepositsParams { seasons: BigInt[] | null; // Seasons not present in v3+ stems: BigInt[] | null; // Stems not present in v2 amounts: BigInt[]; - bdvs: BigInt[] | null; // bdv not present in v2 + bdvs: BigInt[] | null; // bdv not present in v2 removal depositVersion: String; } @@ -122,6 +122,10 @@ function removeDeposits(params: AddRemoveDepositsParams): void { */ export function handleAddDeposit(event: AddDeposit): void { + if (event.params.amount == ZERO_BI && event.params.bdv == ZERO_BI) { + // During replant there is at least one such event which should be ignored + return; + } addDeposits({ event, account: event.params.account, diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index dfe135431f..85bdc4c8de 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -1,18 +1,7 @@ -import { Address, BigInt, Bytes, ethereum, store } from "@graphprotocol/graph-ts"; -import { - Silo, - SiloDeposit, - SiloWithdraw, - SiloYield, - SiloAsset, - WhitelistTokenSetting, - WhitelistTokenHourlySnapshot, - WhitelistTokenDailySnapshot, - TokenYield -} from "../../generated/schema"; +import { Address, BigInt, Bytes, ethereum, store, log } from "@graphprotocol/graph-ts"; +import { Silo, SiloDeposit, SiloWithdraw, SiloYield, SiloAsset, WhitelistTokenSetting, TokenYield } from "../../generated/schema"; import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { dayFromTimestamp, hourFromTimestamp } from "../../../subgraph-core/utils/Dates"; /* ===== Base Silo Entities ===== */ From 16aa8b42b1da182c7c2270e31ffd20d97adb21f1 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Fri, 9 Aug 2024 11:10:19 -0700 Subject: [PATCH 19/59] remove unnecessary event --- projects/subgraph-beanstalk/schema.graphql | 42 ------------------- .../subgraph-beanstalk/src/GaugeHandler.ts | 10 ----- .../subgraph-beanstalk/src/SiloHandler.ts | 37 ---------------- 3 files changed, 89 deletions(-) diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index b0a00ebfa4..199a91983f 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -1491,48 +1491,6 @@ type PodOrderCancelled implements MarketplaceEvent @entity(immutable: true) { createdAt: BigInt! } -type WhitelistToken implements SiloEvent @entity(immutable: true) { - "whitelistToken-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - "Token address whitelisted" - token: String! - "Stalk per BDV" - stalk: BigInt - "Seeds per BDV" - seeds: BigInt - "Stalk earned per season" - stalkPerSeason: BigInt - "Selector for token" - selector: String - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - -type DewhitelistToken implements SiloEvent @entity(immutable: true) { - "dewhitelistToken-{ Transaction hash }-{ Log index }" - id: ID! - " Transaction hash of the transaction that emitted this event " - hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " - logIndex: Int! - " The protocol this transaction belongs to " - protocol: Beanstalk! - "Token address dewhitelisted" - token: String! - " Block number of this event " - blockNumber: BigInt! - " Timestamp of this event " - createdAt: BigInt! -} - # For each applicable address there will be a max of two germinating entities - one even and one odd type Germinating @entity { "Address-(EVEN|ODD)" diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index 74f1f155fa..fa2fc8dd25 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -158,16 +158,6 @@ export function handleWhitelistToken_BIP45(event: WhitelistToken): void { takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); siloSettings.save(); - - let id = "whitelistToken-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new WhitelistTokenEntity(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.token = event.params.token.toHexString(); - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); } export function handleUpdateGaugeSettings(event: UpdateGaugeSettings): void { diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts index 741154a8d9..0ce5c77bdc 100644 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/SiloHandler.ts @@ -444,19 +444,6 @@ export function handleWhitelistToken(event: WhitelistToken): void { takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); setting.save(); - - let id = "whitelistToken-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new WhitelistTokenEntity(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.token = event.params.token.toHexString(); - rawEvent.stalk = event.params.stalk; - rawEvent.seeds = event.params.seeds; - rawEvent.selector = event.params.selector.toHexString(); - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); } export function handleWhitelistToken_V3(event: WhitelistToken_V3): void { @@ -469,20 +456,6 @@ export function handleWhitelistToken_V3(event: WhitelistToken_V3): void { takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); setting.save(); - - let id = "whitelistToken-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new WhitelistTokenEntity(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.token = event.params.token.toHexString(); - rawEvent.stalk = event.params.stalk; - rawEvent.seeds = ZERO_BI; - rawEvent.stalkPerSeason = event.params.stalkEarnedPerSeason; - rawEvent.selector = event.params.selector.toHexString(); - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); } // V4 whitelist for seed gauge is in GaugeHandler @@ -497,16 +470,6 @@ export function handleDewhitelistToken(event: DewhitelistToken): void { silo.dewhitelistedTokens = currentDewhitelist; silo.save(); } - - let id = "dewhitelistToken-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new DewhitelistTokenEntity(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.token = event.params.token.toHexString(); - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); } export function handleUpdatedStalkPerBdvPerSeason(event: UpdatedStalkPerBdvPerSeason): void { From ff9dd9c3b2d2108fd3fc9e65d426390284bc5a4c Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Sat, 10 Aug 2024 21:21:32 -0700 Subject: [PATCH 20/59] major file restructure --- projects/subgraph-beanstalk/README.md | 8 + .../manifests/codegen-abis.yaml | 6 +- .../manifests/ethereum.yaml | 11 +- projects/subgraph-beanstalk/schema.graphql | 231 ++++--- .../subgraph-beanstalk/src/BeanHandler.ts | 76 --- .../subgraph-beanstalk/src/FieldHandler.ts | 585 ------------------ .../subgraph-beanstalk/src/SiloHandler.ts | 483 --------------- .../src/{utils => entities}/Beanstalk.ts | 28 +- .../src/{utils => entities}/Fertilizer.ts | 12 +- .../subgraph-beanstalk/src/entities/Field.ts | 59 ++ .../src/{utils => entities}/Germinating.ts | 0 .../src/entities/PodMarketplace.ts | 165 +++++ .../subgraph-beanstalk/src/entities/Silo.ts | 209 +++++++ .../{utils => entities}/snapshots/Field.ts | 3 +- .../snapshots/Marketplace.ts | 0 .../src/{utils => entities}/snapshots/Silo.ts | 2 +- .../snapshots/SiloAsset.ts | 2 +- .../snapshots/WhitelistTokenSetting.ts | 0 .../src/{ => handlers}/BarnHandler.ts | 21 +- .../src/handlers/BeanHandler.ts | 20 + .../src/{ => handlers}/DiamondHandler.ts | 5 +- .../src/{ => handlers}/FarmHandler.ts | 8 +- .../src/handlers/FieldHandler.ts | 51 ++ .../src/{ => handlers}/GaugeHandler.ts | 52 +- .../src/handlers/MarketplaceHandler.ts | 149 +++++ .../src/{ => handlers}/SeasonHandler.ts | 72 +-- .../src/handlers/SiloHandler.ts | 135 ++++ .../src/handlers/legacy/LegacyFieldHandler.ts | 78 +++ .../legacy/LegacyMarketplaceHandler.ts | 96 +++ .../handlers/legacy/LegacySeasonHandler.ts | 29 + .../src/handlers/legacy/LegacySiloHandler.ts | 143 +++++ .../subgraph-beanstalk/src/utils/Field.ts | 568 +++++++++++++++-- .../Marketplace.ts} | 457 ++++++-------- .../src/utils/PodListing.ts | 125 ---- .../src/utils/PodMarketplace.ts | 184 ------ .../subgraph-beanstalk/src/utils/PodOrder.ts | 55 -- projects/subgraph-beanstalk/src/utils/Silo.ts | 357 ++++++----- .../src/{YieldHandler.ts => utils/Yield.ts} | 211 +++---- .../src/utils/contracts/BeanstalkPrice.ts | 2 +- .../src/utils/legacy/LegacySilo.ts | 45 ++ .../src/utils/legacy/LegacyYield.ts | 73 +++ .../{ => utils}/yield_cache/CacheLoader.ts | 2 +- .../window_1/HistoricSilo_10_000.ts | 0 .../window_1/HistoricSilo_15_000.ts | 0 .../window_1/HistoricSilo_20_000.ts | 0 .../window_1/HistoricToken_12_000.ts | 0 .../window_1/HistoricToken_20_000.ts | 0 .../yield_cache/window_1/LoadSilo_1.ts | 2 +- .../yield_cache/window_1/LoadSilo_2.ts | 2 +- .../yield_cache/window_1/LoadSilo_3.ts | 2 +- .../yield_cache/window_1/LoadToken_1.ts | 2 +- .../yield_cache/window_1/LoadToken_2.ts | 2 +- .../window_2/HistoricSilo_10_000.ts | 0 .../window_2/HistoricSilo_15_000.ts | 0 .../window_2/HistoricSilo_20_000.ts | 0 .../window_2/HistoricToken_12_000.ts | 0 .../window_2/HistoricToken_20_000.ts | 0 .../yield_cache/window_2/LoadSilo_1.ts | 2 +- .../yield_cache/window_2/LoadSilo_2.ts | 2 +- .../yield_cache/window_2/LoadSilo_3.ts | 2 +- .../yield_cache/window_2/LoadToken_1.ts | 2 +- .../yield_cache/window_2/LoadToken_2.ts | 2 +- .../window_3/HistoricSilo_10_000.ts | 0 .../window_3/HistoricSilo_15_000.ts | 0 .../window_3/HistoricSilo_20_000.ts | 0 .../window_3/HistoricToken_12_000.ts | 0 .../window_3/HistoricToken_20_000.ts | 0 .../yield_cache/window_3/LoadSilo_1.ts | 2 +- .../yield_cache/window_3/LoadSilo_2.ts | 2 +- .../yield_cache/window_3/LoadSilo_3.ts | 2 +- .../yield_cache/window_3/LoadToken_1.ts | 2 +- .../yield_cache/window_3/LoadToken_2.ts | 2 +- .../tests/SeedGauge.test.ts | 14 +- .../subgraph-beanstalk/tests/Silo.test.ts | 72 +-- .../tests/YieldHandler.test.ts | 21 +- .../tests/event-mocking/Field.ts | 3 +- .../tests/event-mocking/Marketplace.ts | 38 +- .../tests/event-mocking/Season.ts | 3 +- .../tests/event-mocking/Silo.ts | 37 +- .../tests/event-mocking/Whitelist.ts | 10 +- .../subgraph-beanstalk/tests/utils/Field.ts | 4 +- .../tests/utils/Marketplace.ts | 70 ++- .../subgraph-beanstalk/tests/utils/Season.ts | 2 +- .../abis/Beanstalk/Beanstalk-BIP45.json | 19 + 84 files changed, 2579 insertions(+), 2562 deletions(-) delete mode 100644 projects/subgraph-beanstalk/src/BeanHandler.ts delete mode 100644 projects/subgraph-beanstalk/src/FieldHandler.ts delete mode 100644 projects/subgraph-beanstalk/src/SiloHandler.ts rename projects/subgraph-beanstalk/src/{utils => entities}/Beanstalk.ts (69%) rename projects/subgraph-beanstalk/src/{utils => entities}/Fertilizer.ts (85%) create mode 100644 projects/subgraph-beanstalk/src/entities/Field.ts rename projects/subgraph-beanstalk/src/{utils => entities}/Germinating.ts (100%) create mode 100644 projects/subgraph-beanstalk/src/entities/PodMarketplace.ts create mode 100644 projects/subgraph-beanstalk/src/entities/Silo.ts rename projects/subgraph-beanstalk/src/{utils => entities}/snapshots/Field.ts (98%) rename projects/subgraph-beanstalk/src/{utils => entities}/snapshots/Marketplace.ts (100%) rename projects/subgraph-beanstalk/src/{utils => entities}/snapshots/Silo.ts (98%) rename projects/subgraph-beanstalk/src/{utils => entities}/snapshots/SiloAsset.ts (100%) rename projects/subgraph-beanstalk/src/{utils => entities}/snapshots/WhitelistTokenSetting.ts (100%) rename projects/subgraph-beanstalk/src/{ => handlers}/BarnHandler.ts (69%) create mode 100644 projects/subgraph-beanstalk/src/handlers/BeanHandler.ts rename projects/subgraph-beanstalk/src/{ => handlers}/DiamondHandler.ts (58%) rename projects/subgraph-beanstalk/src/{ => handlers}/FarmHandler.ts (74%) create mode 100644 projects/subgraph-beanstalk/src/handlers/FieldHandler.ts rename projects/subgraph-beanstalk/src/{ => handlers}/GaugeHandler.ts (75%) create mode 100644 projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts rename projects/subgraph-beanstalk/src/{ => handlers}/SeasonHandler.ts (62%) create mode 100644 projects/subgraph-beanstalk/src/handlers/SiloHandler.ts create mode 100644 projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts create mode 100644 projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts create mode 100644 projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts create mode 100644 projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts rename projects/subgraph-beanstalk/src/{MarketplaceHandler.ts => utils/Marketplace.ts} (59%) delete mode 100644 projects/subgraph-beanstalk/src/utils/PodListing.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/PodMarketplace.ts delete mode 100644 projects/subgraph-beanstalk/src/utils/PodOrder.ts rename projects/subgraph-beanstalk/src/{YieldHandler.ts => utils/Yield.ts} (78%) create mode 100644 projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts create mode 100644 projects/subgraph-beanstalk/src/utils/legacy/LegacyYield.ts rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/CacheLoader.ts (93%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/HistoricSilo_10_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/HistoricSilo_15_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/HistoricSilo_20_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/HistoricToken_12_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/HistoricToken_20_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/LoadSilo_1.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/LoadSilo_2.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/LoadSilo_3.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/LoadToken_1.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_1/LoadToken_2.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/HistoricSilo_10_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/HistoricSilo_15_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/HistoricSilo_20_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/HistoricToken_12_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/HistoricToken_20_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/LoadSilo_1.ts (88%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/LoadSilo_2.ts (88%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/LoadSilo_3.ts (88%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/LoadToken_1.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_2/LoadToken_2.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/HistoricSilo_10_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/HistoricSilo_15_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/HistoricSilo_20_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/HistoricToken_12_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/HistoricToken_20_000.ts (100%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/LoadSilo_1.ts (88%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/LoadSilo_2.ts (88%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/LoadSilo_3.ts (88%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/LoadToken_1.ts (89%) rename projects/subgraph-beanstalk/src/{ => utils}/yield_cache/window_3/LoadToken_2.ts (89%) diff --git a/projects/subgraph-beanstalk/README.md b/projects/subgraph-beanstalk/README.md index c7bbaa04b6..183cdba415 100644 --- a/projects/subgraph-beanstalk/README.md +++ b/projects/subgraph-beanstalk/README.md @@ -27,3 +27,11 @@ To test with Docker, the first time you will need to run `yarn run graph test -d ### Deploying When using graph cli commands, you will often need to specify which manifest file should be used. This is necessary to support multiple chains in the same codebase. The commands which need it will be evident - as they will fail when unable to find a `subgraph.yaml` file. In those commands, include `./manifest/${chain}.yaml` as the final argument to the command. See scripts inside `package.json` for examples. + +### Development + +# Handler organization strategy + +Any events that are currently relevant to Beanstalk should reference the codegen for whichever is the latest protocol ABI, and not include v1/v2 etc in the name. Legacy events (that are no longer present on-chain) should reference the codegen for the upgrade in which they were initially deployed, and use the appropriate version number in the method names. Legacy handlers should also be placed in the `legacy` folder. + +Underlying logic should be included in a separate file provided in the `utils` folder. The advantage of this is in accommodating a scenario where an event signature gets updated. The replacement event handler can call into the shared util along with the legacy handler. diff --git a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml index d8170253b6..f32cd23bc1 100644 --- a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml +++ b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml @@ -47,6 +47,6 @@ dataSources: - name: Fertilizer file: ../../subgraph-core/abis/Fertilizer.json eventHandlers: - - event: AddDeposit(indexed address,indexed address,int96,uint256,uint256) - handler: handleAddDeposit_V3 - file: ../src/SiloHandler.ts + - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) + handler: handleDiamondCut + file: ../src/handlers/DiamondHandler.ts diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 9b28f1ffec..00185e4879 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -537,12 +537,13 @@ dataSources: handler: handleDiamondCut file: ../src/DiamondHandler.ts - kind: ethereum/contract - name: Bean + name: BeanERC20-V1 network: mainnet source: address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" abi: ERC20 startBlock: 12974075 + endBlock: 14602789 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -552,14 +553,12 @@ dataSources: abis: - name: ERC20 file: ../../subgraph-core/abis/ERC20.json - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json eventHandlers: - event: Transfer(indexed address,indexed address,uint256) - handler: handleLegacyTransfer + handler: handleTransfer file: ../src/BeanHandler.ts - kind: ethereum/contract - name: Bean-Replanted + name: BeanERC20 network: mainnet source: address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" @@ -574,8 +573,6 @@ dataSources: abis: - name: ERC20 file: ../../subgraph-core/abis/ERC20.json - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json eventHandlers: - event: Transfer(indexed address,indexed address,uint256) handler: handleTransfer diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 199a91983f..f3ebd6db76 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -22,85 +22,62 @@ enum EmaWindow { } type Beanstalk @entity { - " Smart contract address of the protocol's main contract (Factory, Registry, etc) " + "Smart contract address of the protocol's main contract (Factory, Registry, etc) " id: ID! - - " Name of the protocol, including version. e.g. Uniswap v3 " + "Name of the protocol, including version. e.g. Uniswap v3" name: String! - - " Slug of protocol, including version. e.g. uniswap-v3 " - slug: String! - - " Version of the subgraph schema, in SemVer format (e.g. 1.0.0) " + "Bean token address of the protocol" + token: String! + "Address of the fertilizer contract" + fertilizer1155: String + "Version of the subgraph schema, in SemVer format (e.g. 1.0.0) " schemaVersion: String! - - " Version of the subgraph implementation, in SemVer format (e.g. 1.0.0) " + "Version of the subgraph implementation, in SemVer format (e.g. 1.0.0) " subgraphVersion: String! - - " Version of the methodology used to compute metrics, loosely based on SemVer format (e.g. 1.0.0) " + "Version of the methodology used to compute metrics, loosely based on SemVer format (e.g. 1.0.0) " methodologyVersion: String! - - " Timestamp of the latest DiamondCut call " + "Timestamp of the latest DiamondCut call" lastUpgrade: BigInt! - - " Season specific data " + "Season specific data" seasons: [Season!]! @derivedFrom(field: "beanstalk") - - " Silo level data " + "Silo level data" silo: Silo! @derivedFrom(field: "beanstalk") - - " Field level data " + "Field level data" field: Field! @derivedFrom(field: "beanstalk") - - " Last season called " + "Last season called" lastSeason: Int! - - " Array of the addresses for all active farmers in the silo " + "Array of the addresses for all active farmers in the silo" activeFarmers: [String!]! - - " Array of the addresses for all farmers that had silo transfers and need stalk/seeds/roots updated " + "Array of the addresses for all farmers that had silo transfers and need stalk/seeds/roots updated" farmersToUpdate: [String!]! } -# An entity that holds season level data type Season @entity { - " Season Number" + "Season Number" id: ID! - - " Beanstalk Contract Address " + "Beanstalk Contract Address" beanstalk: Beanstalk! - - " Season number in Int form for sorting " + "Season number in Int form for sorting" season: Int! - - " Block in which the season start was triggered by the sunrise call " + "Block in which the season start was triggered by the sunrise call" sunriseBlock: BigInt! - - " Block timestamp when sunrise was called " + "Block timestamp when sunrise was called" createdAt: BigInt! - - " Price of BEAN during sunrise " + "Price of BEAN during sunrise" price: BigDecimal! - - " Total Bean supply " + "Total Bean supply" beans: BigInt! - - " Bean Market Cap " + "Bean Market Cap" marketCap: BigDecimal! - - " Time weighted deltaB " + "Time weighted deltaB" deltaB: BigInt! - - " Change in Bean supply " + "Change in Bean supply" deltaBeans: BigInt! - - " Amount of Beans minted during sunrise " + "Amount of Beans minted during sunrise" rewardBeans: BigInt! - - " Amount of Beans paid to sunrise caller " + "Amount of Beans paid to sunrise caller" incentiveBeans: BigInt! - - " New harvestable index for the season " + "New harvestable index for the season" harvestableIndex: BigInt! } @@ -458,7 +435,7 @@ type WhitelistTokenDailySnapshot @entity { } type Field @entity { - " Contract address for this field or farmer " + "Contract address for this field or farmer" id: ID! "Contract address of beanstalk" beanstalk: Beanstalk! @@ -718,7 +695,7 @@ type Plot @entity { } type PodMarketplace @entity { - " Contract address of beanstalk " + "Contract address of beanstalk" id: ID! "Current season of the marketplace" season: Int! @@ -1176,6 +1153,8 @@ type PodFill @entity { type Fertilizer @entity { "Token address for fert" id: ID! + "Address of parent beanstalk" + beanstalk: String! "Total overall suppy of fert tokens" supply: BigInt! tokens: [FertilizerToken!]! @derivedFrom(field: "fertilizer") @@ -1244,91 +1223,91 @@ store them as events, although they are not technically Ethereum events emitted contracts. """ interface SiloEvent { - " { Event type }-{ Transaction hash }-{ Log index } " + "{ Event type }-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } interface FieldEvent { - " { Event type }-{ Transaction hash }-{ Log index } " + "{ Event type }-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } interface MarketplaceEvent { - " { Event type }-{ Transaction hash }-{ Log index } " + "{ Event type }-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } type Chop implements SiloEvent @entity(immutable: true) { "chop-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Address chopping " + "Address chopping" farmer: String! - " Unripe token being chopped " + "Unripe token being chopped" unripe: String! - " Amount being chopped" + "Amount being chopped" amount: BigInt! - " Underlying token " + "Underlying token" underlying: String! - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } type PodListingCreated implements MarketplaceEvent @entity(immutable: true) { "podListingCreated-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Historical ID for joins" + "Historical ID for joins" historyID: String! - " Account creating the listing" + "Account creating the listing" account: String! "Where these pods were in line when listed" placeInLine: BigInt! - " Index of the plot listed" + "Index of the plot listed" index: BigInt! - " Start value of the plot listed " + "Start value of the plot listed" start: BigInt! "Amount of pods listed" amount: BigInt! @@ -1344,22 +1323,22 @@ type PodListingCreated implements MarketplaceEvent @entity(immutable: true) { pricingFunction: Bytes "Pricing Type" pricingType: Int - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } type PodListingFilled implements MarketplaceEvent @entity(immutable: true) { "podListingFilled-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Historical ID for joins" + "Historical ID for joins" historyID: String! "Account selling pods" fromFarmer: String! @@ -1375,49 +1354,49 @@ type PodListingFilled implements MarketplaceEvent @entity(immutable: true) { amount: BigInt! "Beans paid to fill the listing" costInBeans: BigInt - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } type PodListingCancelled implements MarketplaceEvent @entity(immutable: true) { "seedChange-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Historical ID for joins" + "Historical ID for joins" historyID: String! - " Account cancelling listing" + "Account cancelling listing" account: String! "Where these pods were in line when cancelled" placeInLine: BigInt! - " Index of plot listing being cancelled" + "Index of plot listing being cancelled" index: BigInt! - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } type PodOrderCreated implements MarketplaceEvent @entity(immutable: true) { "podOrderCreated-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Historical ID for joins" + "Historical ID for joins" historyID: String! - " Account creating the listing" + "Account creating the listing" account: String! - " ID of the pod order" + "ID of the pod order" orderId: String! """ The represented value emitted with this event changed with BIP-29 at block 15277986 @@ -1433,22 +1412,22 @@ type PodOrderCreated implements MarketplaceEvent @entity(immutable: true) { pricingFunction: Bytes "Pricing Type" pricingType: Int - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } type PodOrderFilled implements MarketplaceEvent @entity(immutable: true) { "podOrderFilled-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Historical ID for joins" + "Historical ID for joins" historyID: String! "Account selling pods" fromFarmer: String! @@ -1464,30 +1443,30 @@ type PodOrderFilled implements MarketplaceEvent @entity(immutable: true) { amount: BigInt! "Beans paid to fill the order" costInBeans: BigInt - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } type PodOrderCancelled implements MarketplaceEvent @entity(immutable: true) { "podOrderCancelled-{ Transaction hash }-{ Log index }" id: ID! - " Transaction hash of the transaction that emitted this event " + "Transaction hash of the transaction that emitted this event" hash: String! - " Event log index. For transactions that don't emit event, create arbitrary index starting from 0 " + "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" logIndex: Int! - " The protocol this transaction belongs to " + "The protocol this transaction belongs to" protocol: Beanstalk! - " Historical ID for joins" + "Historical ID for joins" historyID: String! - " Account cancelling listing" + "Account cancelling listing" account: String! - " ID of order cancelled" + "ID of order cancelled" orderId: String! - " Block number of this event " + "Block number of this event" blockNumber: BigInt! - " Timestamp of this event " + "Timestamp of this event" createdAt: BigInt! } diff --git a/projects/subgraph-beanstalk/src/BeanHandler.ts b/projects/subgraph-beanstalk/src/BeanHandler.ts deleted file mode 100644 index 45ca5959e2..0000000000 --- a/projects/subgraph-beanstalk/src/BeanHandler.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; -import { Transfer as LegacyTransfer } from "../generated/Beanstalk-ABIs/ERC20"; -import { Transfer } from "../generated/Beanstalk-ABIs/ERC20"; -import { ADDRESS_ZERO, BEANSTALK } from "../../subgraph-core/utils/Constants"; -import { toDecimal, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadBeanstalk, loadSeason } from "./utils/Beanstalk"; - -export function handleLegacyTransfer(event: LegacyTransfer): void { - if (event.block.number > BigInt.fromI32(14603000)) { - return; - } - - if (event.block.number > BigInt.fromI32(14602789)) { - let beanstalk = loadBeanstalk(BEANSTALK); - let season = loadSeason(BEANSTALK, BigInt.fromI32(beanstalk.lastSeason)); - season.deltaBeans = ZERO_BI; - season.beans = ZERO_BI; - season.price = BigDecimal.fromString("1.022"); - season.save(); - return; - } - - if (event.params.from == ADDRESS_ZERO || event.params.to == ADDRESS_ZERO) { - let beanstalk = loadBeanstalk(BEANSTALK); - let season = loadSeason(BEANSTALK, BigInt.fromI32(beanstalk.lastSeason)); - - log.debug("\nBeanSupply: ============\nBeanSupply: Starting Supply - {}\n", [season.beans.toString()]); - - if (event.params.from == ADDRESS_ZERO) { - season.deltaBeans = season.deltaBeans.plus(event.params.value); - season.beans = season.beans.plus(event.params.value); - log.debug("\nBeanSupply: Beans Minted - {}\nBeanSupply: Season - {}\nBeanSupply: Total Supply - {}\n", [ - event.params.value.toString(), - season.season.toString(), - season.beans.toString() - ]); - } else { - season.deltaBeans = season.deltaBeans.minus(event.params.value); - season.beans = season.beans.minus(event.params.value); - log.debug("\nBeanSupply: Beans Burned - {}\nBeanSupply: Season - {}\nBeanSupply: Total Supply - {}\n", [ - event.params.value.toString(), - season.season.toString(), - season.beans.toString() - ]); - } - season.save(); - } -} - -export function handleTransfer(event: Transfer): void { - if (event.params.from == ADDRESS_ZERO || event.params.to == ADDRESS_ZERO) { - let beanstalk = loadBeanstalk(BEANSTALK); - let season = loadSeason(BEANSTALK, BigInt.fromI32(beanstalk.lastSeason)); - - log.debug("\nBeanSupply: ============\nBeanSupply: Starting Supply - {}\n", [toDecimal(season.beans).toString()]); - - if (event.params.from == ADDRESS_ZERO) { - season.deltaBeans = season.deltaBeans.plus(event.params.value); - season.beans = season.beans.plus(event.params.value); - log.debug("\nBeanSupply: Beans Minted - {}\nBeanSupply: Season - {}\nBeanSupply: Total Supply - {}\n", [ - toDecimal(event.params.value).toString(), - season.season.toString(), - toDecimal(season.beans).toString() - ]); - } else { - season.deltaBeans = season.deltaBeans.minus(event.params.value); - season.beans = season.beans.minus(event.params.value); - log.debug("\nBeanSupply: Beans Burned - {}\nBeanSupply: Season - {}\nBeanSupply: Total Supply - {}\n", [ - toDecimal(event.params.value).toString(), - season.season.toString(), - toDecimal(season.beans).toString() - ]); - } - season.save(); - } -} diff --git a/projects/subgraph-beanstalk/src/FieldHandler.ts b/projects/subgraph-beanstalk/src/FieldHandler.ts deleted file mode 100644 index 9612d05618..0000000000 --- a/projects/subgraph-beanstalk/src/FieldHandler.ts +++ /dev/null @@ -1,585 +0,0 @@ -import { Address, BigInt, log } from "@graphprotocol/graph-ts"; -import { - FundFundraiser, - Harvest, - PlotTransfer, - Sow, - SupplyDecrease, - SupplyIncrease, - SupplyNeutral, - WeatherChange -} from "../generated/Beanstalk-ABIs/PreReplant"; -import { BEANSTALK, BEANSTALK_FARMS } from "../../subgraph-core/utils/Constants"; -import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { getHarvestableIndex, handleRateChange, loadField, loadPlot } from "./utils/Field"; -import { getCurrentSeason, loadBeanstalk, loadFarmer, loadSeason } from "./utils/Beanstalk"; -import { expirePodListingIfExists } from "./utils/PodListing"; -import { setHourlySoilSoldOut, takeFieldSnapshots } from "./utils/snapshots/Field"; - -export function handleWeatherChange(event: WeatherChange): void { - handleRateChange(event.address, event.block, event.params.season, event.params.caseId, event.params.change); -} - -export function handleSow(event: Sow): void { - let sownBeans = event.params.beans; - - if (event.params.account == BEANSTALK_FARMS) { - let startingField = loadField(event.address); - sownBeans = startingField.soil; - } - // Update Farmer Totals - updateFieldTotals( - event.address, - event.params.account, - ZERO_BI, - sownBeans, - event.params.pods, - ZERO_BI, - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number - ); - - let field = loadField(event.address); - loadFarmer(event.params.account); - let plot = loadPlot(event.address, event.params.index); - - let newIndexes = field.plotIndexes; - newIndexes.push(plot.index); - field.plotIndexes = newIndexes; - field.save(); - - plot.farmer = event.params.account.toHexString(); - plot.source = "SOW"; - plot.sourceHash = event.transaction.hash.toHexString(); - plot.season = field.season; - plot.creationHash = event.transaction.hash.toHexString(); - plot.createdAt = event.block.timestamp; - plot.updatedAt = event.block.timestamp; - plot.updatedAtBlock = event.block.number; - plot.pods = event.params.pods; - plot.beansPerPod = event.params.beans.times(BI_10.pow(6)).div(plot.pods); - plot.save(); - - incrementSows(event.address, event.params.account, event.block.timestamp, event.block.number); -} - -export function handleHarvest(event: Harvest): void { - let beanstalk = loadBeanstalk(event.address); - let season = loadSeason(event.address, BigInt.fromI32(beanstalk.lastSeason)); - - // Harvest function is only called with a list of plots - - // Update plots and field totals - - let remainingIndex = ZERO_BI; - - for (let i = 0; i < event.params.plots.length; i++) { - // Plot should exist - let plot = loadPlot(event.address, event.params.plots[i]); - - expirePodListingIfExists(event.address, plot.farmer, plot.index, event.block.timestamp); - - let harvestablePods = season.harvestableIndex.minus(plot.index); - - if (harvestablePods >= plot.pods) { - // Plot fully harvests - updateFieldTotals( - event.address, - event.params.account, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - plot.pods, - event.block.timestamp, - event.block.number - ); - - plot.harvestedPods = plot.pods; - plot.fullyHarvested = true; - plot.save(); - } else { - // Plot partially harvests - updateFieldTotals( - event.address, - event.params.account, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - harvestablePods, - event.block.timestamp, - event.block.number - ); - - remainingIndex = plot.index.plus(harvestablePods); - let remainingPods = plot.pods.minus(harvestablePods); - - let remainingPlot = loadPlot(event.address, remainingIndex); - remainingPlot.farmer = plot.farmer; - remainingPlot.source = plot.source; - remainingPlot.sourceHash = plot.sourceHash; - remainingPlot.season = beanstalk.lastSeason; - remainingPlot.creationHash = event.transaction.hash.toHexString(); - remainingPlot.createdAt = event.block.timestamp; - remainingPlot.updatedAt = event.block.timestamp; - remainingPlot.updatedAtBlock = event.block.number; - remainingPlot.index = remainingIndex; - remainingPlot.pods = remainingPods; - remainingPlot.beansPerPod = plot.beansPerPod; - remainingPlot.save(); - - plot.harvestedPods = harvestablePods; - plot.pods = harvestablePods; - plot.fullyHarvested = true; - plot.save(); - } - } - - // Remove the harvested plot IDs from the field list - let field = loadField(event.address); - let newIndexes = field.plotIndexes; - for (let i = 0; i < event.params.plots.length; i++) { - let plotIndex = newIndexes.indexOf(event.params.plots[i]); - newIndexes.splice(plotIndex, 1); - newIndexes.sort(); - } - if (remainingIndex !== ZERO_BI) { - newIndexes.push(remainingIndex); - } - field.plotIndexes = newIndexes; - field.save(); -} - -export function handlePlotTransfer(event: PlotTransfer): void { - const currentHarvestable = getHarvestableIndex(event.address); - - // Ensure both farmer entites exist - loadFarmer(event.params.from); - loadFarmer(event.params.to); - - // Update farmer field data - updateFieldTotals( - event.address, - event.params.from, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI.minus(event.params.pods), - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number, - false - ); - updateFieldTotals( - event.address, - event.params.to, - ZERO_BI, - ZERO_BI, - ZERO_BI, - event.params.pods, - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number, - false - ); - - let field = loadField(BEANSTALK); - let sortedPlots = field.plotIndexes.sort(); - - let sourceIndex = ZERO_BI; - - for (let i = 0; i < sortedPlots.length; i++) { - // Handle only single comparison for first value of array - if (i == 0) { - if (sortedPlots[i] == event.params.id) { - sourceIndex = sortedPlots[i]; - break; - } else { - continue; - } - } - // Transferred plot matches existing. Start value of zero. - if (sortedPlots[i] == event.params.id) { - sourceIndex = sortedPlots[i]; - break; - } - // Transferred plot is in the middle of existing plot. Non-zero start value. - if (sortedPlots[i - 1] < event.params.id && event.params.id < sortedPlots[i]) { - sourceIndex = sortedPlots[i - 1]; - } - } - - let sourcePlot = loadPlot(event.address, sourceIndex); - let sourceEndIndex = sourceIndex.plus(sourcePlot.pods); - let transferEndIndex = event.params.id.plus(event.params.pods); - - // Determines how many of the pods being transferred are harvestable - const calcHarvestable = (index: BigInt, pods: BigInt, harvestableIndex: BigInt): BigInt => { - let harvestable = harvestableIndex.minus(index); - if (harvestable < ZERO_BI) { - return ZERO_BI; - } else { - return harvestable >= pods ? pods : harvestable; - } - }; - - let transferredHarvestable = calcHarvestable(event.params.id, event.params.pods, currentHarvestable); - - // log.debug("\nPodTransfer: ===================\n", []); - // log.debug("\nPodTransfer: Transfer Season - {}\n", [field.season.toString()]); - // log.debug("\nPodTransfer: Transfer Index - {}\n", [event.params.id.toString()]); - // log.debug("\nPodTransfer: Transfer Pods - {}\n", [event.params.pods.toString()]); - // log.debug("\nPodTransfer: Transfer Harvestable Pods - {}\n", [transferredHarvestable.toString()]); - // log.debug("\nPodTransfer: Transfer Ending Index - {}\n", [event.params.id.plus(event.params.pods).toString()]); - // log.debug("\nPodTransfer: Source Index - {}\n", [sourceIndex.toString()]); - // log.debug("\nPodTransfer: Source Ending Index - {}\n", [sourceIndex.plus(sourcePlot.pods).toString()]); - // log.debug("\nPodTransfer: Source Harvestable Pods - {}\n", [sourcePlot.harvestablePods.toString()]); - // log.debug("\nPodTransfer: Starting Source Pods - {}\n", [sourcePlot.pods.toString()]); - - // Actually transfer the plots - if (sourcePlot.pods == event.params.pods) { - // Sending full plot - const isMarket = sourcePlot.source == "MARKET" && sourcePlot.sourceHash == event.transaction.hash.toHexString(); - if (!isMarket) { - sourcePlot.source = "TRANSFER"; - sourcePlot.sourceHash = event.transaction.hash.toHexString(); - sourcePlot.beansPerPod = sourcePlot.beansPerPod; - } - sourcePlot.farmer = event.params.to.toHexString(); - sourcePlot.updatedAt = event.block.timestamp; - sourcePlot.updatedAtBlock = event.block.number; - sourcePlot.save(); - // log.debug("\nPodTransfer: Sending full plot\n", []); - } else if (sourceIndex == event.params.id) { - // We are only needing to split this plot once to send - // Start value of zero - let remainderIndex = sourceIndex.plus(event.params.pods); - let remainderPlot = loadPlot(event.address, remainderIndex); - sortedPlots.push(remainderIndex); - - const isMarket = sourcePlot.source == "MARKET" && sourcePlot.sourceHash == event.transaction.hash.toHexString(); - if (!isMarket) { - // When sending the start of the plot via market, these cannot be derived from sourcePlot. - remainderPlot.source = sourcePlot.source; - remainderPlot.sourceHash = sourcePlot.sourceHash; - remainderPlot.beansPerPod = sourcePlot.beansPerPod; - - sourcePlot.source = "TRANSFER"; - sourcePlot.sourceHash = event.transaction.hash.toHexString(); - sourcePlot.beansPerPod = sourcePlot.beansPerPod; - } - sourcePlot.farmer = event.params.to.toHexString(); - sourcePlot.updatedAt = event.block.timestamp; - sourcePlot.updatedAtBlock = event.block.number; - sourcePlot.pods = event.params.pods; - sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, currentHarvestable); - sourcePlot.save(); - - remainderPlot.farmer = event.params.from.toHexString(); - remainderPlot.season = field.season; - remainderPlot.creationHash = event.transaction.hash.toHexString(); - remainderPlot.createdAt = event.block.timestamp; - remainderPlot.updatedAt = event.block.timestamp; - remainderPlot.updatedAtBlock = event.block.number; - remainderPlot.index = remainderIndex; - remainderPlot.pods = sourceEndIndex.minus(transferEndIndex); - remainderPlot.harvestablePods = calcHarvestable(remainderPlot.index, remainderPlot.pods, currentHarvestable); - remainderPlot.save(); - - // log.debug("\nPodTransfer: sourceIndex == transferIndex\n", []); - // log.debug("\nPodTransfer: Remainder Index - {}\n", [remainderIndex.toString()]); - // log.debug("\nPodTransfer: Source Pods - {}\n", [sourcePlot.pods.toString()]); - // log.debug("\nPodTransfer: Remainder Pods - {}\n", [remainderPlot.pods.toString()]); - } else if (sourceEndIndex == transferEndIndex) { - // We are only needing to split this plot once to send - // Non-zero start value. Sending to end of plot - let toPlot = loadPlot(event.address, event.params.id); - sortedPlots.push(event.params.id); - - sourcePlot.updatedAt = event.block.timestamp; - sourcePlot.updatedAtBlock = event.block.number; - sourcePlot.pods = sourcePlot.pods.minus(event.params.pods); - sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, currentHarvestable); - sourcePlot.save(); - - const isMarket = toPlot.source == "MARKET" && toPlot.sourceHash == event.transaction.hash.toHexString(); - if (!isMarket) { - toPlot.source = "TRANSFER"; - toPlot.sourceHash = event.transaction.hash.toHexString(); - toPlot.beansPerPod = sourcePlot.beansPerPod; - } - toPlot.farmer = event.params.to.toHexString(); - toPlot.season = field.season; - toPlot.creationHash = event.transaction.hash.toHexString(); - toPlot.createdAt = event.block.timestamp; - toPlot.updatedAt = event.block.timestamp; - toPlot.updatedAtBlock = event.block.number; - toPlot.index = event.params.id; - toPlot.pods = event.params.pods; - toPlot.harvestablePods = calcHarvestable(toPlot.index, toPlot.pods, currentHarvestable); - toPlot.save(); - - // log.debug("\nPodTransfer: sourceEndIndex == transferEndIndex\n", []); - // log.debug("\nPodTransfer: Updated Source Pods - {}\n", [sourcePlot.pods.toString()]); - } else { - // We have to split this plot twice to send - let remainderIndex = event.params.id.plus(event.params.pods); - let toPlot = loadPlot(event.address, event.params.id); - let remainderPlot = loadPlot(event.address, remainderIndex); - - sortedPlots.push(event.params.id); - sortedPlots.push(remainderIndex); - - sourcePlot.updatedAt = event.block.timestamp; - sourcePlot.updatedAtBlock = event.block.number; - sourcePlot.pods = event.params.id.minus(sourcePlot.index); - sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, currentHarvestable); - sourcePlot.save(); - - const isMarket = toPlot.source == "MARKET" && toPlot.sourceHash == event.transaction.hash.toHexString(); - if (!isMarket) { - toPlot.source = "TRANSFER"; - toPlot.sourceHash = event.transaction.hash.toHexString(); - toPlot.beansPerPod = sourcePlot.beansPerPod; - } - toPlot.farmer = event.params.to.toHexString(); - toPlot.season = field.season; - toPlot.creationHash = event.transaction.hash.toHexString(); - toPlot.createdAt = event.block.timestamp; - toPlot.updatedAt = event.block.timestamp; - toPlot.updatedAtBlock = event.block.number; - toPlot.index = event.params.id; - toPlot.pods = event.params.pods; - toPlot.harvestablePods = calcHarvestable(toPlot.index, toPlot.pods, currentHarvestable); - toPlot.save(); - - remainderPlot.farmer = event.params.from.toHexString(); - remainderPlot.source = sourcePlot.source; - remainderPlot.sourceHash = sourcePlot.sourceHash; - remainderPlot.season = field.season; - remainderPlot.creationHash = event.transaction.hash.toHexString(); - remainderPlot.createdAt = event.block.timestamp; - remainderPlot.updatedAt = event.block.timestamp; - remainderPlot.updatedAtBlock = event.block.number; - remainderPlot.index = remainderIndex; - remainderPlot.pods = sourceEndIndex.minus(transferEndIndex); - remainderPlot.harvestablePods = calcHarvestable(remainderPlot.index, remainderPlot.pods, currentHarvestable); - remainderPlot.beansPerPod = sourcePlot.beansPerPod; - remainderPlot.save(); - - // log.debug("\nPodTransfer: split source twice\n", []); - // log.debug("\nPodTransfer: Updated Source Pods - {}\n", [sourcePlot.pods.toString()]); - // log.debug("\nPodTransfer: Transferred Pods - {}\n", [toPlot.pods.toString()]); - // log.debug("\nPodTransfer: Remainder Pods - {}\n", [remainderPlot.pods.toString()]); - } - sortedPlots.sort(); - field.plotIndexes = sortedPlots; - field.save(); - - // Update any harvestable pod amounts - // No need to shift beanstalk field, only the farmer fields. - if (transferredHarvestable != ZERO_BI) { - updateFieldTotals( - event.address, - event.params.from, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI.minus(transferredHarvestable), - ZERO_BI, - event.block.timestamp, - event.block.number, - false - ); - updateFieldTotals( - event.address, - event.params.to, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - transferredHarvestable, - ZERO_BI, - event.block.timestamp, - event.block.number, - false - ); - } -} - -export function handleSupplyIncrease(event: SupplyIncrease): void { - updateFieldTotals( - event.address, - event.address, - event.params.newSoil, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number - ); -} - -export function handleSupplyDecrease(event: SupplyDecrease): void { - updateFieldTotals( - event.address, - event.address, - event.params.newSoil, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number - ); -} - -export function handleSupplyNeutral(event: SupplyNeutral): void { - updateFieldTotals( - event.address, - event.address, - event.params.newSoil, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number - ); -} - -export function handleFundFundraiser(event: FundFundraiser): void { - // Account for the fact that fundraiser sow using no soil. - updateFieldTotals( - event.address, - event.address, - ZERO_BI, - ZERO_BI.minus(event.params.amount), - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - event.block.timestamp, - event.block.number - ); -} - -function updateFieldTotals( - protocol: Address, - account: Address, - soil: BigInt, - sownBeans: BigInt, - sownPods: BigInt, - transferredPods: BigInt, - harvestablePods: BigInt, - harvestedPods: BigInt, - timestamp: BigInt, - blockNumber: BigInt, - recurs: boolean = true -): void { - if (recurs && account != protocol) { - updateFieldTotals( - protocol, - protocol, - soil, - sownBeans, - sownPods, - transferredPods, - harvestablePods, - harvestedPods, - timestamp, - blockNumber - ); - } - let field = loadField(account); - - field.season = getCurrentSeason(protocol); - field.soil = field.soil.plus(soil).minus(sownBeans); - field.sownBeans = field.sownBeans.plus(sownBeans); - field.unharvestablePods = field.unharvestablePods.plus(sownPods).minus(harvestablePods).plus(transferredPods); - field.harvestablePods = field.harvestablePods.plus(harvestablePods); - field.harvestedPods = field.harvestedPods.plus(harvestedPods); - field.podIndex = field.podIndex.plus(sownPods); - - takeFieldSnapshots(field, protocol, timestamp, blockNumber); - field.save(); - - // Set extra info on the hourly snapshot - if (field.soil == ZERO_BI) { - setHourlySoilSoldOut(blockNumber, field, protocol); - } -} - -export function updateHarvestablePlots(protocol: Address, harvestableIndex: BigInt, timestamp: BigInt, blockNumber: BigInt): void { - let field = loadField(protocol); - let sortedIndexes = field.plotIndexes.sort(); - - for (let i = 0; i < sortedIndexes.length; i++) { - if (sortedIndexes[i] > harvestableIndex) { - break; - } - let plot = loadPlot(protocol, sortedIndexes[i]); - - // Plot is fully harvestable, but hasn't been harvested yet - if (plot.harvestablePods == plot.pods) { - continue; - } - - let harvestablePods = harvestableIndex.minus(plot.index); - let oldHarvestablePods = plot.harvestablePods; - plot.harvestablePods = harvestablePods >= plot.pods ? plot.pods : harvestablePods; - plot.save(); - - let deltaHarvestablePods = oldHarvestablePods == ZERO_BI ? plot.harvestablePods : plot.harvestablePods.minus(oldHarvestablePods); - - updateFieldTotals( - protocol, - Address.fromString(plot.farmer), - ZERO_BI, - ZERO_BI, - ZERO_BI, - ZERO_BI, - deltaHarvestablePods, - ZERO_BI, - timestamp, - blockNumber - ); - } -} - -// Increment number of unique sowers (protocol only) -function incrementSowers(protocol: Address, timestamp: BigInt, blockNumber: BigInt): void { - let field = loadField(protocol); - field.numberOfSowers += 1; - takeFieldSnapshots(field, protocol, timestamp, blockNumber); - field.save(); -} - -// Increment total number of sows for either an account or the protocol -function incrementSows(protocol: Address, account: Address, timestamp: BigInt, blockNumber: BigInt, recurs: boolean = true): void { - if (recurs && account != protocol) { - incrementSows(protocol, protocol, timestamp, blockNumber); - } - - let field = loadField(account); - field.numberOfSows += 1; - takeFieldSnapshots(field, protocol, timestamp, blockNumber); - field.save(); - - // Add to protocol numberOfSowers if this is the first time this account has sown - if (account != protocol && field.numberOfSows == 0) { - incrementSowers(protocol, timestamp, blockNumber); - } -} diff --git a/projects/subgraph-beanstalk/src/SiloHandler.ts b/projects/subgraph-beanstalk/src/SiloHandler.ts deleted file mode 100644 index 0ce5c77bdc..0000000000 --- a/projects/subgraph-beanstalk/src/SiloHandler.ts +++ /dev/null @@ -1,483 +0,0 @@ -import { Address, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; -import { - AddDeposit, - StalkBalanceChanged, - SeedsBalanceChanged, - AddWithdrawal, - RemoveDeposit, - RemoveDeposits, - RemoveWithdrawal, - RemoveWithdrawals, - Plant, - WhitelistToken, - DewhitelistToken -} from "../generated/Beanstalk-ABIs/MarketV2"; -import { - AddDeposit as AddDeposit_V3, - RemoveDeposit as RemoveDeposit_V3, - RemoveDeposits as RemoveDeposits_V3, - UpdatedStalkPerBdvPerSeason, - WhitelistToken as WhitelistToken_V3 -} from "../generated/Beanstalk-ABIs/SiloV3"; -import { Replanted, TransferDepositCall, TransferDepositsCall } from "../generated/Beanstalk-ABIs/Replanted"; -import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { - loadSilo, - loadSiloAsset, - loadSiloWithdraw, - loadSiloDeposit, - loadWhitelistTokenSetting, - addToSiloWhitelist, - updateDeposit -} from "./utils/Silo"; -import { WhitelistToken as WhitelistTokenEntity, DewhitelistToken as DewhitelistTokenEntity, SiloDeposit, Silo } from "../generated/schema"; -import { getCurrentSeason, loadBeanstalk, loadFarmer } from "./utils/Beanstalk"; -import { BEANSTALK, BEAN_ERC20, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; -import { takeSiloSnapshots } from "./utils/snapshots/Silo"; -import { stemFromSeason } from "./utils/contracts/SiloCalculations"; -import { takeSiloAssetSnapshots } from "./utils/snapshots/SiloAsset"; -import { takeWhitelistTokenSettingSnapshots } from "./utils/snapshots/WhitelistTokenSetting"; - -class AddRemoveDepositsParams { - event: ethereum.Event; - account: Address; - token: Address; - seasons: BigInt[] | null; // Seasons not present in v3+ - stems: BigInt[] | null; // Stems not present in v2 - amounts: BigInt[]; - bdvs: BigInt[] | null; // bdv not present in v2 removal - depositVersion: String; -} - -function addDeposits(params: AddRemoveDepositsParams): void { - for (let i = 0; i < params.amounts.length; ++i) { - let deposit = loadSiloDeposit({ - account: params.account, - token: params.token, - depositVersion: params.depositVersion, - season: params.seasons != null ? params.seasons![i] : null, - stem: params.stems != null ? params.stems![i] : null - }); - - // Set granular deposit version type - if (params.depositVersion == "season") { - deposit.depositVersion = "season"; - // Fill stem according to legacy conversion - deposit.stemV31 = stemFromSeason(params.seasons![i].toI32(), params.token); - } else { - deposit.depositVersion = params.event.block.number > GAUGE_BIP45_BLOCK ? "v3.1" : "v3"; - deposit.stemV31 = params.event.block.number > GAUGE_BIP45_BLOCK ? deposit.stem! : deposit.stem!.times(BI_10.pow(6)); - } - - deposit = updateDeposit(deposit, params.amounts[i], params.bdvs![i], params.event)!; - deposit.save(); - - // Ensure that a Farmer entity is set up for this account. - loadFarmer(params.account); - - updateDepositInSilo( - params.event.address, - params.account, - params.token, - params.amounts[i], - params.bdvs![i], - params.event.block.timestamp - ); - } -} - -function removeDeposits(params: AddRemoveDepositsParams): void { - for (let i = 0; i < params.amounts.length; ++i) { - let deposit = loadSiloDeposit({ - account: params.account, - token: params.token, - depositVersion: params.depositVersion, - season: params.seasons != null ? params.seasons![i] : null, - stem: params.stems != null ? params.stems![i] : null - }); - - // Use bdv if it was provided (v2 events dont provide bdv), otherwise infer - let removedBdv = params.bdvs != null ? params.bdvs![i] : params.amounts[i].times(deposit.depositedBDV).div(deposit.depositedAmount); - - // If the amount goes to zero, the deposit is deleted and not returned - const updatedDeposit = updateDeposit(deposit, params.amounts[i].neg(), removedBdv.neg(), params.event); - if (updatedDeposit !== null) { - updatedDeposit.save(); - } - - // Update protocol totals - updateDepositInSilo( - params.event.address, - params.account, - params.token, - params.amounts[i].neg(), - removedBdv.neg(), - params.event.block.timestamp - ); - } -} - -/** - * SILO V2 (REPLANT) HANDLERS - */ - -export function handleAddDeposit(event: AddDeposit): void { - if (event.params.amount == ZERO_BI && event.params.bdv == ZERO_BI) { - // During replant there is at least one such event which should be ignored - return; - } - addDeposits({ - event, - account: event.params.account, - token: event.params.token, - seasons: [event.params.season], - stems: null, - amounts: [event.params.amount], - bdvs: [event.params.bdv], - depositVersion: "season" - }); -} - -export function handleRemoveDeposit(event: RemoveDeposit): void { - removeDeposits({ - event, - account: event.params.account, - token: event.params.token, - seasons: [event.params.season], - stems: null, - amounts: [event.params.amount], - bdvs: null, - depositVersion: "season" - }); -} - -export function handleRemoveDeposits(event: RemoveDeposits): void { - removeDeposits({ - event, - account: event.params.account, - token: event.params.token, - seasons: event.params.seasons, - stems: null, - amounts: event.params.amounts, - bdvs: null, - depositVersion: "season" - }); -} - -export function handleAddWithdrawal(event: AddWithdrawal): void { - let withdraw = loadSiloWithdraw(event.params.account, event.params.token, event.params.season.toI32()); - withdraw.amount = withdraw.amount.plus(event.params.amount); - withdraw.createdAt = withdraw.createdAt == ZERO_BI ? event.block.timestamp : withdraw.createdAt; - withdraw.save(); - - addWithdrawToSiloAsset(event.address, event.params.account, event.params.token, event.params.amount, event.block.timestamp); -} - -export function handleRemoveWithdrawal(event: RemoveWithdrawal): void { - updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.season, event.block.timestamp); -} - -export function handleRemoveWithdrawals(event: RemoveWithdrawals): void { - for (let i = 0; i < event.params.seasons.length; i++) { - updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.seasons[i], event.block.timestamp); - } -} - -/** - * SILO V3 HANDLERS - */ - -export function handleAddDeposit_V3(event: AddDeposit_V3): void { - addDeposits({ - event, - account: event.params.account, - token: event.params.token, - seasons: null, - stems: [event.params.stem], - amounts: [event.params.amount], - bdvs: [event.params.bdv], - depositVersion: "stem" - }); -} - -export function handleRemoveDeposit_V3(event: RemoveDeposit_V3): void { - removeDeposits({ - event, - account: event.params.account, - token: event.params.token, - seasons: null, - stems: [event.params.stem], - amounts: [event.params.amount], - bdvs: [event.params.bdv], - depositVersion: "stem" - }); -} - -export function handleRemoveDeposits_V3(event: RemoveDeposits_V3): void { - removeDeposits({ - event, - account: event.params.account, - token: event.params.token, - seasons: null, - stems: event.params.stems, - amounts: event.params.amounts, - bdvs: event.params.bdvs, - depositVersion: "stem" - }); -} - -export function handleStalkBalanceChanged(event: StalkBalanceChanged): void { - // Exclude BIP-24 emission of missed past events - if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { - return; - } - - updateStalkBalances(event.address, event.params.account, event.params.delta, event.params.deltaRoots, event.block.timestamp); -} - -export function handleSeedsBalanceChanged(event: SeedsBalanceChanged): void { - // Exclude BIP-24 emission of missed past events - if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { - return; - } - - updateSeedsBalances(event.address, event.params.account, event.params.delta, event.block.timestamp); -} - -export function handlePlant(event: Plant): void { - // This removes the plantable stalk for planted beans. - // Actual stalk credit for the farmer will be handled under the StalkBalanceChanged event. - - let silo = loadSilo(event.address); - let newPlantableStalk = event.params.beans.times(BigInt.fromI32(10000)); - - // Subtract stalk since it was already added in Reward, and is about to get re-added in StalkBalanceChanged. - silo.stalk = silo.stalk.minus(newPlantableStalk); - silo.plantableStalk = silo.plantableStalk.minus(newPlantableStalk); - silo.depositedBDV = silo.depositedBDV.minus(event.params.beans); - - takeSiloSnapshots(silo, event.address, event.block.timestamp); - silo.save(); - - // Remove the asset-only amount that got added in Reward event handler. - // Will be immediately re-credited to the user/system in AddDeposit - updateDepositInSiloAsset(event.address, event.address, BEAN_ERC20, event.params.beans, event.params.beans, event.block.timestamp); -} - -// These two calls are according to the Replant abi, before stems were included. -// They are not in use anymore and therefore it is unclear whether or not they are actually needed. -export function handleTransferDepositCall(call: TransferDepositCall): void { - let beanstalk = loadBeanstalk(BEANSTALK); - let updateFarmers = beanstalk.farmersToUpdate; - if (updateFarmers.indexOf(call.from.toHexString()) == -1) updateFarmers.push(call.from.toHexString()); - if (updateFarmers.indexOf(call.inputs.recipient.toHexString()) == -1) updateFarmers.push(call.inputs.recipient.toHexString()); - beanstalk.farmersToUpdate = updateFarmers; - beanstalk.save(); -} - -export function handleTransferDepositsCall(call: TransferDepositsCall): void { - let beanstalk = loadBeanstalk(BEANSTALK); - let updateFarmers = beanstalk.farmersToUpdate; - if (updateFarmers.indexOf(call.from.toHexString()) == -1) updateFarmers.push(call.from.toHexString()); - if (updateFarmers.indexOf(call.inputs.recipient.toHexString()) == -1) updateFarmers.push(call.inputs.recipient.toHexString()); - beanstalk.farmersToUpdate = updateFarmers; - beanstalk.save(); -} - -function updateDepositInSilo( - protocol: Address, - account: Address, - token: Address, - deltaAmount: BigInt, - deltaBdv: BigInt, - timestamp: BigInt, - recurs: boolean = true -): void { - if (recurs && account != protocol) { - updateDepositInSilo(protocol, protocol, token, deltaAmount, deltaBdv, timestamp); - } - let silo = loadSilo(account); - silo.depositedBDV = silo.depositedBDV.plus(deltaBdv); - - const newSeedStalk = updateDepositInSiloAsset(protocol, account, token, deltaAmount, deltaBdv, timestamp, false); - // Individual farmer seeds cannot be directly tracked due to seed gauge - if (account == protocol) { - silo.grownStalkPerSeason = silo.grownStalkPerSeason.plus(newSeedStalk); - } - takeSiloSnapshots(silo, protocol, timestamp); - silo.save(); -} - -export function updateDepositInSiloAsset( - protocol: Address, - account: Address, - token: Address, - deltaAmount: BigInt, - deltaBdv: BigInt, - timestamp: BigInt, - recurs: boolean = true -): BigInt { - if (recurs && account != protocol) { - updateDepositInSiloAsset(protocol, protocol, token, deltaAmount, deltaBdv, timestamp); - } - let asset = loadSiloAsset(account, token); - - let tokenSettings = loadWhitelistTokenSetting(token); - let newGrownStalk = deltaBdv.times(tokenSettings.stalkEarnedPerSeason).div(BigInt.fromI32(1000000)); - - asset.depositedBDV = asset.depositedBDV.plus(deltaBdv); - asset.depositedAmount = asset.depositedAmount.plus(deltaAmount); - - takeSiloAssetSnapshots(asset, protocol, timestamp); - asset.save(); - - return newGrownStalk; -} - -function addWithdrawToSiloAsset( - protocol: Address, - account: Address, - token: Address, - deltaAmount: BigInt, - timestamp: BigInt, - recurs: boolean = true -): void { - if (recurs && account != protocol) { - addWithdrawToSiloAsset(protocol, protocol, token, deltaAmount, timestamp); - } - let asset = loadSiloAsset(account, token); - asset.withdrawnAmount = asset.withdrawnAmount.plus(deltaAmount); - takeSiloAssetSnapshots(asset, protocol, timestamp); - asset.save(); -} - -export function updateStalkBalances( - protocol: Address, - account: Address, - deltaStalk: BigInt, - deltaRoots: BigInt, - timestamp: BigInt, - recurs: boolean = true -): void { - if (recurs && account != protocol) { - updateStalkBalances(protocol, protocol, deltaStalk, deltaRoots, timestamp); - } - let silo = loadSilo(account); - silo.stalk = silo.stalk.plus(deltaStalk); - silo.roots = silo.roots.plus(deltaRoots); - - takeSiloSnapshots(silo, protocol, timestamp); - - // Add account to active list if needed - if (account !== protocol) { - let beanstalk = loadBeanstalk(protocol); - let farmerIndex = beanstalk.activeFarmers.indexOf(account.toHexString()); - if (farmerIndex == -1) { - let newFarmers = beanstalk.activeFarmers; - newFarmers.push(account.toHexString()); - beanstalk.activeFarmers = newFarmers; - beanstalk.save(); - silo.activeFarmers += 1; - } else if (silo.stalk == ZERO_BI) { - let newFarmers = beanstalk.activeFarmers; - newFarmers.splice(farmerIndex, 1); - beanstalk.activeFarmers = newFarmers; - beanstalk.save(); - silo.activeFarmers -= 1; - } - } - silo.save(); -} - -function updateSeedsBalances(protocol: Address, account: Address, seeds: BigInt, timestamp: BigInt, recurs: boolean = true): void { - if (recurs && account != protocol) { - updateSeedsBalances(protocol, protocol, seeds, timestamp); - } - let silo = loadSilo(account); - silo.seeds = silo.seeds.plus(seeds); - takeSiloSnapshots(silo, protocol, timestamp); - silo.save(); -} - -function updateClaimedWithdraw(protocol: Address, account: Address, token: Address, withdrawSeason: BigInt, timestamp: BigInt): void { - let withdraw = loadSiloWithdraw(account, token, withdrawSeason.toI32()); - withdraw.claimed = true; - withdraw.save(); - - let asset = loadSiloAsset(account, token); - asset.withdrawnAmount = asset.withdrawnAmount.minus(withdraw.amount); - takeSiloAssetSnapshots(asset, protocol, timestamp); - asset.save(); -} - -export function updateStalkWithCalls(protocol: Address, timestamp: BigInt): void { - // This should be run at sunrise for the previous season to update any farmers stalk/seed/roots balances from silo transfers. - - let beanstalk = loadBeanstalk(protocol); - let beanstalk_call = Replanted.bind(protocol); - - for (let i = 0; i < beanstalk.farmersToUpdate.length; i++) { - let account = Address.fromString(beanstalk.farmersToUpdate[i]); - let silo = loadSilo(account); - updateStalkBalances( - protocol, - account, - beanstalk_call.balanceOfStalk(account).minus(silo.stalk), - beanstalk_call.balanceOfRoots(account).minus(silo.roots), - timestamp, - false - ); - // balanceOfSeeds function was removed in silov2 - updateSeedsBalances(protocol, account, beanstalk_call.balanceOfSeeds(account).minus(silo.seeds), timestamp, false); - } - beanstalk.farmersToUpdate = []; - beanstalk.save(); -} - -export function handleWhitelistToken(event: WhitelistToken): void { - addToSiloWhitelist(event.address, event.params.token); - - let setting = loadWhitelistTokenSetting(event.params.token); - setting.selector = event.params.selector; - setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); - setting.stalkEarnedPerSeason = event.params.stalk.times(BigInt.fromI32(1000000)); - - takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); - setting.save(); -} - -export function handleWhitelistToken_V3(event: WhitelistToken_V3): void { - addToSiloWhitelist(event.address, event.params.token); - - let setting = loadWhitelistTokenSetting(event.params.token); - setting.selector = event.params.selector; - setting.stalkIssuedPerBdv = event.params.stalk.times(BigInt.fromI32(1_000_000)); - setting.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; - - takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); - setting.save(); -} -// V4 whitelist for seed gauge is in GaugeHandler - -export function handleDewhitelistToken(event: DewhitelistToken): void { - let silo = loadSilo(event.address); - let currentWhitelist = silo.whitelistedTokens; - let currentDewhitelist = silo.dewhitelistedTokens; - let index = currentWhitelist.indexOf(event.params.token.toHexString()); - if (index >= 0) { - currentDewhitelist.push(currentWhitelist.splice(index, 1)[0]); - silo.whitelistedTokens = currentWhitelist; - silo.dewhitelistedTokens = currentDewhitelist; - silo.save(); - } -} - -export function handleUpdatedStalkPerBdvPerSeason(event: UpdatedStalkPerBdvPerSeason): void { - let siloSettings = loadWhitelistTokenSetting(event.params.token); - siloSettings.milestoneSeason = event.params.season.toI32(); - siloSettings.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; - siloSettings.updatedAt = event.block.timestamp; - - takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); - siloSettings.save(); -} diff --git a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts similarity index 69% rename from projects/subgraph-beanstalk/src/utils/Beanstalk.ts rename to projects/subgraph-beanstalk/src/entities/Beanstalk.ts index c33345eb48..ccba676725 100644 --- a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts @@ -1,5 +1,8 @@ import { BigInt, Address } from "@graphprotocol/graph-ts"; -import { Beanstalk, Farmer, Season } from "../../generated/schema"; +import { BEAN_ERC20, FERTILIZER } from "../../../subgraph-core/utils/Constants"; +import { Beanstalk } from "../../generated/schema"; +import { Farmer } from "../../generated/schema"; +import { Season } from "../../generated/schema"; import { ONE_BI, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; export function loadBeanstalk(protocol: Address): Beanstalk { @@ -7,7 +10,9 @@ export function loadBeanstalk(protocol: Address): Beanstalk { if (beanstalk == null) { beanstalk = new Beanstalk(protocol.toHexString()); beanstalk.name = "Beanstalk"; - beanstalk.slug = "beanstalk"; + // TODO: how to assign token/fertilizer + beanstalk.token = BEAN_ERC20.toHexString(); + beanstalk.fertilizer1155 = FERTILIZER.toHexString(); beanstalk.schemaVersion = "2.4.0"; beanstalk.subgraphVersion = "2.4.0"; beanstalk.methodologyVersion = "2.4.0"; @@ -61,6 +66,19 @@ export function loadSeason(diamondAddress: Address, id: BigInt): Season { return season; } +export function getBeanstalkToken(protocol: Address): Address { + let beanstalkEntity = loadBeanstalk(protocol); + return Address.fromString(beanstalkEntity.token); +} + +export function getBeanstalkFert(protocol: Address): Address | null { + let beanstalkEntity = loadBeanstalk(protocol); + if (beanstalkEntity.fertilizer1155 !== null) { + return Address.fromString(beanstalkEntity.fertilizer1155); + } + return null; +} + export function getCurrentSeason(protocol: Address): i32 { let beanstalkEntity = loadBeanstalk(protocol); return beanstalkEntity.lastSeason; @@ -74,3 +92,9 @@ export function getRewardMinted(season: i32): BigInt { } return snapshot.rewardBeans; } + +export function getHarvestableIndex(protocol: Address): BigInt { + let bs = loadBeanstalk(protocol); + let season = loadSeason(protocol, BigInt.fromI32(bs.lastSeason)); + return season.harvestableIndex; +} diff --git a/projects/subgraph-beanstalk/src/utils/Fertilizer.ts b/projects/subgraph-beanstalk/src/entities/Fertilizer.ts similarity index 85% rename from projects/subgraph-beanstalk/src/utils/Fertilizer.ts rename to projects/subgraph-beanstalk/src/entities/Fertilizer.ts index 8ac7bba05a..64413b35bc 100644 --- a/projects/subgraph-beanstalk/src/utils/Fertilizer.ts +++ b/projects/subgraph-beanstalk/src/entities/Fertilizer.ts @@ -2,12 +2,14 @@ import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; import { Farmer, Fertilizer, FertilizerBalance, FertilizerToken, FertilizerYield } from "../../generated/schema"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; -import { MarketV2 } from "../../generated/Beanstalk-ABIs/MarketV2"; +import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; export function loadFertilizer(fertilizerAddress: Address): Fertilizer { let fertilizer = Fertilizer.load(fertilizerAddress.toHexString()); if (fertilizer == null) { fertilizer = new Fertilizer(fertilizerAddress.toHexString()); + // TODO: how to assign beanstalk + fertilizer.beanstalk = BEANSTALK.toHexString(); fertilizer.supply = ZERO_BI; fertilizer.save(); } @@ -17,13 +19,13 @@ export function loadFertilizer(fertilizerAddress: Address): Fertilizer { export function loadFertilizerToken(fertilizer: Fertilizer, id: BigInt, blockNumber: BigInt): FertilizerToken { let fertilizerToken = FertilizerToken.load(id.toString()); if (fertilizerToken == null) { - let beanstalk = MarketV2.bind(BEANSTALK); + const beanstalkContract = SeedGauge.bind(Address.fromString(fertilizer.beanstalk)); fertilizerToken = new FertilizerToken(id.toString()); fertilizerToken.fertilizer = fertilizer.id; if (blockNumber.gt(BigInt.fromString("15278963"))) { - fertilizerToken.humidity = BigDecimal.fromString(beanstalk.getCurrentHumidity().toString()).div(BigDecimal.fromString("10")); - fertilizerToken.season = beanstalk.season().toI32(); - fertilizerToken.startBpf = beanstalk.beansPerFertilizer(); + fertilizerToken.humidity = BigDecimal.fromString(beanstalkContract.getCurrentHumidity().toString()).div(BigDecimal.fromString("10")); + fertilizerToken.season = beanstalkContract.season().toI32(); + fertilizerToken.startBpf = beanstalkContract.beansPerFertilizer(); } else { fertilizerToken.humidity = BigDecimal.fromString("500"); fertilizerToken.season = 6074; diff --git a/projects/subgraph-beanstalk/src/entities/Field.ts b/projects/subgraph-beanstalk/src/entities/Field.ts new file mode 100644 index 0000000000..4bc661c8c9 --- /dev/null +++ b/projects/subgraph-beanstalk/src/entities/Field.ts @@ -0,0 +1,59 @@ +import { Address, BigInt } from "@graphprotocol/graph-ts"; +import { Field, Plot } from "../../generated/schema"; +import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { ADDRESS_ZERO, BEANSTALK, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; +import { loadBeanstalk, loadSeason } from "./Beanstalk"; + +export function loadField(account: Address): Field { + let field = Field.load(account.toHexString()); + if (field == null) { + field = new Field(account.toHexString()); + field.beanstalk = BEANSTALK.toHexString(); + if (account !== BEANSTALK) { + field.farmer = account.toHexString(); + } + field.season = 1; + field.temperature = 1; + field.realRateOfReturn = ZERO_BD; + field.numberOfSowers = 0; + field.numberOfSows = 0; + field.sownBeans = ZERO_BI; + field.plotIndexes = []; + field.unharvestablePods = ZERO_BI; + field.harvestablePods = ZERO_BI; + field.harvestedPods = ZERO_BI; + field.soil = ZERO_BI; + field.podIndex = ZERO_BI; + field.podRate = ZERO_BD; + field.save(); + } + return field; +} + +export function loadPlot(diamondAddress: Address, index: BigInt): Plot { + let plot = Plot.load(index.toString()); + if (plot == null) { + plot = new Plot(index.toString()); + plot.field = diamondAddress.toHexString(); + plot.farmer = ADDRESS_ZERO.toHexString(); + plot.source = "SOW"; // Should be overwritten in case of a transfer creating a new plot + plot.sourceHash = ""; + plot.season = 0; + plot.creationHash = ""; + plot.createdAt = ZERO_BI; + plot.updatedAt = ZERO_BI; + plot.updatedAtBlock = ZERO_BI; + plot.index = index; + plot.pods = ZERO_BI; + plot.beansPerPod = ZERO_BI; + plot.harvestablePods = ZERO_BI; + plot.harvestedPods = ZERO_BI; + plot.fullyHarvested = false; + plot.save(); + + let field = loadField(diamondAddress); + field.plotIndexes.push(plot.index); + field.save(); + } + return plot; +} diff --git a/projects/subgraph-beanstalk/src/utils/Germinating.ts b/projects/subgraph-beanstalk/src/entities/Germinating.ts similarity index 100% rename from projects/subgraph-beanstalk/src/utils/Germinating.ts rename to projects/subgraph-beanstalk/src/entities/Germinating.ts diff --git a/projects/subgraph-beanstalk/src/entities/PodMarketplace.ts b/projects/subgraph-beanstalk/src/entities/PodMarketplace.ts new file mode 100644 index 0000000000..96c1c803cd --- /dev/null +++ b/projects/subgraph-beanstalk/src/entities/PodMarketplace.ts @@ -0,0 +1,165 @@ +import { Address, BigInt, Bytes, log } from "@graphprotocol/graph-ts"; +import { loadField } from "./Field"; +import { PodFill, PodListing, PodMarketplace, PodOrder } from "../../generated/schema"; +import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; + +export function loadPodMarketplace(protocol: Address): PodMarketplace { + let marketplace = PodMarketplace.load(protocol.toHexString()); + if (marketplace == null) { + let field = loadField(protocol); + marketplace = new PodMarketplace(protocol.toHexString()); + marketplace.season = field.season; + marketplace.activeListings = []; + marketplace.activeOrders = []; + marketplace.listedPods = ZERO_BI; + marketplace.availableListedPods = ZERO_BI; + marketplace.filledListedPods = ZERO_BI; + marketplace.expiredListedPods = ZERO_BI; + marketplace.cancelledListedPods = ZERO_BI; + marketplace.orderBeans = ZERO_BI; + marketplace.availableOrderBeans = ZERO_BI; + marketplace.filledOrderedPods = ZERO_BI; + marketplace.filledOrderBeans = ZERO_BI; + marketplace.cancelledOrderBeans = ZERO_BI; + marketplace.podVolume = ZERO_BI; + marketplace.beanVolume = ZERO_BI; + marketplace.save(); + } + return marketplace; +} + +export function loadPodFill(protocol: Address, index: BigInt, hash: String): PodFill { + let id = protocol.toHexString() + "-" + index.toString() + "-" + hash; + let fill = PodFill.load(id); + if (fill == null) { + fill = new PodFill(id); + fill.podMarketplace = protocol.toHexString(); + fill.createdAt = ZERO_BI; + fill.fromFarmer = ""; + fill.toFarmer = ""; + fill.placeInLine = ZERO_BI; + fill.amount = ZERO_BI; + fill.index = ZERO_BI; + fill.start = ZERO_BI; + fill.costInBeans = ZERO_BI; + fill.save(); + } + return fill; +} + +export function loadPodListing(account: Address, index: BigInt): PodListing { + let id = account.toHexString() + "-" + index.toString(); + let listing = PodListing.load(id); + if (listing == null) { + listing = new PodListing(id); + listing.podMarketplace = BEANSTALK.toHexString(); + listing.historyID = ""; + listing.plot = index.toString(); + listing.farmer = account.toHexString(); + listing.index = index; + listing.start = ZERO_BI; + listing.mode = 0; + listing.maxHarvestableIndex = ZERO_BI; + listing.minFillAmount = ZERO_BI; + listing.pricePerPod = 0; + listing.originalIndex = index; + listing.originalAmount = ZERO_BI; + listing.filled = ZERO_BI; + listing.amount = ZERO_BI; + listing.remainingAmount = ZERO_BI; + listing.filledAmount = ZERO_BI; + listing.status = "ACTIVE"; + listing.createdAt = ZERO_BI; + listing.creationHash = ""; + listing.updatedAt = ZERO_BI; + listing.save(); + } + return listing; +} + +export function createHistoricalPodListing(listing: PodListing): void { + let created = false; + let id = listing.id; + for (let i = 0; !created; i++) { + id = listing.id + "-" + i.toString(); + let newListing = PodListing.load(id); + if (newListing == null) { + newListing = new PodListing(id); + newListing.podMarketplace = listing.podMarketplace; + newListing.historyID = listing.historyID; + newListing.plot = listing.plot; + newListing.farmer = listing.farmer; + newListing.index = listing.index; + newListing.start = listing.start; + newListing.mode = listing.mode; + newListing.maxHarvestableIndex = listing.maxHarvestableIndex; + newListing.minFillAmount = listing.minFillAmount; + newListing.pricePerPod = listing.pricePerPod; + newListing.originalIndex = listing.originalIndex; + newListing.originalAmount = listing.originalAmount; + newListing.filled = listing.filled; + newListing.amount = listing.amount; + newListing.remainingAmount = listing.remainingAmount; + newListing.filledAmount = listing.filledAmount; + newListing.fill = listing.fill; + newListing.status = listing.status; + newListing.createdAt = listing.createdAt; + newListing.updatedAt = listing.updatedAt; + newListing.creationHash = listing.creationHash; + newListing.save(); + created = true; + } + } +} + +export function loadPodOrder(orderID: Bytes): PodOrder { + let order = PodOrder.load(orderID.toHexString()); + if (order == null) { + order = new PodOrder(orderID.toHexString()); + order.podMarketplace = BEANSTALK.toHexString(); + order.historyID = ""; + order.farmer = ""; + order.createdAt = ZERO_BI; + order.updatedAt = ZERO_BI; + order.status = ""; + order.beanAmount = ZERO_BI; + order.podAmountFilled = ZERO_BI; + order.beanAmountFilled = ZERO_BI; + order.minFillAmount = ZERO_BI; + order.maxPlaceInLine = ZERO_BI; + order.pricePerPod = 0; + order.creationHash = ""; + order.fills = []; + order.save(); + } + return order; +} + +export function createHistoricalPodOrder(order: PodOrder): void { + let created = false; + let id = order.id; + for (let i = 0; !created; i++) { + id = order.id + "-" + i.toString(); + let newOrder = PodOrder.load(id); + if (newOrder == null) { + newOrder = new PodOrder(id); + newOrder.podMarketplace = order.podMarketplace; + newOrder.historyID = order.historyID; + newOrder.farmer = order.farmer; + newOrder.createdAt = order.createdAt; + newOrder.updatedAt = order.updatedAt; + newOrder.status = order.status; + newOrder.beanAmount = order.beanAmount; + newOrder.podAmountFilled = order.podAmountFilled; + newOrder.beanAmountFilled = order.beanAmountFilled; + newOrder.minFillAmount = order.minFillAmount; + newOrder.maxPlaceInLine = order.maxPlaceInLine; + newOrder.pricePerPod = order.pricePerPod; + newOrder.creationHash = order.creationHash; + newOrder.fills = order.fills; + newOrder.save(); + created = true; + } + } +} diff --git a/projects/subgraph-beanstalk/src/entities/Silo.ts b/projects/subgraph-beanstalk/src/entities/Silo.ts new file mode 100644 index 0000000000..85bdc4c8de --- /dev/null +++ b/projects/subgraph-beanstalk/src/entities/Silo.ts @@ -0,0 +1,209 @@ +import { Address, BigInt, Bytes, ethereum, store, log } from "@graphprotocol/graph-ts"; +import { Silo, SiloDeposit, SiloWithdraw, SiloYield, SiloAsset, WhitelistTokenSetting, TokenYield } from "../../generated/schema"; +import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; +import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; + +/* ===== Base Silo Entities ===== */ + +export function loadSilo(account: Address): Silo { + let silo = Silo.load(account.toHexString()); + if (silo == null) { + silo = new Silo(account.toHexString()); + silo.beanstalk = BEANSTALK.toHexString(); + if (account !== BEANSTALK) { + silo.farmer = account.toHexString(); + } + silo.whitelistedTokens = []; + silo.dewhitelistedTokens = []; + silo.depositedBDV = ZERO_BI; + silo.stalk = ZERO_BI; + silo.plantableStalk = ZERO_BI; + silo.seeds = ZERO_BI; + silo.grownStalkPerSeason = ZERO_BI; + silo.roots = ZERO_BI; + silo.germinatingStalk = ZERO_BI; + silo.beanMints = ZERO_BI; + silo.activeFarmers = 0; + silo.save(); + } + return silo as Silo; +} + +/* ===== Asset Entities ===== */ + +export function loadSiloAsset(account: Address, token: Address): SiloAsset { + let id = account.toHexString() + "-" + token.toHexString(); + let asset = SiloAsset.load(id); + + if (asset == null) { + asset = new SiloAsset(id); + asset.silo = account.toHexString(); + asset.token = token.toHexString(); + asset.depositedBDV = ZERO_BI; + asset.depositedAmount = ZERO_BI; + asset.withdrawnAmount = ZERO_BI; + asset.farmAmount = ZERO_BI; + asset.save(); + } + return asset as SiloAsset; +} + +/* ===== Whitelist Token Settings Entities ===== */ + +export function addToSiloWhitelist(siloAddress: Address, token: Address): void { + let silo = loadSilo(siloAddress); + let currentList = silo.whitelistedTokens; + currentList.push(token.toHexString()); + silo.whitelistedTokens = currentList; + silo.save(); +} + +export function loadWhitelistTokenSetting(token: Address): WhitelistTokenSetting { + let setting = WhitelistTokenSetting.load(token); + if (setting == null) { + setting = new WhitelistTokenSetting(token); + setting.selector = Bytes.empty(); + setting.stalkEarnedPerSeason = ZERO_BI; + setting.stalkIssuedPerBdv = ZERO_BI; + setting.milestoneSeason = 0; + setting.updatedAt = ZERO_BI; + setting.save(); + + // Check token addresses and set replant seeds/stalk for Unripe due to event timing. + if (token == UNRIPE_BEAN) { + setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); + setting.stalkEarnedPerSeason = BigInt.fromI32(2000000); + setting.save(); + } else if (token == UNRIPE_BEAN_3CRV) { + setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); + setting.stalkEarnedPerSeason = BigInt.fromI32(4000000); + setting.save(); + } + } + return setting as WhitelistTokenSetting; +} + +/* ===== Deposit Entities ===== */ + +class SiloDepositID { + account: Address; + token: Address; + depositVersion: String; + season: BigInt | null; + stem: BigInt | null; +} + +export function loadSiloDeposit(depositId: SiloDepositID): SiloDeposit { + // id: Account - Token Address - Deposit Version - (Season|Stem) + const seasonOrStem = depositId.depositVersion == "season" ? depositId.season! : depositId.stem!; + const id = + depositId.account.toHexString() + "-" + depositId.token.toHexString() + "-" + depositId.depositVersion + "-" + seasonOrStem.toString(); + let deposit = SiloDeposit.load(id); + if (deposit == null) { + deposit = new SiloDeposit(id); + deposit.farmer = depositId.account.toHexString(); + deposit.token = depositId.token.toHexString(); + deposit.depositVersion = depositId.depositVersion.toString(); + if (depositId.season !== null) { + deposit.season = depositId.season!.toU32(); + } + deposit.stem = depositId.stem; + deposit.stemV31 = ZERO_BI; + deposit.depositedAmount = ZERO_BI; + deposit.depositedBDV = ZERO_BI; + deposit.hashes = []; + deposit.createdBlock = ZERO_BI; + deposit.updatedBlock = ZERO_BI; + deposit.createdAt = ZERO_BI; + deposit.updatedAt = ZERO_BI; + deposit.save(); + } + return deposit; +} + +// Updates the given SiloDeposit with new amounts/bdv. If the deposit was fully withdrawn, delete the SiloDeposit. +export function updateDeposit(deposit: SiloDeposit, deltaAmount: BigInt, deltaBdv: BigInt, event: ethereum.Event): SiloDeposit | null { + deposit.depositedAmount = deposit.depositedAmount.plus(deltaAmount); + if (deposit.depositedAmount <= ZERO_BI) { + store.remove("SiloDeposit", deposit.id); + return null; + } + deposit.depositedBDV = deposit.depositedBDV.plus(deltaBdv); + let depositHashes = deposit.hashes; + depositHashes.push(event.transaction.hash.toHexString()); + deposit.hashes = depositHashes; + deposit.createdBlock = deposit.createdBlock == ZERO_BI ? event.block.number : deposit.createdBlock; + deposit.createdAt = deposit.createdAt == ZERO_BI ? event.block.timestamp : deposit.createdAt; + deposit.updatedBlock = event.block.number; + deposit.updatedAt = event.block.timestamp; + return deposit; +} + +/* ===== Withdraw Entities ===== */ + +export function loadSiloWithdraw(account: Address, token: Address, season: i32): SiloWithdraw { + let id = account.toHexString() + "-" + token.toHexString() + "-" + season.toString(); + let withdraw = SiloWithdraw.load(id); + if (withdraw == null) { + withdraw = new SiloWithdraw(id); + withdraw.farmer = account.toHexString(); + withdraw.token = token.toHexString(); + withdraw.withdrawSeason = season; + withdraw.claimableSeason = season + 1; + withdraw.claimed = false; + withdraw.amount = ZERO_BI; + withdraw.createdAt = ZERO_BI; + withdraw.save(); + } + return withdraw as SiloWithdraw; +} + +/* ===== Yield Entities ===== */ + +export function loadSiloYield(season: i32, window: i32): SiloYield { + let siloYield = SiloYield.load(season.toString() + "-" + window.toString()); + if (siloYield == null) { + siloYield = new SiloYield(season.toString() + "-" + window.toString()); + siloYield.season = season; + siloYield.beta = ZERO_BD; + siloYield.u = 0; + siloYield.beansPerSeasonEMA = ZERO_BD; + siloYield.whitelistedTokens = []; + siloYield.createdAt = ZERO_BI; + + if (window == 24) { + siloYield.emaWindow = "ROLLING_24_HOUR"; + } else if (window == 168) { + siloYield.emaWindow = "ROLLING_7_DAY"; + } else if (window == 720) { + siloYield.emaWindow = "ROLLING_30_DAY"; + } + siloYield.save(); + } + return siloYield as SiloYield; +} + +export function loadTokenYield(token: Address, season: i32, window: i32): TokenYield { + let id = token.concatI32(season).concatI32(window); + let tokenYield = TokenYield.load(id); + if (tokenYield == null) { + tokenYield = new TokenYield(id); + tokenYield.token = token; + tokenYield.season = season; + tokenYield.siloYield = season.toString() + "-" + window.toString(); + tokenYield.beanAPY = ZERO_BD; + tokenYield.stalkAPY = ZERO_BD; + tokenYield.createdAt = ZERO_BI; + tokenYield.save(); + } + return tokenYield as TokenYield; +} + +export function SiloAsset_findIndex_token(a: SiloAsset[], targetToken: string): i32 { + for (let j = 0; j < a.length; j++) { + if (a[j].token == targetToken) { + return j; + } + } + return -1; +} diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Field.ts b/projects/subgraph-beanstalk/src/entities/snapshots/Field.ts similarity index 98% rename from projects/subgraph-beanstalk/src/utils/snapshots/Field.ts rename to projects/subgraph-beanstalk/src/entities/snapshots/Field.ts index cd56e52d68..e94fd9f926 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/Field.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/Field.ts @@ -2,7 +2,6 @@ import { BigInt, Address, log } from "@graphprotocol/graph-ts"; import { Field, FieldDailySnapshot, FieldHourlySnapshot } from "../../../generated/schema"; import { getCurrentSeason } from "../Beanstalk"; import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; -import { BI_MAX, ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; export function takeFieldSnapshots(field: Field, protocol: Address, timestamp: BigInt, blockNumber: BigInt): void { const currentSeason = getCurrentSeason(protocol); @@ -183,7 +182,7 @@ export function takeFieldSnapshots(field: Field, protocol: Address, timestamp: B } // Set case id on hourly. Snapshot must have already been created. -export function setHourlyCaseId(caseId: BigInt, field: Field, protocol: Address): void { +export function setFieldHourlyCaseId(caseId: BigInt, field: Field, protocol: Address): void { const currentSeason = getCurrentSeason(protocol); const hourly = FieldHourlySnapshot.load(field.id + "-" + currentSeason.toString())!; hourly.caseId = caseId; diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Marketplace.ts b/projects/subgraph-beanstalk/src/entities/snapshots/Marketplace.ts similarity index 100% rename from projects/subgraph-beanstalk/src/utils/snapshots/Marketplace.ts rename to projects/subgraph-beanstalk/src/entities/snapshots/Marketplace.ts diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts b/projects/subgraph-beanstalk/src/entities/snapshots/Silo.ts similarity index 98% rename from projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts rename to projects/subgraph-beanstalk/src/entities/snapshots/Silo.ts index 8ebcb4f1fd..c9845b96bb 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/Silo.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/Silo.ts @@ -134,7 +134,7 @@ export function takeSiloSnapshots(silo: Silo, protocol: Address, timestamp: BigI } // Set case id on hourly snapshot. Snapshot must have already been created. -export function setHourlyCaseId(caseId: BigInt, silo: Silo, protocol: Address): void { +export function setSiloHourlyCaseId(caseId: BigInt, silo: Silo, protocol: Address): void { const currentSeason = getCurrentSeason(protocol); const hourly = SiloHourlySnapshot.load(silo.id + "-" + currentSeason.toString())!; hourly.caseId = caseId; diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/SiloAsset.ts b/projects/subgraph-beanstalk/src/entities/snapshots/SiloAsset.ts similarity index 100% rename from projects/subgraph-beanstalk/src/utils/snapshots/SiloAsset.ts rename to projects/subgraph-beanstalk/src/entities/snapshots/SiloAsset.ts index ff66a7cd8d..e9f9e72d10 100644 --- a/projects/subgraph-beanstalk/src/utils/snapshots/SiloAsset.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/SiloAsset.ts @@ -1,7 +1,7 @@ import { BigInt, Address, log } from "@graphprotocol/graph-ts"; import { SiloAsset, SiloAssetDailySnapshot, SiloAssetHourlySnapshot } from "../../../generated/schema"; -import { getCurrentSeason } from "../Beanstalk"; import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; +import { getCurrentSeason } from "../Beanstalk"; export function takeSiloAssetSnapshots(siloAsset: SiloAsset, protocol: Address, timestamp: BigInt): void { const currentSeason = getCurrentSeason(protocol); diff --git a/projects/subgraph-beanstalk/src/utils/snapshots/WhitelistTokenSetting.ts b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts similarity index 100% rename from projects/subgraph-beanstalk/src/utils/snapshots/WhitelistTokenSetting.ts rename to projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts diff --git a/projects/subgraph-beanstalk/src/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts similarity index 69% rename from projects/subgraph-beanstalk/src/BarnHandler.ts rename to projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index e0a108db8a..0c919c62d3 100644 --- a/projects/subgraph-beanstalk/src/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -1,27 +1,26 @@ -import { Chop as ChopEntity } from "../generated/schema"; -import { Chop } from "../generated/Beanstalk-ABIs/MarketV2"; import { Address, BigInt, log } from "@graphprotocol/graph-ts"; -import { TransferSingle, TransferBatch } from "../generated/Beanstalk-ABIs/Fertilizer"; -import { ADDRESS_ZERO, FERTILIZER } from "../../subgraph-core/utils/Constants"; -import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "./utils/Fertilizer"; -import { loadFarmer } from "./utils/Beanstalk"; +import { Chop as ChopEntity } from "../../generated/schema"; +import { Chop } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { TransferSingle, TransferBatch } from "../../generated/Beanstalk-ABIs/Fertilizer"; +import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; +import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; +import { loadFarmer } from "../entities/Beanstalk"; export function handleTransferSingle(event: TransferSingle): void { - handleTransfer(event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); + handleTransfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); } export function handleTransferBatch(event: TransferBatch): void { for (let i = 0; i < event.params.ids.length; i++) { let id = event.params.ids[i]; let amount = event.params.values[i]; - handleTransfer(event.params.from, event.params.to, id, amount, event.block.number); + handleTransfer(event.address, event.params.from, event.params.to, id, amount, event.block.number); } } -function handleTransfer(from: Address, to: Address, id: BigInt, amount: BigInt, blockNumber: BigInt): void { - let fertilizer = loadFertilizer(FERTILIZER); +function handleTransfer(fertilizer1155: Address, from: Address, to: Address, id: BigInt, amount: BigInt, blockNumber: BigInt): void { + let fertilizer = loadFertilizer(fertilizer1155); let fertilizerToken = loadFertilizerToken(fertilizer, id, blockNumber); - log.debug("\nFert Transfer: id – {}\n", [id.toString()]); if (from != ADDRESS_ZERO) { let fromFarmer = loadFarmer(from); let fromFertilizerBalance = loadFertilizerBalance(fertilizerToken, fromFarmer); diff --git a/projects/subgraph-beanstalk/src/handlers/BeanHandler.ts b/projects/subgraph-beanstalk/src/handlers/BeanHandler.ts new file mode 100644 index 0000000000..5017fe9fe0 --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/BeanHandler.ts @@ -0,0 +1,20 @@ +import { BigInt, log } from "@graphprotocol/graph-ts"; +import { Transfer } from "../../generated/Beanstalk-ABIs/ERC20"; +import { ADDRESS_ZERO, BEANSTALK } from "../../../subgraph-core/utils/Constants"; +import { loadBeanstalk, loadSeason } from "../entities/Beanstalk"; + +export function handleTransfer(event: Transfer): void { + if (event.params.from == ADDRESS_ZERO || event.params.to == ADDRESS_ZERO) { + let beanstalk = loadBeanstalk(BEANSTALK); + let season = loadSeason(BEANSTALK, BigInt.fromI32(beanstalk.lastSeason)); + + if (event.params.from == ADDRESS_ZERO) { + season.deltaBeans = season.deltaBeans.plus(event.params.value); + season.beans = season.beans.plus(event.params.value); + } else { + season.deltaBeans = season.deltaBeans.minus(event.params.value); + season.beans = season.beans.minus(event.params.value); + } + season.save(); + } +} diff --git a/projects/subgraph-beanstalk/src/DiamondHandler.ts b/projects/subgraph-beanstalk/src/handlers/DiamondHandler.ts similarity index 58% rename from projects/subgraph-beanstalk/src/DiamondHandler.ts rename to projects/subgraph-beanstalk/src/handlers/DiamondHandler.ts index 338e18afac..933d4aaef7 100644 --- a/projects/subgraph-beanstalk/src/DiamondHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/DiamondHandler.ts @@ -1,9 +1,8 @@ -import { DiamondCut } from "../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "./utils/Beanstalk"; +import { DiamondCut } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { loadBeanstalk } from "../entities/Beanstalk"; export function handleDiamondCut(event: DiamondCut): void { let beanstalk = loadBeanstalk(event.address); - beanstalk.lastUpgrade = event.block.timestamp; beanstalk.save(); } diff --git a/projects/subgraph-beanstalk/src/FarmHandler.ts b/projects/subgraph-beanstalk/src/handlers/FarmHandler.ts similarity index 74% rename from projects/subgraph-beanstalk/src/FarmHandler.ts rename to projects/subgraph-beanstalk/src/handlers/FarmHandler.ts index 8ca6767065..16d443c2e8 100644 --- a/projects/subgraph-beanstalk/src/FarmHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/FarmHandler.ts @@ -1,8 +1,8 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; -import { InternalBalanceChanged } from "../generated/Beanstalk-ABIs/MarketV2"; -import { loadFarmer } from "./utils/Beanstalk"; -import { loadSiloAsset } from "./utils/Silo"; -import { takeSiloAssetSnapshots } from "./utils/snapshots/SiloAsset"; +import { InternalBalanceChanged } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { takeSiloAssetSnapshots } from "../entities/snapshots/SiloAsset"; +import { loadSiloAsset } from "../entities/Silo"; +import { loadFarmer } from "../entities/Beanstalk"; export function handleInternalBalanceChanged(event: InternalBalanceChanged): void { loadFarmer(event.params.user); diff --git a/projects/subgraph-beanstalk/src/handlers/FieldHandler.ts b/projects/subgraph-beanstalk/src/handlers/FieldHandler.ts new file mode 100644 index 0000000000..6477e27923 --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/FieldHandler.ts @@ -0,0 +1,51 @@ +import { BigInt, log } from "@graphprotocol/graph-ts"; +import { BEANSTALK_FARMS } from "../../../subgraph-core/utils/Constants"; +import { loadField } from "../entities/Field"; +import { harvest, plotTransfer, sow, temperatureChanged } from "../utils/Field"; +import { Sow, Harvest, PlotTransfer, TemperatureChange } from "../../generated/Beanstalk-ABIs/SeedGauge"; + +export function handleSow(event: Sow): void { + let sownOverride: BigInt | null = null; + if (event.params.account == BEANSTALK_FARMS) { + let startingField = loadField(event.address); + sownOverride = startingField.soil; + } + sow({ + event, + account: event.params.account, + fieldId: null, + index: event.params.index, + beans: sownOverride !== null ? sownOverride : event.params.beans, + pods: event.params.pods + }); +} + +export function handleHarvest(event: Harvest): void { + harvest({ + event, + account: event.params.account, + fieldId: null, + plots: event.params.plots, + beans: event.params.beans + }); +} + +export function handlePlotTransfer(event: PlotTransfer): void { + plotTransfer({ + event, + from: event.params.from, + to: event.params.to, + fieldId: null, + index: event.params.id, + amount: event.params.pods + }); +} + +export function handleTemperatureChange(event: TemperatureChange): void { + temperatureChanged({ + event, + season: event.params.season, + caseId: event.params.caseId, + absChange: event.params.absChange + }); +} diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts similarity index 75% rename from projects/subgraph-beanstalk/src/GaugeHandler.ts rename to projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts index fa2fc8dd25..9aad908f87 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts @@ -1,30 +1,22 @@ import { BeanToMaxLpGpPerBdvRatioChange, GaugePointChange, - TemperatureChange, UpdateAverageStalkPerBdvPerSeason, FarmerGerminatingStalkBalanceChanged, TotalGerminatingBalanceChanged, UpdateGaugeSettings, - WhitelistToken, TotalGerminatingStalkChanged, TotalStalkChangedFromGermination -} from "../generated/Beanstalk-ABIs/SeedGauge"; -import { handleRateChange } from "./utils/Field"; -import { loadSilo, loadWhitelistTokenSetting, addToSiloWhitelist } from "./utils/Silo"; -import { deleteGerminating, loadGerminating, loadOrCreateGerminating } from "./utils/Germinating"; -import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { updateStalkBalances } from "./SiloHandler"; -import { WhitelistToken as WhitelistTokenEntity } from "../generated/schema"; -import { BEAN_WETH_CP2_WELL } from "../../subgraph-core/utils/Constants"; -import { Bytes4_emptyToNull } from "../../subgraph-core/utils/Bytes"; -import { getCurrentSeason } from "./utils/Beanstalk"; -import { setHourlyCaseId, takeSiloSnapshots } from "./utils/snapshots/Silo"; -import { takeWhitelistTokenSettingSnapshots } from "./utils/snapshots/WhitelistTokenSetting"; - -export function handleTemperatureChange(event: TemperatureChange): void { - handleRateChange(event.address, event.block, event.params.season, event.params.caseId, event.params.absChange); -} +} from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { deleteGerminating, loadGerminating, loadOrCreateGerminating } from "../entities/Germinating"; +import { BI_10, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { BEAN_WETH_CP2_WELL } from "../../../subgraph-core/utils/Constants"; +import { Bytes4_emptyToNull } from "../../../subgraph-core/utils/Bytes"; +import { setSiloHourlyCaseId, takeSiloSnapshots } from "../entities/snapshots/Silo"; +import { loadSilo, loadWhitelistTokenSetting } from "../entities/Silo"; +import { takeWhitelistTokenSettingSnapshots } from "../entities/snapshots/WhitelistTokenSetting"; +import { getCurrentSeason } from "../entities/Beanstalk"; +import { updateStalkBalances } from "../utils/Silo"; // SEED GAUGE SEASONAL ADJUSTMENTS // @@ -37,7 +29,7 @@ export function handleBeanToMaxLpGpPerBdvRatioChange(event: BeanToMaxLpGpPerBdvR silo.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio!.plus(event.params.absChange); } takeSiloSnapshots(silo, event.address, event.block.timestamp); - setHourlyCaseId(event.params.caseId, silo, event.address); + setSiloHourlyCaseId(event.params.caseId, silo, event.address); silo.save(); } @@ -57,7 +49,7 @@ export function handleUpdateAverageStalkPerBdvPerSeason(event: UpdateAverageStal takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); - // Individual asset grown stalk is set by the UpdatedStalkPerBdvPerSeason event in SiloHandler + // Individual asset grown stalk is set by the UpdatedStalkPerBdvPerSeason event. } // GERMINATING STALK // @@ -140,25 +132,7 @@ export function handleTotalStalkChangedFromGermination(event: TotalStalkChangedF updateStalkBalances(event.address, event.address, event.params.deltaStalk, event.params.deltaRoots, event.block.timestamp); } -// WHITELIST / GAUGE CONFIGURATION SETTINGS // - -export function handleWhitelistToken_BIP45(event: WhitelistToken): void { - addToSiloWhitelist(event.address, event.params.token); - - let siloSettings = loadWhitelistTokenSetting(event.params.token); - - siloSettings.selector = event.params.selector; - siloSettings.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; - siloSettings.stalkIssuedPerBdv = event.params.stalkIssuedPerBdv; - siloSettings.gaugePoints = event.params.gaugePoints; - siloSettings.gpSelector = Bytes4_emptyToNull(event.params.gpSelector); - siloSettings.lwSelector = Bytes4_emptyToNull(event.params.lwSelector); - siloSettings.optimalPercentDepositedBdv = event.params.optimalPercentDepositedBdv; - siloSettings.updatedAt = event.block.timestamp; - - takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); - siloSettings.save(); -} +// GAUGE CONFIGURATION SETTINGS // export function handleUpdateGaugeSettings(event: UpdateGaugeSettings): void { let siloSettings = loadWhitelistTokenSetting(event.params.token); diff --git a/projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts b/projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts new file mode 100644 index 0000000000..fb1a21bb5a --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts @@ -0,0 +1,149 @@ +import { Address, BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"; +import { + PodListingCreated, + PodListingFilled, + PodOrderCreated, + PodOrderFilled, + PodListingCancelled, + PodOrderCancelled +} from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { + PodListingCancelled as PodListingCancelledEvent, + PodOrderCancelled as PodOrderCancelledEvent, + PodOrder, + PodListing +} from "../../generated/schema"; +import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { + MarketplaceAction, + podListingCreated, + podListingFilled, + podOrderCreated, + podOrderFilled, + updateActiveListings, + updateActiveOrders, + updateMarketListingBalances, + updateMarketOrderBalances +} from "../utils/Marketplace"; +import { getHarvestableIndex } from "../entities/Beanstalk"; + +export function handlePodListingCreated(event: PodListingCreated): void { + podListingCreated({ + event: event, + account: event.params.account, + index: event.params.index, + start: event.params.start, + amount: event.params.amount, + pricePerPod: event.params.pricePerPod, + maxHarvestableIndex: event.params.maxHarvestableIndex, + mode: event.params.mode, + minFillAmount: event.params.minFillAmount, + pricingFunction: event.params.pricingFunction, + pricingType: event.params.pricingType + }); +} + +export function handlePodListingFilled(event: PodListingFilled): void { + podListingFilled({ + event: event, + from: event.params.from, + to: event.params.to, + id: null, + index: event.params.index, + start: event.params.start, + amount: event.params.amount, + costInBeans: event.params.costInBeans + }); +} + +export function handlePodOrderCreated(event: PodOrderCreated): void { + podOrderCreated({ + event: event, + account: event.params.account, + id: event.params.id, + beanAmount: event.params.amount, + pricePerPod: event.params.pricePerPod, + maxPlaceInLine: event.params.maxPlaceInLine, + minFillAmount: event.params.minFillAmount, + pricingFunction: event.params.pricingFunction, + pricingType: event.params.priceType + }); +} + +export function handlePodOrderFilled(event: PodOrderFilled): void { + podOrderFilled({ + event: event, + from: event.params.from, + to: event.params.to, + id: event.params.id, + index: event.params.index, + start: event.params.start, + amount: event.params.amount, + costInBeans: event.params.costInBeans + }); +} + +export function handlePodListingCancelled(event: PodListingCancelled): void { + let listing = PodListing.load(event.params.account.toHexString() + "-" + event.params.index.toString()); + if (listing !== null && listing.status == "ACTIVE") { + updateActiveListings( + event.address, + MarketplaceAction.CANCELLED, + event.params.account.toHexString(), + listing.index, + listing.maxHarvestableIndex + ); + updateMarketListingBalances(event.address, event.address, ZERO_BI, listing.remainingAmount, ZERO_BI, ZERO_BI, event.block.timestamp); + + listing.status = listing.filled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; + listing.updatedAt = event.block.timestamp; + listing.save(); + + // Save the raw event data + let id = "podListingCancelled-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); + let rawEvent = new PodListingCancelledEvent(id); + rawEvent.hash = event.transaction.hash.toHexString(); + rawEvent.logIndex = event.logIndex.toI32(); + rawEvent.protocol = event.address.toHexString(); + rawEvent.historyID = listing.historyID; + rawEvent.account = event.params.account.toHexString(); + rawEvent.placeInLine = event.params.index.plus(listing.start).minus(getHarvestableIndex(event.address)); + rawEvent.index = event.params.index; + rawEvent.blockNumber = event.block.number; + rawEvent.createdAt = event.block.timestamp; + rawEvent.save(); + } +} + +export function handlePodOrderCancelled(event: PodOrderCancelled): void { + let order = PodOrder.load(event.params.id.toHexString()); + if (order !== null && order.status == "ACTIVE") { + order.status = order.podAmountFilled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; + order.updatedAt = event.block.timestamp; + order.save(); + + updateActiveOrders(event.address, MarketplaceAction.CANCELLED, order.id, order.maxPlaceInLine); + updateMarketOrderBalances( + event.address, + event.address, + ZERO_BI, + order.beanAmount.minus(order.beanAmountFilled), + ZERO_BI, + ZERO_BI, + event.block.timestamp + ); + + // Save the raw event data + let id = "podOrderCancelled-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); + let rawEvent = new PodOrderCancelledEvent(id); + rawEvent.hash = event.transaction.hash.toHexString(); + rawEvent.logIndex = event.logIndex.toI32(); + rawEvent.protocol = event.address.toHexString(); + rawEvent.historyID = order.historyID; + rawEvent.account = event.params.account.toHexString(); + rawEvent.orderId = event.params.id.toHexString(); + rawEvent.blockNumber = event.block.number; + rawEvent.createdAt = event.block.timestamp; + rawEvent.save(); + } +} diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts similarity index 62% rename from projects/subgraph-beanstalk/src/SeasonHandler.ts rename to projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts index 4e6a1336e2..a19643b92d 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts @@ -1,24 +1,24 @@ import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; -import { MetapoolOracle, Reward, Soil, WellOracle } from "../generated/Beanstalk-ABIs/BasinBip"; -import { CurvePrice } from "../generated/Beanstalk-ABIs/CurvePrice"; -import { SeasonSnapshot, Sunrise, Incentivization, PreReplant } from "../generated/Beanstalk-ABIs/PreReplant"; -import { updateHarvestablePlots } from "./FieldHandler"; -import { loadBeanstalk, loadSeason } from "./utils/Beanstalk"; -import { BEANSTALK, BEAN_ERC20, CURVE_PRICE, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; -import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadField } from "./utils/Field"; -import { loadPodMarketplace, updateExpiredPlots } from "./utils/PodMarketplace"; -import { updateDepositInSiloAsset, updateStalkWithCalls } from "./SiloHandler"; -import { updateBeanEMA } from "./YieldHandler"; -import { loadSilo, loadSiloAsset } from "./utils/Silo"; -import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/contracts/BeanstalkPrice"; -import { takeSiloSnapshots } from "./utils/snapshots/Silo"; -import { takeSiloAssetSnapshots } from "./utils/snapshots/SiloAsset"; -import { takeMarketSnapshots } from "./utils/snapshots/Marketplace"; -import { takeFieldSnapshots } from "./utils/snapshots/Field"; +import { Reward, Soil, WellOracle, Sunrise, Incentivization, SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { BEANSTALK, GAUGE_BIP45_BLOCK } from "../../../subgraph-core/utils/Constants"; +import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { updateStalkWithCalls } from "../utils/legacy/LegacySilo"; +import { getBeanstalkToken, loadBeanstalk, loadSeason } from "../entities/Beanstalk"; +import { takeMarketSnapshots } from "../entities/snapshots/Marketplace"; +import { loadSilo, loadSiloAsset } from "../entities/Silo"; +import { takeSiloSnapshots } from "../entities/snapshots/Silo"; +import { updateDepositInSiloAsset } from "../utils/Silo"; +import { getBeanstalkPrice } from "../utils/contracts/BeanstalkPrice"; +import { takeSiloAssetSnapshots } from "../entities/snapshots/SiloAsset"; +import { takeFieldSnapshots } from "../entities/snapshots/Field"; +import { loadField } from "../entities/Field"; +import { loadPodMarketplace } from "../entities/PodMarketplace"; +import { updateBeanEMA } from "../utils/Yield"; +import { updateExpiredPlots } from "../utils/Marketplace"; +import { updateHarvestablePlots } from "../utils/Field"; export function handleSunrise(event: Sunrise): void { - // Update any farmers that had silo transfers from the prior season. + // (Legacy) Update any farmers that had silo transfers from the prior season. // This is intentionally done before beanstalk.lastSeason gets updated updateStalkWithCalls(event.address, event.block.timestamp); @@ -45,7 +45,6 @@ export function handleSunrise(event: Sunrise): void { field.save(); // Marketplace Season Update - let market = loadPodMarketplace(event.address); market.season = currentSeason; takeMarketSnapshots(market, event.address, event.block.timestamp); @@ -62,12 +61,6 @@ export function handleSunrise(event: Sunrise): void { silo.save(); } -export function handleSeasonSnapshot(event: SeasonSnapshot): void { - let season = loadSeason(event.address, event.params.season); - season.price = toDecimal(event.params.price, 18); - season.save(); -} - export function handleReward(event: Reward): void { let season = loadSeason(event.address, event.params.season); season.rewardBeans = event.params.toField.plus(event.params.toSilo).plus(event.params.toFertilizer); @@ -86,23 +79,14 @@ export function handleReward(event: Reward): void { takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); - updateDepositInSiloAsset(event.address, event.address, BEAN_ERC20, event.params.toSilo, event.params.toSilo, event.block.timestamp); -} - -export function handleMetapoolOracle(event: MetapoolOracle): void { - if (event.block.number < GAUGE_BIP45_BLOCK) { - let season = loadSeason(event.address, event.params.season); - // Attempt to pull from Beanstalk Price contract first - let beanstalkQuery = BeanstalkPrice_try_price(event.address, event.block.number); - if (beanstalkQuery.reverted) { - let curvePrice = CurvePrice.bind(CURVE_PRICE); - season.price = toDecimal(curvePrice.getCurve().price); - } else { - season.price = toDecimal(beanstalkQuery.value.price); - } - season.deltaB = event.params.deltaB; - season.save(); - } + updateDepositInSiloAsset( + event.address, + event.address, + getBeanstalkToken(event.address), + event.params.toSilo, + event.params.toSilo, + event.block.timestamp + ); } export function handleWellOracle(event: WellOracle): void { @@ -128,7 +112,7 @@ export function handleSoil(event: Soil): void { field.save(); if (event.params.season.toI32() >= 6075) { - updateBeanEMA(event.params.season.toI32(), event.block.timestamp); + updateBeanEMA(event.address, event.block.timestamp); } } @@ -136,7 +120,7 @@ export function handleSoil(event: Soil): void { export function handleIncentive(event: Incentivization): void { // Update market cap for season let beanstalk = loadBeanstalk(event.address); - let beanstalk_contract = PreReplant.bind(BEANSTALK); + let beanstalk_contract = SeedGauge.bind(BEANSTALK); let season = loadSeason(event.address, BigInt.fromI32(beanstalk.lastSeason)); season.marketCap = season.price.times(toDecimal(season.beans)); diff --git a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts new file mode 100644 index 0000000000..39be66dc1f --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts @@ -0,0 +1,135 @@ +import { BigInt, log } from "@graphprotocol/graph-ts"; +import { addDeposits, removeDeposits, updateDepositInSiloAsset, updateSeedsBalances, updateStalkBalances } from "../utils/Silo"; +import { addToSiloWhitelist, loadSilo, loadWhitelistTokenSetting } from "../entities/Silo"; +import { takeSiloSnapshots } from "../entities/snapshots/Silo"; +import { takeWhitelistTokenSettingSnapshots } from "../entities/snapshots/WhitelistTokenSetting"; +import { Bytes4_emptyToNull } from "../../../subgraph-core/utils/Bytes"; +import { + AddDeposit, + DewhitelistToken, + Plant, + RemoveDeposit, + RemoveDeposits, + SeedsBalanceChanged, + StalkBalanceChanged, + UpdatedStalkPerBdvPerSeason, + WhitelistToken +} from "../../generated/Beanstalk-ABIs/SeedGauge"; + +export function handleAddDeposit(event: AddDeposit): void { + addDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: null, + stems: [event.params.stem], + amounts: [event.params.amount], + bdvs: [event.params.bdv], + depositVersion: "stem" + }); +} + +export function handleRemoveDeposit(event: RemoveDeposit): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: null, + stems: [event.params.stem], + amounts: [event.params.amount], + bdvs: [event.params.bdv], + depositVersion: "stem" + }); +} + +export function handleRemoveDeposits(event: RemoveDeposits): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: null, + stems: event.params.stems, + amounts: event.params.amounts, + bdvs: event.params.bdvs, + depositVersion: "stem" + }); +} + +export function handleStalkBalanceChanged(event: StalkBalanceChanged): void { + // Exclude BIP-24 emission of missed past events + if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { + return; + } + + updateStalkBalances(event.address, event.params.account, event.params.delta, event.params.deltaRoots, event.block.timestamp); +} + +export function handleSeedsBalanceChanged(event: SeedsBalanceChanged): void { + // Exclude BIP-24 emission of missed past events + if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { + return; + } + + updateSeedsBalances(event.address, event.params.account, event.params.delta, event.block.timestamp); +} + +export function handlePlant(event: Plant): void { + // This removes the plantable stalk for planted beans. + // Actual stalk credit for the farmer will be handled under the StalkBalanceChanged event. + + let silo = loadSilo(event.address); + let newPlantableStalk = event.params.beans.times(BigInt.fromI32(10000)); + + // Subtract stalk since it was already added in Reward, and is about to get re-added in StalkBalanceChanged. + silo.stalk = silo.stalk.minus(newPlantableStalk); + silo.plantableStalk = silo.plantableStalk.minus(newPlantableStalk); + silo.depositedBDV = silo.depositedBDV.minus(event.params.beans); + + takeSiloSnapshots(silo, event.address, event.block.timestamp); + silo.save(); + + // Remove the asset-only amount that got added in Reward event handler. + // Will be immediately re-credited to the user/system in AddDeposit + updateDepositInSiloAsset(event.address, event.address, BEAN_ERC20, event.params.beans, event.params.beans, event.block.timestamp); +} + +export function handleWhitelistToken(event: WhitelistToken): void { + addToSiloWhitelist(event.address, event.params.token); + + let siloSettings = loadWhitelistTokenSetting(event.params.token); + + siloSettings.selector = event.params.selector; + siloSettings.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; + siloSettings.stalkIssuedPerBdv = event.params.stalkIssuedPerBdv; + siloSettings.gaugePoints = event.params.gaugePoints; + siloSettings.gpSelector = Bytes4_emptyToNull(event.params.gpSelector); + siloSettings.lwSelector = Bytes4_emptyToNull(event.params.lwSelector); + siloSettings.optimalPercentDepositedBdv = event.params.optimalPercentDepositedBdv; + siloSettings.updatedAt = event.block.timestamp; + + takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); + siloSettings.save(); +} + +export function handleDewhitelistToken(event: DewhitelistToken): void { + let silo = loadSilo(event.address); + let currentWhitelist = silo.whitelistedTokens; + let currentDewhitelist = silo.dewhitelistedTokens; + let index = currentWhitelist.indexOf(event.params.token.toHexString()); + if (index >= 0) { + currentDewhitelist.push(currentWhitelist.splice(index, 1)[0]); + silo.whitelistedTokens = currentWhitelist; + silo.dewhitelistedTokens = currentDewhitelist; + silo.save(); + } +} + +export function handleUpdatedStalkPerBdvPerSeason(event: UpdatedStalkPerBdvPerSeason): void { + let siloSettings = loadWhitelistTokenSetting(event.params.token); + siloSettings.milestoneSeason = event.params.season.toI32(); + siloSettings.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; + siloSettings.updatedAt = event.block.timestamp; + + takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); + siloSettings.save(); +} diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts new file mode 100644 index 0000000000..3edb2d5200 --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts @@ -0,0 +1,78 @@ +import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; +import { WeatherChange, SupplyIncrease, SupplyDecrease, SupplyNeutral, FundFundraiser } from "../../../generated/Beanstalk-ABIs/PreReplant"; +import { temperatureChanged, updateFieldTotals } from "../../utils/Field"; + +// Pre-Replant -> Seed Gauge +export function handleWeatherChange(event: WeatherChange): void { + temperatureChanged({ + event, + season: event.params.season, + caseId: event.params.caseId, + absChange: event.params.change + }); +} + +// Pre-Replant +export function handleSupplyIncrease(event: SupplyIncrease): void { + updateFieldTotals( + event.address, + event.address, + event.params.newSoil, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + event.block.timestamp, + event.block.number + ); +} + +// Pre-Replant +export function handleSupplyDecrease(event: SupplyDecrease): void { + updateFieldTotals( + event.address, + event.address, + event.params.newSoil, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + event.block.timestamp, + event.block.number + ); +} + +// Pre-Replant +export function handleSupplyNeutral(event: SupplyNeutral): void { + updateFieldTotals( + event.address, + event.address, + event.params.newSoil, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + event.block.timestamp, + event.block.number + ); +} + +// Pre-Replant +export function handleFundFundraiser(event: FundFundraiser): void { + // Account for the fact that fundraiser sow using no soil. + updateFieldTotals( + event.address, + event.address, + ZERO_BI, + ZERO_BI.minus(event.params.amount), + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + event.block.timestamp, + event.block.number + ); +} diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts new file mode 100644 index 0000000000..853854ecfc --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts @@ -0,0 +1,96 @@ +import { Address, BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"; +import { + PodListingCreated as PodListingCreated_v1, + PodListingFilled as PodListingFilled_v1, + PodOrderCreated as PodOrderCreated_v1, + PodOrderFilled as PodOrderFilled_v1 +} from "../../../generated/Beanstalk-ABIs/PreReplant"; +import { PodListingCreated as PodListingCreated_v1_1 } from "../../../generated/Beanstalk-ABIs/Replanted"; +import { podListingCreated, podListingFilled, podOrderCreated, podOrderFilled } from "../../utils/Marketplace"; +import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; +import { loadPodListing, loadPodOrder } from "../../entities/PodMarketplace"; + +// Pre-replant -> Replant +export function handlePodListingCreated_v1(event: PodListingCreated_v1): void { + podListingCreated({ + event: event, + account: event.params.account, + index: event.params.index, + start: event.params.start, + amount: event.params.amount, + pricePerPod: event.params.pricePerPod, + maxHarvestableIndex: event.params.maxHarvestableIndex, + mode: event.params.toWallet ? 0 : 1, + minFillAmount: ZERO_BI, + pricingFunction: null, + pricingType: 0 + }); +} + +// Replant -> Marketplace V2 +// When Beanstalk was Replanted, event.params.mode was changed from bool to uint8 +export function handlePodListingCreated_v1_1(event: PodListingCreated_v1_1): void { + podListingCreated({ + event: event, + account: event.params.account, + index: event.params.index, + start: event.params.start, + amount: event.params.amount, + pricePerPod: event.params.pricePerPod, + maxHarvestableIndex: event.params.maxHarvestableIndex, + mode: event.params.mode, + minFillAmount: ZERO_BI, + pricingFunction: null, + pricingType: 0 + }); +} + +// Pre-Replant -> Marketplace V2 +export function handlePodListingFilled_v1(event: PodListingFilled_v1): void { + let listing = loadPodListing(event.params.from, event.params.index); + const beanAmount = BigInt.fromI32(listing.pricePerPod).times(event.params.amount).div(BigInt.fromI32(1000000)); + + podListingFilled({ + event: event, + from: event.params.from, + to: event.params.to, + id: null, + index: event.params.index, + start: event.params.start, + amount: event.params.amount, + costInBeans: beanAmount + }); +} + +// Pre-Replant -> Marketplace V2 +export function handlePodOrderCreated_v1(event: PodOrderCreated_v1): void { + const beanAmount = event.params.amount.times(BigInt.fromI32(event.params.pricePerPod)).div(BigInt.fromString("1000000")); + podOrderCreated({ + event: event, + account: event.params.account, + id: event.params.id, + beanAmount: beanAmount, + pricePerPod: event.params.pricePerPod, + maxPlaceInLine: event.params.maxPlaceInLine, + minFillAmount: ZERO_BI, + pricingFunction: null, + pricingType: 0 + }); +} + +// Pre-Replant -> Marketplace V2 +export function handlePodOrderFilled_v1(event: PodOrderFilled_v1): void { + let order = loadPodOrder(event.params.id); + let beanAmount = BigInt.fromI32(order.pricePerPod).times(event.params.amount).div(BigInt.fromI32(1000000)); + + podOrderFilled({ + event: event, + from: event.params.from, + to: event.params.to, + id: event.params.id, + index: event.params.index, + start: event.params.start, + amount: event.params.amount, + costInBeans: beanAmount + }); +} diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts new file mode 100644 index 0000000000..7c171bfef7 --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts @@ -0,0 +1,29 @@ +import { CURVE_PRICE } from "../../../../subgraph-core/utils/Constants"; +import { toDecimal } from "../../../../subgraph-core/utils/Decimals"; +import { CurvePrice } from "../../../generated/Beanstalk-ABIs/CurvePrice"; +import { SeasonSnapshot } from "../../../generated/Beanstalk-ABIs/PreReplant"; +import { MetapoolOracle } from "../../../generated/Beanstalk-ABIs/Replanted"; +import { BeanstalkPrice_try_price } from "../../utils/contracts/BeanstalkPrice"; +import { loadSeason } from "../../entities/Beanstalk"; + +// Pre-Replant only +export function handleSeasonSnapshot(event: SeasonSnapshot): void { + let season = loadSeason(event.address, event.params.season); + season.price = toDecimal(event.params.price, 18); + season.save(); +} + +// Replant until Seed Gauge +export function handleMetapoolOracle(event: MetapoolOracle): void { + let season = loadSeason(event.address, event.params.season); + // Attempt to pull from Beanstalk Price contract first + let beanstalkQuery = BeanstalkPrice_try_price(event.address, event.block.number); + if (beanstalkQuery.reverted) { + let curvePrice = CurvePrice.bind(CURVE_PRICE); + season.price = toDecimal(curvePrice.getCurve().price); + } else { + season.price = toDecimal(beanstalkQuery.value.price); + } + season.deltaB = event.params.deltaB; + season.save(); +} diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts new file mode 100644 index 0000000000..4a49cb8a0a --- /dev/null +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts @@ -0,0 +1,143 @@ +import { Address, BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"; +import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; +import { + AddWithdrawal, + RemoveWithdrawals, + RemoveWithdrawal, + TransferDepositsCall, + TransferDepositCall, + WhitelistToken as WhitelistToken_v2 +} from "../../../generated/Beanstalk-ABIs/Replanted"; +import { + AddDeposit as AddDeposit_v2, + RemoveDeposit as RemoveDeposit_v2, + RemoveDeposits as RemoveDeposits_v2 +} from "../../../generated/Beanstalk-ABIs/Replanted"; +import { loadBeanstalk } from "../../entities/Beanstalk"; +import { addToSiloWhitelist, loadSiloWithdraw, loadWhitelistTokenSetting } from "../../entities/Silo"; +import { updateClaimedWithdraw } from "../../utils/legacy/LegacySilo"; +import { addDeposits, addWithdrawToSiloAsset, removeDeposits } from "../../utils/Silo"; +import { takeWhitelistTokenSettingSnapshots } from "../../entities/snapshots/WhitelistTokenSetting"; +import { WhitelistToken as WhitelistToken_v3 } from "../../../generated/Beanstalk-ABIs/SiloV3"; + +// Note: No silo v1 (pre-replant) handlers have been developed. + +// Replant -> Silo V3 +export function handleAddDeposit_v2(event: AddDeposit_v2): void { + if (event.params.amount == ZERO_BI && event.params.bdv == ZERO_BI) { + // During replant there is at least one such event which should be ignored + return; + } + addDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: [event.params.season], + stems: null, + amounts: [event.params.amount], + bdvs: [event.params.bdv], + depositVersion: "season" + }); +} + +// Replant -> Silo V3 +export function handleRemoveDeposit_v2(event: RemoveDeposit_v2): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: [event.params.season], + stems: null, + amounts: [event.params.amount], + bdvs: null, + depositVersion: "season" + }); +} + +// Replant -> Silo V3 +export function handleRemoveDeposits_v2(event: RemoveDeposits_v2): void { + removeDeposits({ + event, + account: event.params.account, + token: event.params.token, + seasons: event.params.seasons, + stems: null, + amounts: event.params.amounts, + bdvs: null, + depositVersion: "season" + }); +} + +export function handleAddWithdrawal(event: AddWithdrawal): void { + let withdraw = loadSiloWithdraw(event.params.account, event.params.token, event.params.season.toI32()); + withdraw.amount = withdraw.amount.plus(event.params.amount); + withdraw.createdAt = withdraw.createdAt == ZERO_BI ? event.block.timestamp : withdraw.createdAt; + withdraw.save(); + + addWithdrawToSiloAsset(event.address, event.params.account, event.params.token, event.params.amount, event.block.timestamp); +} + +// Note: Legacy removals are still possible today. +export function handleRemoveWithdrawal(event: RemoveWithdrawal): void { + updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.season, event.block.timestamp); +} + +export function handleRemoveWithdrawals(event: RemoveWithdrawals): void { + for (let i = 0; i < event.params.seasons.length; i++) { + updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.seasons[i], event.block.timestamp); + } +} + +// Replant -> Silo V3 +export function handleTransferDepositCall(call: TransferDepositCall): void { + let beanstalk = loadBeanstalk(call.to); + let updateFarmers = beanstalk.farmersToUpdate; + if (updateFarmers.indexOf(call.from.toHexString()) == -1) { + updateFarmers.push(call.from.toHexString()); + } + if (updateFarmers.indexOf(call.inputs.recipient.toHexString()) == -1) { + updateFarmers.push(call.inputs.recipient.toHexString()); + } + beanstalk.farmersToUpdate = updateFarmers; + beanstalk.save(); +} + +// Replant -> Silo V3 +export function handleTransferDepositsCall(call: TransferDepositsCall): void { + let beanstalk = loadBeanstalk(call.to); + let updateFarmers = beanstalk.farmersToUpdate; + if (updateFarmers.indexOf(call.from.toHexString()) == -1) { + updateFarmers.push(call.from.toHexString()); + } + if (updateFarmers.indexOf(call.inputs.recipient.toHexString()) == -1) { + updateFarmers.push(call.inputs.recipient.toHexString()); + } + beanstalk.farmersToUpdate = updateFarmers; + beanstalk.save(); +} + +// Replant -> Silo V3 +export function handleWhitelistToken_v2(event: WhitelistToken_v2): void { + addToSiloWhitelist(event.address, event.params.token); + + let setting = loadWhitelistTokenSetting(event.params.token); + setting.selector = event.params.selector; + setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); + setting.stalkEarnedPerSeason = event.params.stalk.times(BigInt.fromI32(1000000)); + + takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); + setting.save(); +} + +// Silo V3 -> Seed Gauge +export function handleWhitelistToken_v3(event: WhitelistToken_v3): void { + addToSiloWhitelist(event.address, event.params.token); + + let setting = loadWhitelistTokenSetting(event.params.token); + setting.selector = event.params.selector; + setting.stalkIssuedPerBdv = event.params.stalk.times(BigInt.fromI32(1_000_000)); + setting.stalkEarnedPerSeason = event.params.stalkEarnedPerSeason; + + takeWhitelistTokenSettingSnapshots(setting, event.address, event.block.timestamp); + setting.save(); +} diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index f2210860b3..373299830f 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -1,25 +1,423 @@ import { Address, BigInt, BigDecimal, ethereum } from "@graphprotocol/graph-ts"; -import { Field, Plot } from "../../generated/schema"; -import { ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { ADDRESS_ZERO, BEANSTALK, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; import { CurvePrice } from "../../generated/Beanstalk-ABIs/CurvePrice"; import { BeanstalkPrice_try_price } from "./contracts/BeanstalkPrice"; -import { loadBeanstalk, loadSeason } from "./Beanstalk"; -import { setHourlyCaseId, takeFieldSnapshots } from "./snapshots/Field"; +import { CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; +import { BI_10, ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { setFieldHourlyCaseId, setHourlySoilSoldOut, takeFieldSnapshots } from "../entities/snapshots/Field"; +import { getCurrentSeason, getHarvestableIndex, loadBeanstalk, loadFarmer, loadSeason } from "../entities/Beanstalk"; +import { loadField, loadPlot } from "../entities/Field"; +import { expirePodListingIfExists } from "./Marketplace"; + +class SowParams { + event: ethereum.Event; + account: Address; + fieldId: BigInt | null; + index: BigInt; + beans: BigInt; + pods: BigInt; +} + +class HarvestParams { + event: ethereum.Event; + account: Address; + fieldId: BigInt | null; + plots: BigInt[]; + beans: BigInt; +} + +class PlotTransferParams { + event: ethereum.Event; + from: Address; + to: Address; + fieldId: BigInt | null; + index: BigInt; + amount: BigInt; +} + +class TemperatureChangedParams { + event: ethereum.Event; + season: BigInt; + caseId: BigInt; + absChange: i32; +} + +export function sow(params: SowParams): void { + const protocol = params.event.address; + let sownBeans = params.beans; + // Update Farmer Totals + updateFieldTotals( + protocol, + params.account, + ZERO_BI, + sownBeans, + params.pods, + ZERO_BI, + ZERO_BI, + ZERO_BI, + params.event.block.timestamp, + params.event.block.number + ); + + let field = loadField(protocol); + loadFarmer(params.account); + let plot = loadPlot(protocol, params.index); + + let newIndexes = field.plotIndexes; + newIndexes.push(plot.index); + field.plotIndexes = newIndexes; + field.save(); + + plot.farmer = params.account.toHexString(); + plot.source = "SOW"; + plot.sourceHash = params.event.transaction.hash.toHexString(); + plot.season = field.season; + plot.creationHash = params.event.transaction.hash.toHexString(); + plot.createdAt = params.event.block.timestamp; + plot.updatedAt = params.event.block.timestamp; + plot.updatedAtBlock = params.event.block.number; + plot.pods = params.pods; + plot.beansPerPod = params.beans.times(BI_10.pow(6)).div(plot.pods); + plot.save(); + + incrementSows(protocol, params.account, params.event.block.timestamp, params.event.block.number); +} + +export function harvest(params: HarvestParams): void { + const protocol = params.event.address; + let beanstalk = loadBeanstalk(protocol); + let season = loadSeason(protocol, BigInt.fromI32(beanstalk.lastSeason)); + + let remainingIndex = ZERO_BI; + for (let i = 0; i < params.plots.length; i++) { + // Plot should exist + let plot = loadPlot(protocol, params.plots[i]); + + expirePodListingIfExists(protocol, plot.farmer, plot.index, params.event.block.timestamp); + + let harvestablePods = season.harvestableIndex.minus(plot.index); + + if (harvestablePods >= plot.pods) { + // Plot fully harvests + updateFieldTotals( + protocol, + params.account, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + plot.pods, + params.event.block.timestamp, + params.event.block.number + ); + + plot.harvestedPods = plot.pods; + plot.fullyHarvested = true; + plot.save(); + } else { + // Plot partially harvests + updateFieldTotals( + protocol, + params.account, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + harvestablePods, + params.event.block.timestamp, + params.event.block.number + ); + + remainingIndex = plot.index.plus(harvestablePods); + let remainingPods = plot.pods.minus(harvestablePods); + + let remainingPlot = loadPlot(protocol, remainingIndex); + remainingPlot.farmer = plot.farmer; + remainingPlot.source = plot.source; + remainingPlot.sourceHash = plot.sourceHash; + remainingPlot.season = beanstalk.lastSeason; + remainingPlot.creationHash = params.event.transaction.hash.toHexString(); + remainingPlot.createdAt = params.event.block.timestamp; + remainingPlot.updatedAt = params.event.block.timestamp; + remainingPlot.updatedAtBlock = params.event.block.number; + remainingPlot.index = remainingIndex; + remainingPlot.pods = remainingPods; + remainingPlot.beansPerPod = plot.beansPerPod; + remainingPlot.save(); + + plot.harvestedPods = harvestablePods; + plot.pods = harvestablePods; + plot.fullyHarvested = true; + plot.save(); + } + } + + // Remove the harvested plot IDs from the field list + let field = loadField(protocol); + let newIndexes = field.plotIndexes; + for (let i = 0; i < params.plots.length; i++) { + let plotIndex = newIndexes.indexOf(params.plots[i]); + newIndexes.splice(plotIndex, 1); + newIndexes.sort(); + } + if (remainingIndex !== ZERO_BI) { + newIndexes.push(remainingIndex); + } + field.plotIndexes = newIndexes; + field.save(); +} + +export function plotTransfer(params: PlotTransferParams): void { + const protocol = params.event.address; + const currentHarvestable = getHarvestableIndex(protocol); + + // Ensure both farmer entites exist + loadFarmer(params.from); + loadFarmer(params.to); + + // Update farmer field data + updateFieldTotals( + protocol, + params.from, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI.minus(params.amount), + ZERO_BI, + ZERO_BI, + params.event.block.timestamp, + params.event.block.number, + false + ); + updateFieldTotals( + protocol, + params.to, + ZERO_BI, + ZERO_BI, + ZERO_BI, + params.amount, + ZERO_BI, + ZERO_BI, + params.event.block.timestamp, + params.event.block.number, + false + ); + + let field = loadField(protocol); + let sortedPlots = field.plotIndexes.sort(); + + let sourceIndex = ZERO_BI; + + for (let i = 0; i < sortedPlots.length; i++) { + // Handle only single comparison for first value of array + if (i == 0) { + if (sortedPlots[i] == params.index) { + sourceIndex = sortedPlots[i]; + break; + } else { + continue; + } + } + // Transferred plot matches existing. Start value of zero. + if (sortedPlots[i] == params.index) { + sourceIndex = sortedPlots[i]; + break; + } + // Transferred plot is in the middle of existing plot. Non-zero start value. + if (sortedPlots[i - 1] < params.index && params.index < sortedPlots[i]) { + sourceIndex = sortedPlots[i - 1]; + } + } + + let sourcePlot = loadPlot(protocol, sourceIndex); + let sourceEndIndex = sourceIndex.plus(sourcePlot.pods); + let transferEndIndex = params.index.plus(params.amount); + + // Determines how many of the pods being transferred are harvestable + const calcHarvestable = (index: BigInt, pods: BigInt, harvestableIndex: BigInt): BigInt => { + let harvestable = harvestableIndex.minus(index); + if (harvestable < ZERO_BI) { + return ZERO_BI; + } else { + return harvestable >= pods ? pods : harvestable; + } + }; + + let transferredHarvestable = calcHarvestable(params.index, params.amount, currentHarvestable); + + // Actually transfer the plots + if (sourcePlot.pods == params.amount) { + // Sending full plot + const isMarket = sourcePlot.source == "MARKET" && sourcePlot.sourceHash == params.event.transaction.hash.toHexString(); + if (!isMarket) { + sourcePlot.source = "TRANSFER"; + sourcePlot.sourceHash = params.event.transaction.hash.toHexString(); + sourcePlot.beansPerPod = sourcePlot.beansPerPod; + } + sourcePlot.farmer = params.to.toHexString(); + sourcePlot.updatedAt = params.event.block.timestamp; + sourcePlot.updatedAtBlock = params.event.block.number; + sourcePlot.save(); + } else if (sourceIndex == params.index) { + // We are only needing to split this plot once to send + // Start value of zero + let remainderIndex = sourceIndex.plus(params.amount); + let remainderPlot = loadPlot(protocol, remainderIndex); + sortedPlots.push(remainderIndex); + + const isMarket = sourcePlot.source == "MARKET" && sourcePlot.sourceHash == params.event.transaction.hash.toHexString(); + if (!isMarket) { + // When sending the start of the plot via market, these cannot be derived from sourcePlot. + remainderPlot.source = sourcePlot.source; + remainderPlot.sourceHash = sourcePlot.sourceHash; + remainderPlot.beansPerPod = sourcePlot.beansPerPod; + + sourcePlot.source = "TRANSFER"; + sourcePlot.sourceHash = params.event.transaction.hash.toHexString(); + sourcePlot.beansPerPod = sourcePlot.beansPerPod; + } + sourcePlot.farmer = params.to.toHexString(); + sourcePlot.updatedAt = params.event.block.timestamp; + sourcePlot.updatedAtBlock = params.event.block.number; + sourcePlot.pods = params.amount; + sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, currentHarvestable); + sourcePlot.save(); + + remainderPlot.farmer = params.from.toHexString(); + remainderPlot.season = field.season; + remainderPlot.creationHash = params.event.transaction.hash.toHexString(); + remainderPlot.createdAt = params.event.block.timestamp; + remainderPlot.updatedAt = params.event.block.timestamp; + remainderPlot.updatedAtBlock = params.event.block.number; + remainderPlot.index = remainderIndex; + remainderPlot.pods = sourceEndIndex.minus(transferEndIndex); + remainderPlot.harvestablePods = calcHarvestable(remainderPlot.index, remainderPlot.pods, currentHarvestable); + remainderPlot.save(); + } else if (sourceEndIndex == transferEndIndex) { + // We are only needing to split this plot once to send + // Non-zero start value. Sending to end of plot + let toPlot = loadPlot(protocol, params.index); + sortedPlots.push(params.index); + + sourcePlot.updatedAt = params.event.block.timestamp; + sourcePlot.updatedAtBlock = params.event.block.number; + sourcePlot.pods = sourcePlot.pods.minus(params.amount); + sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, currentHarvestable); + sourcePlot.save(); + + const isMarket = toPlot.source == "MARKET" && toPlot.sourceHash == params.event.transaction.hash.toHexString(); + if (!isMarket) { + toPlot.source = "TRANSFER"; + toPlot.sourceHash = params.event.transaction.hash.toHexString(); + toPlot.beansPerPod = sourcePlot.beansPerPod; + } + toPlot.farmer = params.to.toHexString(); + toPlot.season = field.season; + toPlot.creationHash = params.event.transaction.hash.toHexString(); + toPlot.createdAt = params.event.block.timestamp; + toPlot.updatedAt = params.event.block.timestamp; + toPlot.updatedAtBlock = params.event.block.number; + toPlot.index = params.index; + toPlot.pods = params.amount; + toPlot.harvestablePods = calcHarvestable(toPlot.index, toPlot.pods, currentHarvestable); + toPlot.save(); + } else { + // We have to split this plot twice to send + let remainderIndex = params.index.plus(params.amount); + let toPlot = loadPlot(protocol, params.index); + let remainderPlot = loadPlot(protocol, remainderIndex); + + sortedPlots.push(params.index); + sortedPlots.push(remainderIndex); + + sourcePlot.updatedAt = params.event.block.timestamp; + sourcePlot.updatedAtBlock = params.event.block.number; + sourcePlot.pods = params.index.minus(sourcePlot.index); + sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, currentHarvestable); + sourcePlot.save(); + + const isMarket = toPlot.source == "MARKET" && toPlot.sourceHash == params.event.transaction.hash.toHexString(); + if (!isMarket) { + toPlot.source = "TRANSFER"; + toPlot.sourceHash = params.event.transaction.hash.toHexString(); + toPlot.beansPerPod = sourcePlot.beansPerPod; + } + toPlot.farmer = params.to.toHexString(); + toPlot.season = field.season; + toPlot.creationHash = params.event.transaction.hash.toHexString(); + toPlot.createdAt = params.event.block.timestamp; + toPlot.updatedAt = params.event.block.timestamp; + toPlot.updatedAtBlock = params.event.block.number; + toPlot.index = params.index; + toPlot.pods = params.amount; + toPlot.harvestablePods = calcHarvestable(toPlot.index, toPlot.pods, currentHarvestable); + toPlot.save(); + + remainderPlot.farmer = params.from.toHexString(); + remainderPlot.source = sourcePlot.source; + remainderPlot.sourceHash = sourcePlot.sourceHash; + remainderPlot.season = field.season; + remainderPlot.creationHash = params.event.transaction.hash.toHexString(); + remainderPlot.createdAt = params.event.block.timestamp; + remainderPlot.updatedAt = params.event.block.timestamp; + remainderPlot.updatedAtBlock = params.event.block.number; + remainderPlot.index = remainderIndex; + remainderPlot.pods = sourceEndIndex.minus(transferEndIndex); + remainderPlot.harvestablePods = calcHarvestable(remainderPlot.index, remainderPlot.pods, currentHarvestable); + remainderPlot.beansPerPod = sourcePlot.beansPerPod; + remainderPlot.save(); + } + sortedPlots.sort(); + field.plotIndexes = sortedPlots; + field.save(); + + // Update any harvestable pod amounts + // No need to shift beanstalk field, only the farmer fields. + if (transferredHarvestable != ZERO_BI) { + updateFieldTotals( + protocol, + params.from, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI.minus(transferredHarvestable), + ZERO_BI, + params.event.block.timestamp, + params.event.block.number, + false + ); + updateFieldTotals( + protocol, + params.to, + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + transferredHarvestable, + ZERO_BI, + params.event.block.timestamp, + params.event.block.number, + false + ); + } +} // This function is for handling both the WeatherChange and TemperatureChange events. // The logic is the same for both, this is intended to accommodate the renamed event and fields. -export function handleRateChange(protocol: Address, evtBlock: ethereum.Block, season: BigInt, caseId: BigInt, absChange: i32): void { +export function temperatureChanged(params: TemperatureChangedParams): void { + const protocol = params.event.address; let field = loadField(protocol); - field.temperature += absChange; + field.temperature += params.absChange; - let seasonEntity = loadSeason(protocol, season); + let seasonEntity = loadSeason(protocol, params.season); let currentPrice = ZERO_BD; if (seasonEntity.price != ZERO_BD) { currentPrice = seasonEntity.price; } else { // Attempt to pull from Beanstalk Price contract first - let beanstalkQuery = BeanstalkPrice_try_price(protocol, evtBlock.number); + let beanstalkQuery = BeanstalkPrice_try_price(protocol, params.event.block.number); if (beanstalkQuery.reverted) { let curvePrice = CurvePrice.bind(CURVE_PRICE); currentPrice = toDecimal(curvePrice.getCurve().price); @@ -30,69 +428,117 @@ export function handleRateChange(protocol: Address, evtBlock: ethereum.Block, se field.realRateOfReturn = ONE_BD.plus(BigDecimal.fromString((field.temperature / 100).toString())).div(currentPrice); - takeFieldSnapshots(field, protocol, evtBlock.timestamp, evtBlock.number); + takeFieldSnapshots(field, protocol, params.event.block.timestamp, params.event.block.number); field.save(); // Set caseId on the hourly snapshot - setHourlyCaseId(caseId, field, protocol); + setFieldHourlyCaseId(params.caseId, field, protocol); +} + +export function updateFieldTotals( + protocol: Address, + account: Address, + soil: BigInt, + sownBeans: BigInt, + sownPods: BigInt, + transferredPods: BigInt, + harvestablePods: BigInt, + harvestedPods: BigInt, + timestamp: BigInt, + blockNumber: BigInt, + recurs: boolean = true +): void { + if (recurs && account != protocol) { + updateFieldTotals( + protocol, + protocol, + soil, + sownBeans, + sownPods, + transferredPods, + harvestablePods, + harvestedPods, + timestamp, + blockNumber + ); + } + let field = loadField(account); + + field.season = getCurrentSeason(protocol); + field.soil = field.soil.plus(soil).minus(sownBeans); + field.sownBeans = field.sownBeans.plus(sownBeans); + field.unharvestablePods = field.unharvestablePods.plus(sownPods).minus(harvestablePods).plus(transferredPods); + field.harvestablePods = field.harvestablePods.plus(harvestablePods); + field.harvestedPods = field.harvestedPods.plus(harvestedPods); + field.podIndex = field.podIndex.plus(sownPods); + + takeFieldSnapshots(field, protocol, timestamp, blockNumber); + field.save(); + + // Set extra info on the hourly snapshot + if (field.soil == ZERO_BI) { + setHourlySoilSoldOut(blockNumber, field, protocol); + } } -export function loadField(account: Address): Field { - let field = Field.load(account.toHexString()); - if (field == null) { - field = new Field(account.toHexString()); - field.beanstalk = BEANSTALK.toHexString(); - if (account !== BEANSTALK) { - field.farmer = account.toHexString(); +export function updateHarvestablePlots(protocol: Address, harvestableIndex: BigInt, timestamp: BigInt, blockNumber: BigInt): void { + let field = loadField(protocol); + let sortedIndexes = field.plotIndexes.sort(); + + for (let i = 0; i < sortedIndexes.length; i++) { + if (sortedIndexes[i] > harvestableIndex) { + break; } - field.season = 1; - field.temperature = 1; - field.realRateOfReturn = ZERO_BD; - field.numberOfSowers = 0; - field.numberOfSows = 0; - field.sownBeans = ZERO_BI; - field.plotIndexes = []; - field.unharvestablePods = ZERO_BI; - field.harvestablePods = ZERO_BI; - field.harvestedPods = ZERO_BI; - field.soil = ZERO_BI; - field.podIndex = ZERO_BI; - field.podRate = ZERO_BD; - field.save(); + let plot = loadPlot(protocol, sortedIndexes[i]); + + // Plot is fully harvestable, but hasn't been harvested yet + if (plot.harvestablePods == plot.pods) { + continue; + } + + let harvestablePods = harvestableIndex.minus(plot.index); + let oldHarvestablePods = plot.harvestablePods; + plot.harvestablePods = harvestablePods >= plot.pods ? plot.pods : harvestablePods; + plot.save(); + + let deltaHarvestablePods = oldHarvestablePods == ZERO_BI ? plot.harvestablePods : plot.harvestablePods.minus(oldHarvestablePods); + + updateFieldTotals( + protocol, + Address.fromString(plot.farmer), + ZERO_BI, + ZERO_BI, + ZERO_BI, + ZERO_BI, + deltaHarvestablePods, + ZERO_BI, + timestamp, + blockNumber + ); } - return field; } -export function getHarvestableIndex(protocol: Address): BigInt { - let bs = loadBeanstalk(protocol); - let season = loadSeason(protocol, BigInt.fromI32(bs.lastSeason)); - return season.harvestableIndex; +// Increment number of unique sowers (protocol only) +function incrementSowers(protocol: Address, timestamp: BigInt, blockNumber: BigInt): void { + let field = loadField(protocol); + field.numberOfSowers += 1; + takeFieldSnapshots(field, protocol, timestamp, blockNumber); + field.save(); } -export function loadPlot(diamondAddress: Address, index: BigInt): Plot { - let plot = Plot.load(index.toString()); - if (plot == null) { - plot = new Plot(index.toString()); - plot.field = diamondAddress.toHexString(); - plot.farmer = ADDRESS_ZERO.toHexString(); - plot.source = "SOW"; // Should be overwritten in case of a transfer creating a new plot - plot.sourceHash = ""; - plot.season = 0; - plot.creationHash = ""; - plot.createdAt = ZERO_BI; - plot.updatedAt = ZERO_BI; - plot.updatedAtBlock = ZERO_BI; - plot.index = index; - plot.pods = ZERO_BI; - plot.beansPerPod = ZERO_BI; - plot.harvestablePods = ZERO_BI; - plot.harvestedPods = ZERO_BI; - plot.fullyHarvested = false; - plot.save(); +// Increment total number of sows for either an account or the protocol +function incrementSows(protocol: Address, account: Address, timestamp: BigInt, blockNumber: BigInt, recurs: boolean = true): void { + if (recurs && account != protocol) { + incrementSows(protocol, protocol, timestamp, blockNumber); + } + + let field = loadField(account); + field.numberOfSows += 1; + takeFieldSnapshots(field, protocol, timestamp, blockNumber); + field.save(); - let field = loadField(diamondAddress); - field.plotIndexes.push(plot.index); - field.save(); + // Add to protocol numberOfSowers if this is the first time this account has sown + if (account != protocol && field.numberOfSows == 0) { + incrementSowers(protocol, timestamp, blockNumber); } - return plot; } diff --git a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts b/projects/subgraph-beanstalk/src/utils/Marketplace.ts similarity index 59% rename from projects/subgraph-beanstalk/src/MarketplaceHandler.ts rename to projects/subgraph-beanstalk/src/utils/Marketplace.ts index 26b3f7eda3..002c5356e9 100644 --- a/projects/subgraph-beanstalk/src/MarketplaceHandler.ts +++ b/projects/subgraph-beanstalk/src/utils/Marketplace.ts @@ -1,43 +1,27 @@ import { Address, BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"; -import { - PodListingCancelled, - PodListingCreated as PodListingCreated_v1, - PodListingFilled as PodListingFilled_v1, - PodOrderCancelled, - PodOrderCreated as PodOrderCreated_v1, - PodOrderFilled as PodOrderFilled_v1 -} from "../generated/Beanstalk-ABIs/PreReplant"; -import { PodListingCreated as PodListingCreated_v1_1 } from "../generated/Beanstalk-ABIs/Replanted"; -import { - PodListingCreated as PodListingCreated_v2, - PodListingFilled as PodListingFilled_v2, - PodOrderCreated as PodOrderCreated_v2, - PodOrderFilled as PodOrderFilled_v2 -} from "../generated/Beanstalk-ABIs/MarketV2"; +import { loadPlot } from "../entities/Field"; +import { BI_10, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { loadPodFill, loadPodMarketplace } from "../entities/PodMarketplace"; +import { createHistoricalPodOrder, loadPodOrder } from "../entities/PodMarketplace"; +import { createHistoricalPodListing, loadPodListing } from "../entities/PodMarketplace"; import { Plot, + PodListing, PodListingCreated as PodListingCreatedEvent, PodListingFilled as PodListingFilledEvent, - PodListingCancelled as PodListingCancelledEvent, PodOrderCreated as PodOrderCreatedEvent, - PodOrderFilled as PodOrderFilledEvent, - PodOrderCancelled as PodOrderCancelledEvent, - PodOrder, - PodListing -} from "../generated/schema"; -import { BI_10, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { createHistoricalPodListing, loadPodListing } from "./utils/PodListing"; -import { - loadPodFill, - MarketplaceAction, - updateActiveListings, - updateActiveOrders, - updateMarketListingBalances, - updateMarketOrderBalances -} from "./utils/PodMarketplace"; -import { createHistoricalPodOrder, loadPodOrder } from "./utils/PodOrder"; -import { loadFarmer } from "./utils/Beanstalk"; -import { getHarvestableIndex, loadPlot } from "./utils/Field"; + PodOrderFilled as PodOrderFilledEvent +} from "../../generated/schema"; +import { getHarvestableIndex, loadFarmer } from "../entities/Beanstalk"; +import { takeMarketSnapshots } from "../entities/snapshots/Marketplace"; + +export enum MarketplaceAction { + CREATED, + FILLED_PARTIAL, + FILLED_FULL, + CANCELLED, + EXPIRED +} class PodListingCreatedParams { event: ethereum.Event; @@ -80,240 +64,7 @@ class MarketFillParams { costInBeans: BigInt; } -/* ------------------------------------ - * POD MARKETPLACE V1 - * - * Proposal: BIP-11 https://bean.money/bip-11 - * Deployed: 02/05/2022 @ block 14148509 - * Code: https://github.com/BeanstalkFarms/Beanstalk/commit/75a67fc94cf2637ac1d7d7c89645492e31423fed - * ------------------------------------ - */ - -export function handlePodListingCreated(event: PodListingCreated_v1): void { - podListingCreated({ - event: event, - account: event.params.account, - index: event.params.index, - start: event.params.start, - amount: event.params.amount, - pricePerPod: event.params.pricePerPod, - maxHarvestableIndex: event.params.maxHarvestableIndex, - mode: event.params.toWallet ? 0 : 1, - minFillAmount: ZERO_BI, - pricingFunction: null, - pricingType: 0 - }); -} - -export function handlePodListingCancelled(event: PodListingCancelled): void { - let listing = PodListing.load(event.params.account.toHexString() + "-" + event.params.index.toString()); - if (listing !== null && listing.status == "ACTIVE") { - updateActiveListings( - event.address, - MarketplaceAction.CANCELLED, - event.params.account.toHexString(), - listing.index, - listing.maxHarvestableIndex - ); - updateMarketListingBalances(event.address, event.address, ZERO_BI, listing.remainingAmount, ZERO_BI, ZERO_BI, event.block.timestamp); - - listing.status = listing.filled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; - listing.updatedAt = event.block.timestamp; - listing.save(); - - // Save the raw event data - let id = "podListingCancelled-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new PodListingCancelledEvent(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.historyID = listing.historyID; - rawEvent.account = event.params.account.toHexString(); - rawEvent.placeInLine = event.params.index.plus(listing.start).minus(getHarvestableIndex(event.address)); - rawEvent.index = event.params.index; - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); - } -} - -export function handlePodListingFilled(event: PodListingFilled_v1): void { - let listing = loadPodListing(event.params.from, event.params.index); - const beanAmount = BigInt.fromI32(listing.pricePerPod).times(event.params.amount).div(BigInt.fromI32(1000000)); - - podListingFilled({ - event: event, - from: event.params.from, - to: event.params.to, - id: null, - index: event.params.index, - start: event.params.start, - amount: event.params.amount, - costInBeans: beanAmount - }); -} - -export function handlePodOrderCreated(event: PodOrderCreated_v1): void { - const beanAmount = event.params.amount.times(BigInt.fromI32(event.params.pricePerPod)).div(BigInt.fromString("1000000")); - podOrderCreated({ - event: event, - account: event.params.account, - id: event.params.id, - beanAmount: beanAmount, - pricePerPod: event.params.pricePerPod, - maxPlaceInLine: event.params.maxPlaceInLine, - minFillAmount: ZERO_BI, - pricingFunction: null, - pricingType: 0 - }); -} - -export function handlePodOrderFilled(event: PodOrderFilled_v1): void { - let order = loadPodOrder(event.params.id); - let beanAmount = BigInt.fromI32(order.pricePerPod).times(event.params.amount).div(BigInt.fromI32(1000000)); - - podOrderFilled({ - event: event, - from: event.params.from, - to: event.params.to, - id: event.params.id, - index: event.params.index, - start: event.params.start, - amount: event.params.amount, - costInBeans: beanAmount - }); -} - -export function handlePodOrderCancelled(event: PodOrderCancelled): void { - let order = PodOrder.load(event.params.id.toHexString()); - if (order !== null && order.status == "ACTIVE") { - order.status = order.podAmountFilled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; - order.updatedAt = event.block.timestamp; - order.save(); - - updateActiveOrders(event.address, MarketplaceAction.CANCELLED, order.id, order.maxPlaceInLine); - updateMarketOrderBalances( - event.address, - event.address, - ZERO_BI, - order.beanAmount.minus(order.beanAmountFilled), - ZERO_BI, - ZERO_BI, - event.block.timestamp - ); - - // Save the raw event data - let id = "podOrderCancelled-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new PodOrderCancelledEvent(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.historyID = order.historyID; - rawEvent.account = event.params.account.toHexString(); - rawEvent.orderId = event.params.id.toHexString(); - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); - } -} - -/* ------------------------------------ - * POD MARKETPLACE V1 - REPLANTED - * - * When Beanstalk was Replanted, `event.params.mode` was changed from - * `bool` to `uint8`. - * - * Proposal: BIP-21 - * Deployed: 08/05/2022 at block 15278963 - * ------------------------------------ - */ - -export function handlePodListingCreated_v1_1(event: PodListingCreated_v1_1): void { - podListingCreated({ - event: event, - account: event.params.account, - index: event.params.index, - start: event.params.start, - amount: event.params.amount, - pricePerPod: event.params.pricePerPod, - maxHarvestableIndex: event.params.maxHarvestableIndex, - mode: event.params.mode, - minFillAmount: ZERO_BI, - pricingFunction: null, - pricingType: 0 - }); -} - -/* ------------------------------------ - * POD MARKETPLACE V2 - * - * Proposal: BIP-29 https://bean.money/bip-29 - * Deployed: 11/12/2022 @ block 15951072 - * ------------------------------------ - */ - -export function handlePodListingCreated_v2(event: PodListingCreated_v2): void { - podListingCreated({ - event: event, - account: event.params.account, - index: event.params.index, - start: event.params.start, - amount: event.params.amount, - pricePerPod: event.params.pricePerPod, - maxHarvestableIndex: event.params.maxHarvestableIndex, - mode: event.params.mode, - minFillAmount: event.params.minFillAmount, - pricingFunction: event.params.pricingFunction, - pricingType: event.params.pricingType - }); -} - -export function handlePodListingFilled_v2(event: PodListingFilled_v2): void { - podListingFilled({ - event: event, - from: event.params.from, - to: event.params.to, - id: null, - index: event.params.index, - start: event.params.start, - amount: event.params.amount, - costInBeans: event.params.costInBeans - }); -} - -export function handlePodOrderCreated_v2(event: PodOrderCreated_v2): void { - podOrderCreated({ - event: event, - account: event.params.account, - id: event.params.id, - beanAmount: event.params.amount, - pricePerPod: event.params.pricePerPod, - maxPlaceInLine: event.params.maxPlaceInLine, - minFillAmount: event.params.minFillAmount, - pricingFunction: event.params.pricingFunction, - pricingType: event.params.priceType - }); -} - -export function handlePodOrderFilled_v2(event: PodOrderFilled_v2): void { - podOrderFilled({ - event: event, - from: event.params.from, - to: event.params.to, - id: event.params.id, - index: event.params.index, - start: event.params.start, - amount: event.params.amount, - costInBeans: event.params.costInBeans - }); -} - -/* ------------------------------------ - * SHARED FUNCTIONS - * ------------------------------------ - */ - -function podListingCreated(params: PodListingCreatedParams): void { +export function podListingCreated(params: PodListingCreatedParams): void { let plot = Plot.load(params.index.toString()); if (plot == null) { return; @@ -400,7 +151,7 @@ function podListingCreated(params: PodListingCreatedParams): void { rawEvent.save(); } -function podListingFilled(params: MarketFillParams): void { +export function podListingFilled(params: MarketFillParams): void { let listing = loadPodListing(params.from, params.index); updateMarketListingBalances( @@ -503,7 +254,7 @@ function podListingFilled(params: MarketFillParams): void { rawEvent.save(); } -function podOrderCreated(params: PodOrderCreatedParams): void { +export function podOrderCreated(params: PodOrderCreatedParams): void { let order = loadPodOrder(params.id); loadFarmer(params.account); @@ -558,7 +309,7 @@ function podOrderCreated(params: PodOrderCreatedParams): void { rawEvent.save(); } -function podOrderFilled(params: MarketFillParams): void { +export function podOrderFilled(params: MarketFillParams): void { let order = loadPodOrder(params.id!); let fill = loadPodFill(params.event.address, params.index, params.event.transaction.hash.toHexString()); @@ -617,6 +368,72 @@ function podOrderFilled(params: MarketFillParams): void { rawEvent.save(); } +export function updateMarketListingBalances( + protocol: Address, + marketAddress: Address, + newPodAmount: BigInt, + cancelledPodAmount: BigInt, + filledPodAmount: BigInt, + filledBeanAmount: BigInt, + timestamp: BigInt +): void { + let market = loadPodMarketplace(marketAddress); + + const netListingChange = newPodAmount.minus(cancelledPodAmount).minus(filledPodAmount); + + market.listedPods = market.listedPods.plus(newPodAmount); + market.availableListedPods = market.availableListedPods.plus(netListingChange); + market.cancelledListedPods = market.cancelledListedPods.plus(cancelledPodAmount); + market.filledListedPods = market.filledListedPods.plus(filledPodAmount); + market.podVolume = market.podVolume.plus(filledPodAmount); + market.beanVolume = market.beanVolume.plus(filledBeanAmount); + + takeMarketSnapshots(market, protocol, timestamp); + market.save(); +} + +export function updateMarketOrderBalances( + protocol: Address, + marketAddress: Address, + newBeanAmount: BigInt, + cancelledBeanAmount: BigInt, + filledPodAmount: BigInt, + filledBeanAmount: BigInt, + timestamp: BigInt +): void { + let market = loadPodMarketplace(marketAddress); + + const netOrderChange = newBeanAmount.minus(cancelledBeanAmount).minus(filledBeanAmount); + + market.orderBeans = market.orderBeans.plus(newBeanAmount); + market.availableOrderBeans = market.availableOrderBeans.plus(netOrderChange); + market.filledOrderedPods = market.filledOrderedPods.plus(filledPodAmount); + market.filledOrderBeans = market.filledOrderBeans.plus(filledBeanAmount); + market.podVolume = market.podVolume.plus(filledPodAmount); + market.beanVolume = market.beanVolume.plus(filledBeanAmount); + market.cancelledOrderBeans = market.cancelledOrderBeans.plus(cancelledBeanAmount); + + takeMarketSnapshots(market, protocol, timestamp); + market.save(); +} + +export function updateExpiredPlots(protocol: Address, harvestableIndex: BigInt, timestamp: BigInt): void { + let market = loadPodMarketplace(protocol); + let remainingListings = market.activeListings; + + // Cancel any pod marketplace listings beyond the index + for (let i = 0; i < remainingListings.length; i++) { + const destructured = remainingListings[i].split("-"); + const maxHarvestableIndex = BigInt.fromString(destructured[2]); + if (harvestableIndex > maxHarvestableIndex) { + // This method updates the marketplace entity, so it will perform the splice. + expirePodListingIfExists(protocol, destructured[0], BigInt.fromString(destructured[1]), timestamp, i); + // A similar splice is done here also to track the updated index on the underlying array. + remainingListings.splice(i--, 1); + } + } +} + function setBeansPerPodAfterFill(event: ethereum.Event, plotIndex: BigInt, start: BigInt, length: BigInt, costInBeans: BigInt): void { // Load the plot that is being sent. It may or may not have been created already, depending // on whether the PlotTransfer event has already been processed (sometims its emitted after the market transfer). @@ -638,3 +455,101 @@ function setBeansPerPodAfterFill(event: ethereum.Event, plotIndex: BigInt, start fillPlot.sourceHash = event.transaction.hash.toHexString(); fillPlot.save(); } + +export function expirePodListingIfExists( + protocol: Address, + farmer: string, + listedPlotIndex: BigInt, + timestamp: BigInt, + activeListingIndex: i32 = -1 // If provided, avoids having to lookup the index +): void { + let listing = PodListing.load(farmer + "-" + listedPlotIndex.toString()); + if (listing == null || listing.status != "ACTIVE") { + return; + } + listing.status = "EXPIRED"; + listing.save(); + + let market = loadPodMarketplace(protocol); + + if (activeListingIndex == -1) { + // There should always be a matching entry in this list because it is verified that the listing is ACTIVE + for (let i = 0; i < market.activeListings.length; i++) { + const destructured = market.activeListings[i].split("-"); + // Unnecessary to check if the account matches. + if (destructured[1] == listedPlotIndex.toString()) { + activeListingIndex = i; + break; + } + } + } + + market.expiredListedPods = market.expiredListedPods.plus(listing.remainingAmount); + market.availableListedPods = market.availableListedPods.minus(listing.remainingAmount); + let activeListings = market.activeListings; + activeListings.splice(activeListingIndex, 1); + market.activeListings = activeListings; + + takeMarketSnapshots(market, protocol, timestamp); + market.save(); +} + +export function updateActiveListings( + protocol: Address, + action: MarketplaceAction, + farmer: string, + plotIndex: BigInt, + expiryIndex: BigInt +): void { + let market = loadPodMarketplace(protocol); + let listings = market.activeListings; + + if (action == MarketplaceAction.CREATED) { + listings.push(farmer + "-" + plotIndex.toString() + "-" + expiryIndex.toString()); + } + if ( + [MarketplaceAction.CANCELLED, MarketplaceAction.FILLED_PARTIAL, MarketplaceAction.FILLED_FULL, MarketplaceAction.EXPIRED].includes( + action + ) + ) { + listings.splice(Marketplace_findIndex_listing(listings, plotIndex), 1); + } + + market.activeListings = listings; + market.save(); +} + +export function updateActiveOrders(protocol: Address, action: MarketplaceAction, orderId: string, maxPlaceInLine: BigInt): void { + let market = loadPodMarketplace(protocol); + let orders = market.activeOrders; + + if (action == MarketplaceAction.CREATED) { + orders.push(orderId + "-" + maxPlaceInLine.toString()); + } + if ([MarketplaceAction.CANCELLED, MarketplaceAction.FILLED_FULL, MarketplaceAction.EXPIRED].includes(action)) { + orders.splice(Marketplace_findIndex_order(orders, orderId), 1); + } + + market.activeOrders = orders; + market.save(); +} + +function Marketplace_findIndex_listing(listings: string[], plotIndex: BigInt): i32 { + for (let i = 0; i < listings.length; i++) { + const values = listings[i].split("-"); + if (BigInt.fromString(values[1]) == plotIndex) { + return i; + } + } + return -1; +} + +function Marketplace_findIndex_order(orders: string[], orderId: string): i32 { + for (let i = 0; i < orders.length; i++) { + const values = orders[i].split("-"); + if (values[0] == orderId) { + return i; + } + } + return -1; +} diff --git a/projects/subgraph-beanstalk/src/utils/PodListing.ts b/projects/subgraph-beanstalk/src/utils/PodListing.ts deleted file mode 100644 index d1ede5e444..0000000000 --- a/projects/subgraph-beanstalk/src/utils/PodListing.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { Address, BigInt, log } from "@graphprotocol/graph-ts"; -import { PodListing } from "../../generated/schema"; -import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { loadPodMarketplace } from "./PodMarketplace"; -import { takeMarketSnapshots } from "./snapshots/Marketplace"; - -export function loadPodListing(account: Address, index: BigInt): PodListing { - let id = account.toHexString() + "-" + index.toString(); - let listing = PodListing.load(id); - - if (listing == null) { - listing = new PodListing(id); - listing.podMarketplace = BEANSTALK.toHexString(); - listing.historyID = ""; - listing.plot = index.toString(); - listing.farmer = account.toHexString(); - - listing.index = index; - listing.start = ZERO_BI; - listing.mode = 0; - - listing.maxHarvestableIndex = ZERO_BI; - listing.minFillAmount = ZERO_BI; - - listing.pricePerPod = 0; - - listing.originalIndex = index; - listing.originalAmount = ZERO_BI; - listing.filled = ZERO_BI; - - listing.amount = ZERO_BI; - listing.remainingAmount = ZERO_BI; - listing.filledAmount = ZERO_BI; - - listing.status = "ACTIVE"; - listing.createdAt = ZERO_BI; - listing.creationHash = ""; - listing.updatedAt = ZERO_BI; - - listing.save(); - } - - return listing; -} - -export function expirePodListingIfExists( - protocol: Address, - farmer: string, - listedPlotIndex: BigInt, - timestamp: BigInt, - activeListingIndex: i32 = -1 // If provided, avoids having to lookup the index -): void { - let listing = PodListing.load(farmer + "-" + listedPlotIndex.toString()); - if (listing == null || listing.status != "ACTIVE") { - return; - } - listing.status = "EXPIRED"; - listing.save(); - - let market = loadPodMarketplace(protocol); - - if (activeListingIndex == -1) { - // There should always be a matching entry in this list because it is verified that the listing is ACTIVE - for (let i = 0; i < market.activeListings.length; i++) { - const destructured = market.activeListings[i].split("-"); - // Unnecessary to check if the account matches. - if (destructured[1] == listedPlotIndex.toString()) { - activeListingIndex = i; - break; - } - } - } - - market.expiredListedPods = market.expiredListedPods.plus(listing.remainingAmount); - market.availableListedPods = market.availableListedPods.minus(listing.remainingAmount); - let activeListings = market.activeListings; - activeListings.splice(activeListingIndex, 1); - market.activeListings = activeListings; - - takeMarketSnapshots(market, protocol, timestamp); - market.save(); -} - -export function createHistoricalPodListing(listing: PodListing): void { - let created = false; - let id = listing.id; - for (let i = 0; !created; i++) { - id = listing.id + "-" + i.toString(); - let newListing = PodListing.load(id); - if (newListing == null) { - newListing = new PodListing(id); - newListing.podMarketplace = listing.podMarketplace; - newListing.historyID = listing.historyID; - newListing.plot = listing.plot; - newListing.farmer = listing.farmer; - - newListing.index = listing.index; - newListing.start = listing.start; - newListing.mode = listing.mode; - - newListing.maxHarvestableIndex = listing.maxHarvestableIndex; - newListing.minFillAmount = listing.minFillAmount; - - newListing.pricePerPod = listing.pricePerPod; - - newListing.originalIndex = listing.originalIndex; - newListing.originalAmount = listing.originalAmount; - newListing.filled = listing.filled; - - newListing.amount = listing.amount; - newListing.remainingAmount = listing.remainingAmount; - newListing.filledAmount = listing.filledAmount; - - newListing.fill = listing.fill; - - newListing.status = listing.status; - newListing.createdAt = listing.createdAt; - newListing.updatedAt = listing.updatedAt; - newListing.creationHash = listing.creationHash; - newListing.save(); - created = true; - } - } -} diff --git a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts b/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts deleted file mode 100644 index deadc82333..0000000000 --- a/projects/subgraph-beanstalk/src/utils/PodMarketplace.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Address, BigInt, log } from "@graphprotocol/graph-ts"; -import { PodMarketplace, PodFill } from "../../generated/schema"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { loadField } from "./Field"; -import { expirePodListingIfExists } from "./PodListing"; -import { takeMarketSnapshots } from "./snapshots/Marketplace"; - -export enum MarketplaceAction { - CREATED, - FILLED_PARTIAL, - FILLED_FULL, - CANCELLED, - EXPIRED -} - -export function loadPodMarketplace(diamondAddress: Address): PodMarketplace { - let marketplace = PodMarketplace.load(diamondAddress.toHexString()); - if (marketplace == null) { - let field = loadField(diamondAddress); - marketplace = new PodMarketplace(diamondAddress.toHexString()); - marketplace.season = field.season; - marketplace.activeListings = []; - marketplace.activeOrders = []; - marketplace.listedPods = ZERO_BI; - marketplace.availableListedPods = ZERO_BI; - marketplace.filledListedPods = ZERO_BI; - marketplace.expiredListedPods = ZERO_BI; - marketplace.cancelledListedPods = ZERO_BI; - marketplace.orderBeans = ZERO_BI; - marketplace.availableOrderBeans = ZERO_BI; - marketplace.filledOrderedPods = ZERO_BI; - marketplace.filledOrderBeans = ZERO_BI; - marketplace.cancelledOrderBeans = ZERO_BI; - marketplace.podVolume = ZERO_BI; - marketplace.beanVolume = ZERO_BI; - marketplace.save(); - } - return marketplace; -} - -export function loadPodFill(diamondAddress: Address, index: BigInt, hash: String): PodFill { - let id = diamondAddress.toHexString() + "-" + index.toString() + "-" + hash; - let fill = PodFill.load(id); - if (fill == null) { - fill = new PodFill(id); - fill.podMarketplace = diamondAddress.toHexString(); - fill.createdAt = ZERO_BI; - fill.fromFarmer = ""; - fill.toFarmer = ""; - fill.placeInLine = ZERO_BI; - fill.amount = ZERO_BI; - fill.index = ZERO_BI; - fill.start = ZERO_BI; - fill.costInBeans = ZERO_BI; - fill.save(); - } - return fill; -} - -export function updateMarketListingBalances( - protocol: Address, - marketAddress: Address, - newPodAmount: BigInt, - cancelledPodAmount: BigInt, - filledPodAmount: BigInt, - filledBeanAmount: BigInt, - timestamp: BigInt -): void { - let market = loadPodMarketplace(marketAddress); - - const netListingChange = newPodAmount.minus(cancelledPodAmount).minus(filledPodAmount); - - market.listedPods = market.listedPods.plus(newPodAmount); - market.availableListedPods = market.availableListedPods.plus(netListingChange); - market.cancelledListedPods = market.cancelledListedPods.plus(cancelledPodAmount); - market.filledListedPods = market.filledListedPods.plus(filledPodAmount); - market.podVolume = market.podVolume.plus(filledPodAmount); - market.beanVolume = market.beanVolume.plus(filledBeanAmount); - - takeMarketSnapshots(market, protocol, timestamp); - market.save(); -} - -export function updateMarketOrderBalances( - protocol: Address, - marketAddress: Address, - newBeanAmount: BigInt, - cancelledBeanAmount: BigInt, - filledPodAmount: BigInt, - filledBeanAmount: BigInt, - timestamp: BigInt -): void { - let market = loadPodMarketplace(marketAddress); - - const netOrderChange = newBeanAmount.minus(cancelledBeanAmount).minus(filledBeanAmount); - - market.orderBeans = market.orderBeans.plus(newBeanAmount); - market.availableOrderBeans = market.availableOrderBeans.plus(netOrderChange); - market.filledOrderedPods = market.filledOrderedPods.plus(filledPodAmount); - market.filledOrderBeans = market.filledOrderBeans.plus(filledBeanAmount); - market.podVolume = market.podVolume.plus(filledPodAmount); - market.beanVolume = market.beanVolume.plus(filledBeanAmount); - market.cancelledOrderBeans = market.cancelledOrderBeans.plus(cancelledBeanAmount); - - takeMarketSnapshots(market, protocol, timestamp); - market.save(); -} - -export function updateExpiredPlots(protocol: Address, harvestableIndex: BigInt, timestamp: BigInt): void { - let market = loadPodMarketplace(protocol); - let remainingListings = market.activeListings; - - // Cancel any pod marketplace listings beyond the index - for (let i = 0; i < remainingListings.length; i++) { - const destructured = remainingListings[i].split("-"); - const maxHarvestableIndex = BigInt.fromString(destructured[2]); - if (harvestableIndex > maxHarvestableIndex) { - // This method updates the marketplace entity, so it will perform the splice. - expirePodListingIfExists(protocol, destructured[0], BigInt.fromString(destructured[1]), timestamp, i); - // A similar splice is done here also to track the updated index on the underlying array. - remainingListings.splice(i--, 1); - } - } -} - -export function updateActiveListings( - protocol: Address, - action: MarketplaceAction, - farmer: string, - plotIndex: BigInt, - expiryIndex: BigInt -): void { - let market = loadPodMarketplace(protocol); - let listings = market.activeListings; - - if (action == MarketplaceAction.CREATED) { - listings.push(farmer + "-" + plotIndex.toString() + "-" + expiryIndex.toString()); - } - if ( - [MarketplaceAction.CANCELLED, MarketplaceAction.FILLED_PARTIAL, MarketplaceAction.FILLED_FULL, MarketplaceAction.EXPIRED].includes( - action - ) - ) { - listings.splice(Marketplace_findIndex_listing(listings, plotIndex), 1); - } - - market.activeListings = listings; - market.save(); -} - -export function updateActiveOrders(diamondAddress: Address, action: MarketplaceAction, orderId: string, maxPlaceInLine: BigInt): void { - let market = loadPodMarketplace(diamondAddress); - let orders = market.activeOrders; - - if (action == MarketplaceAction.CREATED) { - orders.push(orderId + "-" + maxPlaceInLine.toString()); - } - if ([MarketplaceAction.CANCELLED, MarketplaceAction.FILLED_FULL, MarketplaceAction.EXPIRED].includes(action)) { - orders.splice(Marketplace_findIndex_order(orders, orderId), 1); - } - - market.activeOrders = orders; - market.save(); -} - -export function Marketplace_findIndex_listing(listings: string[], plotIndex: BigInt): i32 { - for (let i = 0; i < listings.length; i++) { - const values = listings[i].split("-"); - if (BigInt.fromString(values[1]) == plotIndex) { - return i; - } - } - return -1; -} - -export function Marketplace_findIndex_order(orders: string[], orderId: string): i32 { - for (let i = 0; i < orders.length; i++) { - const values = orders[i].split("-"); - if (values[0] == orderId) { - return i; - } - } - return -1; -} diff --git a/projects/subgraph-beanstalk/src/utils/PodOrder.ts b/projects/subgraph-beanstalk/src/utils/PodOrder.ts deleted file mode 100644 index 31c8ed8b6c..0000000000 --- a/projects/subgraph-beanstalk/src/utils/PodOrder.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Bytes } from "@graphprotocol/graph-ts"; -import { PodOrder } from "../../generated/schema"; -import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; -import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; - -export function loadPodOrder(orderID: Bytes): PodOrder { - let order = PodOrder.load(orderID.toHexString()); - if (order == null) { - order = new PodOrder(orderID.toHexString()); - order.podMarketplace = BEANSTALK.toHexString(); - order.historyID = ""; - order.farmer = ""; - order.createdAt = ZERO_BI; - order.updatedAt = ZERO_BI; - order.status = ""; - order.beanAmount = ZERO_BI; - order.podAmountFilled = ZERO_BI; - order.beanAmountFilled = ZERO_BI; - order.minFillAmount = ZERO_BI; - order.maxPlaceInLine = ZERO_BI; - order.pricePerPod = 0; - order.creationHash = ""; - order.fills = []; - order.save(); - } - return order; -} - -export function createHistoricalPodOrder(order: PodOrder): void { - let created = false; - let id = order.id; - for (let i = 0; !created; i++) { - id = order.id + "-" + i.toString(); - let newOrder = PodOrder.load(id); - if (newOrder == null) { - newOrder = new PodOrder(id); - newOrder.podMarketplace = order.podMarketplace; - newOrder.historyID = order.historyID; - newOrder.farmer = order.farmer; - newOrder.createdAt = order.createdAt; - newOrder.updatedAt = order.updatedAt; - newOrder.status = order.status; - newOrder.beanAmount = order.beanAmount; - newOrder.podAmountFilled = order.podAmountFilled; - newOrder.beanAmountFilled = order.beanAmountFilled; - newOrder.minFillAmount = order.minFillAmount; - newOrder.maxPlaceInLine = order.maxPlaceInLine; - newOrder.pricePerPod = order.pricePerPod; - newOrder.creationHash = order.creationHash; - newOrder.fills = order.fills; - newOrder.save(); - created = true; - } - } -} diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 85bdc4c8de..35976decc0 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -1,209 +1,202 @@ -import { Address, BigInt, Bytes, ethereum, store, log } from "@graphprotocol/graph-ts"; -import { Silo, SiloDeposit, SiloWithdraw, SiloYield, SiloAsset, WhitelistTokenSetting, TokenYield } from "../../generated/schema"; -import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; -import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; - -/* ===== Base Silo Entities ===== */ - -export function loadSilo(account: Address): Silo { - let silo = Silo.load(account.toHexString()); - if (silo == null) { - silo = new Silo(account.toHexString()); - silo.beanstalk = BEANSTALK.toHexString(); - if (account !== BEANSTALK) { - silo.farmer = account.toHexString(); +import { Address, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; +import { takeSiloSnapshots } from "../entities/snapshots/Silo"; +import { loadSilo, loadSiloAsset, loadSiloDeposit, loadWhitelistTokenSetting, updateDeposit } from "../entities/Silo"; +import { takeSiloAssetSnapshots } from "../entities/snapshots/SiloAsset"; +import { stemFromSeason } from "./contracts/SiloCalculations"; +import { GAUGE_BIP45_BLOCK } from "../../../subgraph-core/utils/Constants"; +import { BI_10, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { loadBeanstalk, loadFarmer } from "../entities/Beanstalk"; + +class AddRemoveDepositsParams { + event: ethereum.Event; + account: Address; + token: Address; + seasons: BigInt[] | null; // Seasons not present in v3+ + stems: BigInt[] | null; // Stems not present in v2 + amounts: BigInt[]; + bdvs: BigInt[] | null; // bdv not present in v2 removal + depositVersion: String; +} + +export function addDeposits(params: AddRemoveDepositsParams): void { + for (let i = 0; i < params.amounts.length; ++i) { + let deposit = loadSiloDeposit({ + account: params.account, + token: params.token, + depositVersion: params.depositVersion, + season: params.seasons != null ? params.seasons![i] : null, + stem: params.stems != null ? params.stems![i] : null + }); + + // Set granular deposit version type + if (params.depositVersion == "season") { + deposit.depositVersion = "season"; + // Fill stem according to legacy conversion + deposit.stemV31 = stemFromSeason(params.seasons![i].toI32(), params.token); + } else { + deposit.depositVersion = params.event.block.number > GAUGE_BIP45_BLOCK ? "v3.1" : "v3"; + deposit.stemV31 = params.event.block.number > GAUGE_BIP45_BLOCK ? deposit.stem! : deposit.stem!.times(BI_10.pow(6)); } - silo.whitelistedTokens = []; - silo.dewhitelistedTokens = []; - silo.depositedBDV = ZERO_BI; - silo.stalk = ZERO_BI; - silo.plantableStalk = ZERO_BI; - silo.seeds = ZERO_BI; - silo.grownStalkPerSeason = ZERO_BI; - silo.roots = ZERO_BI; - silo.germinatingStalk = ZERO_BI; - silo.beanMints = ZERO_BI; - silo.activeFarmers = 0; - silo.save(); + + deposit = updateDeposit(deposit, params.amounts[i], params.bdvs![i], params.event)!; + deposit.save(); + + // Ensure that a Farmer entity is set up for this account. + loadFarmer(params.account); + + updateDepositInSilo( + params.event.address, + params.account, + params.token, + params.amounts[i], + params.bdvs![i], + params.event.block.timestamp + ); } - return silo as Silo; } -/* ===== Asset Entities ===== */ - -export function loadSiloAsset(account: Address, token: Address): SiloAsset { - let id = account.toHexString() + "-" + token.toHexString(); - let asset = SiloAsset.load(id); - - if (asset == null) { - asset = new SiloAsset(id); - asset.silo = account.toHexString(); - asset.token = token.toHexString(); - asset.depositedBDV = ZERO_BI; - asset.depositedAmount = ZERO_BI; - asset.withdrawnAmount = ZERO_BI; - asset.farmAmount = ZERO_BI; - asset.save(); +export function removeDeposits(params: AddRemoveDepositsParams): void { + for (let i = 0; i < params.amounts.length; ++i) { + let deposit = loadSiloDeposit({ + account: params.account, + token: params.token, + depositVersion: params.depositVersion, + season: params.seasons != null ? params.seasons![i] : null, + stem: params.stems != null ? params.stems![i] : null + }); + + // Use bdv if it was provided (v2 events dont provide bdv), otherwise infer + let removedBdv = params.bdvs != null ? params.bdvs![i] : params.amounts[i].times(deposit.depositedBDV).div(deposit.depositedAmount); + + // If the amount goes to zero, the deposit is deleted and not returned + const updatedDeposit = updateDeposit(deposit, params.amounts[i].neg(), removedBdv.neg(), params.event); + if (updatedDeposit !== null) { + updatedDeposit.save(); + } + + // Update protocol totals + updateDepositInSilo( + params.event.address, + params.account, + params.token, + params.amounts[i].neg(), + removedBdv.neg(), + params.event.block.timestamp + ); } - return asset as SiloAsset; } -/* ===== Whitelist Token Settings Entities ===== */ +export function updateDepositInSilo( + protocol: Address, + account: Address, + token: Address, + deltaAmount: BigInt, + deltaBdv: BigInt, + timestamp: BigInt, + recurs: boolean = true +): void { + if (recurs && account != protocol) { + updateDepositInSilo(protocol, protocol, token, deltaAmount, deltaBdv, timestamp); + } + let silo = loadSilo(account); + silo.depositedBDV = silo.depositedBDV.plus(deltaBdv); -export function addToSiloWhitelist(siloAddress: Address, token: Address): void { - let silo = loadSilo(siloAddress); - let currentList = silo.whitelistedTokens; - currentList.push(token.toHexString()); - silo.whitelistedTokens = currentList; + const newSeedStalk = updateDepositInSiloAsset(protocol, account, token, deltaAmount, deltaBdv, timestamp, false); + // Individual farmer seeds cannot be directly tracked due to seed gauge + if (account == protocol) { + silo.grownStalkPerSeason = silo.grownStalkPerSeason.plus(newSeedStalk); + } + takeSiloSnapshots(silo, protocol, timestamp); silo.save(); } -export function loadWhitelistTokenSetting(token: Address): WhitelistTokenSetting { - let setting = WhitelistTokenSetting.load(token); - if (setting == null) { - setting = new WhitelistTokenSetting(token); - setting.selector = Bytes.empty(); - setting.stalkEarnedPerSeason = ZERO_BI; - setting.stalkIssuedPerBdv = ZERO_BI; - setting.milestoneSeason = 0; - setting.updatedAt = ZERO_BI; - setting.save(); - - // Check token addresses and set replant seeds/stalk for Unripe due to event timing. - if (token == UNRIPE_BEAN) { - setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); - setting.stalkEarnedPerSeason = BigInt.fromI32(2000000); - setting.save(); - } else if (token == UNRIPE_BEAN_3CRV) { - setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); - setting.stalkEarnedPerSeason = BigInt.fromI32(4000000); - setting.save(); - } +export function updateDepositInSiloAsset( + protocol: Address, + account: Address, + token: Address, + deltaAmount: BigInt, + deltaBdv: BigInt, + timestamp: BigInt, + recurs: boolean = true +): BigInt { + if (recurs && account != protocol) { + updateDepositInSiloAsset(protocol, protocol, token, deltaAmount, deltaBdv, timestamp); } - return setting as WhitelistTokenSetting; -} + let asset = loadSiloAsset(account, token); -/* ===== Deposit Entities ===== */ + let tokenSettings = loadWhitelistTokenSetting(token); + let newGrownStalk = deltaBdv.times(tokenSettings.stalkEarnedPerSeason).div(BigInt.fromI32(1000000)); -class SiloDepositID { - account: Address; - token: Address; - depositVersion: String; - season: BigInt | null; - stem: BigInt | null; -} + asset.depositedBDV = asset.depositedBDV.plus(deltaBdv); + asset.depositedAmount = asset.depositedAmount.plus(deltaAmount); -export function loadSiloDeposit(depositId: SiloDepositID): SiloDeposit { - // id: Account - Token Address - Deposit Version - (Season|Stem) - const seasonOrStem = depositId.depositVersion == "season" ? depositId.season! : depositId.stem!; - const id = - depositId.account.toHexString() + "-" + depositId.token.toHexString() + "-" + depositId.depositVersion + "-" + seasonOrStem.toString(); - let deposit = SiloDeposit.load(id); - if (deposit == null) { - deposit = new SiloDeposit(id); - deposit.farmer = depositId.account.toHexString(); - deposit.token = depositId.token.toHexString(); - deposit.depositVersion = depositId.depositVersion.toString(); - if (depositId.season !== null) { - deposit.season = depositId.season!.toU32(); - } - deposit.stem = depositId.stem; - deposit.stemV31 = ZERO_BI; - deposit.depositedAmount = ZERO_BI; - deposit.depositedBDV = ZERO_BI; - deposit.hashes = []; - deposit.createdBlock = ZERO_BI; - deposit.updatedBlock = ZERO_BI; - deposit.createdAt = ZERO_BI; - deposit.updatedAt = ZERO_BI; - deposit.save(); - } - return deposit; -} + takeSiloAssetSnapshots(asset, protocol, timestamp); + asset.save(); -// Updates the given SiloDeposit with new amounts/bdv. If the deposit was fully withdrawn, delete the SiloDeposit. -export function updateDeposit(deposit: SiloDeposit, deltaAmount: BigInt, deltaBdv: BigInt, event: ethereum.Event): SiloDeposit | null { - deposit.depositedAmount = deposit.depositedAmount.plus(deltaAmount); - if (deposit.depositedAmount <= ZERO_BI) { - store.remove("SiloDeposit", deposit.id); - return null; - } - deposit.depositedBDV = deposit.depositedBDV.plus(deltaBdv); - let depositHashes = deposit.hashes; - depositHashes.push(event.transaction.hash.toHexString()); - deposit.hashes = depositHashes; - deposit.createdBlock = deposit.createdBlock == ZERO_BI ? event.block.number : deposit.createdBlock; - deposit.createdAt = deposit.createdAt == ZERO_BI ? event.block.timestamp : deposit.createdAt; - deposit.updatedBlock = event.block.number; - deposit.updatedAt = event.block.timestamp; - return deposit; + return newGrownStalk; } -/* ===== Withdraw Entities ===== */ - -export function loadSiloWithdraw(account: Address, token: Address, season: i32): SiloWithdraw { - let id = account.toHexString() + "-" + token.toHexString() + "-" + season.toString(); - let withdraw = SiloWithdraw.load(id); - if (withdraw == null) { - withdraw = new SiloWithdraw(id); - withdraw.farmer = account.toHexString(); - withdraw.token = token.toHexString(); - withdraw.withdrawSeason = season; - withdraw.claimableSeason = season + 1; - withdraw.claimed = false; - withdraw.amount = ZERO_BI; - withdraw.createdAt = ZERO_BI; - withdraw.save(); +export function addWithdrawToSiloAsset( + protocol: Address, + account: Address, + token: Address, + deltaAmount: BigInt, + timestamp: BigInt, + recurs: boolean = true +): void { + if (recurs && account != protocol) { + addWithdrawToSiloAsset(protocol, protocol, token, deltaAmount, timestamp); } - return withdraw as SiloWithdraw; + let asset = loadSiloAsset(account, token); + asset.withdrawnAmount = asset.withdrawnAmount.plus(deltaAmount); + takeSiloAssetSnapshots(asset, protocol, timestamp); + asset.save(); } -/* ===== Yield Entities ===== */ - -export function loadSiloYield(season: i32, window: i32): SiloYield { - let siloYield = SiloYield.load(season.toString() + "-" + window.toString()); - if (siloYield == null) { - siloYield = new SiloYield(season.toString() + "-" + window.toString()); - siloYield.season = season; - siloYield.beta = ZERO_BD; - siloYield.u = 0; - siloYield.beansPerSeasonEMA = ZERO_BD; - siloYield.whitelistedTokens = []; - siloYield.createdAt = ZERO_BI; - - if (window == 24) { - siloYield.emaWindow = "ROLLING_24_HOUR"; - } else if (window == 168) { - siloYield.emaWindow = "ROLLING_7_DAY"; - } else if (window == 720) { - siloYield.emaWindow = "ROLLING_30_DAY"; - } - siloYield.save(); +export function updateStalkBalances( + protocol: Address, + account: Address, + deltaStalk: BigInt, + deltaRoots: BigInt, + timestamp: BigInt, + recurs: boolean = true +): void { + if (recurs && account != protocol) { + updateStalkBalances(protocol, protocol, deltaStalk, deltaRoots, timestamp); } - return siloYield as SiloYield; -} - -export function loadTokenYield(token: Address, season: i32, window: i32): TokenYield { - let id = token.concatI32(season).concatI32(window); - let tokenYield = TokenYield.load(id); - if (tokenYield == null) { - tokenYield = new TokenYield(id); - tokenYield.token = token; - tokenYield.season = season; - tokenYield.siloYield = season.toString() + "-" + window.toString(); - tokenYield.beanAPY = ZERO_BD; - tokenYield.stalkAPY = ZERO_BD; - tokenYield.createdAt = ZERO_BI; - tokenYield.save(); + let silo = loadSilo(account); + silo.stalk = silo.stalk.plus(deltaStalk); + silo.roots = silo.roots.plus(deltaRoots); + + takeSiloSnapshots(silo, protocol, timestamp); + + // Add account to active list if needed + if (account !== protocol) { + let beanstalk = loadBeanstalk(protocol); + let farmerIndex = beanstalk.activeFarmers.indexOf(account.toHexString()); + if (farmerIndex == -1) { + let newFarmers = beanstalk.activeFarmers; + newFarmers.push(account.toHexString()); + beanstalk.activeFarmers = newFarmers; + beanstalk.save(); + silo.activeFarmers += 1; + } else if (silo.stalk == ZERO_BI) { + let newFarmers = beanstalk.activeFarmers; + newFarmers.splice(farmerIndex, 1); + beanstalk.activeFarmers = newFarmers; + beanstalk.save(); + silo.activeFarmers -= 1; + } } - return tokenYield as TokenYield; + silo.save(); } -export function SiloAsset_findIndex_token(a: SiloAsset[], targetToken: string): i32 { - for (let j = 0; j < a.length; j++) { - if (a[j].token == targetToken) { - return j; - } +export function updateSeedsBalances(protocol: Address, account: Address, seeds: BigInt, timestamp: BigInt, recurs: boolean = true): void { + if (recurs && account != protocol) { + updateSeedsBalances(protocol, protocol, seeds, timestamp); } - return -1; + let silo = loadSilo(account); + silo.seeds = silo.seeds.plus(seeds); + takeSiloSnapshots(silo, protocol, timestamp); + silo.save(); } diff --git a/projects/subgraph-beanstalk/src/YieldHandler.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts similarity index 78% rename from projects/subgraph-beanstalk/src/YieldHandler.ts rename to projects/subgraph-beanstalk/src/utils/Yield.ts index 6af1fb648b..c6fa094108 100644 --- a/projects/subgraph-beanstalk/src/YieldHandler.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -1,46 +1,53 @@ import { Address, BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; -import { BasinBip } from "../generated/Beanstalk-ABIs/BasinBip"; -import { BEANSTALK, BEAN_ERC20, FERTILIZER } from "../../subgraph-core/utils/Constants"; -import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadFertilizer, loadFertilizerYield } from "./utils/Fertilizer"; -import { loadSilo, loadSiloAsset, loadSiloYield, loadTokenYield, loadWhitelistTokenSetting, SiloAsset_findIndex_token } from "./utils/Silo"; -import { BigDecimal_sum, f64_sum, f64_max } from "../../subgraph-core/utils/ArrayMath"; -import { getGerminatingBdvs } from "./utils/Germinating"; -import { SiloAsset, WhitelistTokenSetting } from "../generated/schema"; -import { getCurrentSeason, getRewardMinted } from "./utils/Beanstalk"; +import { BasinBip } from "../../generated/Beanstalk-ABIs/BasinBip"; +import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { + loadSilo, + loadSiloAsset, + loadSiloYield, + loadTokenYield, + loadWhitelistTokenSetting, + SiloAsset_findIndex_token +} from "../entities/Silo"; +import { BigDecimal_sum, f64_sum, f64_max } from "../../../subgraph-core/utils/ArrayMath"; +import { SiloAsset, WhitelistTokenSetting } from "../../generated/schema"; +import { calculateAPYPreGauge } from "./legacy/LegacyYield"; +import { getGerminatingBdvs } from "../entities/Germinating"; +import { getCurrentSeason, getRewardMinted, loadBeanstalk } from "../entities/Beanstalk"; +import { loadFertilizer, loadFertilizerYield } from "../entities/Fertilizer"; const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; const ROLLING_30_DAY_WINDOW = 720; // Note: minimum value of `t` is 6075 -export function updateBeanEMA(t: i32, timestamp: BigInt): void { - updateWindowEMA(t, timestamp, ROLLING_24_WINDOW); - updateWindowEMA(t, timestamp, ROLLING_7_DAY_WINDOW); - updateWindowEMA(t, timestamp, ROLLING_30_DAY_WINDOW); +export function updateBeanEMA(protocol: Address, timestamp: BigInt): void { + updateWindowEMA(protocol, timestamp, ROLLING_24_WINDOW); + updateWindowEMA(protocol, timestamp, ROLLING_7_DAY_WINDOW); + updateWindowEMA(protocol, timestamp, ROLLING_30_DAY_WINDOW); + + updateSiloVAPYs(protocol, timestamp, ROLLING_24_WINDOW); + updateSiloVAPYs(protocol, timestamp, ROLLING_7_DAY_WINDOW); + updateSiloVAPYs(protocol, timestamp, ROLLING_30_DAY_WINDOW); + + updateFertAPY(protocol, timestamp, ROLLING_24_WINDOW); + updateFertAPY(protocol, timestamp, ROLLING_7_DAY_WINDOW); + updateFertAPY(protocol, timestamp, ROLLING_30_DAY_WINDOW); } -/** - * - * - */ -function updateWindowEMA(t: i32, timestamp: BigInt, window: i32): void { +function updateWindowEMA(protocol: Address, timestamp: BigInt, window: i32): void { + const beanstalk = loadBeanstalk(protocol); + const t = beanstalk.lastSeason; + let silo = loadSilo(protocol); + let siloYield = loadSiloYield(t, window); + // Historic cache values up to season 20,000 if (t <= 20_000) { - let silo = loadSilo(BEANSTALK); - let siloYield = loadSiloYield(t, window); - siloYield.whitelistedTokens = silo.whitelistedTokens; siloYield.save(); - - updateFertAPY(t, timestamp, window); - return; } - let silo = loadSilo(BEANSTALK); - let siloYield = loadSiloYield(t, window); - // When less then window data points are available, // smooth over whatever is available. Otherwise use the full window. siloYield.u = t - 6074 < window ? t - 6074 : window; @@ -72,13 +79,12 @@ function updateWindowEMA(t: i32, timestamp: BigInt, window: i32): void { siloYield.beansPerSeasonEMA = currentEMA; siloYield.createdAt = timestamp; siloYield.save(); - - updateSiloVAPYs(t, timestamp, window); - updateFertAPY(t, timestamp, window); } -export function updateSiloVAPYs(t: i32, timestamp: BigInt, window: i32): void { - let silo = loadSilo(BEANSTALK); +export function updateSiloVAPYs(protocol: Address, timestamp: BigInt, window: i32): void { + const beanstalk = loadBeanstalk(protocol); + const t = beanstalk.lastSeason; + let silo = loadSilo(protocol); let siloYield = loadSiloYield(t, window); const currentEMA = siloYield.beansPerSeasonEMA; @@ -104,7 +110,7 @@ export function updateSiloVAPYs(t: i32, timestamp: BigInt, window: i32): void { // Chooses which apy calculation to use if (!isGaugeLive) { - const beanGrownStalk = loadWhitelistTokenSetting(BEAN_ERC20).stalkEarnedPerSeason; + const beanGrownStalk = loadWhitelistTokenSetting(Address.fromString(beanstalk.token)).stalkEarnedPerSeason; for (let i = 0; i < whitelistSettings.length; ++i) { const tokenAPY = calculateAPYPreGauge( currentEMA, @@ -138,7 +144,7 @@ export function updateSiloVAPYs(t: i32, timestamp: BigInt, window: i32): void { const siloTokens = siloYield.whitelistedTokens.concat(silo.dewhitelistedTokens); const depositedAssets: SiloAsset[] = []; for (let i = 0; i < siloTokens.length; ++i) { - depositedAssets.push(loadSiloAsset(BEANSTALK, Address.fromString(siloTokens[i]))); + depositedAssets.push(loadSiloAsset(protocol, Address.fromString(siloTokens[i]))); } // .load() is not supported on graph-node v0.30.0. Instead the above derivation of depositedAssets is used @@ -160,7 +166,7 @@ export function updateSiloVAPYs(t: i32, timestamp: BigInt, window: i32): void { germinatingGaugeLpBdv.push(germinating); staticSeeds.push(null); } else { - if (whitelistSettings[i].id == BEAN_ERC20) { + if (whitelistSettings[i].id == Address.fromString(beanstalk.token)) { tokens.push(-1); depositedBeanBdv = depositedBdv; germinatingBeanBdv = germinating; @@ -191,7 +197,7 @@ export function updateSiloVAPYs(t: i32, timestamp: BigInt, window: i32): void { depositedBeanBdv, siloStalk, CATCH_UP_RATE, - BigInt.fromU32(getCurrentSeason(BEANSTALK)), + BigInt.fromU32(getCurrentSeason(protocol)), germinatingBeanBdv, germinatingGaugeLpBdv, germinatingNonGaugeBdv, @@ -209,79 +215,6 @@ export function updateSiloVAPYs(t: i32, timestamp: BigInt, window: i32): void { } } -/** - * - * @param n An estimate of number of Beans minted to the Silo per Season on average - * over the next 720 Seasons. This could be pre-calculated as a SMA, EMA, or otherwise. - * @param seedsPerBDV The number of seeds per BDV Beanstalk rewards for this token. - * @returns - */ - -export function calculateAPYPreGauge( - n: BigDecimal, - seedsPerBDV: BigDecimal, - seedsPerBeanBDV: BigDecimal, - stalk: BigInt, - seeds: BigInt -): BigDecimal[] { - // Initialize sequence - const beansPerSeason: f64 = parseFloat(n.toString()); - let C: f64 = parseFloat(toDecimal(seeds).toString()); // Init: Total Seeds - let K: f64 = parseFloat(toDecimal(stalk, 10).toString()); // Init: Total Stalk - let b: f64 = parseFloat(seedsPerBDV.div(seedsPerBeanBDV).toString()); // Init: User BDV - let k: f64 = 1; // Init: User Stalk - - let _seedsPerBeanBdv: f64 = parseInt(seedsPerBeanBDV.toString()); - - // Farmer initial values - let b_start: f64 = b; - let k_start: f64 = k; - - // Placeholders for above values during each iteration - let C_i: f64 = 0; - let K_i: f64 = 0; - let b_i: f64 = 0; - let k_i: f64 = 0; - - // Stalk and Seeds per Deposited Bean. - let STALK_PER_SEED: f64 = 0.0001; // 1/10,000 Stalk per Seed - let STALK_PER_BEAN: f64 = parseFloat(seedsPerBeanBDV.div(BigDecimal.fromString("10000")).toString()); // 3 Seeds per Bean * 1/10,000 Stalk per Seed - - for (let i = 0; i < 8760; i++) { - // Each Season, Farmer's ownership = `current Stalk / total Stalk` - let ownership: f64 = k / K; - let newBDV: f64 = beansPerSeason * ownership; - - // Total Seeds: each seignorage Bean => 3 Seeds - C_i = C + beansPerSeason * _seedsPerBeanBdv; - // Total Stalk: each seignorage Bean => 1 Stalk, each outstanding Bean => 1/10_000 Stalk - K_i = K + beansPerSeason + STALK_PER_SEED * C; - // Farmer BDV: each seignorage Bean => 1 BDV - b_i = b + newBDV; - // Farmer Stalk: each 1 BDV => 1 Stalk, each outstanding Bean => d = 1/5_000 Stalk per Bean - k_i = k + newBDV + STALK_PER_BEAN * b; - - C = C_i; - K = K_i; - b = b_i; - k = k_i; - } - - // Examples: - // ------------------------------- - // b_start = 1 - // b = 1 - // b.minus(b_start) = 0 = 0% APY - // - // b_start = 1 - // b = 1.1 - // b.minus(b_start) = 0.1 = 10% APY - let beanApy = b - b_start; // beanAPY - let stalkApy = k - k_start; // stalkAPY - - return [BigDecimal.fromString(beanApy.toString()), BigDecimal.fromString(stalkApy.toString())]; -} - /** * Calculates silo Bean/Stalk vAPY when Seed Gauge is active. * @@ -445,35 +378,6 @@ export function calculateGaugeVAPYs( return retval; } -function updateFertAPY(t: i32, timestamp: BigInt, window: i32): void { - let siloYield = loadSiloYield(t, window); - let fertilizerYield = loadFertilizerYield(t, window); - let fertilizer = loadFertilizer(FERTILIZER); - let beanstalk = BasinBip.bind(BEANSTALK); - if (t < 6534) { - let currentFertHumidity = beanstalk.try_getCurrentHumidity(); - fertilizerYield.humidity = BigDecimal.fromString(currentFertHumidity.reverted ? "500" : currentFertHumidity.value.toString()).div( - BigDecimal.fromString("1000") - ); - } else { - // Avoid contract call for season >= 6534 since humidity will always be 0.2 - // This gives a significant performance improvement, but will need to be revisited if humidity ever changes - fertilizerYield.humidity = BigDecimal.fromString("0.2"); - } - - fertilizerYield.outstandingFert = fertilizer.supply; - fertilizerYield.beansPerSeasonEMA = siloYield.beansPerSeasonEMA; - fertilizerYield.deltaBpf = fertilizerYield.beansPerSeasonEMA.div(BigDecimal.fromString(fertilizerYield.outstandingFert.toString())); - fertilizerYield.simpleAPY = - fertilizerYield.deltaBpf == ZERO_BD - ? ZERO_BD - : fertilizerYield.humidity.div( - BigDecimal.fromString("1").plus(fertilizerYield.humidity).div(fertilizerYield.deltaBpf).div(BigDecimal.fromString("8760")) - ); - fertilizerYield.createdAt = timestamp; - fertilizerYield.save(); -} - function updateR(R: f64, change: f64): f64 { const newR = R + change; if (newR > 1) { @@ -504,3 +408,34 @@ function deltaRFromState(earnedBeans: f64): f64 { function updateGaugePoints(gaugePoints: f64, currentPercent: f64, optimalPercent: f64): f64 { return gaugePoints; } + +function updateFertAPY(protocol: Address, timestamp: BigInt, window: i32): void { + const beanstalk = loadBeanstalk(protocol); + const t = beanstalk.lastSeason; + let siloYield = loadSiloYield(t, window); + let fertilizerYield = loadFertilizerYield(t, window); + let fertilizer = loadFertilizer(Address.fromString(beanstalk.fertilizer1155!)); + let contract = BasinBip.bind(protocol); + if (t < 6534) { + let currentFertHumidity = contract.try_getCurrentHumidity(); + fertilizerYield.humidity = BigDecimal.fromString(currentFertHumidity.reverted ? "500" : currentFertHumidity.value.toString()).div( + BigDecimal.fromString("1000") + ); + } else { + // Avoid contract call for season >= 6534 since humidity will always be 0.2 + // This gives a significant performance improvement, but will need to be revisited if humidity ever changes + fertilizerYield.humidity = BigDecimal.fromString("0.2"); + } + + fertilizerYield.outstandingFert = fertilizer.supply; + fertilizerYield.beansPerSeasonEMA = siloYield.beansPerSeasonEMA; + fertilizerYield.deltaBpf = fertilizerYield.beansPerSeasonEMA.div(BigDecimal.fromString(fertilizerYield.outstandingFert.toString())); + fertilizerYield.simpleAPY = + fertilizerYield.deltaBpf == ZERO_BD + ? ZERO_BD + : fertilizerYield.humidity.div( + BigDecimal.fromString("1").plus(fertilizerYield.humidity).div(fertilizerYield.deltaBpf).div(BigDecimal.fromString("8760")) + ); + fertilizerYield.createdAt = timestamp; + fertilizerYield.save(); +} diff --git a/projects/subgraph-beanstalk/src/utils/contracts/BeanstalkPrice.ts b/projects/subgraph-beanstalk/src/utils/contracts/BeanstalkPrice.ts index bc751fd313..53a5da5dca 100644 --- a/projects/subgraph-beanstalk/src/utils/contracts/BeanstalkPrice.ts +++ b/projects/subgraph-beanstalk/src/utils/contracts/BeanstalkPrice.ts @@ -7,7 +7,7 @@ import { } from "../../../generated/Beanstalk-ABIs/BeanstalkPrice"; import { BEANSTALK_PRICE_1, BEANSTALK_PRICE_2, PRICE_2_BLOCK } from "../../../../subgraph-core/utils/Constants"; import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { loadSilo } from "../Silo"; +import { loadSilo } from "../../entities/Silo"; // Can't use the autogenerated one because the fields need to be updateable class PriceOverallStruct { diff --git a/projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts b/projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts new file mode 100644 index 0000000000..cc928aec1d --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts @@ -0,0 +1,45 @@ +import { Address, BigInt, log } from "@graphprotocol/graph-ts"; +import { loadSilo, loadSiloAsset, loadSiloWithdraw } from "../../entities/Silo"; +import { takeSiloAssetSnapshots } from "../../entities/snapshots/SiloAsset"; +import { loadBeanstalk } from "../../entities/Beanstalk"; +import { updateSeedsBalances, updateStalkBalances } from "../Silo"; +import { Replanted } from "../../../generated/Beanstalk-ABIs/Replanted"; + +export function updateClaimedWithdraw( + protocol: Address, + account: Address, + token: Address, + withdrawSeason: BigInt, + timestamp: BigInt +): void { + let withdraw = loadSiloWithdraw(account, token, withdrawSeason.toI32()); + withdraw.claimed = true; + withdraw.save(); + + let asset = loadSiloAsset(account, token); + asset.withdrawnAmount = asset.withdrawnAmount.minus(withdraw.amount); + takeSiloAssetSnapshots(asset, protocol, timestamp); + asset.save(); +} + +// This should be run at sunrise for the previous season to update any farmers stalk/seed/roots balances from silo transfers. +export function updateStalkWithCalls(protocol: Address, timestamp: BigInt): void { + let beanstalk = loadBeanstalk(protocol); + let beanstalk_call = Replanted.bind(protocol); + + for (let i = 0; i < beanstalk.farmersToUpdate.length; i++) { + let account = Address.fromString(beanstalk.farmersToUpdate[i]); + let silo = loadSilo(account); + updateStalkBalances( + protocol, + account, + beanstalk_call.balanceOfStalk(account).minus(silo.stalk), + beanstalk_call.balanceOfRoots(account).minus(silo.roots), + timestamp, + false + ); + updateSeedsBalances(protocol, account, beanstalk_call.balanceOfSeeds(account).minus(silo.seeds), timestamp, false); + } + beanstalk.farmersToUpdate = []; + beanstalk.save(); +} diff --git a/projects/subgraph-beanstalk/src/utils/legacy/LegacyYield.ts b/projects/subgraph-beanstalk/src/utils/legacy/LegacyYield.ts new file mode 100644 index 0000000000..041fbc8931 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/legacy/LegacyYield.ts @@ -0,0 +1,73 @@ +import { BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; +import { toDecimal } from "../../../../subgraph-core/utils/Decimals"; + +/** + * @param n An estimate of number of Beans minted to the Silo per Season on average + * over the next 720 Seasons. This could be pre-calculated as a SMA, EMA, or otherwise. + * @param seedsPerBDV The number of seeds per BDV Beanstalk rewards for this token. + * @returns + */ +export function calculateAPYPreGauge( + n: BigDecimal, + seedsPerBDV: BigDecimal, + seedsPerBeanBDV: BigDecimal, + stalk: BigInt, + seeds: BigInt +): BigDecimal[] { + // Initialize sequence + const beansPerSeason: f64 = parseFloat(n.toString()); + let C: f64 = parseFloat(toDecimal(seeds).toString()); // Init: Total Seeds + let K: f64 = parseFloat(toDecimal(stalk, 10).toString()); // Init: Total Stalk + let b: f64 = parseFloat(seedsPerBDV.div(seedsPerBeanBDV).toString()); // Init: User BDV + let k: f64 = 1; // Init: User Stalk + + let _seedsPerBeanBdv: f64 = parseInt(seedsPerBeanBDV.toString()); + + // Farmer initial values + let b_start: f64 = b; + let k_start: f64 = k; + + // Placeholders for above values during each iteration + let C_i: f64 = 0; + let K_i: f64 = 0; + let b_i: f64 = 0; + let k_i: f64 = 0; + + // Stalk and Seeds per Deposited Bean. + let STALK_PER_SEED: f64 = 0.0001; // 1/10,000 Stalk per Seed + let STALK_PER_BEAN: f64 = parseFloat(seedsPerBeanBDV.div(BigDecimal.fromString("10000")).toString()); // 3 Seeds per Bean * 1/10,000 Stalk per Seed + + for (let i = 0; i < 8760; i++) { + // Each Season, Farmer's ownership = `current Stalk / total Stalk` + let ownership: f64 = k / K; + let newBDV: f64 = beansPerSeason * ownership; + + // Total Seeds: each seignorage Bean => 3 Seeds + C_i = C + beansPerSeason * _seedsPerBeanBdv; + // Total Stalk: each seignorage Bean => 1 Stalk, each outstanding Bean => 1/10_000 Stalk + K_i = K + beansPerSeason + STALK_PER_SEED * C; + // Farmer BDV: each seignorage Bean => 1 BDV + b_i = b + newBDV; + // Farmer Stalk: each 1 BDV => 1 Stalk, each outstanding Bean => d = 1/5_000 Stalk per Bean + k_i = k + newBDV + STALK_PER_BEAN * b; + + C = C_i; + K = K_i; + b = b_i; + k = k_i; + } + + // Examples: + // ------------------------------- + // b_start = 1 + // b = 1 + // b.minus(b_start) = 0 = 0% APY + // + // b_start = 1 + // b = 1.1 + // b.minus(b_start) = 0.1 = 10% APY + let beanApy = b - b_start; // beanAPY + let stalkApy = k - k_start; // stalkAPY + + return [BigDecimal.fromString(beanApy.toString()), BigDecimal.fromString(stalkApy.toString())]; +} diff --git a/projects/subgraph-beanstalk/src/yield_cache/CacheLoader.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/CacheLoader.ts similarity index 93% rename from projects/subgraph-beanstalk/src/yield_cache/CacheLoader.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/CacheLoader.ts index 723e86718c..68569f0306 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/CacheLoader.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/CacheLoader.ts @@ -1,5 +1,5 @@ import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; -import { loadSiloYield, loadTokenYield } from "../utils/Silo"; +import { loadSiloYield, loadTokenYield } from "../utils/entities/Silo"; export function loadSiloCache(SILO_YIELD: string[][]): void { for (let i = 0; i < SILO_YIELD.length; i++) { diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricSilo_10_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricSilo_10_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricSilo_10_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricSilo_10_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricSilo_15_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricSilo_15_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricSilo_15_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricSilo_15_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricSilo_20_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricSilo_20_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricSilo_20_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricSilo_20_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricToken_12_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricToken_12_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricToken_12_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricToken_12_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricToken_20_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricToken_20_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/HistoricToken_20_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/HistoricToken_20_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_1.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts index 4579daa4be..b334bd5490 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_10_000 } from "./HistoricSilo_10_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_2.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts index dae3a046c6..5bd9dc5207 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_15_000 } from "./HistoricSilo_15_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_3.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts index 607d193fd6..bb6b17ed02 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_20_000 } from "./HistoricSilo_20_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/LoadToken_1.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts index e997119726..4386990457 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_24_HOUR_12_000 } from "./HistoricToken_12_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_1/LoadToken_2.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts index a76315ec93..bc98aaac3c 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_1/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_24_HOUR_20_000 } from "./HistoricToken_20_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricSilo_10_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricSilo_10_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricSilo_10_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricSilo_10_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricSilo_15_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricSilo_15_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricSilo_15_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricSilo_15_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricSilo_20_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricSilo_20_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricSilo_20_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricSilo_20_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricToken_12_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricToken_12_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricToken_12_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricToken_12_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricToken_20_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricToken_20_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/HistoricToken_20_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/HistoricToken_20_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts similarity index 88% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_1.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts index e46610d6ff..7768f99a5a 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_10_000 } from "./HistoricSilo_10_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts similarity index 88% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_2.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts index 448a714f8b..09298ccd75 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_15_000 } from "./HistoricSilo_15_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts similarity index 88% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_3.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts index 5ada4329f0..c16abb4c71 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_20_000 } from "./HistoricSilo_20_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/LoadToken_1.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts index 9af4d83f9a..884125ba9c 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_7_DAY_12_000 } from "./HistoricToken_12_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_2/LoadToken_2.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts index ffae89e7c2..6f8213006a 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_2/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_7_DAY_20_000 } from "./HistoricToken_20_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricSilo_10_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricSilo_10_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricSilo_10_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricSilo_10_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricSilo_15_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricSilo_15_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricSilo_15_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricSilo_15_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricSilo_20_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricSilo_20_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricSilo_20_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricSilo_20_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricToken_12_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricToken_12_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricToken_12_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricToken_12_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricToken_20_000.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricToken_20_000.ts similarity index 100% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/HistoricToken_20_000.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/HistoricToken_20_000.ts diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts similarity index 88% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_1.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts index 19f13a4f28..c0a32bba2f 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_10_000 } from "./HistoricSilo_10_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts similarity index 88% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_2.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts index 6c50058e54..4e191f10d5 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_15_000 } from "./HistoricSilo_15_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts similarity index 88% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_3.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts index e9252a6867..482195e61d 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_20_000 } from "./HistoricSilo_20_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/LoadToken_1.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts index f9133bbb3f..bf291cd471 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_30_DAY_12_000 } from "./HistoricToken_12_000"; diff --git a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts similarity index 89% rename from projects/subgraph-beanstalk/src/yield_cache/window_3/LoadToken_2.ts rename to projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts index 306b9e2977..b4ae5b2946 100644 --- a/projects/subgraph-beanstalk/src/yield_cache/window_3/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts @@ -1,6 +1,6 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/Beanstalk"; +import { loadBeanstalk } from "../../utils/entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_30_DAY_20_000 } from "./HistoricToken_20_000"; diff --git a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts index f19d26cbd4..b00d7c2ec1 100644 --- a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts +++ b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts @@ -1,21 +1,17 @@ import { afterEach, assert, clearStore, describe, test } from "matchstick-as/assembly/index"; import { log } from "matchstick-as/assembly/log"; import { BigInt } from "@graphprotocol/graph-ts"; - import { - handleTemperatureChange, handleBeanToMaxLpGpPerBdvRatioChange, handleGaugePointChange, handleUpdateAverageStalkPerBdvPerSeason, handleFarmerGerminatingStalkBalanceChanged, handleTotalGerminatingBalanceChanged, - handleWhitelistToken_BIP45, handleUpdateGaugeSettings, handleTotalGerminatingStalkChanged, handleTotalStalkChangedFromGermination -} from "../src/GaugeHandler"; - -import { BEAN_ERC20, BEAN_WETH_CP2_WELL, BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../subgraph-core/utils/Constants"; +} from "../src/handlers/GaugeHandler"; +import { BEAN_ERC20, BEANSTALK } from "../../subgraph-core/utils/Constants"; import { createBeanToMaxLpGpPerBdvRatioChangeEvent, createFarmerGerminatingStalkBalanceChangedEvent, @@ -29,10 +25,12 @@ import { import { createWhitelistTokenV4Event } from "./event-mocking/Whitelist"; import { createTemperatureChangeEvent } from "./event-mocking/Field"; import { simpleMockPrice } from "../../subgraph-core/tests/event-mocking/Price"; -import { loadSilo } from "../src/utils/Silo"; import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block"; import { setSeason } from "./utils/Season"; import { dayFromTimestamp } from "../../subgraph-core/utils/Dates"; +import { loadSilo } from "../src/entities/Silo"; +import { handleWhitelistToken } from "../src/handlers/SiloHandler"; +import { handleTemperatureChange } from "../src/handlers/FieldHandler"; const ANVIL_ADDR_1 = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".toLowerCase(); @@ -174,7 +172,7 @@ describe("Seed Gauge", () => { describe("Owner Configuration", () => { test("event: WhitelistToken", () => { - handleWhitelistToken_BIP45( + handleWhitelistToken( createWhitelistTokenV4Event( BEAN_ERC20.toHexString(), "0x12345678", diff --git a/projects/subgraph-beanstalk/tests/Silo.test.ts b/projects/subgraph-beanstalk/tests/Silo.test.ts index b97e0762e4..ac532535e0 100644 --- a/projects/subgraph-beanstalk/tests/Silo.test.ts +++ b/projects/subgraph-beanstalk/tests/Silo.test.ts @@ -1,15 +1,5 @@ import { BigInt } from "@graphprotocol/graph-ts"; import { afterEach, assert, clearStore, describe, test } from "matchstick-as/assembly/index"; -import { - handleAddDeposit, - handleAddDeposit_V3, - handleDewhitelistToken, - handleRemoveDeposit, - handleRemoveDeposit_V3, - handleRemoveDeposits, - handleWhitelistToken, - handleWhitelistToken_V3 -} from "../src/SiloHandler"; import { BEAN_3CRV, BEAN_ERC20, @@ -29,10 +19,18 @@ import { } from "./event-mocking/Silo"; import { createDewhitelistTokenEvent, createWhitelistTokenV2Event, createWhitelistTokenV3Event } from "./event-mocking/Whitelist"; import { ONE_BI, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { stemFromSeason } from "../src/utils/contracts/SiloCalculations"; import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block"; import { dayFromTimestamp } from "../../subgraph-core/utils/Dates"; import { setSeason } from "./utils/Season"; +import { + handleAddDeposit_v2, + handleRemoveDeposit_v2, + handleRemoveDeposits_v2, + handleWhitelistToken_v2, + handleWhitelistToken_v3 +} from "../src/handlers/legacy/LegacySiloHandler"; +import { handleAddDeposit, handleDewhitelistToken, handleRemoveDeposit } from "../src/handlers/SiloHandler"; +import { stemFromSeason } from "../src/utils/contracts/SiloCalculations"; describe("Silo Events", () => { afterEach(() => { @@ -45,7 +43,7 @@ describe("Silo Events", () => { let token = BEAN_ERC20.toHexString().toLowerCase(); let newAddDepositEvent = createAddDepositV2Event(account, token, 6100, 1000, 6, 1000); - handleAddDeposit(newAddDepositEvent); + handleAddDeposit_v2(newAddDepositEvent); assert.fieldEquals("Silo", account, "depositedBDV", "1000000000"); assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "season", "6100"); @@ -61,7 +59,7 @@ describe("Silo Events", () => { let token = BEAN_ERC20.toHexString().toLowerCase(); let newAddDepositEvent = createAddDepositV3Event(account, token, BigInt.fromU32(1500), 1000, 6, 1000); - handleAddDeposit_V3(newAddDepositEvent); + handleAddDeposit(newAddDepositEvent); assert.fieldEquals("Silo", account, "depositedBDV", "1000000000"); assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-1500", "stem", "1500"); @@ -73,7 +71,7 @@ describe("Silo Events", () => { // with V3.1 stem let addDeposit31 = createAddDepositV3Event(account, token, BigInt.fromI64(5700000000), 2500, 6, 2500); addDeposit31.block = mockBlock(GAUGE_BIP45_BLOCK.plus(ONE_BI)); - handleAddDeposit_V3(addDeposit31); + handleAddDeposit(addDeposit31); assert.fieldEquals("Silo", account, "depositedBDV", "3500000000"); assert.fieldEquals("SiloDeposit", account + "-" + token + "-stem-5700000000", "stem", "5700000000"); @@ -88,10 +86,10 @@ describe("Silo Events", () => { let token = BEAN_ERC20.toHexString().toLowerCase(); let newAddDepositEvent = createAddDepositV2Event(account, token, 6100, 1000, 6, 1000); - handleAddDeposit(newAddDepositEvent); + handleAddDeposit_v2(newAddDepositEvent); let newRemoveDepositEvent = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("800000000")); - handleRemoveDeposit(newRemoveDepositEvent); + handleRemoveDeposit_v2(newRemoveDepositEvent); assert.fieldEquals("Silo", account, "depositedBDV", "200000000"); assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "200000000"); @@ -105,13 +103,13 @@ describe("Silo Events", () => { let token = BEAN_ERC20.toHexString().toLowerCase(); let newAddDepositEvent = createAddDepositV2Event(account, token, 6100, 1000, 6, 1000); - handleAddDeposit(newAddDepositEvent); + handleAddDeposit_v2(newAddDepositEvent); let removeEvent = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("500000000")); - handleRemoveDeposit(removeEvent); + handleRemoveDeposit_v2(removeEvent); let removeEvent2 = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("200000000")); - handleRemoveDeposit(removeEvent2); + handleRemoveDeposit_v2(removeEvent2); assert.fieldEquals("Silo", account, "depositedBDV", "300000000"); assert.fieldEquals("SiloDeposit", account + "-" + token + "-season-6100", "depositedAmount", "300000000"); @@ -121,7 +119,7 @@ describe("Silo Events", () => { // Remove the deposit completely let removeEvent3 = createRemoveDepositV2Event(account, token, 6100, BigInt.fromString("300000000")); - handleRemoveDeposit(removeEvent3); + handleRemoveDeposit_v2(removeEvent3); assert.fieldEquals("Silo", account, "depositedBDV", "0"); assert.notInStore("SiloDeposit", account + "-" + token + "-season-6100"); @@ -135,13 +133,13 @@ describe("Silo Events", () => { let token2 = BEAN_3CRV.toHexString().toLowerCase(); let addV2_1 = createAddDepositV2Event(account1, token1, 6100, 1000, 6, 1000); - handleAddDeposit(addV2_1); + handleAddDeposit_v2(addV2_1); let addV3_1 = createAddDepositV3Event(account1, token1, BigInt.fromU32(70), 2000, 6, 2000); - handleAddDeposit_V3(addV3_1); + handleAddDeposit(addV3_1); let addV3_2 = createAddDepositV3Event(account1, token2, BigInt.fromU32(50), 1000, 6, 1000); - handleAddDeposit_V3(addV3_2); + handleAddDeposit(addV3_2); let addV3_3 = createAddDepositV3Event(account2, token2, BigInt.fromU32(90), 5000, 6, 4000); - handleAddDeposit_V3(addV3_3); + handleAddDeposit(addV3_3); assert.fieldEquals("Silo", BEANSTALK.toHexString(), "depositedBDV", "8000000000"); assert.fieldEquals("Silo", account1, "depositedBDV", "4000000000"); @@ -153,7 +151,7 @@ describe("Silo Events", () => { assert.fieldEquals("SiloAsset", account2 + "-" + token2, "depositedBDV", "4000000000"); let removeV2_1 = createRemoveDepositsV2Event(account1, token1, [6100], [BigInt.fromU32(1000000000)], BigInt.fromU32(1000000000)); - handleRemoveDeposits(removeV2_1); + handleRemoveDeposits_v2(removeV2_1); let removeV3_1 = createRemoveDepositV3Event( account2, token2, @@ -161,7 +159,7 @@ describe("Silo Events", () => { BigInt.fromU32(1500000000), BigInt.fromU32(1500000000) ); - handleRemoveDeposit_V3(removeV3_1); + handleRemoveDeposit(removeV3_1); assert.fieldEquals("Silo", BEANSTALK.toHexString(), "depositedBDV", "5500000000"); assert.fieldEquals("Silo", account1, "depositedBDV", "3000000000"); @@ -183,7 +181,7 @@ describe("Silo Events", () => { let addV3_1 = createAddDepositV3Event(account, token, BigInt.fromU32(70), 2000, 6, 2000); addV3_1.block = mockBlock(ZERO_BI, baseTimestamp); setSeason(20000); - handleAddDeposit_V3(addV3_1); + handleAddDeposit(addV3_1); assert.fieldEquals("SiloHourlySnapshot", account + "-20000", "depositedBDV", "2000000000"); assert.fieldEquals("SiloHourlySnapshot", account + "-20000", "deltaDepositedBDV", "2000000000"); @@ -203,7 +201,7 @@ describe("Silo Events", () => { let addV3_2 = createAddDepositV3Event(account, token, BigInt.fromU32(50), 1000, 6, 1000); addV3_2.block = mockBlock(ZERO_BI, baseTimestamp.plus(hours15)); setSeason(20015); - handleAddDeposit_V3(addV3_2); + handleAddDeposit(addV3_2); assert.fieldEquals("SiloHourlySnapshot", account + "-20015", "depositedBDV", "3000000000"); assert.fieldEquals("SiloHourlySnapshot", account + "-20015", "deltaDepositedBDV", "1000000000"); @@ -223,7 +221,7 @@ describe("Silo Events", () => { let addV3_3 = createAddDepositV3Event(account, token, BigInt.fromU32(90), 5000, 6, 4000); addV3_3.block = mockBlock(ZERO_BI, baseTimestamp.plus(hours15).plus(hours15)); setSeason(20030); - handleAddDeposit_V3(addV3_3); + handleAddDeposit(addV3_3); assert.fieldEquals("SiloHourlySnapshot", account + "-20030", "depositedBDV", "7000000000"); assert.fieldEquals("SiloHourlySnapshot", account + "-20030", "deltaDepositedBDV", "4000000000"); @@ -244,10 +242,12 @@ describe("Silo Events", () => { describe("Whitelist", () => { test("Whitelist token v2", () => { - handleWhitelistToken(createWhitelistTokenV2Event(BEAN_ERC20.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); + handleWhitelistToken_v2(createWhitelistTokenV2Event(BEAN_ERC20.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); assert.fieldEquals("Silo", BEANSTALK.toHexString(), "whitelistedTokens", "[" + BEAN_ERC20.toHexString() + "]"); - handleWhitelistToken(createWhitelistTokenV2Event(BEAN_WETH_CP2_WELL.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); + handleWhitelistToken_v2( + createWhitelistTokenV2Event(BEAN_WETH_CP2_WELL.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234")) + ); assert.fieldEquals( "Silo", BEANSTALK.toHexString(), @@ -257,10 +257,10 @@ describe("Silo Events", () => { }); test("Whitelist token v3", () => { - handleWhitelistToken_V3(createWhitelistTokenV3Event(BEAN_ERC20.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); + handleWhitelistToken_v3(createWhitelistTokenV3Event(BEAN_ERC20.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); assert.fieldEquals("Silo", BEANSTALK.toHexString(), "whitelistedTokens", "[" + BEAN_ERC20.toHexString() + "]"); - handleWhitelistToken_V3( + handleWhitelistToken_v3( createWhitelistTokenV3Event(BEAN_WETH_CP2_WELL.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234")) ); assert.fieldEquals( @@ -274,8 +274,10 @@ describe("Silo Events", () => { // v4 tested in gauge test test("Dewhitelist token", () => { - handleWhitelistToken(createWhitelistTokenV2Event(BEAN_ERC20.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); - handleWhitelistToken(createWhitelistTokenV2Event(BEAN_WETH_CP2_WELL.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); + handleWhitelistToken_v2(createWhitelistTokenV2Event(BEAN_ERC20.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234"))); + handleWhitelistToken_v2( + createWhitelistTokenV2Event(BEAN_WETH_CP2_WELL.toHexString(), "0xabcd1234", ONE_BI, BigInt.fromString("1234")) + ); assert.fieldEquals( "Silo", BEANSTALK.toHexString(), diff --git a/projects/subgraph-beanstalk/tests/YieldHandler.test.ts b/projects/subgraph-beanstalk/tests/YieldHandler.test.ts index 55595bcdae..ccff8b89ea 100644 --- a/projects/subgraph-beanstalk/tests/YieldHandler.test.ts +++ b/projects/subgraph-beanstalk/tests/YieldHandler.test.ts @@ -1,8 +1,7 @@ import { BigInt, BigDecimal, log, Bytes } from "@graphprotocol/graph-ts"; -import { afterEach, assert, clearStore, describe, test } from "matchstick-as/assembly/index"; -import * as YieldHandler from "../src/YieldHandler"; -import { BI_10, BigDecimal_isClose, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; -import { loadSilo, loadSiloAsset, loadSiloYield, loadTokenYield, loadWhitelistTokenSetting } from "../src/utils/Silo"; +import { assert, describe, test } from "matchstick-as/assembly/index"; +import { BigDecimal_isClose, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; +import { loadSilo, loadSiloAsset, loadSiloYield, loadTokenYield, loadWhitelistTokenSetting } from "../src/entities/Silo"; import { BEAN_3CRV, BEAN_ERC20, @@ -13,11 +12,13 @@ import { LUSD_3POOL } from "../../subgraph-core/utils/Constants"; import { setSeason } from "./utils/Season"; +import { calculateAPYPreGauge } from "../src/utils/legacy/LegacyYield"; +import { calculateGaugeVAPYs, updateSiloVAPYs } from "../src/utils/Yield"; describe("APY Calculations", () => { describe("Pre-Gauge", () => { test("No Bean mints", () => { - const apy = YieldHandler.calculateAPYPreGauge( + const apy = calculateAPYPreGauge( BigDecimal.fromString("0"), // n BigDecimal.fromString("2"), // seedsPerBDV BigDecimal.fromString("2"), // seedsPerBeanBDV @@ -34,14 +35,14 @@ describe("APY Calculations", () => { // Sequence recreated here for testing: // https://docs.google.com/spreadsheets/d/1h7pPEydeAMze_uZMZzodTB3kvEXz_dGGje4KKm83gRM/edit#gid=1845553589 test("Yields are higher with 4 seeds", () => { - const apy2 = YieldHandler.calculateAPYPreGauge( + const apy2 = calculateAPYPreGauge( BigDecimal.fromString("1278"), BigDecimal.fromString("3"), BigDecimal.fromString("3"), BigInt.fromString("1636664801904743831"), BigInt.fromString("24942000280720") ); - const apy4 = YieldHandler.calculateAPYPreGauge( + const apy4 = calculateAPYPreGauge( BigDecimal.fromString("1278"), BigDecimal.fromString("4.5"), BigDecimal.fromString("3"), @@ -64,7 +65,7 @@ describe("APY Calculations", () => { describe("With Seed Gauge", () => { test("Token yields - direct calculation", () => { // using non-gauge bdv 19556945 + 24417908 + 164986 (Unripe + 3crv after dewhitelisted) - const apy = YieldHandler.calculateGaugeVAPYs( + const apy = calculateGaugeVAPYs( [-1, 0, -2], BigDecimal.fromString("1278"), [BigDecimal.fromString("100")], @@ -217,7 +218,7 @@ describe("APY Calculations", () => { siloYield.save(); /// Actual entity-based calculation here - YieldHandler.updateSiloVAPYs(20000, ZERO_BI, 720); + updateSiloVAPYs(BEANSTALK, ZERO_BI, 720); const desiredPrecision = BigDecimal.fromString("0.0001"); const beanResult = loadTokenYield(BEAN_ERC20, 20000, 720); @@ -241,7 +242,7 @@ describe("APY Calculations", () => { test("Token yields - multiple gauge LP, one with no GP", () => { // 0 is beanweth, 1 is beanwsteth - const apy = YieldHandler.calculateGaugeVAPYs( + const apy = calculateGaugeVAPYs( [0, 1], BigDecimal.fromString("100"), // [BigDecimal.fromString("1"), BigDecimal.fromString("499")], diff --git a/projects/subgraph-beanstalk/tests/event-mocking/Field.ts b/projects/subgraph-beanstalk/tests/event-mocking/Field.ts index f1726f9c9e..b05d3a1bc6 100644 --- a/projects/subgraph-beanstalk/tests/event-mocking/Field.ts +++ b/projects/subgraph-beanstalk/tests/event-mocking/Field.ts @@ -1,6 +1,5 @@ import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; -import { Sow, PlotTransfer, Harvest } from "../../generated/Beanstalk-ABIs/PreReplant"; -import { TemperatureChange } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { Sow, PlotTransfer, Harvest, TemperatureChange } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { mockBeanstalkEvent } from "../../../subgraph-core/tests/event-mocking/Util"; export function createWeatherChangeEvent(season: BigInt, caseID: BigInt, change: i32): void {} diff --git a/projects/subgraph-beanstalk/tests/event-mocking/Marketplace.ts b/projects/subgraph-beanstalk/tests/event-mocking/Marketplace.ts index c770d2947f..c9ad6482e4 100644 --- a/projects/subgraph-beanstalk/tests/event-mocking/Marketplace.ts +++ b/projects/subgraph-beanstalk/tests/event-mocking/Marketplace.ts @@ -1,20 +1,20 @@ import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; import { - PodListingCancelled, PodListingCreated as PodListingCreated_v1, PodListingFilled as PodListingFilled_v1, - PodOrderCancelled, PodOrderCreated as PodOrderCreated_v1, PodOrderFilled as PodOrderFilled_v1 } from "../../generated/Beanstalk-ABIs/PreReplant"; import { PodListingCreated as PodListingCreated_v1_1 } from "../../generated/Beanstalk-ABIs/Replanted"; import { - PodListingCreated as PodListingCreated_v2, - PodListingFilled as PodListingFilled_v2, - PodOrderCreated as PodOrderCreated_v2, - PodOrderFilled as PodOrderFilled_v2 -} from "../../generated/Beanstalk-ABIs/MarketV2"; + PodListingCreated, + PodListingFilled, + PodOrderCreated, + PodOrderFilled, + PodOrderCancelled, + PodListingCancelled +} from "../../generated/Beanstalk-ABIs/SeedGauge"; import { mockBeanstalkEvent } from "../../../subgraph-core/tests/event-mocking/Util"; /** ===== Marketplace V1 Events ===== */ @@ -165,8 +165,8 @@ export function createPodListingCreatedEvent_v2( pricingFunction: Bytes, mode: BigInt, pricingType: BigInt -): PodListingCreated_v2 { - let event = changetype(mockBeanstalkEvent()); +): PodListingCreated { + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); let param1 = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); @@ -191,7 +191,7 @@ export function createPodListingCreatedEvent_v2( event.parameters.push(param9); event.parameters.push(param10); - return event as PodListingCreated_v2; + return event as PodListingCreated; } export function createPodListingFilledEvent_v2( @@ -201,8 +201,8 @@ export function createPodListingFilledEvent_v2( start: BigInt, amount: BigInt, costInBeans: BigInt -): PodListingFilled_v2 { - let event = changetype(mockBeanstalkEvent()); +): PodListingFilled { + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); let param1 = new ethereum.EventParam("from", ethereum.Value.fromAddress(Address.fromString(from))); @@ -219,7 +219,7 @@ export function createPodListingFilledEvent_v2( event.parameters.push(param5); event.parameters.push(param6); - return event as PodListingFilled_v2; + return event as PodListingFilled; } export function createPodOrderCreatedEvent_v2( @@ -231,8 +231,8 @@ export function createPodOrderCreatedEvent_v2( minFillAmount: BigInt, pricingFunction: Bytes, pricingType: BigInt -): PodOrderCreated_v2 { - let event = changetype(mockBeanstalkEvent()); +): PodOrderCreated { + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); let param1 = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); @@ -253,7 +253,7 @@ export function createPodOrderCreatedEvent_v2( event.parameters.push(param7); event.parameters.push(param8); - return event as PodOrderCreated_v2; + return event as PodOrderCreated; } export function createPodOrderFilledEvent_v2( @@ -264,8 +264,8 @@ export function createPodOrderFilledEvent_v2( start: BigInt, amount: BigInt, costInBeans: BigInt -): PodOrderFilled_v2 { - let event = changetype(mockBeanstalkEvent()); +): PodOrderFilled { + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); let param1 = new ethereum.EventParam("from", ethereum.Value.fromAddress(Address.fromString(from))); @@ -284,7 +284,7 @@ export function createPodOrderFilledEvent_v2( event.parameters.push(param6); event.parameters.push(param7); - return event as PodOrderFilled_v2; + return event as PodOrderFilled; } /* Cancellation events */ diff --git a/projects/subgraph-beanstalk/tests/event-mocking/Season.ts b/projects/subgraph-beanstalk/tests/event-mocking/Season.ts index 8dd8a86cdf..b04656e82e 100644 --- a/projects/subgraph-beanstalk/tests/event-mocking/Season.ts +++ b/projects/subgraph-beanstalk/tests/event-mocking/Season.ts @@ -1,6 +1,5 @@ import { Address, BigInt, ethereum } from "@graphprotocol/graph-ts"; -import { Incentivization } from "../../generated/Beanstalk-ABIs/PreReplant"; - +import { Incentivization } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { mockBeanstalkEvent } from "../../../subgraph-core/tests/event-mocking/Util"; export function createSunriseEvent(season: BigInt): void {} diff --git a/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts b/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts index 3c4b04c643..3150b81c4b 100644 --- a/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts +++ b/projects/subgraph-beanstalk/tests/event-mocking/Silo.ts @@ -5,19 +5,18 @@ import { RemoveDeposits as RemoveDepositsV2, AddWithdrawal, RemoveWithdrawal, - RemoveWithdrawals, - SeedsBalanceChanged, - StalkBalanceChanged, - Plant -} from "../../generated/Beanstalk-ABIs/MarketV2"; + RemoveWithdrawals +} from "../../generated/Beanstalk-ABIs/Replanted"; import { BEAN_DECIMALS } from "../../../subgraph-core/utils/Constants"; import { mockBeanstalkEvent } from "../../../subgraph-core/tests/event-mocking/Util"; import { - AddDeposit as AddDepositV3, - RemoveDeposits as RemoveDepositsV3, - RemoveDeposit as RemoveDepositV3 -} from "../../generated/Beanstalk-ABIs/SiloV3"; - + AddDeposit, + RemoveDeposits, + RemoveDeposit, + SeedsBalanceChanged, + StalkBalanceChanged, + Plant +} from "../../generated/Beanstalk-ABIs/SeedGauge"; export function createAddDepositV2Event( account: string, token: string, @@ -56,8 +55,8 @@ export function createAddDepositV3Event( amount: i32, tokenDecimals: i32, bdv: i32 -): AddDepositV3 { - let addDepositEvent = changetype(mockBeanstalkEvent()); +): AddDeposit { + let addDepositEvent = changetype(mockBeanstalkEvent()); addDepositEvent.parameters = new Array(); let accountParam = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); let tokenParam = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); @@ -77,7 +76,7 @@ export function createAddDepositV3Event( addDepositEvent.parameters.push(amountParam); addDepositEvent.parameters.push(bdvParam); - return addDepositEvent as AddDepositV3; + return addDepositEvent as AddDeposit; } export function createRemoveDepositV2Event(account: string, token: string, season: i32, amount: BigInt): RemoveDepositV2 { @@ -96,8 +95,8 @@ export function createRemoveDepositV2Event(account: string, token: string, seaso return removeDepositEvent as RemoveDepositV2; } -export function createRemoveDepositV3Event(account: string, token: string, stem: BigInt, amount: BigInt, bdv: BigInt): RemoveDepositV3 { - let removeDepositEvent = changetype(mockBeanstalkEvent()); +export function createRemoveDepositV3Event(account: string, token: string, stem: BigInt, amount: BigInt, bdv: BigInt): RemoveDeposit { + let removeDepositEvent = changetype(mockBeanstalkEvent()); removeDepositEvent.parameters = new Array(); let accountParam = new ethereum.EventParam("account", ethereum.Value.fromAddress(Address.fromString(account))); let tokenParam = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); @@ -111,7 +110,7 @@ export function createRemoveDepositV3Event(account: string, token: string, stem: removeDepositEvent.parameters.push(amountParam); removeDepositEvent.parameters.push(bdvParam); - return removeDepositEvent as RemoveDepositV3; + return removeDepositEvent as RemoveDeposit; } export function createRemoveDepositsV2Event( @@ -156,8 +155,8 @@ export function createRemoveDepositsV3Event( amounts: BigInt[], amount: BigInt, bdvs: BigInt[] -): RemoveDepositsV3 { - let event = changetype(mockBeanstalkEvent()); +): RemoveDeposits { + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); let stemsArray: ethereum.Value[] = []; @@ -189,7 +188,7 @@ export function createRemoveDepositsV3Event( event.parameters.push(param5); event.parameters.push(param6); - return event as RemoveDepositsV3; + return event as RemoveDeposits; } export function createAddWithdrawalEvent(account: string, token: string, season: i32, amount: BigInt): AddWithdrawal { diff --git a/projects/subgraph-beanstalk/tests/event-mocking/Whitelist.ts b/projects/subgraph-beanstalk/tests/event-mocking/Whitelist.ts index cbc4944afb..dcd20b5f48 100644 --- a/projects/subgraph-beanstalk/tests/event-mocking/Whitelist.ts +++ b/projects/subgraph-beanstalk/tests/event-mocking/Whitelist.ts @@ -1,8 +1,8 @@ import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; -import { WhitelistToken as WhitelistToken_V2, DewhitelistToken } from "../../generated/Beanstalk-ABIs/MarketV2"; +import { WhitelistToken as WhitelistToken_V2 } from "../../generated/Beanstalk-ABIs/Replanted"; import { WhitelistToken as WhitelistToken_V3 } from "../../generated/Beanstalk-ABIs/SiloV3"; -import { WhitelistToken as WhitelistToken_V4 } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { WhitelistToken, DewhitelistToken } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { mockBeanstalkEvent } from "../../../subgraph-core/tests/event-mocking/Util"; export function createWhitelistTokenV2Event(token: string, selector: string, seeds: BigInt, stalk: BigInt): WhitelistToken_V2 { @@ -53,8 +53,8 @@ export function createWhitelistTokenV4Event( lwSelector: string, gaugePoints: BigInt, optimalPercentDepositedBdv: BigInt -): WhitelistToken_V4 { - let event = changetype(mockBeanstalkEvent()); +): WhitelistToken { + let event = changetype(mockBeanstalkEvent()); event.parameters = new Array(); let param1 = new ethereum.EventParam("token", ethereum.Value.fromAddress(Address.fromString(token))); @@ -75,7 +75,7 @@ export function createWhitelistTokenV4Event( event.parameters.push(param7); event.parameters.push(param8); - return event as WhitelistToken_V4; + return event as WhitelistToken; } export function createDewhitelistTokenEvent(token: string): DewhitelistToken { diff --git a/projects/subgraph-beanstalk/tests/utils/Field.ts b/projects/subgraph-beanstalk/tests/utils/Field.ts index 31103182ec..879381bcf5 100644 --- a/projects/subgraph-beanstalk/tests/utils/Field.ts +++ b/projects/subgraph-beanstalk/tests/utils/Field.ts @@ -1,9 +1,9 @@ import { BigInt, ethereum, log } from "@graphprotocol/graph-ts"; import { assert, createMockedFunction } from "matchstick-as/assembly/index"; import { createHarvestEvent, createPlotTransferEvent, createSowEvent } from "../event-mocking/Field"; -import { handleHarvest, handlePlotTransfer, handleSow } from "../../src/FieldHandler"; +import { handleHarvest, handlePlotTransfer, handleSow } from "../../src/handlers/FieldHandler"; import { createIncentivizationEvent } from "../event-mocking/Season"; -import { handleIncentive } from "../../src/SeasonHandler"; +import { handleIncentive } from "../../src/handlers/SeasonHandler"; import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; diff --git a/projects/subgraph-beanstalk/tests/utils/Marketplace.ts b/projects/subgraph-beanstalk/tests/utils/Marketplace.ts index 19ef5f0ac3..2411a8fc87 100644 --- a/projects/subgraph-beanstalk/tests/utils/Marketplace.ts +++ b/projects/subgraph-beanstalk/tests/utils/Marketplace.ts @@ -1,18 +1,5 @@ import { BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"; import { assert } from "matchstick-as/assembly/index"; -import { - handlePodListingCancelled, - handlePodListingCreated, - handlePodListingCreated_v1_1, - handlePodListingCreated_v2, - handlePodListingFilled, - handlePodListingFilled_v2, - handlePodOrderCancelled, - handlePodOrderCreated, - handlePodOrderCreated_v2, - handlePodOrderFilled, - handlePodOrderFilled_v2 -} from "../../src/MarketplaceHandler"; import { createPodListingCancelledEvent, createPodListingCreatedEvent, @@ -28,22 +15,37 @@ import { } from "../event-mocking/Marketplace"; import { BI_10, ONE_BI, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { - PodListingCreated as PodListingCreated_v2, - PodListingFilled as PodListingFilled_v2, - PodOrderCreated as PodOrderCreated_v2, - PodOrderFilled as PodOrderFilled_v2 -} from "../../generated/Beanstalk-ABIs/MarketV2"; + PodListingCreated, + PodListingFilled, + PodOrderCreated, + PodOrderFilled, + PodOrderCancelled, + PodListingCancelled +} from "../../generated/Beanstalk-ABIs/SeedGauge"; import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; import { transferPlot } from "./Field"; import { - PodOrderCancelled, - PodListingCancelled, PodListingCreated as PodListingCreated_v1, PodListingFilled as PodListingFilled_v1, PodOrderCreated as PodOrderCreated_v1, PodOrderFilled as PodOrderFilled_v1 } from "../../generated/Beanstalk-ABIs/PreReplant"; import { PodListingCreated as PodListingCreated_v1_1 } from "../../generated/Beanstalk-ABIs/Replanted"; +import { + handlePodListingCreated_v1, + handlePodListingCreated_v1_1, + handlePodListingFilled_v1, + handlePodOrderCreated_v1, + handlePodOrderFilled_v1 +} from "../../src/handlers/legacy/LegacyMarketplaceHandler"; +import { + handlePodListingCancelled, + handlePodListingCreated, + handlePodListingFilled, + handlePodOrderCancelled, + handlePodOrderCreated, + handlePodOrderFilled +} from "../../src/handlers/MarketplaceHandler"; const pricingFunction = Bytes.fromHexString( "0x0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001010101010101010101010101010000" @@ -65,7 +67,7 @@ export function fillListing_v1( transferPlot(from, to, listingIndex.plus(listingStart), podAmount); const event = createPodListingFilledEvent(from, to, listingIndex, listingStart, podAmount); - handlePodListingFilled(event); + handlePodListingFilled_v1(event); // Assert PodFill const podFillId = getPodFillId(event.params.index, event); @@ -87,9 +89,9 @@ export function fillListing_v2( listingStart: BigInt, podAmount: BigInt, costInBeans: BigInt -): PodListingFilled_v2 { +): PodListingFilled { const event = createPodListingFilledEvent_v2(from, to, listingIndex, listingStart, podAmount, costInBeans); - handlePodListingFilled_v2(event); + handlePodListingFilled(event); // Perform plot transfer transferPlot(from, to, listingIndex.plus(listingStart), podAmount); @@ -117,7 +119,7 @@ export function fillOrder_v1( pricePerPod: BigInt ): PodOrderFilled_v1 { const event = createPodOrderFilledEvent(from, to, orderId, index, start, podAmount); - handlePodOrderFilled(event); + handlePodOrderFilled_v1(event); // Perform plot transfer transferPlot(from, to, index.plus(start), podAmount); @@ -143,9 +145,9 @@ export function fillOrder_v2( start: BigInt, podAmount: BigInt, costInBeans: BigInt -): PodOrderFilled_v2 { +): PodOrderFilled { const event = createPodOrderFilledEvent_v2(from, to, orderId, index, start, podAmount, costInBeans); - handlePodOrderFilled_v2(event); + handlePodOrderFilled(event); // Perform plot transfer transferPlot(from, to, index.plus(start), podAmount); @@ -207,7 +209,7 @@ function assertListingCreated_v1_1(event: PodListingCreated_v1_1): void { assert.fieldEquals("PodListing", listingID, "mode", event.params.mode.toString()); } -function assertListingCreated_v2(event: PodListingCreated_v2): void { +function assertListingCreated_v2(event: PodListingCreated): void { let listingID = event.params.account.toHexString() + "-" + event.params.index.toString(); assert.fieldEquals("PodListing", listingID, "plot", event.params.index.toString()); assert.fieldEquals("PodListing", listingID, "farmer", event.params.account.toHexString()); @@ -242,7 +244,7 @@ function assertOrderCreated_v1(account: string, event: PodOrderCreated_v1): void assert.fieldEquals("PodOrder", orderID, "pricePerPod", event.params.pricePerPod.toString()); } -function assertOrderCreated_v2(account: string, event: PodOrderCreated_v2): void { +function assertOrderCreated_v2(account: string, event: PodOrderCreated): void { let orderID = event.params.id.toHexString(); assert.fieldEquals("PodOrder", orderID, "historyID", orderID + "-" + event.block.timestamp.toString() + "-" + event.logIndex.toString()); assert.fieldEquals("PodOrder", orderID, "farmer", account); @@ -265,7 +267,7 @@ export function createListing_v1( maxHarvestableIndex: BigInt ): PodListingCreated_v1 { const event = createPodListingCreatedEvent(account, index, start, listedPods, pricePerPod, maxHarvestableIndex, true); - handlePodListingCreated(event); + handlePodListingCreated_v1(event); assertListingCreated_v1(event); return event; } @@ -290,7 +292,7 @@ export function createListing_v2( listedPods: BigInt, start: BigInt, maxHarvestableIndex: BigInt -): PodListingCreated_v2 { +): PodListingCreated { const event = createPodListingCreatedEvent_v2( account, index, @@ -303,21 +305,21 @@ export function createListing_v2( BigInt.fromI32(0), BigInt.fromI32(1) ); - handlePodListingCreated_v2(event); + handlePodListingCreated(event); assertListingCreated_v2(event); return event; } export function createOrder_v1(account: string, id: Bytes, beans: BigInt, pricePerPod: BigInt, maxPlaceInLine: BigInt): PodOrderCreated_v1 { const event = createPodOrderCreatedEvent(account, id, beans.times(BI_10.pow(6)).div(pricePerPod), pricePerPod, maxPlaceInLine); - handlePodOrderCreated(event); + handlePodOrderCreated_v1(event); assertOrderCreated_v1(account, event); return event; } -export function createOrder_v2(account: string, id: Bytes, beans: BigInt, pricePerPod: BigInt, maxPlaceInLine: BigInt): PodOrderCreated_v2 { +export function createOrder_v2(account: string, id: Bytes, beans: BigInt, pricePerPod: BigInt, maxPlaceInLine: BigInt): PodOrderCreated { const event = createPodOrderCreatedEvent_v2(account, id, beans, pricePerPod, maxPlaceInLine, ONE_BI, pricingFunction, ZERO_BI); - handlePodOrderCreated_v2(event); + handlePodOrderCreated(event); assertOrderCreated_v2(account, event); return event; } diff --git a/projects/subgraph-beanstalk/tests/utils/Season.ts b/projects/subgraph-beanstalk/tests/utils/Season.ts index 775486c734..79ab3b69b1 100644 --- a/projects/subgraph-beanstalk/tests/utils/Season.ts +++ b/projects/subgraph-beanstalk/tests/utils/Season.ts @@ -1,5 +1,5 @@ import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; -import { loadBeanstalk } from "../../src/utils/Beanstalk"; +import { loadBeanstalk } from "../../src/entities/Beanstalk"; export function setSeason(season: u32): void { let beanstalk = loadBeanstalk(BEANSTALK); diff --git a/projects/subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json b/projects/subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json index 859fa13f12..751ef14717 100644 --- a/projects/subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json +++ b/projects/subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json @@ -8292,5 +8292,24 @@ ], "stateMutability": "payable", "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beans", + "type": "uint256" + } + ], + "name": "Incentivization", + "type": "event" } ] From 90ddc8e84a876373de6db0e47a9db72e4a15bda1 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:28:43 -0700 Subject: [PATCH 21/59] rewrite manifest --- .../manifests/codegen-abis.yaml | 2 - .../manifests/ethereum.yaml | 582 ++++++++++-------- .../subgraph-beanstalk/manifests/no-apy.yaml | 551 +++++++++-------- .../src/handlers/BarnHandler.ts | 30 +- .../src/handlers/GaugeHandler.ts | 6 + .../src/handlers/MarketplaceHandler.ts | 71 +-- .../src/handlers/SiloHandler.ts | 24 +- .../src/handlers/legacy/LegacyFieldHandler.ts | 10 +- .../legacy/LegacyMarketplaceHandler.ts | 27 +- .../handlers/legacy/LegacySeasonHandler.ts | 4 +- .../src/handlers/legacy/LegacySiloHandler.ts | 33 +- .../src/utils/Marketplace.ts | 90 ++- .../src/utils/yield_cache/CacheLoader.ts | 2 +- .../utils/yield_cache/window_1/LoadSilo_1.ts | 6 +- .../utils/yield_cache/window_1/LoadSilo_2.ts | 6 +- .../utils/yield_cache/window_1/LoadSilo_3.ts | 6 +- .../utils/yield_cache/window_1/LoadToken_1.ts | 6 +- .../utils/yield_cache/window_1/LoadToken_2.ts | 6 +- .../utils/yield_cache/window_2/LoadSilo_1.ts | 6 +- .../utils/yield_cache/window_2/LoadSilo_2.ts | 6 +- .../utils/yield_cache/window_2/LoadSilo_3.ts | 6 +- .../utils/yield_cache/window_2/LoadToken_1.ts | 6 +- .../utils/yield_cache/window_2/LoadToken_2.ts | 6 +- .../utils/yield_cache/window_3/LoadSilo_1.ts | 6 +- .../utils/yield_cache/window_3/LoadSilo_2.ts | 6 +- .../utils/yield_cache/window_3/LoadSilo_3.ts | 6 +- .../utils/yield_cache/window_3/LoadToken_1.ts | 6 +- .../utils/yield_cache/window_3/LoadToken_2.ts | 6 +- 28 files changed, 841 insertions(+), 681 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml index f32cd23bc1..0777f6c0d8 100644 --- a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml +++ b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml @@ -34,8 +34,6 @@ dataSources: file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP37.json - name: SeedGauge file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - name: ERC20 file: ../../subgraph-core/abis/ERC20.json - name: CurvePrice diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 00185e4879..2b28791372 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -2,7 +2,9 @@ specVersion: 0.0.4 schema: file: ../schema.graphql dataSources: - # Historical Cache loading + ### + # HISTORICAL vAPY CACHE + ### - kind: ethereum/contract name: TokenCacheWindow1_1 network: mainnet @@ -22,7 +24,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadToken1_1 - file: ../src/yield_cache/window_1/LoadToken_1.ts + file: ../src/utils/yield_cache/window_1/LoadToken_1.ts - kind: ethereum/contract name: TokenCacheWindow1_2 network: mainnet @@ -42,7 +44,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadToken1_2 - file: ../src/yield_cache/window_1/LoadToken_2.ts + file: ../src/utils/yield_cache/window_1/LoadToken_2.ts - kind: ethereum/contract name: SiloCacheWindow1_1 network: mainnet @@ -62,7 +64,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo1_1 - file: ../src/yield_cache/window_1/LoadSilo_1.ts + file: ../src/utils/yield_cache/window_1/LoadSilo_1.ts - kind: ethereum/contract name: SiloCacheWindow1_2 network: mainnet @@ -82,7 +84,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo1_2 - file: ../src/yield_cache/window_1/LoadSilo_2.ts + file: ../src/utils/yield_cache/window_1/LoadSilo_2.ts - kind: ethereum/contract name: SiloCacheWindow1_3 network: mainnet @@ -102,8 +104,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo1_3 - file: ../src/yield_cache/window_1/LoadSilo_3.ts - # Window 2 + file: ../src/utils/yield_cache/window_1/LoadSilo_3.ts - kind: ethereum/contract name: TokenCacheWindow2_1 network: mainnet @@ -123,7 +124,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadToken2_1 - file: ../src/yield_cache/window_2/LoadToken_1.ts + file: ../src/utils/yield_cache/window_2/LoadToken_1.ts - kind: ethereum/contract name: TokenCacheWindow2_2 network: mainnet @@ -143,7 +144,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadToken2_2 - file: ../src/yield_cache/window_2/LoadToken_2.ts + file: ../src/utils/yield_cache/window_2/LoadToken_2.ts - kind: ethereum/contract name: SiloCacheWindow2_1 network: mainnet @@ -163,7 +164,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo2_1 - file: ../src/yield_cache/window_2/LoadSilo_1.ts + file: ../src/utils/yield_cache/window_2/LoadSilo_1.ts - kind: ethereum/contract name: SiloCacheWindow2_2 network: mainnet @@ -183,7 +184,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo2_2 - file: ../src/yield_cache/window_2/LoadSilo_2.ts + file: ../src/utils/yield_cache/window_2/LoadSilo_2.ts - kind: ethereum/contract name: SiloCacheWindow2_3 network: mainnet @@ -203,8 +204,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo2_3 - file: ../src/yield_cache/window_2/LoadSilo_3.ts - # Window 3 + file: ../src/utils/yield_cache/window_2/LoadSilo_3.ts - kind: ethereum/contract name: TokenCacheWindow3_1 network: mainnet @@ -224,7 +224,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadToken3_1 - file: ../src/yield_cache/window_3/LoadToken_1.ts + file: ../src/utils/yield_cache/window_3/LoadToken_1.ts - kind: ethereum/contract name: TokenCacheWindow3_2 network: mainnet @@ -244,7 +244,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadToken3_2 - file: ../src/yield_cache/window_3/LoadToken_2.ts + file: ../src/utils/yield_cache/window_3/LoadToken_2.ts - kind: ethereum/contract name: SiloCacheWindow3_1 network: mainnet @@ -264,7 +264,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo3_1 - file: ../src/yield_cache/window_3/LoadSilo_1.ts + file: ../src/utils/yield_cache/window_3/LoadSilo_1.ts - kind: ethereum/contract name: SiloCacheWindow3_2 network: mainnet @@ -284,7 +284,7 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo3_2 - file: ../src/yield_cache/window_3/LoadSilo_2.ts + file: ../src/utils/yield_cache/window_3/LoadSilo_2.ts - kind: ethereum/contract name: SiloCacheWindow3_3 network: mainnet @@ -304,93 +304,172 @@ dataSources: eventHandlers: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleLoadSilo3_3 - file: ../src/yield_cache/window_3/LoadSilo_3.ts - # Silo V3 + file: ../src/utils/yield_cache/window_3/LoadSilo_3.ts + ### + # SILO + ### - kind: ethereum/contract - name: Silo-V3 + name: Silo network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: SiloV3 - startBlock: 17636279 # Placeholder + abi: SeedGauge + startBlock: 15277986 # Silo currently has no support for pre-exploit mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Silo-V3 + - Silo abis: - - name: SiloV3 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP36.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - event: AddDeposit(indexed address,indexed address,int96,uint256,uint256) - handler: handleAddDeposit_V3 + handler: handleAddDeposit - event: RemoveDeposit(indexed address,indexed address,int96,uint256,uint256) - handler: handleRemoveDeposit_V3 + handler: handleRemoveDeposit - event: RemoveDeposits(indexed address,indexed address,int96[],uint256[],uint256,uint256[]) - handler: handleRemoveDeposits_V3 - - event: WhitelistToken(indexed address,bytes4,uint32,uint256) - handler: handleWhitelistToken_V3 + handler: handleRemoveDeposits + - event: StalkBalanceChanged(indexed address,int256,int256) + handler: handleStalkBalanceChanged + - event: SeedsBalanceChanged(indexed address,int256) + handler: handleSeedsBalanceChanged + - event: Plant(indexed address,uint256) + handler: handlePlant + - event: WhitelistToken(indexed address,bytes4,uint32,uint256,bytes4,bytes4,uint128,uint64) + handler: handleWhitelistToken + - event: DewhitelistToken(indexed address) + handler: handleDewhitelistToken - event: UpdatedStalkPerBdvPerSeason(indexed address,uint32,uint32) handler: handleUpdatedStalkPerBdvPerSeason - file: ../src/SiloHandler.ts - # Silo V2 / Replanted + - event: RemoveWithdrawal(indexed address,indexed address,uint32,uint256) + handler: handleRemoveWithdrawal + - event: RemoveWithdrawals(indexed address,indexed address,uint32[],uint256) + handler: handleRemoveWithdrawals + file: ../src/handlers/SiloHandler.ts - kind: ethereum/contract - name: Silo-Replanted + name: LegacySilo-Replanted network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 + abi: Replanted startBlock: 15277986 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Silo-Replanted + - Silo abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json eventHandlers: - event: AddDeposit(indexed address,indexed address,uint32,uint256,uint256) - handler: handleAddDeposit + handler: handleAddDeposit_v2 - event: RemoveDeposit(indexed address,indexed address,uint32,uint256) - handler: handleRemoveDeposit + handler: handleRemoveDeposit_v2 - event: RemoveDeposits(indexed address,indexed address,uint32[],uint256[],uint256) - handler: handleRemoveDeposits + handler: handleRemoveDeposits_v2 - event: AddWithdrawal(indexed address,indexed address,uint32,uint256) handler: handleAddWithdrawal - - event: RemoveWithdrawal(indexed address,indexed address,uint32,uint256) - handler: handleRemoveWithdrawal - - event: RemoveWithdrawals(indexed address,indexed address,uint32[],uint256) - handler: handleRemoveWithdrawals - - event: SeedsBalanceChanged(indexed address,int256) - handler: handleSeedsBalanceChanged - - event: StalkBalanceChanged(indexed address,int256,int256) - handler: handleStalkBalanceChanged - - event: Plant(indexed address,uint256) - handler: handlePlant - event: WhitelistToken(indexed address,bytes4,uint256,uint256) - handler: handleWhitelistToken - - event: DewhitelistToken(indexed address) - handler: handleDewhitelistToken - file: ../src/SiloHandler.ts - # Field - Original + handler: handleWhitelistToken_v2 + file: ../src/handlers/legacy/LegacySiloHandler.ts + - kind: ethereum/contract + name: LegacySiloCalls-Replanted + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: Replanted + startBlock: 15277986 + endBlock: 19927634 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Silo + abis: + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + callHandlers: + - function: transferDeposit(address,address,uint32,uint256) + handler: handleTransferDepositCall + - function: transferDeposits(address,address,uint32[],uint256[]) + handler: handleTransferDepositsCall + file: ../src/handlers/legacy/LegacySiloHandler.ts + - kind: ethereum/contract + name: LegacySilo-SiloV3 + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SiloV3 + startBlock: 17671557 # BIP-36 + endBlock: 19927634 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Silo + abis: + - name: SiloV3 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP36.json + eventHandlers: + - event: WhitelistToken(indexed address,bytes4,uint32,uint256) + handler: handleWhitelistToken_v3 + file: ../src/handlers/legacy/LegacySiloHandler.ts + ### + # SEED GAUGE + ### + - kind: ethereum/contract + name: SeedGauge + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SeedGauge + startBlock: 19628074 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - SeedGauge + abis: + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json + eventHandlers: + - event: BeanToMaxLpGpPerBdvRatioChange(indexed uint256,uint256,int80) + handler: handleBeanToMaxLpGpPerBdvRatioChange + - event: GaugePointChange(indexed uint256,indexed address,uint256) + handler: handleGaugePointChange + - event: UpdateAverageStalkPerBdvPerSeason(uint256) + handler: handleUpdateAverageStalkPerBdvPerSeason + - event: FarmerGerminatingStalkBalanceChanged(indexed address,int256,uint8) + handler: handleFarmerGerminatingStalkBalanceChanged + - event: TotalGerminatingBalanceChanged(uint256,indexed address,int256,int256) + handler: handleTotalGerminatingBalanceChanged + - event: TotalGerminatingStalkChanged(uint256,int256) + handler: handleTotalGerminatingStalkChanged + - event: TotalStalkChangedFromGermination(int256,int256) + handler: handleTotalStalkChangedFromGermination + - event: UpdateGaugeSettings(indexed address,bytes4,bytes4,uint64) + handler: handleUpdateGaugeSettings + file: ../src/handlers/GaugeHandler.ts + ### + # FIELD + ### - kind: ethereum/contract name: Field network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: PreReplant - startBlock: 12974075 + abi: SeedGauge + startBlock: 12974075 # Field has all-time support mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -398,383 +477,352 @@ dataSources: entities: - Field abis: - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json - name: CurvePrice file: ../../subgraph-core/abis/CurvePrice.json - name: BeanstalkPrice file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - - event: WeatherChange(indexed uint256,uint256,int8) - handler: handleWeatherChange - event: Sow(indexed address,uint256,uint256,uint256) handler: handleSow - event: Harvest(indexed address,uint256[],uint256) handler: handleHarvest - event: PlotTransfer(indexed address,indexed address,indexed uint256,uint256) handler: handlePlotTransfer - - event: SupplyIncrease(indexed uint256,uint256,uint256,uint256,int256) - handler: handleSupplyIncrease - - event: SupplyDecrease(indexed uint256,uint256,int256) - handler: handleSupplyDecrease - - event: SupplyNeutral(indexed uint256,int256) - handler: handleSupplyNeutral - - event: FundFundraiser(indexed address,indexed uint32,uint256) - handler: handleFundFundraiser - file: ../src/FieldHandler.ts + - event: TemperatureChange(indexed uint256,uint256,int8) + handler: handleTemperatureChange + file: ../src/handlers/FieldHandler.ts - kind: ethereum/contract - name: Season + name: LegacyField-PreReplant network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant startBlock: 12974075 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Season + - Field abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - - name: Replanted - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: CurvePrice + file: ../../subgraph-core/abis/CurvePrice.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - - event: Sunrise(indexed uint256) - handler: handleSunrise - - event: SeasonSnapshot(indexed uint32,uint256,uint256,uint256,uint256,uint256,uint256) - handler: handleSeasonSnapshot - - event: Incentivization(indexed address,uint256) - handler: handleIncentive - file: ../src/SeasonHandler.ts + - event: WeatherChange(indexed uint256,uint256,int8) + handler: handleWeatherChange + - event: SupplyIncrease(indexed uint256,uint256,uint256,uint256,int256) + handler: handleSupplyIncrease + - event: SupplyDecrease(indexed uint256,uint256,int256) + handler: handleSupplyDecrease + - event: SupplyNeutral(indexed uint256,int256) + handler: handleSupplyNeutral + - event: FundFundraiser(indexed address,indexed uint32,uint256) + handler: handleFundFundraiser + file: ../src/handlers/legacy/LegacyFieldHandler.ts + ### + # MARKETPLACE + ### - kind: ethereum/contract name: Marketplace network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: PreReplant - startBlock: 12974075 + abi: SeedGauge + startBlock: 14148509 # BIP-11 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Season + - PodMarketplace abis: - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,bool) + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint256,bytes,uint8,uint8) handler: handlePodListingCreated - - event: PodListingCancelled(indexed address,uint256) - handler: handlePodListingCancelled - - event: PodListingCancelled(indexed address,indexed uint256) - handler: handlePodListingCancelled - - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256) + - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256,uint256) handler: handlePodListingFilled - - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256) + - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256,uint256,bytes,uint8) handler: handlePodOrderCreated - - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256) + - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256,uint256) handler: handlePodOrderFilled + # NOT a duplicate, this signature does not have an indexed uint256. + # Both signatures are required to recognize all events. + - event: PodListingCancelled(indexed address,uint256) + handler: handlePodListingCancelled - event: PodOrderCancelled(indexed address,bytes32) handler: handlePodOrderCancelled - file: ../src/MarketplaceHandler.ts + file: ../src/handlers/MarketplaceHandler.ts - kind: ethereum/contract - name: Marketplace-Replanted + name: LegacyMarketplace-PreReplant network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: Replanted - startBlock: 15277986 + abi: PreReplant + startBlock: 14148509 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Marketplace-Replanted + - PodMarketplace abis: - - name: Replanted - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json eventHandlers: - - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint8) - handler: handlePodListingCreated_v1_1 - file: ../src/MarketplaceHandler.ts + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,bool) + handler: handlePodListingCreated_v1 + - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256) + handler: handlePodListingFilled_v1 + - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256) + handler: handlePodOrderCreated_v1 + - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256) + handler: handlePodOrderFilled_v1 + # NOT a duplicate, this signature has an indexed uint256. + # Both signatures are required to recognize all events. + - event: PodListingCancelled(indexed address,indexed uint256) + handler: handlePodListingCancelled_indexed + file: ../src/handlers/legacy/LegacyMarketplaceHandler.ts - kind: ethereum/contract - name: Diamond + name: LegacyMarketplace-Replanted network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: PreReplant - startBlock: 12974075 + abi: Replanted + startBlock: 15277986 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - PodMarketplace abis: - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleDiamondCut - file: ../src/DiamondHandler.ts + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint8) + handler: handlePodListingCreated_v1_1 + file: ../src/handlers/legacy/LegacyMarketplaceHandler.ts + ### + # FERTILIZER + ### - kind: ethereum/contract - name: BeanERC20-V1 + name: Fertilizer-1155 network: mainnet source: - address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" - abi: ERC20 - startBlock: 12974075 - endBlock: 14602789 + address: "0x402c84De2Ce49aF88f5e2eF3710ff89bFED36cB6" + abi: Fertilizer + startBlock: 14910573 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Bean + - Fertilizer abis: - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: Fertilizer + file: ../../subgraph-core/abis/Fertilizer.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: Transfer(indexed address,indexed address,uint256) - handler: handleTransfer - file: ../src/BeanHandler.ts + - event: TransferBatch(indexed address,indexed address,indexed address,uint256[],uint256[]) + handler: handleTransferBatch + - event: TransferSingle(indexed address,indexed address,indexed address,uint256,uint256) + handler: handleTransferSingle + file: ../src/handlers/BarnHandler.ts - kind: ethereum/contract - name: BeanERC20 + name: Fertilizer-Beanstalk network: mainnet source: - address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" - abi: ERC20 + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SeedGauge startBlock: 15277986 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Bean + - Chop abis: - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: Transfer(indexed address,indexed address,uint256) - handler: handleTransfer - file: ../src/BeanHandler.ts + - event: Chop(indexed address,indexed address,uint256,uint256) + handler: handleChop + file: ../src/handlers/BarnHandler.ts + ### + # SEASON + ### - kind: ethereum/contract - name: Season-Replanted + name: Season network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: BasinBip - startBlock: 15277986 + abi: SeedGauge + startBlock: 12974075 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Season-Replanted + - Season abis: - - name: BasinBip - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP37.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json - - name: CurvePrice - file: ../../subgraph-core/abis/CurvePrice.json - - name: BeanstalkPrice - file: ../../subgraph-core/abis/BeanstalkPrice.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleSunrise - event: Reward(indexed uint32,uint256,uint256,uint256) handler: handleReward - - event: MetapoolOracle(indexed uint32,int256,uint256[2]) - handler: handleMetapoolOracle - event: WellOracle(indexed uint32,address,int256,bytes) handler: handleWellOracle - event: Soil(indexed uint32,uint256) handler: handleSoil - file: ../src/SeasonHandler.ts + - event: Incentivization(indexed address,uint256) + handler: handleIncentive + file: ../src/handlers/SeasonHandler.ts - kind: ethereum/contract - name: Fertilizer-1155 + name: LegacySeason-PreReplant network: mainnet source: - address: "0x402c84De2Ce49aF88f5e2eF3710ff89bFED36cB6" - abi: Fertilizer - startBlock: 14910573 + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Fertilizer + - Season abis: - - name: Fertilizer - file: ../../subgraph-core/abis/Fertilizer.json - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json eventHandlers: - - event: TransferBatch(indexed address,indexed address,indexed address,uint256[],uint256[]) - handler: handleTransferBatch - - event: TransferSingle(indexed address,indexed address,indexed address,uint256,uint256) - handler: handleTransferSingle - file: ../src/BarnHandler.ts + - event: SeasonSnapshot(indexed uint32,uint256,uint256,uint256,uint256,uint256,uint256) + handler: handleSeasonSnapshot + file: ../src/handlers/legacy/LegacySeasonHandler.ts - kind: ethereum/contract - name: Fertilizer-Beanstalk + name: LegacySeason-Replanted network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 - startBlock: 15277986 + abi: Replanted + startBlock: 12974075 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Replant + - Season abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json eventHandlers: - - event: Chop(indexed address,indexed address,uint256,uint256) - handler: handleChop - file: ../src/BarnHandler.ts + - event: MetapoolOracle(indexed uint32,int256,uint256[2]) + handler: handleMetapoolOracle + file: ../src/handlers/legacy/LegacySeasonHandler.ts + ### + # BEAN ERC20 + ### - kind: ethereum/contract - name: Farm + name: Bean-Replant network: mainnet source: - address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 + address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" + abi: ERC20 startBlock: 15277986 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Farm + - Season abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - name: ERC20 file: ../../subgraph-core/abis/ERC20.json eventHandlers: - - event: InternalBalanceChanged(indexed address,indexed address,int256) - handler: handleInternalBalanceChanged - file: ../src/FarmHandler.ts + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + file: ../src/handlers/BeanHandler.ts - kind: ethereum/contract - name: Silo-Calls + name: Bean-PreReplant network: mainnet source: - address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: Replanted - startBlock: 15277986 + address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" + abi: ERC20 + startBlock: 12974075 + endBlock: 14602789 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Silo + - Season abis: - - name: Replanted - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json - name: ERC20 file: ../../subgraph-core/abis/ERC20.json - callHandlers: - - function: transferDeposit(address,address,uint32,uint256) - handler: handleTransferDepositCall - - function: transferDeposits(address,address,uint32[],uint256[]) - handler: handleTransferDepositsCall - file: ../src/SiloHandler.ts + eventHandlers: + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + file: ../src/handlers/BeanHandler.ts + ### + # FARM BALANCE + ### - kind: ethereum/contract - name: BIP29-PodMarketplace + name: Farm network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 + abi: SeedGauge startBlock: 15277986 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - PodMarketplaceV2 + - SiloAsset abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint256,bytes,uint8,uint8) - handler: handlePodListingCreated_v2 - - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256,uint256) - handler: handlePodListingFilled_v2 - - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256,uint256,bytes,uint8) - handler: handlePodOrderCreated_v2 - - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256,uint256) - handler: handlePodOrderFilled_v2 - file: ../src/MarketplaceHandler.ts + - event: InternalBalanceChanged(indexed address,indexed address,int256) + handler: handleInternalBalanceChanged + file: ../src/handlers/FarmHandler.ts + ### + # DIAMOND + ### - kind: ethereum/contract - name: BIP45-SeedGauge + name: Diamond network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 19628074 + startBlock: 12974075 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - SeedGauge + - Beanstalk abis: - name: SeedGauge file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json - - name: BeanstalkPrice - file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - - event: TemperatureChange(indexed uint256,uint256,int8) - handler: handleTemperatureChange - - event: BeanToMaxLpGpPerBdvRatioChange(indexed uint256,uint256,int80) - handler: handleBeanToMaxLpGpPerBdvRatioChange - - event: GaugePointChange(indexed uint256,indexed address,uint256) - handler: handleGaugePointChange - - event: UpdateAverageStalkPerBdvPerSeason(uint256) - handler: handleUpdateAverageStalkPerBdvPerSeason - - event: FarmerGerminatingStalkBalanceChanged(indexed address,int256,uint8) - handler: handleFarmerGerminatingStalkBalanceChanged - - event: TotalGerminatingBalanceChanged(uint256,indexed address,int256,int256) - handler: handleTotalGerminatingBalanceChanged - - event: TotalGerminatingStalkChanged(uint256,int256) - handler: handleTotalGerminatingStalkChanged - - event: TotalStalkChangedFromGermination(int256,int256) - handler: handleTotalStalkChangedFromGermination - - event: WhitelistToken(indexed address,bytes4,uint32,uint256,bytes4,bytes4,uint128,uint64) - handler: handleWhitelistToken_BIP45 - - event: UpdateGaugeSettings(indexed address,bytes4,bytes4,uint64) - handler: handleUpdateGaugeSettings - file: ../src/GaugeHandler.ts + - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) + handler: handleDiamondCut + file: ../src/handlers/DiamondHandler.ts # features: # - grafting # graft: diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml index 8aee7a6396..df72430321 100644 --- a/projects/subgraph-beanstalk/manifests/no-apy.yaml +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -3,92 +3,171 @@ specVersion: 0.0.4 schema: file: ../schema.graphql dataSources: - # Silo V3 + ### + # SILO + ### - kind: ethereum/contract - name: Silo-V3 + name: Silo network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: SiloV3 - startBlock: 17636279 # Placeholder + abi: SeedGauge + startBlock: 15277986 # Silo currently has no support for pre-exploit mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Silo-V3 + - Silo abis: - - name: SiloV3 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP36.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - event: AddDeposit(indexed address,indexed address,int96,uint256,uint256) - handler: handleAddDeposit_V3 + handler: handleAddDeposit - event: RemoveDeposit(indexed address,indexed address,int96,uint256,uint256) - handler: handleRemoveDeposit_V3 + handler: handleRemoveDeposit - event: RemoveDeposits(indexed address,indexed address,int96[],uint256[],uint256,uint256[]) - handler: handleRemoveDeposits_V3 - - event: WhitelistToken(indexed address,bytes4,uint32,uint256) - handler: handleWhitelistToken_V3 + handler: handleRemoveDeposits + - event: StalkBalanceChanged(indexed address,int256,int256) + handler: handleStalkBalanceChanged + - event: SeedsBalanceChanged(indexed address,int256) + handler: handleSeedsBalanceChanged + - event: Plant(indexed address,uint256) + handler: handlePlant + - event: WhitelistToken(indexed address,bytes4,uint32,uint256,bytes4,bytes4,uint128,uint64) + handler: handleWhitelistToken + - event: DewhitelistToken(indexed address) + handler: handleDewhitelistToken - event: UpdatedStalkPerBdvPerSeason(indexed address,uint32,uint32) handler: handleUpdatedStalkPerBdvPerSeason - file: ../src/SiloHandler.ts - # Silo V2 / Replanted + - event: RemoveWithdrawal(indexed address,indexed address,uint32,uint256) + handler: handleRemoveWithdrawal + - event: RemoveWithdrawals(indexed address,indexed address,uint32[],uint256) + handler: handleRemoveWithdrawals + file: ../src/handlers/SiloHandler.ts - kind: ethereum/contract - name: Silo-Replanted + name: LegacySilo-Replanted network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 + abi: Replanted startBlock: 15277986 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Silo-Replanted + - Silo abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json eventHandlers: - event: AddDeposit(indexed address,indexed address,uint32,uint256,uint256) - handler: handleAddDeposit + handler: handleAddDeposit_v2 - event: RemoveDeposit(indexed address,indexed address,uint32,uint256) - handler: handleRemoveDeposit + handler: handleRemoveDeposit_v2 - event: RemoveDeposits(indexed address,indexed address,uint32[],uint256[],uint256) - handler: handleRemoveDeposits + handler: handleRemoveDeposits_v2 - event: AddWithdrawal(indexed address,indexed address,uint32,uint256) handler: handleAddWithdrawal - - event: RemoveWithdrawal(indexed address,indexed address,uint32,uint256) - handler: handleRemoveWithdrawal - - event: RemoveWithdrawals(indexed address,indexed address,uint32[],uint256) - handler: handleRemoveWithdrawals - - event: SeedsBalanceChanged(indexed address,int256) - handler: handleSeedsBalanceChanged - - event: StalkBalanceChanged(indexed address,int256,int256) - handler: handleStalkBalanceChanged - - event: Plant(indexed address,uint256) - handler: handlePlant - event: WhitelistToken(indexed address,bytes4,uint256,uint256) - handler: handleWhitelistToken - - event: DewhitelistToken(indexed address) - handler: handleDewhitelistToken - file: ../src/SiloHandler.ts - # Field - Original + handler: handleWhitelistToken_v2 + file: ../src/handlers/legacy/LegacySiloHandler.ts + - kind: ethereum/contract + name: LegacySiloCalls-Replanted + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: Replanted + startBlock: 15277986 + endBlock: 19927634 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Silo + abis: + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + callHandlers: + - function: transferDeposit(address,address,uint32,uint256) + handler: handleTransferDepositCall + - function: transferDeposits(address,address,uint32[],uint256[]) + handler: handleTransferDepositsCall + file: ../src/handlers/legacy/LegacySiloHandler.ts + - kind: ethereum/contract + name: LegacySilo-SiloV3 + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SiloV3 + startBlock: 15277986 + endBlock: 19927634 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Silo + abis: + - name: SiloV3 + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP36.json + eventHandlers: + - event: WhitelistToken(indexed address,bytes4,uint32,uint256) + handler: handleWhitelistToken_v3 + file: ../src/handlers/legacy/LegacySiloHandler.ts + ### + # SEED GAUGE + ### + - kind: ethereum/contract + name: SeedGauge + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SeedGauge + startBlock: 19628074 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - SeedGauge + abis: + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json + eventHandlers: + - event: BeanToMaxLpGpPerBdvRatioChange(indexed uint256,uint256,int80) + handler: handleBeanToMaxLpGpPerBdvRatioChange + - event: GaugePointChange(indexed uint256,indexed address,uint256) + handler: handleGaugePointChange + - event: UpdateAverageStalkPerBdvPerSeason(uint256) + handler: handleUpdateAverageStalkPerBdvPerSeason + - event: FarmerGerminatingStalkBalanceChanged(indexed address,int256,uint8) + handler: handleFarmerGerminatingStalkBalanceChanged + - event: TotalGerminatingBalanceChanged(uint256,indexed address,int256,int256) + handler: handleTotalGerminatingBalanceChanged + - event: TotalGerminatingStalkChanged(uint256,int256) + handler: handleTotalGerminatingStalkChanged + - event: TotalStalkChangedFromGermination(int256,int256) + handler: handleTotalStalkChangedFromGermination + - event: UpdateGaugeSettings(indexed address,bytes4,bytes4,uint64) + handler: handleUpdateGaugeSettings + file: ../src/handlers/GaugeHandler.ts + ### + # FIELD + ### - kind: ethereum/contract name: Field network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: PreReplant - startBlock: 12974075 + abi: SeedGauge + startBlock: 12974075 # Field has all-time support mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -96,388 +175,354 @@ dataSources: entities: - Field abis: - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json - name: CurvePrice file: ../../subgraph-core/abis/CurvePrice.json - name: BeanstalkPrice file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - - event: WeatherChange(indexed uint256,uint256,int8) - handler: handleWeatherChange - event: Sow(indexed address,uint256,uint256,uint256) handler: handleSow - event: Harvest(indexed address,uint256[],uint256) handler: handleHarvest - event: PlotTransfer(indexed address,indexed address,indexed uint256,uint256) handler: handlePlotTransfer - - event: SupplyIncrease(indexed uint256,uint256,uint256,uint256,int256) - handler: handleSupplyIncrease - - event: SupplyDecrease(indexed uint256,uint256,int256) - handler: handleSupplyDecrease - - event: SupplyNeutral(indexed uint256,int256) - handler: handleSupplyNeutral - - event: FundFundraiser(indexed address,indexed uint32,uint256) - handler: handleFundFundraiser - file: ../src/FieldHandler.ts + - event: TemperatureChange(indexed uint256,uint256,int8) + handler: handleTemperatureChange + file: ../src/handlers/FieldHandler.ts - kind: ethereum/contract - name: Season + name: LegacyField-PreReplant network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant startBlock: 12974075 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Season + - Field abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - - name: Replanted - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: CurvePrice + file: ../../subgraph-core/abis/CurvePrice.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - - event: Sunrise(indexed uint256) - handler: handleSunrise - - event: SeasonSnapshot(indexed uint32,uint256,uint256,uint256,uint256,uint256,uint256) - handler: handleSeasonSnapshot - - event: Incentivization(indexed address,uint256) - handler: handleIncentive - file: ../src/SeasonHandler.ts + - event: WeatherChange(indexed uint256,uint256,int8) + handler: handleWeatherChange + - event: SupplyIncrease(indexed uint256,uint256,uint256,uint256,int256) + handler: handleSupplyIncrease + - event: SupplyDecrease(indexed uint256,uint256,int256) + handler: handleSupplyDecrease + - event: SupplyNeutral(indexed uint256,int256) + handler: handleSupplyNeutral + - event: FundFundraiser(indexed address,indexed uint32,uint256) + handler: handleFundFundraiser + file: ../src/handlers/legacy/LegacyFieldHandler.ts + ### + # MARKETPLACE + ### - kind: ethereum/contract name: Marketplace network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: PreReplant + abi: SeedGauge startBlock: 12974075 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Season + - PodMarketplace abis: - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,bool) + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint256,bytes,uint8,uint8) handler: handlePodListingCreated - - event: PodListingCancelled(indexed address,uint256) - handler: handlePodListingCancelled - - event: PodListingCancelled(indexed address,indexed uint256) - handler: handlePodListingCancelled - - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256) + - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256,uint256) handler: handlePodListingFilled - - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256) + - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256,uint256,bytes,uint8) handler: handlePodOrderCreated - - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256) + - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256,uint256) handler: handlePodOrderFilled + # NOT a duplicate, this signature does not have an indexed uint256. + # Both signatures are required to recognize all events. + - event: PodListingCancelled(indexed address,uint256) + handler: handlePodListingCancelled - event: PodOrderCancelled(indexed address,bytes32) handler: handlePodOrderCancelled - file: ../src/MarketplaceHandler.ts + file: ../src/handlers/MarketplaceHandler.ts - kind: ethereum/contract - name: Marketplace-Replanted + name: LegacyMarketplace-PreReplant network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: Replanted - startBlock: 15277986 + abi: PreReplant + startBlock: 12974075 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Marketplace-Replanted + - PodMarketplace abis: - - name: Replanted - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json eventHandlers: - - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint8) - handler: handlePodListingCreated_v1_1 - file: ../src/MarketplaceHandler.ts + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,bool) + handler: handlePodListingCreated_v1 + - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256) + handler: handlePodListingFilled_v1 + - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256) + handler: handlePodOrderCreated_v1 + - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256) + handler: handlePodOrderFilled_v1 + # NOT a duplicate, this signature has an indexed uint256. + # Both signatures are required to recognize all events. + - event: PodListingCancelled(indexed address,indexed uint256) + handler: handlePodListingCancelled_indexed + file: ../src/handlers/legacy/LegacyMarketplaceHandler.ts - kind: ethereum/contract - name: Diamond + name: LegacyMarketplace-Replanted network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: PreReplant - startBlock: 12974075 + abi: Replanted + startBlock: 15277986 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - PodMarketplace abis: - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleDiamondCut - file: ../src/DiamondHandler.ts + - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint8) + handler: handlePodListingCreated_v1_1 + file: ../src/handlers/legacy/LegacyMarketplaceHandler.ts + ### + # FERTILIZER + ### - kind: ethereum/contract - name: Bean + name: Fertilizer-1155 network: mainnet source: - address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" - abi: ERC20 - startBlock: 12974075 + address: "0x402c84De2Ce49aF88f5e2eF3710ff89bFED36cB6" + abi: Fertilizer + startBlock: 14910573 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Bean + - Fertilizer abis: - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: Fertilizer + file: ../../subgraph-core/abis/Fertilizer.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: Transfer(indexed address,indexed address,uint256) - handler: handleLegacyTransfer - file: ../src/BeanHandler.ts + - event: TransferBatch(indexed address,indexed address,indexed address,uint256[],uint256[]) + handler: handleTransferBatch + - event: TransferSingle(indexed address,indexed address,indexed address,uint256,uint256) + handler: handleTransferSingle + file: ../src/handlers/BarnHandler.ts - kind: ethereum/contract - name: Bean-Replanted + name: Fertilizer-Beanstalk network: mainnet source: - address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" - abi: ERC20 + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SeedGauge startBlock: 15277986 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Bean + - Chop abis: - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: Transfer(indexed address,indexed address,uint256) - handler: handleTransfer - file: ../src/BeanHandler.ts + - event: Chop(indexed address,indexed address,uint256,uint256) + handler: handleChop + file: ../src/handlers/BarnHandler.ts + ### + # SEASON + ### - kind: ethereum/contract - name: Season-Replanted + name: Season network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: BasinBip - startBlock: 15277986 + abi: SeedGauge + startBlock: 12974075 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Season-Replanted + - Season abis: - - name: BasinBip - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP37.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json - - name: CurvePrice - file: ../../subgraph-core/abis/CurvePrice.json - - name: BeanstalkPrice - file: ../../subgraph-core/abis/BeanstalkPrice.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleSunrise - event: Reward(indexed uint32,uint256,uint256,uint256) handler: handleReward - - event: MetapoolOracle(indexed uint32,int256,uint256[2]) - handler: handleMetapoolOracle - event: WellOracle(indexed uint32,address,int256,bytes) handler: handleWellOracle - event: Soil(indexed uint32,uint256) handler: handleSoil - file: ../src/SeasonHandler.ts + - event: Incentivization(indexed address,uint256) + handler: handleIncentive + file: ../src/handlers/SeasonHandler.ts - kind: ethereum/contract - name: Fertilizer-1155 + name: LegacySeason-PreReplant network: mainnet source: - address: "0x402c84De2Ce49aF88f5e2eF3710ff89bFED36cB6" - abi: Fertilizer - startBlock: 14910573 + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Fertilizer + - Season abis: - - name: Fertilizer - file: ../../subgraph-core/abis/Fertilizer.json - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json eventHandlers: - - event: TransferBatch(indexed address,indexed address,indexed address,uint256[],uint256[]) - handler: handleTransferBatch - - event: TransferSingle(indexed address,indexed address,indexed address,uint256,uint256) - handler: handleTransferSingle - file: ../src/BarnHandler.ts + - event: SeasonSnapshot(indexed uint32,uint256,uint256,uint256,uint256,uint256,uint256) + handler: handleSeasonSnapshot + file: ../src/handlers/legacy/LegacySeasonHandler.ts - kind: ethereum/contract - name: Fertilizer-Beanstalk + name: LegacySeason-Replanted network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 - startBlock: 15277986 + abi: Replanted + startBlock: 12974075 + endBlock: 19927634 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Replant + - Season abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json eventHandlers: - - event: Chop(indexed address,indexed address,uint256,uint256) - handler: handleChop - file: ../src/BarnHandler.ts + - event: MetapoolOracle(indexed uint32,int256,uint256[2]) + handler: handleMetapoolOracle + file: ../src/handlers/legacy/LegacySeasonHandler.ts + ### + # BEAN ERC20 + ### - kind: ethereum/contract - name: Farm + name: Bean-Replant network: mainnet source: - address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 + address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" + abi: ERC20 startBlock: 15277986 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Farm + - Season abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - name: ERC20 file: ../../subgraph-core/abis/ERC20.json eventHandlers: - - event: InternalBalanceChanged(indexed address,indexed address,int256) - handler: handleInternalBalanceChanged - file: ../src/FarmHandler.ts + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + file: ../src/handlers/BeanHandler.ts - kind: ethereum/contract - name: Silo-Calls + name: Bean-PreReplant network: mainnet source: - address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: Replanted - startBlock: 15277986 + address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" + abi: ERC20 + startBlock: 12974075 + endBlock: 14602789 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Silo + - Season abis: - - name: Replanted - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json - name: ERC20 file: ../../subgraph-core/abis/ERC20.json - callHandlers: - - function: transferDeposit(address,address,uint32,uint256) - handler: handleTransferDepositCall - - function: transferDeposits(address,address,uint32[],uint256[]) - handler: handleTransferDepositsCall - file: ../src/SiloHandler.ts + eventHandlers: + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + file: ../src/handlers/BeanHandler.ts + ### + # FARM BALANCE + ### - kind: ethereum/contract - name: BIP29-PodMarketplace + name: Farm network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: MarketV2 + abi: SeedGauge startBlock: 15277986 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - PodMarketplaceV2 + - SiloAsset abis: - - name: MarketV2 - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP29.json - - name: UniswapV2Pair - file: ../../subgraph-core/abis/UniswapV2Pair.json - - name: ERC20 - file: ../../subgraph-core/abis/ERC20.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: PodListingCreated(indexed address,uint256,uint256,uint256,uint24,uint256,uint256,bytes,uint8,uint8) - handler: handlePodListingCreated_v2 - - event: PodListingFilled(indexed address,indexed address,uint256,uint256,uint256,uint256) - handler: handlePodListingFilled_v2 - - event: PodOrderCreated(indexed address,bytes32,uint256,uint24,uint256,uint256,bytes,uint8) - handler: handlePodOrderCreated_v2 - - event: PodOrderFilled(indexed address,indexed address,bytes32,uint256,uint256,uint256,uint256) - handler: handlePodOrderFilled_v2 - file: ../src/MarketplaceHandler.ts + - event: InternalBalanceChanged(indexed address,indexed address,int256) + handler: handleInternalBalanceChanged + file: ../src/handlers/FarmHandler.ts + ### + # DIAMOND + ### - kind: ethereum/contract - name: BIP45-SeedGauge + name: Diamond network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 19628074 + startBlock: 12974075 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - SeedGauge + - Beanstalk abis: - name: SeedGauge file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json - - name: BeanstalkPrice - file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - - event: TemperatureChange(indexed uint256,uint256,int8) - handler: handleTemperatureChange - - event: BeanToMaxLpGpPerBdvRatioChange(indexed uint256,uint256,int80) - handler: handleBeanToMaxLpGpPerBdvRatioChange - - event: GaugePointChange(indexed uint256,indexed address,uint256) - handler: handleGaugePointChange - - event: UpdateAverageStalkPerBdvPerSeason(uint256) - handler: handleUpdateAverageStalkPerBdvPerSeason - - event: FarmerGerminatingStalkBalanceChanged(indexed address,int256,uint8) - handler: handleFarmerGerminatingStalkBalanceChanged - - event: TotalGerminatingBalanceChanged(uint256,indexed address,int256,int256) - handler: handleTotalGerminatingBalanceChanged - - event: TotalGerminatingStalkChanged(uint256,int256) - handler: handleTotalGerminatingStalkChanged - - event: TotalStalkChangedFromGermination(int256,int256) - handler: handleTotalStalkChangedFromGermination - - event: WhitelistToken(indexed address,bytes4,uint32,uint256,bytes4,bytes4,uint128,uint64) - handler: handleWhitelistToken_BIP45 - - event: UpdateGaugeSettings(indexed address,bytes4,bytes4,uint64) - handler: handleUpdateGaugeSettings - file: ../src/GaugeHandler.ts + - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) + handler: handleDiamondCut + file: ../src/handlers/DiamondHandler.ts # features: # - grafting # graft: -# base: QmcZq7RVCbzixsh7PoHCVKXHsXnpigNo7JWvzj6rUsuvPd -# block: 19393254 +# base: QmQCyzt2SH1dnGyPDaWUCWCxAhdaYwxHa1MgMEJLLizw1L +# block: 15278000 diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 0c919c62d3..2e62eb9478 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -18,6 +18,21 @@ export function handleTransferBatch(event: TransferBatch): void { } } +export function handleChop(event: Chop): void { + let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); + let chop = new ChopEntity(id); + chop.hash = event.transaction.hash.toHexString(); + chop.logIndex = event.transactionLogIndex.toI32(); + chop.protocol = event.address.toHexString(); + chop.farmer = event.params.account.toHexString(); + chop.unripe = event.params.token.toHexString(); + chop.amount = event.params.amount; + chop.underlying = event.params.underlying.toHexString(); + chop.blockNumber = event.block.number; + chop.createdAt = event.block.timestamp; + chop.save(); +} + function handleTransfer(fertilizer1155: Address, from: Address, to: Address, id: BigInt, amount: BigInt, blockNumber: BigInt): void { let fertilizer = loadFertilizer(fertilizer1155); let fertilizerToken = loadFertilizerToken(fertilizer, id, blockNumber); @@ -38,18 +53,3 @@ function handleTransfer(fertilizer1155: Address, from: Address, to: Address, id: toFertilizerBalance.amount = toFertilizerBalance.amount.plus(amount); toFertilizerBalance.save(); } - -export function handleChop(event: Chop): void { - let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let chop = new ChopEntity(id); - chop.hash = event.transaction.hash.toHexString(); - chop.logIndex = event.transactionLogIndex.toI32(); - chop.protocol = event.address.toHexString(); - chop.farmer = event.params.account.toHexString(); - chop.unripe = event.params.token.toHexString(); - chop.amount = event.params.amount; - chop.underlying = event.params.underlying.toHexString(); - chop.blockNumber = event.block.number; - chop.createdAt = event.block.timestamp; - chop.save(); -} diff --git a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts index 9aad908f87..116e6d1c2d 100644 --- a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts @@ -45,6 +45,7 @@ export function handleGaugePointChange(event: GaugePointChange): void { export function handleUpdateAverageStalkPerBdvPerSeason(event: UpdateAverageStalkPerBdvPerSeason): void { let silo = loadSilo(event.address); + // TODO: this is not accurate, the value in this event is pertaining to gauge only and does not include unripe silo.grownStalkPerSeason = silo.depositedBDV.times(event.params.newStalkPerBdvPerSeason); takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); @@ -77,6 +78,8 @@ export function handleFarmerGerminatingStalkBalanceChanged(event: FarmerGerminat farmerGerminating.save(); } + // TODO: it is not necessarily the case that this germinating stalk has finished germinating. could be early withdraw + // Need to subtract stalk from system silo. The finished germinating stalk was already added // into system stalk, and there are subsequent StalkBalanceChanged events for this transaction. let systemSilo = loadSilo(event.address); @@ -109,11 +112,14 @@ export function handleTotalGerminatingBalanceChanged(event: TotalGerminatingBala } // This occurs at the beanstalk level regardless of whether users mow their own germinating stalk into regular stalk. +// It can also occur if a user withdraws early, before the germinating period completes. export function handleTotalGerminatingStalkChanged(event: TotalGerminatingStalkChanged): void { if (event.params.deltaGerminatingStalk == ZERO_BI) { return; } + // TODO: handle early withdraw + let siloGerminating = loadOrCreateGerminating(event.address, event.params.germinationSeason.toU32(), false); siloGerminating.season = event.params.germinationSeason.toU32(); siloGerminating.stalk = siloGerminating.stalk.plus(event.params.deltaGerminatingStalk); diff --git a/projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts b/projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts index fb1a21bb5a..95b5c624be 100644 --- a/projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/MarketplaceHandler.ts @@ -16,8 +16,10 @@ import { import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { MarketplaceAction, + podListingCancelled, podListingCreated, podListingFilled, + podOrderCancelled, podOrderCreated, podOrderFilled, updateActiveListings, @@ -84,66 +86,17 @@ export function handlePodOrderFilled(event: PodOrderFilled): void { } export function handlePodListingCancelled(event: PodListingCancelled): void { - let listing = PodListing.load(event.params.account.toHexString() + "-" + event.params.index.toString()); - if (listing !== null && listing.status == "ACTIVE") { - updateActiveListings( - event.address, - MarketplaceAction.CANCELLED, - event.params.account.toHexString(), - listing.index, - listing.maxHarvestableIndex - ); - updateMarketListingBalances(event.address, event.address, ZERO_BI, listing.remainingAmount, ZERO_BI, ZERO_BI, event.block.timestamp); - - listing.status = listing.filled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; - listing.updatedAt = event.block.timestamp; - listing.save(); - - // Save the raw event data - let id = "podListingCancelled-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new PodListingCancelledEvent(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.historyID = listing.historyID; - rawEvent.account = event.params.account.toHexString(); - rawEvent.placeInLine = event.params.index.plus(listing.start).minus(getHarvestableIndex(event.address)); - rawEvent.index = event.params.index; - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); - } + podListingCancelled({ + event, + account: event.params.account, + index: event.params.index + }); } export function handlePodOrderCancelled(event: PodOrderCancelled): void { - let order = PodOrder.load(event.params.id.toHexString()); - if (order !== null && order.status == "ACTIVE") { - order.status = order.podAmountFilled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; - order.updatedAt = event.block.timestamp; - order.save(); - - updateActiveOrders(event.address, MarketplaceAction.CANCELLED, order.id, order.maxPlaceInLine); - updateMarketOrderBalances( - event.address, - event.address, - ZERO_BI, - order.beanAmount.minus(order.beanAmountFilled), - ZERO_BI, - ZERO_BI, - event.block.timestamp - ); - - // Save the raw event data - let id = "podOrderCancelled-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); - let rawEvent = new PodOrderCancelledEvent(id); - rawEvent.hash = event.transaction.hash.toHexString(); - rawEvent.logIndex = event.logIndex.toI32(); - rawEvent.protocol = event.address.toHexString(); - rawEvent.historyID = order.historyID; - rawEvent.account = event.params.account.toHexString(); - rawEvent.orderId = event.params.id.toHexString(); - rawEvent.blockNumber = event.block.number; - rawEvent.createdAt = event.block.timestamp; - rawEvent.save(); - } + podOrderCancelled({ + event, + account: event.params.account, + id: event.params.id + }); } diff --git a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts index 39be66dc1f..aecf8133d9 100644 --- a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts @@ -10,11 +10,15 @@ import { Plant, RemoveDeposit, RemoveDeposits, + RemoveWithdrawal, + RemoveWithdrawals, SeedsBalanceChanged, StalkBalanceChanged, UpdatedStalkPerBdvPerSeason, WhitelistToken } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { updateClaimedWithdraw } from "../utils/legacy/LegacySilo"; +import { getBeanstalkToken } from "../entities/Beanstalk"; export function handleAddDeposit(event: AddDeposit): void { addDeposits({ @@ -90,7 +94,14 @@ export function handlePlant(event: Plant): void { // Remove the asset-only amount that got added in Reward event handler. // Will be immediately re-credited to the user/system in AddDeposit - updateDepositInSiloAsset(event.address, event.address, BEAN_ERC20, event.params.beans, event.params.beans, event.block.timestamp); + updateDepositInSiloAsset( + event.address, + event.address, + getBeanstalkToken(event.address), + event.params.beans, + event.params.beans, + event.block.timestamp + ); } export function handleWhitelistToken(event: WhitelistToken): void { @@ -133,3 +144,14 @@ export function handleUpdatedStalkPerBdvPerSeason(event: UpdatedStalkPerBdvPerSe takeWhitelistTokenSettingSnapshots(siloSettings, event.address, event.block.timestamp); siloSettings.save(); } + +// Withdrawal is a legacy feature from replant, but these events are still present +export function handleRemoveWithdrawal(event: RemoveWithdrawal): void { + updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.season, event.block.timestamp); +} + +export function handleRemoveWithdrawals(event: RemoveWithdrawals): void { + for (let i = 0; i < event.params.seasons.length; i++) { + updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.seasons[i], event.block.timestamp); + } +} diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts index 3edb2d5200..f2d969a43c 100644 --- a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyFieldHandler.ts @@ -2,7 +2,7 @@ import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { WeatherChange, SupplyIncrease, SupplyDecrease, SupplyNeutral, FundFundraiser } from "../../../generated/Beanstalk-ABIs/PreReplant"; import { temperatureChanged, updateFieldTotals } from "../../utils/Field"; -// Pre-Replant -> Seed Gauge +// PreReplant -> SeedGauge export function handleWeatherChange(event: WeatherChange): void { temperatureChanged({ event, @@ -12,7 +12,7 @@ export function handleWeatherChange(event: WeatherChange): void { }); } -// Pre-Replant +// PreReplant -> Replanted export function handleSupplyIncrease(event: SupplyIncrease): void { updateFieldTotals( event.address, @@ -28,7 +28,7 @@ export function handleSupplyIncrease(event: SupplyIncrease): void { ); } -// Pre-Replant +// PreReplant -> Replanted export function handleSupplyDecrease(event: SupplyDecrease): void { updateFieldTotals( event.address, @@ -44,7 +44,7 @@ export function handleSupplyDecrease(event: SupplyDecrease): void { ); } -// Pre-Replant +// PreReplant -> Replanted export function handleSupplyNeutral(event: SupplyNeutral): void { updateFieldTotals( event.address, @@ -60,7 +60,7 @@ export function handleSupplyNeutral(event: SupplyNeutral): void { ); } -// Pre-Replant +// PreReplant -> Replanted export function handleFundFundraiser(event: FundFundraiser): void { // Account for the fact that fundraiser sow using no soil. updateFieldTotals( diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts index 853854ecfc..32505673ee 100644 --- a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts @@ -3,14 +3,17 @@ import { PodListingCreated as PodListingCreated_v1, PodListingFilled as PodListingFilled_v1, PodOrderCreated as PodOrderCreated_v1, - PodOrderFilled as PodOrderFilled_v1 + PodOrderFilled as PodOrderFilled_v1, + PodListingCancelled as PodListingCancelled_indexed } from "../../../generated/Beanstalk-ABIs/PreReplant"; +import { PodListingCancelled } from "../../../../subgraph-bean/generated/Bean-ABIs/SeedGauge"; import { PodListingCreated as PodListingCreated_v1_1 } from "../../../generated/Beanstalk-ABIs/Replanted"; -import { podListingCreated, podListingFilled, podOrderCreated, podOrderFilled } from "../../utils/Marketplace"; +import { podListingCancelled, podListingCreated, podListingFilled, podOrderCreated, podOrderFilled } from "../../utils/Marketplace"; import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { loadPodListing, loadPodOrder } from "../../entities/PodMarketplace"; +import { handlePodListingCancelled } from "../MarketplaceHandler"; -// Pre-replant -> Replant +// PreReplant -> Replanted export function handlePodListingCreated_v1(event: PodListingCreated_v1): void { podListingCreated({ event: event, @@ -27,7 +30,7 @@ export function handlePodListingCreated_v1(event: PodListingCreated_v1): void { }); } -// Replant -> Marketplace V2 +// Replanted -> MarketV2 // When Beanstalk was Replanted, event.params.mode was changed from bool to uint8 export function handlePodListingCreated_v1_1(event: PodListingCreated_v1_1): void { podListingCreated({ @@ -45,7 +48,7 @@ export function handlePodListingCreated_v1_1(event: PodListingCreated_v1_1): voi }); } -// Pre-Replant -> Marketplace V2 +// PreReplant -> MarketV2 export function handlePodListingFilled_v1(event: PodListingFilled_v1): void { let listing = loadPodListing(event.params.from, event.params.index); const beanAmount = BigInt.fromI32(listing.pricePerPod).times(event.params.amount).div(BigInt.fromI32(1000000)); @@ -62,7 +65,17 @@ export function handlePodListingFilled_v1(event: PodListingFilled_v1): void { }); } -// Pre-Replant -> Marketplace V2 +// Pre-Replant -> Replanted (but also emitted during the Replant in WTP-3) +// This event has a variety where the second parameter is indexed. Otherwise this event is identical to the other. +export function handlePodListingCancelled_indexed(event: PodListingCancelled_indexed): void { + podListingCancelled({ + event, + account: event.params.account, + index: event.params.index + }); +} + +// PreReplant -> MarketV2 export function handlePodOrderCreated_v1(event: PodOrderCreated_v1): void { const beanAmount = event.params.amount.times(BigInt.fromI32(event.params.pricePerPod)).div(BigInt.fromString("1000000")); podOrderCreated({ @@ -78,7 +91,7 @@ export function handlePodOrderCreated_v1(event: PodOrderCreated_v1): void { }); } -// Pre-Replant -> Marketplace V2 +// PreReplant -> MarketV2 export function handlePodOrderFilled_v1(event: PodOrderFilled_v1): void { let order = loadPodOrder(event.params.id); let beanAmount = BigInt.fromI32(order.pricePerPod).times(event.params.amount).div(BigInt.fromI32(1000000)); diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts index 7c171bfef7..d8f65e0e77 100644 --- a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts @@ -6,14 +6,14 @@ import { MetapoolOracle } from "../../../generated/Beanstalk-ABIs/Replanted"; import { BeanstalkPrice_try_price } from "../../utils/contracts/BeanstalkPrice"; import { loadSeason } from "../../entities/Beanstalk"; -// Pre-Replant only +// PreReplant -> Replanted export function handleSeasonSnapshot(event: SeasonSnapshot): void { let season = loadSeason(event.address, event.params.season); season.price = toDecimal(event.params.price, 18); season.save(); } -// Replant until Seed Gauge +// Replanted -> SeedGauge export function handleMetapoolOracle(event: MetapoolOracle): void { let season = loadSeason(event.address, event.params.season); // Attempt to pull from Beanstalk Price contract first diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts index 4a49cb8a0a..75ced01685 100644 --- a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySiloHandler.ts @@ -2,27 +2,22 @@ import { Address, BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"; import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { AddWithdrawal, - RemoveWithdrawals, - RemoveWithdrawal, TransferDepositsCall, TransferDepositCall, - WhitelistToken as WhitelistToken_v2 -} from "../../../generated/Beanstalk-ABIs/Replanted"; -import { + WhitelistToken as WhitelistToken_v2, AddDeposit as AddDeposit_v2, RemoveDeposit as RemoveDeposit_v2, RemoveDeposits as RemoveDeposits_v2 } from "../../../generated/Beanstalk-ABIs/Replanted"; import { loadBeanstalk } from "../../entities/Beanstalk"; import { addToSiloWhitelist, loadSiloWithdraw, loadWhitelistTokenSetting } from "../../entities/Silo"; -import { updateClaimedWithdraw } from "../../utils/legacy/LegacySilo"; import { addDeposits, addWithdrawToSiloAsset, removeDeposits } from "../../utils/Silo"; import { takeWhitelistTokenSettingSnapshots } from "../../entities/snapshots/WhitelistTokenSetting"; import { WhitelistToken as WhitelistToken_v3 } from "../../../generated/Beanstalk-ABIs/SiloV3"; // Note: No silo v1 (pre-replant) handlers have been developed. -// Replant -> Silo V3 +// Replant -> SiloV3 export function handleAddDeposit_v2(event: AddDeposit_v2): void { if (event.params.amount == ZERO_BI && event.params.bdv == ZERO_BI) { // During replant there is at least one such event which should be ignored @@ -40,7 +35,7 @@ export function handleAddDeposit_v2(event: AddDeposit_v2): void { }); } -// Replant -> Silo V3 +// Replant -> SiloV3 export function handleRemoveDeposit_v2(event: RemoveDeposit_v2): void { removeDeposits({ event, @@ -54,7 +49,7 @@ export function handleRemoveDeposit_v2(event: RemoveDeposit_v2): void { }); } -// Replant -> Silo V3 +// Replant -> SiloV3 export function handleRemoveDeposits_v2(event: RemoveDeposits_v2): void { removeDeposits({ event, @@ -68,6 +63,7 @@ export function handleRemoveDeposits_v2(event: RemoveDeposits_v2): void { }); } +// Replant -> SiloV3 export function handleAddWithdrawal(event: AddWithdrawal): void { let withdraw = loadSiloWithdraw(event.params.account, event.params.token, event.params.season.toI32()); withdraw.amount = withdraw.amount.plus(event.params.amount); @@ -77,18 +73,9 @@ export function handleAddWithdrawal(event: AddWithdrawal): void { addWithdrawToSiloAsset(event.address, event.params.account, event.params.token, event.params.amount, event.block.timestamp); } -// Note: Legacy removals are still possible today. -export function handleRemoveWithdrawal(event: RemoveWithdrawal): void { - updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.season, event.block.timestamp); -} - -export function handleRemoveWithdrawals(event: RemoveWithdrawals): void { - for (let i = 0; i < event.params.seasons.length; i++) { - updateClaimedWithdraw(event.address, event.params.account, event.params.token, event.params.seasons[i], event.block.timestamp); - } -} +// Note: Legacy removals are still possible today, and are therefore not Legacy handlers. -// Replant -> Silo V3 +// Replant -> SiloV3 export function handleTransferDepositCall(call: TransferDepositCall): void { let beanstalk = loadBeanstalk(call.to); let updateFarmers = beanstalk.farmersToUpdate; @@ -102,7 +89,7 @@ export function handleTransferDepositCall(call: TransferDepositCall): void { beanstalk.save(); } -// Replant -> Silo V3 +// Replant -> SiloV3 export function handleTransferDepositsCall(call: TransferDepositsCall): void { let beanstalk = loadBeanstalk(call.to); let updateFarmers = beanstalk.farmersToUpdate; @@ -116,7 +103,7 @@ export function handleTransferDepositsCall(call: TransferDepositsCall): void { beanstalk.save(); } -// Replant -> Silo V3 +// Replant -> SiloV3 export function handleWhitelistToken_v2(event: WhitelistToken_v2): void { addToSiloWhitelist(event.address, event.params.token); @@ -129,7 +116,7 @@ export function handleWhitelistToken_v2(event: WhitelistToken_v2): void { setting.save(); } -// Silo V3 -> Seed Gauge +// SiloV3 -> SeedGauge export function handleWhitelistToken_v3(event: WhitelistToken_v3): void { addToSiloWhitelist(event.address, event.params.token); diff --git a/projects/subgraph-beanstalk/src/utils/Marketplace.ts b/projects/subgraph-beanstalk/src/utils/Marketplace.ts index 002c5356e9..70214835a6 100644 --- a/projects/subgraph-beanstalk/src/utils/Marketplace.ts +++ b/projects/subgraph-beanstalk/src/utils/Marketplace.ts @@ -9,8 +9,11 @@ import { PodListing, PodListingCreated as PodListingCreatedEvent, PodListingFilled as PodListingFilledEvent, + PodListingCancelled as PodListingCancelledEvent, PodOrderCreated as PodOrderCreatedEvent, - PodOrderFilled as PodOrderFilledEvent + PodOrderFilled as PodOrderFilledEvent, + PodOrderCancelled as PodOrderCancelledEvent, + PodOrder } from "../../generated/schema"; import { getHarvestableIndex, loadFarmer } from "../entities/Beanstalk"; import { takeMarketSnapshots } from "../entities/snapshots/Marketplace"; @@ -38,6 +41,12 @@ class PodListingCreatedParams { pricingType: i32; // for v1, always 0 } +class PodListingCancelledParams { + event: ethereum.Event; + account: Address; + index: BigInt; +} + class PodOrderCreatedParams { event: ethereum.Event; account: Address; @@ -51,6 +60,12 @@ class PodOrderCreatedParams { pricingType: i32; // for v1, always 0 } +class PodOrderCancelledParams { + event: ethereum.Event; + account: Address; + id: Bytes; +} + // This one is the same for both listing/order fills. class MarketFillParams { event: ethereum.Event; @@ -254,6 +269,46 @@ export function podListingFilled(params: MarketFillParams): void { rawEvent.save(); } +export function podListingCancelled(params: PodListingCancelledParams): void { + let listing = PodListing.load(params.account.toHexString() + "-" + params.index.toString()); + if (listing !== null && listing.status == "ACTIVE") { + updateActiveListings( + params.event.address, + MarketplaceAction.CANCELLED, + params.account.toHexString(), + listing.index, + listing.maxHarvestableIndex + ); + updateMarketListingBalances( + params.event.address, + params.event.address, + ZERO_BI, + listing.remainingAmount, + ZERO_BI, + ZERO_BI, + params.event.block.timestamp + ); + + listing.status = listing.filled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; + listing.updatedAt = params.event.block.timestamp; + listing.save(); + + // Save the raw event data + let id = "podListingCancelled-" + params.event.transaction.hash.toHexString() + "-" + params.event.logIndex.toString(); + let rawEvent = new PodListingCancelledEvent(id); + rawEvent.hash = params.event.transaction.hash.toHexString(); + rawEvent.logIndex = params.event.logIndex.toI32(); + rawEvent.protocol = params.event.address.toHexString(); + rawEvent.historyID = listing.historyID; + rawEvent.account = params.account.toHexString(); + rawEvent.placeInLine = params.index.plus(listing.start).minus(getHarvestableIndex(params.event.address)); + rawEvent.index = params.index; + rawEvent.blockNumber = params.event.block.number; + rawEvent.createdAt = params.event.block.timestamp; + rawEvent.save(); + } +} + export function podOrderCreated(params: PodOrderCreatedParams): void { let order = loadPodOrder(params.id); loadFarmer(params.account); @@ -368,6 +423,39 @@ export function podOrderFilled(params: MarketFillParams): void { rawEvent.save(); } +export function podOrderCancelled(params: PodOrderCancelledParams): void { + let order = PodOrder.load(params.id.toHexString()); + if (order !== null && order.status == "ACTIVE") { + order.status = order.podAmountFilled == ZERO_BI ? "CANCELLED" : "CANCELLED_PARTIAL"; + order.updatedAt = params.event.block.timestamp; + order.save(); + + updateActiveOrders(params.event.address, MarketplaceAction.CANCELLED, order.id, order.maxPlaceInLine); + updateMarketOrderBalances( + params.event.address, + params.event.address, + ZERO_BI, + order.beanAmount.minus(order.beanAmountFilled), + ZERO_BI, + ZERO_BI, + params.event.block.timestamp + ); + + // Save the raw event data + let id = "podOrderCancelled-" + params.event.transaction.hash.toHexString() + "-" + params.event.logIndex.toString(); + let rawEvent = new PodOrderCancelledEvent(id); + rawEvent.hash = params.event.transaction.hash.toHexString(); + rawEvent.logIndex = params.event.logIndex.toI32(); + rawEvent.protocol = params.event.address.toHexString(); + rawEvent.historyID = order.historyID; + rawEvent.account = params.account.toHexString(); + rawEvent.orderId = params.id.toHexString(); + rawEvent.blockNumber = params.event.block.number; + rawEvent.createdAt = params.event.block.timestamp; + rawEvent.save(); + } +} + export function updateMarketListingBalances( protocol: Address, marketAddress: Address, diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/CacheLoader.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/CacheLoader.ts index 68569f0306..1858abe128 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/CacheLoader.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/CacheLoader.ts @@ -1,5 +1,5 @@ import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; -import { loadSiloYield, loadTokenYield } from "../utils/entities/Silo"; +import { loadSiloYield, loadTokenYield } from "../../entities/Silo"; export function loadSiloCache(SILO_YIELD: string[][]): void { for (let i = 0; i < SILO_YIELD.length; i++) { diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts index b334bd5490..f1996cca4a 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_10_000 } from "./HistoricSilo_10_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts index 5bd9dc5207..dace728128 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_15_000 } from "./HistoricSilo_15_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts index bb6b17ed02..f1f4ab673c 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_20_000 } from "./HistoricSilo_20_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts index 4386990457..113b2cc924 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_24_HOUR_12_000 } from "./HistoricToken_12_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts index bc98aaac3c..deb60e1658 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_24_HOUR_20_000 } from "./HistoricToken_20_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts index 7768f99a5a..07629f51aa 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_10_000 } from "./HistoricSilo_10_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts index 09298ccd75..df6e94890d 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_15_000 } from "./HistoricSilo_15_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts index c16abb4c71..d2a21e83c8 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_20_000 } from "./HistoricSilo_20_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts index 884125ba9c..0eb4fb6ed7 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_7_DAY_12_000 } from "./HistoricToken_12_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts index 6f8213006a..30705ca2ec 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_7_DAY_20_000 } from "./HistoricToken_20_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts index c0a32bba2f..b1e709b1d7 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_10_000 } from "./HistoricSilo_10_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts index 4e191f10d5..af708cd1f4 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_15_000 } from "./HistoricSilo_15_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts index 482195e61d..09f84f73f4 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_20_000 } from "./HistoricSilo_20_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts index bf291cd471..e3f2942af5 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_30_DAY_12_000 } from "./HistoricToken_12_000"; diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts index b4ae5b2946..1f2d548e38 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts @@ -1,6 +1,6 @@ -import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../utils/entities/Beanstalk"; +import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; +import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; +import { loadBeanstalk } from "../../../entities/Beanstalk"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_30_DAY_20_000 } from "./HistoricToken_20_000"; From 1d0e9feb9096d006839ac904452c87ccdc82cdb0 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:33:53 -0700 Subject: [PATCH 22/59] dont calculate cached yield --- projects/subgraph-beanstalk/src/utils/Yield.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/projects/subgraph-beanstalk/src/utils/Yield.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts index c6fa094108..9474559c68 100644 --- a/projects/subgraph-beanstalk/src/utils/Yield.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -20,15 +20,18 @@ const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; const ROLLING_30_DAY_WINDOW = 720; -// Note: minimum value of `t` is 6075 +// Note: minimum allowable season is 6075 export function updateBeanEMA(protocol: Address, timestamp: BigInt): void { updateWindowEMA(protocol, timestamp, ROLLING_24_WINDOW); updateWindowEMA(protocol, timestamp, ROLLING_7_DAY_WINDOW); updateWindowEMA(protocol, timestamp, ROLLING_30_DAY_WINDOW); - updateSiloVAPYs(protocol, timestamp, ROLLING_24_WINDOW); - updateSiloVAPYs(protocol, timestamp, ROLLING_7_DAY_WINDOW); - updateSiloVAPYs(protocol, timestamp, ROLLING_30_DAY_WINDOW); + if (getCurrentSeason(protocol) > 20_000) { + // Earlier values were set by cache + updateSiloVAPYs(protocol, timestamp, ROLLING_24_WINDOW); + updateSiloVAPYs(protocol, timestamp, ROLLING_7_DAY_WINDOW); + updateSiloVAPYs(protocol, timestamp, ROLLING_30_DAY_WINDOW); + } updateFertAPY(protocol, timestamp, ROLLING_24_WINDOW); updateFertAPY(protocol, timestamp, ROLLING_7_DAY_WINDOW); @@ -36,8 +39,7 @@ export function updateBeanEMA(protocol: Address, timestamp: BigInt): void { } function updateWindowEMA(protocol: Address, timestamp: BigInt, window: i32): void { - const beanstalk = loadBeanstalk(protocol); - const t = beanstalk.lastSeason; + const t = getCurrentSeason(protocol); let silo = loadSilo(protocol); let siloYield = loadSiloYield(t, window); From fbacbeced69e976c8824fb7f9c045636902ee513 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:10:38 -0700 Subject: [PATCH 23/59] dynamically set protocol assets --- projects/subgraph-bean/src/utils/Bean.ts | 14 ++++++++--- .../src/entities/Beanstalk.ts | 21 +++++++---------- .../src/entities/Fertilizer.ts | 4 ++-- .../src/handlers/SeasonHandler.ts | 5 ++-- .../src/handlers/SiloHandler.ts | 4 ++-- .../subgraph-beanstalk/src/utils/Constants.ts | 23 +++++++++++++++++++ .../subgraph-beanstalk/src/utils/Yield.ts | 8 ++++++- projects/subgraph-core/utils/Constants.ts | 1 + 8 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 projects/subgraph-beanstalk/src/utils/Constants.ts diff --git a/projects/subgraph-bean/src/utils/Bean.ts b/projects/subgraph-bean/src/utils/Bean.ts index 33c74a2477..17b5220e53 100644 --- a/projects/subgraph-bean/src/utils/Bean.ts +++ b/projects/subgraph-bean/src/utils/Bean.ts @@ -1,6 +1,14 @@ import { BigDecimal, BigInt } from "@graphprotocol/graph-ts"; import { Bean, BeanDailySnapshot, BeanHourlySnapshot, Pool } from "../../generated/schema"; -import { BEAN_ERC20_V1, BEAN_ERC20, BEAN_WETH_V1, BEAN_3CRV_V1, BEAN_LUSD_V1, BEANSTALK } from "../../../subgraph-core/utils/Constants"; +import { + BEAN_ERC20_V1, + BEAN_ERC20, + BEAN_WETH_V1, + BEAN_3CRV_V1, + BEAN_LUSD_V1, + BEANSTALK, + NEW_BEAN_TOKEN_BLOCK +} from "../../../subgraph-core/utils/Constants"; import { dayFromTimestamp, hourFromTimestamp } from "../../../subgraph-core/utils/Dates"; import { ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { checkBeanCross, getV1Crosses } from "./Cross"; @@ -178,11 +186,11 @@ export function calcLiquidityWeightedBeanPrice(token: string): BigDecimal { } export function getBeanTokenAddress(blockNumber: BigInt): string { - return blockNumber < BigInt.fromString("15278082") ? BEAN_ERC20_V1.toHexString() : BEAN_ERC20.toHexString(); + return blockNumber < NEW_BEAN_TOKEN_BLOCK ? BEAN_ERC20_V1.toHexString() : BEAN_ERC20.toHexString(); } export function updateBeanSupplyPegPercent(blockNumber: BigInt): void { - if (blockNumber < BigInt.fromString("15278082")) { + if (blockNumber < NEW_BEAN_TOKEN_BLOCK) { let bean = loadBean(BEAN_ERC20_V1.toHexString()); let lpSupply = ZERO_BD; diff --git a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts index ccba676725..08a40e2f8e 100644 --- a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts @@ -1,18 +1,21 @@ import { BigInt, Address } from "@graphprotocol/graph-ts"; -import { BEAN_ERC20, FERTILIZER } from "../../../subgraph-core/utils/Constants"; import { Beanstalk } from "../../generated/schema"; import { Farmer } from "../../generated/schema"; import { Season } from "../../generated/schema"; -import { ONE_BI, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { BI_MAX, ONE_BI, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { getProtocolFertilizer, getProtocolToken } from "../utils/Constants"; export function loadBeanstalk(protocol: Address): Beanstalk { let beanstalk = Beanstalk.load(protocol.toHexString()); if (beanstalk == null) { beanstalk = new Beanstalk(protocol.toHexString()); beanstalk.name = "Beanstalk"; - // TODO: how to assign token/fertilizer - beanstalk.token = BEAN_ERC20.toHexString(); - beanstalk.fertilizer1155 = FERTILIZER.toHexString(); + // Pre-replant token currently would not be set + beanstalk.token = getProtocolToken(protocol, BI_MAX).toHexString(); + const fert = getProtocolFertilizer(protocol); + if (fert != null) { + beanstalk.fertilizer1155 = fert.toHexString(); + } beanstalk.schemaVersion = "2.4.0"; beanstalk.subgraphVersion = "2.4.0"; beanstalk.methodologyVersion = "2.4.0"; @@ -71,14 +74,6 @@ export function getBeanstalkToken(protocol: Address): Address { return Address.fromString(beanstalkEntity.token); } -export function getBeanstalkFert(protocol: Address): Address | null { - let beanstalkEntity = loadBeanstalk(protocol); - if (beanstalkEntity.fertilizer1155 !== null) { - return Address.fromString(beanstalkEntity.fertilizer1155); - } - return null; -} - export function getCurrentSeason(protocol: Address): i32 { let beanstalkEntity = loadBeanstalk(protocol); return beanstalkEntity.lastSeason; diff --git a/projects/subgraph-beanstalk/src/entities/Fertilizer.ts b/projects/subgraph-beanstalk/src/entities/Fertilizer.ts index 64413b35bc..20445b0754 100644 --- a/projects/subgraph-beanstalk/src/entities/Fertilizer.ts +++ b/projects/subgraph-beanstalk/src/entities/Fertilizer.ts @@ -3,13 +3,13 @@ import { Farmer, Fertilizer, FertilizerBalance, FertilizerToken, FertilizerYield import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { BEANSTALK } from "../../../subgraph-core/utils/Constants"; import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { getFertilizerProtocol } from "../utils/Constants"; export function loadFertilizer(fertilizerAddress: Address): Fertilizer { let fertilizer = Fertilizer.load(fertilizerAddress.toHexString()); if (fertilizer == null) { fertilizer = new Fertilizer(fertilizerAddress.toHexString()); - // TODO: how to assign beanstalk - fertilizer.beanstalk = BEANSTALK.toHexString(); + fertilizer.beanstalk = getFertilizerProtocol(fertilizerAddress).toHexString(); fertilizer.supply = ZERO_BI; fertilizer.save(); } diff --git a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts index a19643b92d..1b8edaf52c 100644 --- a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts @@ -3,7 +3,7 @@ import { Reward, Soil, WellOracle, Sunrise, Incentivization, SeedGauge } from ". import { BEANSTALK, GAUGE_BIP45_BLOCK } from "../../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { updateStalkWithCalls } from "../utils/legacy/LegacySilo"; -import { getBeanstalkToken, loadBeanstalk, loadSeason } from "../entities/Beanstalk"; +import { loadBeanstalk, loadSeason } from "../entities/Beanstalk"; import { takeMarketSnapshots } from "../entities/snapshots/Marketplace"; import { loadSilo, loadSiloAsset } from "../entities/Silo"; import { takeSiloSnapshots } from "../entities/snapshots/Silo"; @@ -16,6 +16,7 @@ import { loadPodMarketplace } from "../entities/PodMarketplace"; import { updateBeanEMA } from "../utils/Yield"; import { updateExpiredPlots } from "../utils/Marketplace"; import { updateHarvestablePlots } from "../utils/Field"; +import { getProtocolToken } from "../utils/Constants"; export function handleSunrise(event: Sunrise): void { // (Legacy) Update any farmers that had silo transfers from the prior season. @@ -82,7 +83,7 @@ export function handleReward(event: Reward): void { updateDepositInSiloAsset( event.address, event.address, - getBeanstalkToken(event.address), + getProtocolToken(event.address, event.block.number), event.params.toSilo, event.params.toSilo, event.block.timestamp diff --git a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts index aecf8133d9..14caec7ea5 100644 --- a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts @@ -18,7 +18,7 @@ import { WhitelistToken } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { updateClaimedWithdraw } from "../utils/legacy/LegacySilo"; -import { getBeanstalkToken } from "../entities/Beanstalk"; +import { getProtocolToken } from "../utils/Constants"; export function handleAddDeposit(event: AddDeposit): void { addDeposits({ @@ -97,7 +97,7 @@ export function handlePlant(event: Plant): void { updateDepositInSiloAsset( event.address, event.address, - getBeanstalkToken(event.address), + getProtocolToken(event.address, event.block.number), event.params.beans, event.params.beans, event.block.timestamp diff --git a/projects/subgraph-beanstalk/src/utils/Constants.ts b/projects/subgraph-beanstalk/src/utils/Constants.ts new file mode 100644 index 0000000000..64bc834b80 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/Constants.ts @@ -0,0 +1,23 @@ +import { BigInt, Address } from "@graphprotocol/graph-ts"; +import { BEAN_ERC20, BEAN_ERC20_V1, BEANSTALK, FERTILIZER, NEW_BEAN_TOKEN_BLOCK } from "../../../subgraph-core/utils/Constants"; + +export function getProtocolToken(protocol: Address, blockNumber: BigInt): Address { + if (protocol == BEANSTALK) { + return blockNumber < NEW_BEAN_TOKEN_BLOCK ? BEAN_ERC20_V1 : BEAN_ERC20; + } + throw new Error("Unsupported protocol"); +} + +export function getProtocolFertilizer(protocol: Address): Address | null { + if (protocol == BEANSTALK) { + return FERTILIZER; + } + throw new Error("Unsupported protocol"); +} + +export function getFertilizerProtocol(fertilizer: Address): Address { + if (fertilizer == FERTILIZER) { + return BEANSTALK; + } + throw new Error("Unsupported fertilizer"); +} diff --git a/projects/subgraph-beanstalk/src/utils/Yield.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts index 9474559c68..8da4861ee9 100644 --- a/projects/subgraph-beanstalk/src/utils/Yield.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -15,6 +15,7 @@ import { calculateAPYPreGauge } from "./legacy/LegacyYield"; import { getGerminatingBdvs } from "../entities/Germinating"; import { getCurrentSeason, getRewardMinted, loadBeanstalk } from "../entities/Beanstalk"; import { loadFertilizer, loadFertilizerYield } from "../entities/Fertilizer"; +import { getProtocolFertilizer } from "./Constants"; const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; @@ -412,11 +413,16 @@ function updateGaugePoints(gaugePoints: f64, currentPercent: f64, optimalPercent } function updateFertAPY(protocol: Address, timestamp: BigInt, window: i32): void { + const fertAddress = getProtocolFertilizer(protocol); + if (fertAddress == null) { + return; + } + const beanstalk = loadBeanstalk(protocol); const t = beanstalk.lastSeason; let siloYield = loadSiloYield(t, window); let fertilizerYield = loadFertilizerYield(t, window); - let fertilizer = loadFertilizer(Address.fromString(beanstalk.fertilizer1155!)); + let fertilizer = loadFertilizer(fertAddress); let contract = BasinBip.bind(protocol); if (t < 6534) { let currentFertHumidity = contract.try_getCurrentHumidity(); diff --git a/projects/subgraph-core/utils/Constants.ts b/projects/subgraph-core/utils/Constants.ts index 5c6f9cb042..77ab5ff2d4 100644 --- a/projects/subgraph-core/utils/Constants.ts +++ b/projects/subgraph-core/utils/Constants.ts @@ -46,6 +46,7 @@ export const CALCULATIONS_CURVE = Address.fromString("0x25BF7b72815476Dd515044F9 // Milestone blocks export const BEANSTALK_BLOCK = BigInt.fromU32(12974075); export const EXPLOIT_BLOCK = BigInt.fromU32(14602790); +export const NEW_BEAN_TOKEN_BLOCK = BigInt.fromU32(15278082); export const REPLANT_SUNRISE_BLOCK = BigInt.fromU32(15289934); export const GAUGE_BIP45_BLOCK = BigInt.fromU32(19927634); From f44a50e59699dcccb2f7be24476d193b58ff109a Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:31:56 -0700 Subject: [PATCH 24/59] fix for FarmerGerminatingStalkBalanceChanged when germinating didnt complete --- .../src/handlers/GaugeHandler.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts index 116e6d1c2d..cd9fce576d 100644 --- a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts @@ -78,14 +78,14 @@ export function handleFarmerGerminatingStalkBalanceChanged(event: FarmerGerminat farmerGerminating.save(); } - // TODO: it is not necessarily the case that this germinating stalk has finished germinating. could be early withdraw - - // Need to subtract stalk from system silo. The finished germinating stalk was already added - // into system stalk, and there are subsequent StalkBalanceChanged events for this transaction. - let systemSilo = loadSilo(event.address); - systemSilo.stalk = systemSilo.stalk.plus(event.params.deltaGerminatingStalk); - takeSiloSnapshots(systemSilo, event.address, event.block.timestamp); - systemSilo.save(); + if (currentSeason >= farmerGerminating.season + 2) { + // If germination finished, need to subtract stalk from system silo. This stalk was already added + // into system stalk upon sunrise for season - 2. + let systemSilo = loadSilo(event.address); + systemSilo.stalk = systemSilo.stalk.plus(event.params.deltaGerminatingStalk); + takeSiloSnapshots(systemSilo, event.address, event.block.timestamp); + systemSilo.save(); + } } let farmerSilo = loadSilo(event.params.account); @@ -118,8 +118,6 @@ export function handleTotalGerminatingStalkChanged(event: TotalGerminatingStalkC return; } - // TODO: handle early withdraw - let siloGerminating = loadOrCreateGerminating(event.address, event.params.germinationSeason.toU32(), false); siloGerminating.season = event.params.germinationSeason.toU32(); siloGerminating.stalk = siloGerminating.stalk.plus(event.params.deltaGerminatingStalk); From 4c0a13b619744786529cf37264ea66a23732e288 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:42:48 -0700 Subject: [PATCH 25/59] fix comparison --- projects/subgraph-beanstalk/src/entities/Beanstalk.ts | 2 +- projects/subgraph-beanstalk/src/utils/Yield.ts | 2 +- .../tests/{YieldHandler.test.ts => Yield.test.ts} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename projects/subgraph-beanstalk/tests/{YieldHandler.test.ts => Yield.test.ts} (100%) diff --git a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts index 08a40e2f8e..4f8791480d 100644 --- a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts @@ -13,7 +13,7 @@ export function loadBeanstalk(protocol: Address): Beanstalk { // Pre-replant token currently would not be set beanstalk.token = getProtocolToken(protocol, BI_MAX).toHexString(); const fert = getProtocolFertilizer(protocol); - if (fert != null) { + if (fert !== null) { beanstalk.fertilizer1155 = fert.toHexString(); } beanstalk.schemaVersion = "2.4.0"; diff --git a/projects/subgraph-beanstalk/src/utils/Yield.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts index 8da4861ee9..3b7b433cbf 100644 --- a/projects/subgraph-beanstalk/src/utils/Yield.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -414,7 +414,7 @@ function updateGaugePoints(gaugePoints: f64, currentPercent: f64, optimalPercent function updateFertAPY(protocol: Address, timestamp: BigInt, window: i32): void { const fertAddress = getProtocolFertilizer(protocol); - if (fertAddress == null) { + if (fertAddress === null) { return; } diff --git a/projects/subgraph-beanstalk/tests/YieldHandler.test.ts b/projects/subgraph-beanstalk/tests/Yield.test.ts similarity index 100% rename from projects/subgraph-beanstalk/tests/YieldHandler.test.ts rename to projects/subgraph-beanstalk/tests/Yield.test.ts From 8478325cb13e00e6054ffffbfedcef7d1d5e7fae Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:02:34 -0700 Subject: [PATCH 26/59] adjust params --- projects/subgraph-beanstalk/src/entities/Beanstalk.ts | 2 +- projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts | 4 +++- projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts | 2 +- projects/subgraph-beanstalk/src/handlers/SiloHandler.ts | 2 +- projects/subgraph-beanstalk/src/utils/Constants.ts | 8 ++++---- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts index 4f8791480d..51a0776d34 100644 --- a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts @@ -11,7 +11,7 @@ export function loadBeanstalk(protocol: Address): Beanstalk { beanstalk = new Beanstalk(protocol.toHexString()); beanstalk.name = "Beanstalk"; // Pre-replant token currently would not be set - beanstalk.token = getProtocolToken(protocol, BI_MAX).toHexString(); + beanstalk.token = getProtocolToken(protocol).toHexString(); const fert = getProtocolFertilizer(protocol); if (fert !== null) { beanstalk.fertilizer1155 = fert.toHexString(); diff --git a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts index cd9fce576d..7a0d5af7ba 100644 --- a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts @@ -45,7 +45,9 @@ export function handleGaugePointChange(event: GaugePointChange): void { export function handleUpdateAverageStalkPerBdvPerSeason(event: UpdateAverageStalkPerBdvPerSeason): void { let silo = loadSilo(event.address); - // TODO: this is not accurate, the value in this event is pertaining to gauge only and does not include unripe + // This is not exactly accurate, the value in this event is pertaining to gauge only and does not include unripe. + // In practice, seed values for non-gauge assets are negligible. + // The correct approach is iterating whitelisted assets each season, multipying bdv and seeds silo.grownStalkPerSeason = silo.depositedBDV.times(event.params.newStalkPerBdvPerSeason); takeSiloSnapshots(silo, event.address, event.block.timestamp); silo.save(); diff --git a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts index 1b8edaf52c..37e749ab04 100644 --- a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts @@ -83,7 +83,7 @@ export function handleReward(event: Reward): void { updateDepositInSiloAsset( event.address, event.address, - getProtocolToken(event.address, event.block.number), + getProtocolToken(event.address), event.params.toSilo, event.params.toSilo, event.block.timestamp diff --git a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts index 14caec7ea5..57198dddba 100644 --- a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts @@ -97,7 +97,7 @@ export function handlePlant(event: Plant): void { updateDepositInSiloAsset( event.address, event.address, - getProtocolToken(event.address, event.block.number), + getProtocolToken(event.address), event.params.beans, event.params.beans, event.block.timestamp diff --git a/projects/subgraph-beanstalk/src/utils/Constants.ts b/projects/subgraph-beanstalk/src/utils/Constants.ts index 64bc834b80..479a027c30 100644 --- a/projects/subgraph-beanstalk/src/utils/Constants.ts +++ b/projects/subgraph-beanstalk/src/utils/Constants.ts @@ -1,9 +1,9 @@ -import { BigInt, Address } from "@graphprotocol/graph-ts"; -import { BEAN_ERC20, BEAN_ERC20_V1, BEANSTALK, FERTILIZER, NEW_BEAN_TOKEN_BLOCK } from "../../../subgraph-core/utils/Constants"; +import { Address } from "@graphprotocol/graph-ts"; +import { BEAN_ERC20, BEANSTALK, FERTILIZER } from "../../../subgraph-core/utils/Constants"; -export function getProtocolToken(protocol: Address, blockNumber: BigInt): Address { +export function getProtocolToken(protocol: Address): Address { if (protocol == BEANSTALK) { - return blockNumber < NEW_BEAN_TOKEN_BLOCK ? BEAN_ERC20_V1 : BEAN_ERC20; + return BEAN_ERC20; } throw new Error("Unsupported protocol"); } From 2c0dcd406099f934959971501fcfdce50d12bba9 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:37:40 -0700 Subject: [PATCH 27/59] increment spec version --- projects/subgraph-beanstalk/manifests/codegen-abis.yaml | 2 +- projects/subgraph-beanstalk/manifests/ethereum.yaml | 2 +- projects/subgraph-beanstalk/manifests/no-apy.yaml | 2 +- projects/subgraph-beanstalk/schema.graphql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml index 0777f6c0d8..036ca0643b 100644 --- a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml +++ b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml @@ -3,7 +3,7 @@ # the only important part is in the `abis` and `templates` sections. # - For abis, its only the list of abis that is relevant. The name of the dataSource is also visible. # - For templates, it is only the name of the template that is relevant. -specVersion: 0.0.4 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 2b28791372..25d7f7f955 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -1,4 +1,4 @@ -specVersion: 0.0.4 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml index df72430321..eab74afa9e 100644 --- a/projects/subgraph-beanstalk/manifests/no-apy.yaml +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -1,5 +1,5 @@ # Use this file for faster testing of whether the subgraph build works -specVersion: 0.0.4 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index f3ebd6db76..d771304eba 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -1482,7 +1482,7 @@ type Germinating @entity { isFarmer: Boolean! "The season in which the germination started" season: Int! - "Germinating stalk. This only applies to farmer/Beanstalk address" + "Germinating stalk. This only applies to farmer/protocol address" stalk: BigInt! "Germinating tokens. This only applies to a Token address" tokenAmount: BigInt! From a1ceff6a5f9a476630373038c46b6c81d24b6806 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:29:45 -0700 Subject: [PATCH 28/59] schema for unripe --- projects/subgraph-beanstalk/schema.graphql | 157 +++++++++++++++++++-- 1 file changed, 148 insertions(+), 9 deletions(-) diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index d771304eba..bcaf0cd975 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -125,7 +125,7 @@ type Silo @entity { } type SiloHourlySnapshot @entity { - "ID of silo-Unix Hour Timestamp" + "ID of silo - Season" id: ID! "Season for the snapshot" season: Int! @@ -172,7 +172,7 @@ type SiloHourlySnapshot @entity { } type SiloDailySnapshot @entity { - "ID of silo-Unix Hour Timestamp" + "ID of silo - Day" id: ID! "Last season for the snapshot" season: Int! @@ -240,7 +240,7 @@ type SiloAsset @entity { } type SiloAssetHourlySnapshot @entity { - "Silo Asset ID - Unix Timestamp" + "Silo Asset ID - Season" id: ID! "Season for the snapshot" season: Int! @@ -267,7 +267,7 @@ type SiloAssetHourlySnapshot @entity { } type SiloAssetDailySnapshot @entity { - "Silo Asset ID - Unix Timestamp" + "Silo Asset ID - Day" id: ID! "Last season for the snapshot" season: Int! @@ -399,7 +399,7 @@ type WhitelistTokenHourlySnapshot @entity { } type WhitelistTokenDailySnapshot @entity { - "Token address - Unix Timestamp" + "Token address - Day" id: ID! "The season for this snapshot" season: Int! @@ -478,7 +478,7 @@ type Field @entity { } type FieldHourlySnapshot @entity { - "Field ID - Unix Timestamp" + "Field ID - Season" id: ID! "Field associated with this snapshot" field: Field! @@ -539,7 +539,7 @@ type FieldHourlySnapshot @entity { } type FieldDailySnapshot @entity { - "Field ID - Unix Timestamp" + "Field ID - Day" id: ID! "Field associated with this snapshot" field: Field! @@ -744,7 +744,7 @@ type PodMarketplace @entity { } type PodMarketplaceHourlySnapshot @entity { - "Marketplace ID - Unix Timestamp" + "Marketplace ID - Season" id: ID! "Point in time latest season" season: Int! @@ -795,7 +795,7 @@ type PodMarketplaceHourlySnapshot @entity { } type PodMarketplaceDailySnapshot @entity { - "Marketplace ID - Unix Timestamp" + "Marketplace ID - Day" id: ID! "Point in time latest season" season: Int! @@ -1489,3 +1489,142 @@ type Germinating @entity { "Germinating bdv. This only applies to a Token address" bdv: BigInt! } + +type UnripeToken @entity { + "Token Address" + id: ID! + "The ripe token underlying this unripe asset" + underlyingToken: String! + "The total amount of `underlyingToken` for this unripe token (getTotalUnderlying)" + totalUnderlying: BigInt! + "The amount of `underlyingToken` corresponding to one of this unripe token (getUnderlyingPerUnripeToken)" + amountUnderlyingOne: BigInt! + "The bdv of `amountUnderlyingOne` of `underlyingToken`. Assumed to not always be the same as bdv(id)" + bdvUnderlyingOne: BigInt! + "The amount of `underlyingToken` which would be received if one of this unripe token were to be chopped (getPenalty)" + choppableAmountOne: BigInt! + "The bdv that would be received if one of this unripe token were to be chopped" + choppableBdvOne: BigInt! + "The chop rate, in percent (getPercentPenalty)" + chopRate: BigDecimal! + "The amount recapitalized, in percent (getRecapFundedPercent)" + recapPercent: BigDecimal! + "The total amount of this unripe token which has been chopped" + totalChoppedAmount: BigInt! + "The total bdv of this unripe token which has been chopped" + totalChoppedBdv: BigInt! + "The total bdv of all `underlyingToken` that has been received from chopping" + totalChoppedBdvReceived: BigInt! + "Season when the previous hourly snapshot was taken/updated" + lastHourlySnapshotSeason: Int + "Day of when the previous daily snapshot was taken/updated" + lastDailySnapshotDay: BigInt + "Link to hourly snapshot data" + hourlySnapshots: [UnripeTokenHourlySnapshot!]! @derivedFrom(field: "unripeToken") + "Link to daily snapshot data" + dailySnapshots: [UnripeTokenDailySnapshot!]! @derivedFrom(field: "unripeToken") +} + +type UnripeTokenHourlySnapshot @entity { + "UnripeToken ID - Season" + id: ID! + "Season for the snapshot" + season: Int! + "Unripe token associated with this snapshot" + unripeToken: UnripeToken! + + "Point in time ripe token underlying this unripe asset" + underlyingToken: String! + "Point in time total amount of `underlyingToken` for this unripe token (getTotalUnderlying)" + totalUnderlying: BigInt! + "Point in time amount of `underlyingToken` corresponding to one of this unripe token (getUnderlyingPerUnripeToken)" + amountUnderlyingOne: BigInt! + "Point in time bdv of `amountUnderlyingOne` of `underlyingToken`. Assumed to not always be the same as bdv(id)" + bdvUnderlyingOne: BigInt! + "Point in time amount of `underlyingToken` which would be received if one of this unripe token were to be chopped (getPenalty)" + choppableAmountOne: BigInt! + "Point in time bdv that would be received if one of this unripe token were to be chopped" + choppableBdvOne: BigInt! + "Point in time chop rate, in percent (getPercentPenalty)" + chopRate: BigDecimal! + "Point in time amount recapitalized, in percent (getRecapFundedPercent)" + recapPercent: BigDecimal! + "Point in time total amount of this unripe token which has been chopped" + totalChoppedAmount: BigInt! + "Point in time total bdv of this unripe token which has been chopped" + totalChoppedBdv: BigInt! + "Point in time total bdv of all `underlyingToken` that has been received from chopping" + totalChoppedBdvReceived: BigInt! + + deltaUnderlyingToken: Boolean! + "Note that the contents of this field are nonsense when deltaUnderlyingToken = true" + deltaTotalUnderlying: BigInt! + "Note that the contents of this field are nonsense when deltaUnderlyingToken = true" + deltaAmountUnderlyingOne: BigInt! + deltaBdvUnderlyingOne: BigInt! + "Note that the contents of this field are nonsense when deltaUnderlyingToken = true" + deltaChoppableAmountOne: BigInt! + deltaChoppableBdvOne: BigInt! + deltaChopRate: BigDecimal! + deltaRecapPercent: BigDecimal! + deltaTotalChoppedAmount: BigInt! + deltaTotalChoppedBdv: BigInt! + deltaTotalChoppedBdvReceived: BigInt! + + "Timestamp of initial snapshot creation" + createdAt: BigInt! + "Timestamp of last entity update" + updatedAt: BigInt! +} + +type UnripeTokenDailySnapshot @entity { + "UnripeToken ID - Day" + id: ID! + "Last season for the snapshot" + season: Int! + "Unripe token associated with this snapshot" + unripeToken: UnripeToken! + + "Point in time ripe token underlying this unripe asset" + underlyingToken: String! + "Point in time total amount of `underlyingToken` for this unripe token (getTotalUnderlying)" + totalUnderlying: BigInt! + "Point in time amount of `underlyingToken` corresponding to one of this unripe token (getUnderlyingPerUnripeToken)" + amountUnderlyingOne: BigInt! + "Point in time bdv of `amountUnderlyingOne` of `underlyingToken`. Assumed to not always be the same as bdv(id)" + bdvUnderlyingOne: BigInt! + "Point in time amount of `underlyingToken` which would be received if one of this unripe token were to be chopped (getPenalty)" + choppableAmountOne: BigInt! + "Point in time bdv that would be received if one of this unripe token were to be chopped" + choppableBdvOne: BigInt! + "Point in time chop rate, in percent (getPercentPenalty)" + chopRate: BigDecimal! + "Point in time amount recapitalized, in percent (getRecapFundedPercent)" + recapPercent: BigDecimal! + "Point in time total amount of this unripe token which has been chopped" + totalChoppedAmount: BigInt! + "Point in time total bdv of this unripe token which has been chopped" + totalChoppedBdv: BigInt! + "Point in time total bdv of all `underlyingToken` that has been received from chopping" + totalChoppedBdvReceived: BigInt! + + deltaUnderlyingToken: Boolean! + "Note that the contents of this field are nonsense when deltaUnderlyingToken = true" + deltaTotalUnderlying: BigInt! + "Note that the contents of this field are nonsense when deltaUnderlyingToken = true" + deltaAmountUnderlyingOne: BigInt! + deltaBdvUnderlyingOne: BigInt! + "Note that the contents of this field are nonsense when deltaUnderlyingToken = true" + deltaChoppableAmountOne: BigInt! + deltaChoppableBdvOne: BigInt! + deltaChopRate: BigDecimal! + deltaRecapPercent: BigDecimal! + deltaTotalChoppedAmount: BigInt! + deltaTotalChoppedBdv: BigInt! + deltaTotalChoppedBdvReceived: BigInt! + + "Timestamp of initial snapshot creation" + createdAt: BigInt! + "Timestamp of last entity update" + updatedAt: BigInt! +} From 1ae2ce65f809a9fbae72209ea2b31036ddf63c63 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:19:43 -0700 Subject: [PATCH 29/59] handle replanted sunrise --- .../manifests/ethereum.yaml | 80 ++++++++++++++++--- .../src/handlers/SeasonHandler.ts | 50 ++---------- .../handlers/legacy/LegacySeasonHandler.ts | 23 +++++- .../subgraph-beanstalk/src/utils/Season.ts | 44 ++++++++++ .../subgraph-beanstalk/src/utils/Yield.ts | 5 +- .../src/utils/legacy/LegacySilo.ts | 1 + projects/subgraph-core/utils/Constants.ts | 2 + 7 files changed, 147 insertions(+), 58 deletions(-) create mode 100644 projects/subgraph-beanstalk/src/utils/Season.ts diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 25d7f7f955..b1aef06d2d 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -680,8 +680,6 @@ dataSources: - name: SeedGauge file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: Sunrise(indexed uint256) - handler: handleSunrise - event: Reward(indexed uint32,uint256,uint256,uint256) handler: handleReward - event: WellOracle(indexed uint32,address,int256,bytes) @@ -692,7 +690,7 @@ dataSources: handler: handleIncentive file: ../src/handlers/SeasonHandler.ts - kind: ethereum/contract - name: LegacySeason-PreReplant + name: LegacySeason-PreReplant-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" @@ -713,12 +711,12 @@ dataSources: handler: handleSeasonSnapshot file: ../src/handlers/legacy/LegacySeasonHandler.ts - kind: ethereum/contract - name: LegacySeason-Replanted + name: LegacySeason-Replanted-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 12974075 + startBlock: 15277986 # Replanted endBlock: 19927634 mapping: kind: ethereum/events @@ -733,6 +731,68 @@ dataSources: - event: MetapoolOracle(indexed uint32,int256,uint256[2]) handler: handleMetapoolOracle file: ../src/handlers/legacy/LegacySeasonHandler.ts + - kind: ethereum/contract + name: Season-PreReplant-Replanted + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + endBlock: 15277986 # Replanted + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleSunrise + file: ../src/handlers/SeasonHandler.ts + - kind: ethereum/contract + name: LegacySeason-Replanted-SiloV3 + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: Replanted + startBlock: 15277986 # Replanted + endBlock: 17671557 # BIP-36 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleReplantSunrise + file: ../src/handlers/legacy/LegacySeasonHandler.ts + - kind: ethereum/contract + name: Season-SiloV3- + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SeedGauge + startBlock: 17671557 # BIP-36 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleSunrise + file: ../src/handlers/SeasonHandler.ts ### # BEAN ERC20 ### @@ -823,8 +883,8 @@ dataSources: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleDiamondCut file: ../src/handlers/DiamondHandler.ts -# features: -# - grafting -# graft: -# base: QmQCyzt2SH1dnGyPDaWUCWCxAhdaYwxHa1MgMEJLLizw1L -# block: 15278000 +features: + - grafting +graft: + base: QmaZ8zSaXfLAS7pTnXQLeWu1qhtRGu6cSPavGk7scJtnLH + block: 15289930 diff --git a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts index 37e749ab04..e97f3a1431 100644 --- a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts @@ -1,65 +1,27 @@ -import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"; +import { Address, BigInt } from "@graphprotocol/graph-ts"; import { Reward, Soil, WellOracle, Sunrise, Incentivization, SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; -import { BEANSTALK, GAUGE_BIP45_BLOCK } from "../../../subgraph-core/utils/Constants"; +import { BEANSTALK, GAUGE_BIP45_BLOCK, REPLANT_SEASON } from "../../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { updateStalkWithCalls } from "../utils/legacy/LegacySilo"; import { loadBeanstalk, loadSeason } from "../entities/Beanstalk"; -import { takeMarketSnapshots } from "../entities/snapshots/Marketplace"; -import { loadSilo, loadSiloAsset } from "../entities/Silo"; +import { loadSilo } from "../entities/Silo"; import { takeSiloSnapshots } from "../entities/snapshots/Silo"; import { updateDepositInSiloAsset } from "../utils/Silo"; import { getBeanstalkPrice } from "../utils/contracts/BeanstalkPrice"; -import { takeSiloAssetSnapshots } from "../entities/snapshots/SiloAsset"; import { takeFieldSnapshots } from "../entities/snapshots/Field"; import { loadField } from "../entities/Field"; -import { loadPodMarketplace } from "../entities/PodMarketplace"; import { updateBeanEMA } from "../utils/Yield"; import { updateExpiredPlots } from "../utils/Marketplace"; import { updateHarvestablePlots } from "../utils/Field"; import { getProtocolToken } from "../utils/Constants"; +import { sunrise } from "../utils/Season"; export function handleSunrise(event: Sunrise): void { // (Legacy) Update any farmers that had silo transfers from the prior season. // This is intentionally done before beanstalk.lastSeason gets updated updateStalkWithCalls(event.address, event.block.timestamp); - let currentSeason = event.params.season.toI32(); - let season = loadSeason(event.address, event.params.season); - - // Update season metrics - if (event.params.season == BigInt.fromI32(6075)) { - // Replant oracle initialization - season.price = BigDecimal.fromString("1.07"); - } - season.sunriseBlock = event.block.number; - season.createdAt = event.block.timestamp; - season.save(); - - // Update field metrics - let field = loadField(event.address); - - // -- Field level totals - field.season = currentSeason; - field.podRate = season.beans == ZERO_BI ? ZERO_BD : toDecimal(field.unharvestablePods, 6).div(toDecimal(season.beans, 6)); - - takeFieldSnapshots(field, event.address, event.block.timestamp, event.block.number); - field.save(); - - // Marketplace Season Update - let market = loadPodMarketplace(event.address); - market.season = currentSeason; - takeMarketSnapshots(market, event.address, event.block.timestamp); - market.save(); - - // Create silo entities for the protocol - let silo = loadSilo(event.address); - takeSiloSnapshots(silo, event.address, event.block.timestamp); - for (let i = 0; i < silo.whitelistedTokens.length; i++) { - let siloAsset = loadSiloAsset(event.address, Address.fromString(silo.whitelistedTokens[i])); - takeSiloAssetSnapshots(siloAsset, event.address, event.block.timestamp); - siloAsset.save(); - } - silo.save(); + sunrise(event.address, event.params.season, event.block); } export function handleReward(event: Reward): void { @@ -112,7 +74,7 @@ export function handleSoil(event: Soil): void { takeFieldSnapshots(field, event.address, event.block.timestamp, event.block.number); field.save(); - if (event.params.season.toI32() >= 6075) { + if (event.params.season >= REPLANT_SEASON) { updateBeanEMA(event.address, event.block.timestamp); } } diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts index d8f65e0e77..f320b1d12e 100644 --- a/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacySeasonHandler.ts @@ -1,10 +1,29 @@ -import { CURVE_PRICE } from "../../../../subgraph-core/utils/Constants"; +import { BigInt, BigDecimal } from "@graphprotocol/graph-ts"; +import { CURVE_PRICE, REPLANT_SEASON } from "../../../../subgraph-core/utils/Constants"; import { toDecimal } from "../../../../subgraph-core/utils/Decimals"; import { CurvePrice } from "../../../generated/Beanstalk-ABIs/CurvePrice"; -import { SeasonSnapshot } from "../../../generated/Beanstalk-ABIs/PreReplant"; +import { SeasonSnapshot, Sunrise } from "../../../generated/Beanstalk-ABIs/PreReplant"; import { MetapoolOracle } from "../../../generated/Beanstalk-ABIs/Replanted"; import { BeanstalkPrice_try_price } from "../../utils/contracts/BeanstalkPrice"; import { loadSeason } from "../../entities/Beanstalk"; +import { updateStalkWithCalls } from "../../utils/legacy/LegacySilo"; +import { sunrise } from "../../utils/Season"; + +// Replanted -> SiloV3 +export function handleReplantSunrise(event: Sunrise): void { + // Update any farmers that had silo transfers from the prior season. + // This is intentionally done before beanstalk.lastSeason gets updated + updateStalkWithCalls(event.address, event.block.timestamp); + + // Replant oracle initialization + if (event.params.season == REPLANT_SEASON) { + let seasonEntity = loadSeason(event.address, event.params.season); + seasonEntity.price = BigDecimal.fromString("1.07"); + seasonEntity.save(); + } + + sunrise(event.address, event.params.season, event.block); +} // PreReplant -> Replanted export function handleSeasonSnapshot(event: SeasonSnapshot): void { diff --git a/projects/subgraph-beanstalk/src/utils/Season.ts b/projects/subgraph-beanstalk/src/utils/Season.ts new file mode 100644 index 0000000000..3eb8109d82 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/Season.ts @@ -0,0 +1,44 @@ +import { Address, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; +import { loadSeason } from "../entities/Beanstalk"; +import { loadPodMarketplace } from "../entities/PodMarketplace"; +import { takeMarketSnapshots } from "../entities/snapshots/Marketplace"; +import { takeSiloSnapshots } from "../entities/snapshots/Silo"; +import { loadSilo, loadSiloAsset } from "../entities/Silo"; +import { takeSiloAssetSnapshots } from "../entities/snapshots/SiloAsset"; +import { takeFieldSnapshots } from "../entities/snapshots/Field"; +import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { loadField } from "../entities/Field"; + +export function sunrise(protocol: Address, season: BigInt, block: ethereum.Block): void { + let currentSeason = season.toI32(); + let seasonEntity = loadSeason(protocol, season); + seasonEntity.sunriseBlock = block.number; + seasonEntity.createdAt = block.timestamp; + seasonEntity.save(); + + // Update field metrics + let field = loadField(protocol); + + // -- Field level totals + field.season = currentSeason; + field.podRate = seasonEntity.beans == ZERO_BI ? ZERO_BD : toDecimal(field.unharvestablePods, 6).div(toDecimal(seasonEntity.beans, 6)); + + takeFieldSnapshots(field, protocol, block.timestamp, block.number); + field.save(); + + // Marketplace Season Update + let market = loadPodMarketplace(protocol); + market.season = currentSeason; + takeMarketSnapshots(market, protocol, block.timestamp); + market.save(); + + // Create silo entities for the protocol + let silo = loadSilo(protocol); + takeSiloSnapshots(silo, protocol, block.timestamp); + for (let i = 0; i < silo.whitelistedTokens.length; i++) { + let siloAsset = loadSiloAsset(protocol, Address.fromString(silo.whitelistedTokens[i])); + takeSiloAssetSnapshots(siloAsset, protocol, block.timestamp); + siloAsset.save(); + } + silo.save(); +} diff --git a/projects/subgraph-beanstalk/src/utils/Yield.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts index 3b7b433cbf..8ffcd0ccff 100644 --- a/projects/subgraph-beanstalk/src/utils/Yield.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -16,12 +16,13 @@ import { getGerminatingBdvs } from "../entities/Germinating"; import { getCurrentSeason, getRewardMinted, loadBeanstalk } from "../entities/Beanstalk"; import { loadFertilizer, loadFertilizerYield } from "../entities/Fertilizer"; import { getProtocolFertilizer } from "./Constants"; +import { REPLANT_SEASON } from "../../../subgraph-core/utils/Constants"; const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; const ROLLING_30_DAY_WINDOW = 720; -// Note: minimum allowable season is 6075 +// Note: minimum allowable season is REPLANT_SEASON export function updateBeanEMA(protocol: Address, timestamp: BigInt): void { updateWindowEMA(protocol, timestamp, ROLLING_24_WINDOW); updateWindowEMA(protocol, timestamp, ROLLING_7_DAY_WINDOW); @@ -65,7 +66,7 @@ function updateWindowEMA(protocol: Address, timestamp: BigInt, window: i32): voi if (siloYield.u < window) { // Recalculate EMA from initial season since beta has changed - for (let i = 6075; i <= t; i++) { + for (let i = REPLANT_SEASON.toU32(); i <= t; i++) { let rewardMint = getRewardMinted(i); currentEMA = toDecimal(rewardMint).minus(priorEMA).times(siloYield.beta).plus(priorEMA); priorEMA = currentEMA; diff --git a/projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts b/projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts index cc928aec1d..750fc0f99b 100644 --- a/projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts +++ b/projects/subgraph-beanstalk/src/utils/legacy/LegacySilo.ts @@ -22,6 +22,7 @@ export function updateClaimedWithdraw( asset.save(); } +// Replanted -> SiloV3 // This should be run at sunrise for the previous season to update any farmers stalk/seed/roots balances from silo transfers. export function updateStalkWithCalls(protocol: Address, timestamp: BigInt): void { let beanstalk = loadBeanstalk(protocol); diff --git a/projects/subgraph-core/utils/Constants.ts b/projects/subgraph-core/utils/Constants.ts index 77ab5ff2d4..a27c328e63 100644 --- a/projects/subgraph-core/utils/Constants.ts +++ b/projects/subgraph-core/utils/Constants.ts @@ -43,6 +43,8 @@ export const DELTA_HUMIDITY = BigDecimal.fromString("0.5"); export const CALCULATIONS_CURVE = Address.fromString("0x25BF7b72815476Dd515044F9650Bf79bAd0Df655"); +export const REPLANT_SEASON = BigInt.fromU32(6075); + // Milestone blocks export const BEANSTALK_BLOCK = BigInt.fromU32(12974075); export const EXPLOIT_BLOCK = BigInt.fromU32(14602790); From 91405d29c60d3310435447ff8a672df973b9a753 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:27:22 -0700 Subject: [PATCH 30/59] fix type --- .../subgraph-beanstalk/manifests/no-apy.yaml | 76 +++++++++++++++++-- .../subgraph-beanstalk/src/utils/Yield.ts | 2 +- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml index eab74afa9e..b376309ef0 100644 --- a/projects/subgraph-beanstalk/manifests/no-apy.yaml +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -104,7 +104,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SiloV3 - startBlock: 15277986 + startBlock: 17671557 # BIP-36 endBlock: 19927634 mapping: kind: ethereum/events @@ -233,7 +233,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 12974075 + startBlock: 14148509 # BIP-11 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -265,7 +265,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 14148509 endBlock: 19927634 mapping: kind: ethereum/events @@ -378,8 +378,6 @@ dataSources: - name: SeedGauge file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - - event: Sunrise(indexed uint256) - handler: handleSunrise - event: Reward(indexed uint32,uint256,uint256,uint256) handler: handleReward - event: WellOracle(indexed uint32,address,int256,bytes) @@ -390,7 +388,7 @@ dataSources: handler: handleIncentive file: ../src/handlers/SeasonHandler.ts - kind: ethereum/contract - name: LegacySeason-PreReplant + name: LegacySeason-PreReplant-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" @@ -411,12 +409,12 @@ dataSources: handler: handleSeasonSnapshot file: ../src/handlers/legacy/LegacySeasonHandler.ts - kind: ethereum/contract - name: LegacySeason-Replanted + name: LegacySeason-Replanted-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 12974075 + startBlock: 15277986 # Replanted endBlock: 19927634 mapping: kind: ethereum/events @@ -431,6 +429,68 @@ dataSources: - event: MetapoolOracle(indexed uint32,int256,uint256[2]) handler: handleMetapoolOracle file: ../src/handlers/legacy/LegacySeasonHandler.ts + - kind: ethereum/contract + name: Season-PreReplant-Replanted + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + endBlock: 15277986 # Replanted + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleSunrise + file: ../src/handlers/SeasonHandler.ts + - kind: ethereum/contract + name: LegacySeason-Replanted-SiloV3 + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: Replanted + startBlock: 15277986 # Replanted + endBlock: 17671557 # BIP-36 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: Replanted + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleReplantSunrise + file: ../src/handlers/legacy/LegacySeasonHandler.ts + - kind: ethereum/contract + name: Season-SiloV3- + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: SeedGauge + startBlock: 17671557 # BIP-36 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Season + abis: + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + eventHandlers: + - event: Sunrise(indexed uint256) + handler: handleSunrise + file: ../src/handlers/SeasonHandler.ts ### # BEAN ERC20 ### diff --git a/projects/subgraph-beanstalk/src/utils/Yield.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts index 8ffcd0ccff..e462be1295 100644 --- a/projects/subgraph-beanstalk/src/utils/Yield.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -66,7 +66,7 @@ function updateWindowEMA(protocol: Address, timestamp: BigInt, window: i32): voi if (siloYield.u < window) { // Recalculate EMA from initial season since beta has changed - for (let i = REPLANT_SEASON.toU32(); i <= t; i++) { + for (let i = REPLANT_SEASON.toI32(); i <= t; i++) { let rewardMint = getRewardMinted(i); currentEMA = toDecimal(rewardMint).minus(priorEMA).times(siloYield.beta).plus(priorEMA); priorEMA = currentEMA; From 5c322eda36beda03dde153669863b37d587bcf8b Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:40:52 -0700 Subject: [PATCH 31/59] comments in manifest --- .../manifests/ethereum.yaml | 66 +++++++++---------- .../subgraph-beanstalk/manifests/no-apy.yaml | 61 ++++++++--------- 2 files changed, 61 insertions(+), 66 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index b1aef06d2d..8de055dc03 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -314,7 +314,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 15277986 # Silo currently has no support for pre-exploit + startBlock: 15277986 # Replanted (Silo currently has no support for pre-exploit) mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -349,13 +349,13 @@ dataSources: handler: handleRemoveWithdrawals file: ../src/handlers/SiloHandler.ts - kind: ethereum/contract - name: LegacySilo-Replanted + name: LegacySilo-Replanted-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 15277986 - endBlock: 19927634 + startBlock: 15277986 # Replanted + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -378,13 +378,13 @@ dataSources: handler: handleWhitelistToken_v2 file: ../src/handlers/legacy/LegacySiloHandler.ts - kind: ethereum/contract - name: LegacySiloCalls-Replanted + name: LegacySiloCalls-Replanted-SiloV3 network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 15277986 - endBlock: 19927634 + startBlock: 15277986 # Replanted + endBlock: 17671557 # SiloV3 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -401,13 +401,13 @@ dataSources: handler: handleTransferDepositsCall file: ../src/handlers/legacy/LegacySiloHandler.ts - kind: ethereum/contract - name: LegacySilo-SiloV3 + name: LegacySilo-SiloV3-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SiloV3 - startBlock: 17671557 # BIP-36 - endBlock: 19927634 + startBlock: 17671557 # SiloV3 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -494,13 +494,13 @@ dataSources: handler: handleTemperatureChange file: ../src/handlers/FieldHandler.ts - kind: ethereum/contract - name: LegacyField-PreReplant + name: LegacyField-PreReplant-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant startBlock: 12974075 - endBlock: 19927634 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -535,7 +535,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 14148509 # BIP-11 + startBlock: 14148509 # BIP-11 Pod Marketplace mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -562,13 +562,13 @@ dataSources: handler: handlePodOrderCancelled file: ../src/handlers/MarketplaceHandler.ts - kind: ethereum/contract - name: LegacyMarketplace-PreReplant + name: LegacyMarketplace-PreReplant-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 14148509 - endBlock: 19927634 + startBlock: 14148509 # BIP-11 Pod Marketplace + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -593,13 +593,13 @@ dataSources: handler: handlePodListingCancelled_indexed file: ../src/handlers/legacy/LegacyMarketplaceHandler.ts - kind: ethereum/contract - name: LegacyMarketplace-Replanted + name: LegacyMarketplace-Replanted-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 15277986 - endBlock: 19927634 + startBlock: 15277986 # Replanted + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -696,7 +696,7 @@ dataSources: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant startBlock: 12974075 - endBlock: 19927634 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -717,7 +717,7 @@ dataSources: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted startBlock: 15277986 # Replanted - endBlock: 19927634 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -759,7 +759,7 @@ dataSources: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted startBlock: 15277986 # Replanted - endBlock: 17671557 # BIP-36 + endBlock: 17671557 # SiloV3 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -779,7 +779,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 17671557 # BIP-36 + startBlock: 17671557 # SiloV3 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -797,12 +797,12 @@ dataSources: # BEAN ERC20 ### - kind: ethereum/contract - name: Bean-Replant + name: Bean-Replanted network: mainnet source: address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" abi: ERC20 - startBlock: 15277986 + startBlock: 15277986 # Replanted mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -817,13 +817,13 @@ dataSources: handler: handleTransfer file: ../src/handlers/BeanHandler.ts - kind: ethereum/contract - name: Bean-PreReplant + name: Bean-PreReplant-Exploit network: mainnet source: address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" abi: ERC20 startBlock: 12974075 - endBlock: 14602789 + endBlock: 14602789 # Exploit mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -846,7 +846,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 15277986 + startBlock: 15277986 # Replanted mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -883,8 +883,8 @@ dataSources: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleDiamondCut file: ../src/handlers/DiamondHandler.ts -features: - - grafting -graft: - base: QmaZ8zSaXfLAS7pTnXQLeWu1qhtRGu6cSPavGk7scJtnLH - block: 15289930 +# features: +# - grafting +# graft: +# base: QmaZ8zSaXfLAS7pTnXQLeWu1qhtRGu6cSPavGk7scJtnLH +# block: 15289930 diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml index b376309ef0..2d2a3d5815 100644 --- a/projects/subgraph-beanstalk/manifests/no-apy.yaml +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -12,7 +12,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 15277986 # Silo currently has no support for pre-exploit + startBlock: 15277986 # Replanted (Silo currently has no support for pre-exploit) mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -47,13 +47,13 @@ dataSources: handler: handleRemoveWithdrawals file: ../src/handlers/SiloHandler.ts - kind: ethereum/contract - name: LegacySilo-Replanted + name: LegacySilo-Replanted-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 15277986 - endBlock: 19927634 + startBlock: 15277986 # Replanted + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -76,13 +76,13 @@ dataSources: handler: handleWhitelistToken_v2 file: ../src/handlers/legacy/LegacySiloHandler.ts - kind: ethereum/contract - name: LegacySiloCalls-Replanted + name: LegacySiloCalls-Replanted-SiloV3 network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 15277986 - endBlock: 19927634 + startBlock: 15277986 # Replanted + endBlock: 17671557 # SiloV3 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -99,13 +99,13 @@ dataSources: handler: handleTransferDepositsCall file: ../src/handlers/legacy/LegacySiloHandler.ts - kind: ethereum/contract - name: LegacySilo-SiloV3 + name: LegacySilo-SiloV3-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SiloV3 - startBlock: 17671557 # BIP-36 - endBlock: 19927634 + startBlock: 17671557 # SiloV3 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -192,13 +192,13 @@ dataSources: handler: handleTemperatureChange file: ../src/handlers/FieldHandler.ts - kind: ethereum/contract - name: LegacyField-PreReplant + name: LegacyField-PreReplant-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant startBlock: 12974075 - endBlock: 19927634 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -233,7 +233,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 14148509 # BIP-11 + startBlock: 14148509 # BIP-11 Pod Marketplace mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -260,13 +260,13 @@ dataSources: handler: handlePodOrderCancelled file: ../src/handlers/MarketplaceHandler.ts - kind: ethereum/contract - name: LegacyMarketplace-PreReplant + name: LegacyMarketplace-PreReplant-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 14148509 - endBlock: 19927634 + startBlock: 14148509 # BIP-11 Pod Marketplace + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -291,13 +291,13 @@ dataSources: handler: handlePodListingCancelled_indexed file: ../src/handlers/legacy/LegacyMarketplaceHandler.ts - kind: ethereum/contract - name: LegacyMarketplace-Replanted + name: LegacyMarketplace-Replanted-SeedGauge network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted - startBlock: 15277986 - endBlock: 19927634 + startBlock: 15277986 # Replanted + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -394,7 +394,7 @@ dataSources: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant startBlock: 12974075 - endBlock: 19927634 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -415,7 +415,7 @@ dataSources: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted startBlock: 15277986 # Replanted - endBlock: 19927634 + endBlock: 19927634 # SeedGauge mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -457,7 +457,7 @@ dataSources: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: Replanted startBlock: 15277986 # Replanted - endBlock: 17671557 # BIP-36 + endBlock: 17671557 # SiloV3 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -477,7 +477,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 17671557 # BIP-36 + startBlock: 17671557 # SiloV3 mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -495,12 +495,12 @@ dataSources: # BEAN ERC20 ### - kind: ethereum/contract - name: Bean-Replant + name: Bean-Replanted network: mainnet source: address: "0xbea0000029ad1c77d3d5d23ba2d8893db9d1efab" abi: ERC20 - startBlock: 15277986 + startBlock: 15277986 # Replanted mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -515,13 +515,13 @@ dataSources: handler: handleTransfer file: ../src/handlers/BeanHandler.ts - kind: ethereum/contract - name: Bean-PreReplant + name: Bean-PreReplant-Exploit network: mainnet source: address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" abi: ERC20 startBlock: 12974075 - endBlock: 14602789 + endBlock: 14602789 # Exploit mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -544,7 +544,7 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: SeedGauge - startBlock: 15277986 + startBlock: 15277986 # Replanted mapping: kind: ethereum/events apiVersion: 0.0.6 @@ -581,8 +581,3 @@ dataSources: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleDiamondCut file: ../src/handlers/DiamondHandler.ts -# features: -# - grafting -# graft: -# base: QmQCyzt2SH1dnGyPDaWUCWCxAhdaYwxHa1MgMEJLLizw1L -# block: 15278000 From 1bf963d9c3fefd74eb88dfc51d48532a980c2c49 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:51:20 -0700 Subject: [PATCH 32/59] update abi reference --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 10 +++++----- projects/subgraph-beanstalk/src/utils/Yield.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 8de055dc03..434044495d 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -883,8 +883,8 @@ dataSources: - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) handler: handleDiamondCut file: ../src/handlers/DiamondHandler.ts -# features: -# - grafting -# graft: -# base: QmaZ8zSaXfLAS7pTnXQLeWu1qhtRGu6cSPavGk7scJtnLH -# block: 15289930 +features: + - grafting +graft: + base: QmaZ8zSaXfLAS7pTnXQLeWu1qhtRGu6cSPavGk7scJtnLH + block: 15289930 diff --git a/projects/subgraph-beanstalk/src/utils/Yield.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts index e462be1295..8c667ff478 100644 --- a/projects/subgraph-beanstalk/src/utils/Yield.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -1,5 +1,4 @@ import { Address, BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; -import { BasinBip } from "../../generated/Beanstalk-ABIs/BasinBip"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { loadSilo, @@ -17,6 +16,7 @@ import { getCurrentSeason, getRewardMinted, loadBeanstalk } from "../entities/Be import { loadFertilizer, loadFertilizerYield } from "../entities/Fertilizer"; import { getProtocolFertilizer } from "./Constants"; import { REPLANT_SEASON } from "../../../subgraph-core/utils/Constants"; +import { SeedGauge } from "../../../subgraph-bean/generated/Bean-ABIs/SeedGauge"; const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; @@ -424,7 +424,7 @@ function updateFertAPY(protocol: Address, timestamp: BigInt, window: i32): void let siloYield = loadSiloYield(t, window); let fertilizerYield = loadFertilizerYield(t, window); let fertilizer = loadFertilizer(fertAddress); - let contract = BasinBip.bind(protocol); + let contract = SeedGauge.bind(protocol); if (t < 6534) { let currentFertHumidity = contract.try_getCurrentHumidity(); fertilizerYield.humidity = BigDecimal.fromString(currentFertHumidity.reverted ? "500" : currentFertHumidity.value.toString()).div( From 500a8cf511ea5afb90d7c3c88bd769c51a662e57 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:29:12 -0700 Subject: [PATCH 33/59] add missing abi --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 434044495d..822ee76521 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -727,6 +727,10 @@ dataSources: abis: - name: Replanted file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + - name: CurvePrice + file: ../../subgraph-core/abis/CurvePrice.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - event: MetapoolOracle(indexed uint32,int256,uint256[2]) handler: handleMetapoolOracle From 9711e0e921f595792ebf6a137853f1a46c093e33 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:47:21 -0700 Subject: [PATCH 34/59] unripe token loader and changeunderlying --- .../subgraph-bean/src/utils/LockedBeans.ts | 4 +- projects/subgraph-bean/tests/l2sr.test.ts | 8 ++-- .../manifests/ethereum.yaml | 2 + projects/subgraph-beanstalk/schema.graphql | 2 +- .../subgraph-beanstalk/src/entities/Silo.ts | 38 +++++++++++++++++-- .../src/handlers/BarnHandler.ts | 11 +++++- .../subgraph-beanstalk/src/utils/Constants.ts | 30 ++++++++++++++- .../src/utils/contracts/SiloCalculations.ts | 4 +- .../subgraph-beanstalk/tests/Silo.test.ts | 4 +- .../subgraph-beanstalk/tests/Yield.test.ts | 8 ++-- projects/subgraph-core/utils/Constants.ts | 2 +- 11 files changed, 91 insertions(+), 22 deletions(-) diff --git a/projects/subgraph-bean/src/utils/LockedBeans.ts b/projects/subgraph-bean/src/utils/LockedBeans.ts index 34de6ed31a..bd006d47fa 100644 --- a/projects/subgraph-bean/src/utils/LockedBeans.ts +++ b/projects/subgraph-bean/src/utils/LockedBeans.ts @@ -8,7 +8,7 @@ import { BEANSTALK, GAUGE_BIP45_BLOCK, UNRIPE_BEAN, - UNRIPE_BEAN_3CRV + UNRIPE_LP } from "../../../subgraph-core/utils/Constants"; import { SeedGauge } from "../../generated/Bean-ABIs/SeedGauge"; import { ONE_BI, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; @@ -46,7 +46,7 @@ export function calcLockedBeans(blockNumber: BigInt): BigInt { const recapPaidPercent = new BigDecimal(recapPercentResult.value).div(BigDecimal.fromString("1000000")); const lockedBeansUrBean = LibLockedUnderlying_getLockedUnderlying(UNRIPE_BEAN, recapPaidPercent); - const lockedUnripeLp = LibLockedUnderlying_getLockedUnderlying(UNRIPE_BEAN_3CRV, recapPaidPercent); + const lockedUnripeLp = LibLockedUnderlying_getLockedUnderlying(UNRIPE_LP, recapPaidPercent); const underlyingLpPool = getUnderlyingUnripe(blockNumber); const poolBeanReserves = loadOrCreatePool(underlyingLpPool.toHexString(), blockNumber).reserves[0]; diff --git a/projects/subgraph-bean/tests/l2sr.test.ts b/projects/subgraph-bean/tests/l2sr.test.ts index 6ff0134fe0..a31842cc21 100644 --- a/projects/subgraph-bean/tests/l2sr.test.ts +++ b/projects/subgraph-bean/tests/l2sr.test.ts @@ -8,7 +8,7 @@ import { BEAN_WETH_UNRIPE_MIGRATION_BLOCK, GAUGE_BIP45_BLOCK, UNRIPE_BEAN, - UNRIPE_BEAN_3CRV + UNRIPE_LP } from "../../subgraph-core/utils/Constants"; import { BI_10, ONE_BI, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { @@ -46,10 +46,10 @@ describe("L2SR", () => { test("Calculation - block 19736119", () => { mockSeedGaugeLockedBeansReverts(mockReserves, mockReservesTime); mockERC20TokenSupply(UNRIPE_BEAN, BigInt.fromString("109291429462926")); - mockERC20TokenSupply(UNRIPE_BEAN_3CRV, BigInt.fromString("88784724593495")); + mockERC20TokenSupply(UNRIPE_LP, BigInt.fromString("88784724593495")); const recapPaidPercent = BigDecimal.fromString("0.045288"); const lockedUnderlyingBean = LibLockedUnderlying_getPercentLockedUnderlying(UNRIPE_BEAN, recapPaidPercent); - const lockedUnderlyingLp = LibLockedUnderlying_getPercentLockedUnderlying(UNRIPE_BEAN_3CRV, recapPaidPercent); + const lockedUnderlyingLp = LibLockedUnderlying_getPercentLockedUnderlying(UNRIPE_LP, recapPaidPercent); assert.assertTrue(lockedUnderlyingBean.equals(BigDecimal.fromString("0.6620572696973799"))); assert.assertTrue(lockedUnderlyingLp.equals(BigDecimal.fromString("0.6620572696973799"))); @@ -60,7 +60,7 @@ describe("L2SR", () => { mockGetRecapPaidPercent(BigDecimal.fromString("0.045288")); mockGetTotalUnderlying(UNRIPE_BEAN, BigInt.fromString("24584183207621")); - mockGetTotalUnderlying(UNRIPE_BEAN_3CRV, BigInt.fromString("246676046856767267392929")); + mockGetTotalUnderlying(UNRIPE_LP, BigInt.fromString("246676046856767267392929")); mockERC20TokenSupply(BEAN_WETH_CP2_WELL, BigInt.fromString("256164804872196346760208")); const lockedBeans = calcLockedBeans(BEAN_WETH_UNRIPE_MIGRATION_BLOCK); diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 25d7f7f955..36ae856c63 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -659,6 +659,8 @@ dataSources: eventHandlers: - event: Chop(indexed address,indexed address,uint256,uint256) handler: handleChop + - event: ChangeUnderlying(indexed address,int256) + handler: handleChangeUnderlying file: ../src/handlers/BarnHandler.ts ### # SEASON diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index bcaf0cd975..2f2d9c0c61 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -1492,7 +1492,7 @@ type Germinating @entity { type UnripeToken @entity { "Token Address" - id: ID! + id: Bytes! "The ripe token underlying this unripe asset" underlyingToken: String! "The total amount of `underlyingToken` for this unripe token (getTotalUnderlying)" diff --git a/projects/subgraph-beanstalk/src/entities/Silo.ts b/projects/subgraph-beanstalk/src/entities/Silo.ts index 85bdc4c8de..f3c9848a7b 100644 --- a/projects/subgraph-beanstalk/src/entities/Silo.ts +++ b/projects/subgraph-beanstalk/src/entities/Silo.ts @@ -1,7 +1,17 @@ import { Address, BigInt, Bytes, ethereum, store, log } from "@graphprotocol/graph-ts"; -import { Silo, SiloDeposit, SiloWithdraw, SiloYield, SiloAsset, WhitelistTokenSetting, TokenYield } from "../../generated/schema"; -import { BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../subgraph-core/utils/Constants"; +import { + Silo, + SiloDeposit, + SiloWithdraw, + SiloYield, + SiloAsset, + WhitelistTokenSetting, + TokenYield, + UnripeToken +} from "../../generated/schema"; +import { BEANSTALK, UNRIPE_BEAN, UNRIPE_LP } from "../../../subgraph-core/utils/Constants"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { getUnripeUnderlying } from "../utils/Constants"; /* ===== Base Silo Entities ===== */ @@ -74,7 +84,7 @@ export function loadWhitelistTokenSetting(token: Address): WhitelistTokenSetting setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); setting.stalkEarnedPerSeason = BigInt.fromI32(2000000); setting.save(); - } else if (token == UNRIPE_BEAN_3CRV) { + } else if (token == UNRIPE_LP) { setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); setting.stalkEarnedPerSeason = BigInt.fromI32(4000000); setting.save(); @@ -83,6 +93,28 @@ export function loadWhitelistTokenSetting(token: Address): WhitelistTokenSetting return setting as WhitelistTokenSetting; } +/* ===== Unripe Entities ===== */ + +export function loadUnripeToken(token: Address): UnripeToken { + let unripe = UnripeToken.load(token); + if (unripe == null) { + unripe = new UnripeToken(token); + unripe.underlyingToken = getUnripeUnderlying(token, ZERO_BI).toHexString(); + unripe.totalUnderlying = ZERO_BI; + unripe.amountUnderlyingOne = ZERO_BI; + unripe.bdvUnderlyingOne = ZERO_BI; + unripe.choppableAmountOne = ZERO_BI; + unripe.choppableBdvOne = ZERO_BI; + unripe.chopRate = ZERO_BD; + unripe.recapPercent = ZERO_BD; + unripe.totalChoppedAmount = ZERO_BI; + unripe.totalChoppedBdv = ZERO_BI; + unripe.totalChoppedBdvReceived = ZERO_BI; + unripe.save(); + } + return unripe as UnripeToken; +} + /* ===== Deposit Entities ===== */ class SiloDepositID { diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 2e62eb9478..18aabbddd9 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -1,10 +1,11 @@ import { Address, BigInt, log } from "@graphprotocol/graph-ts"; import { Chop as ChopEntity } from "../../generated/schema"; -import { Chop } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { ChangeUnderlying, Chop } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { TransferSingle, TransferBatch } from "../../generated/Beanstalk-ABIs/Fertilizer"; import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; import { loadFarmer } from "../entities/Beanstalk"; +import { loadUnripeToken } from "../entities/Silo"; export function handleTransferSingle(event: TransferSingle): void { handleTransfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); @@ -18,6 +19,14 @@ export function handleTransferBatch(event: TransferBatch): void { } } +export function handleChangeUnderlying(event: ChangeUnderlying): void { + const unripe = loadUnripeToken(event.params.token); + unripe.totalUnderlying = unripe.totalUnderlying.plus(event.params.underlying); + // TODO: investigate whether other things need to get calculated, such as recap/bdv/choppable etc. + // TODO: snapshot here + unripe.save(); +} + export function handleChop(event: Chop): void { let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); let chop = new ChopEntity(id); diff --git a/projects/subgraph-beanstalk/src/utils/Constants.ts b/projects/subgraph-beanstalk/src/utils/Constants.ts index 479a027c30..f811337a55 100644 --- a/projects/subgraph-beanstalk/src/utils/Constants.ts +++ b/projects/subgraph-beanstalk/src/utils/Constants.ts @@ -1,5 +1,16 @@ -import { Address } from "@graphprotocol/graph-ts"; -import { BEAN_ERC20, BEANSTALK, FERTILIZER } from "../../../subgraph-core/utils/Constants"; +import { Address, BigInt } from "@graphprotocol/graph-ts"; +import { + BEAN_3CRV, + BEAN_ERC20, + BEAN_WETH_CP2_WELL, + BEAN_WETH_UNRIPE_MIGRATION_BLOCK, + BEAN_WSTETH_CP2_WELL, + BEAN_WSTETH_UNRIPE_MIGRATION_BLOCK, + BEANSTALK, + FERTILIZER, + UNRIPE_BEAN, + UNRIPE_LP +} from "../../../subgraph-core/utils/Constants"; export function getProtocolToken(protocol: Address): Address { if (protocol == BEANSTALK) { @@ -21,3 +32,18 @@ export function getFertilizerProtocol(fertilizer: Address): Address { } throw new Error("Unsupported fertilizer"); } + +export function getUnripeUnderlying(unripeToken: Address, blockNumber: BigInt): Address { + if (unripeToken == UNRIPE_BEAN) { + return BEAN_ERC20; + } else if (unripeToken == UNRIPE_LP) { + if (blockNumber < BEAN_WETH_UNRIPE_MIGRATION_BLOCK) { + return BEAN_3CRV; + } else if (blockNumber < BEAN_WSTETH_UNRIPE_MIGRATION_BLOCK) { + return BEAN_WETH_CP2_WELL; + } else { + return BEAN_WSTETH_CP2_WELL; + } + } + throw new Error("Unsupported unripe token"); +} diff --git a/projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts b/projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts index 106effc3bf..902490fbf0 100644 --- a/projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts +++ b/projects/subgraph-beanstalk/src/utils/contracts/SiloCalculations.ts @@ -1,5 +1,5 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; -import { BEAN_3CRV, BEAN_ERC20, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../../../subgraph-core/utils/Constants"; +import { BEAN_3CRV, BEAN_ERC20, UNRIPE_BEAN, UNRIPE_LP } from "../../../../subgraph-core/utils/Constants"; import { BI_10 } from "../../../../subgraph-core/utils/Decimals"; const STEM_START_SEASON = 14210; @@ -19,7 +19,7 @@ function getLegacySeedsPerToken(token: Address): i32 { return 2; } else if (token == UNRIPE_BEAN) { return 2; - } else if (token == UNRIPE_BEAN_3CRV) { + } else if (token == UNRIPE_LP) { return 4; } else if (token == BEAN_3CRV) { return 4; diff --git a/projects/subgraph-beanstalk/tests/Silo.test.ts b/projects/subgraph-beanstalk/tests/Silo.test.ts index ac532535e0..6b3fb9a5e0 100644 --- a/projects/subgraph-beanstalk/tests/Silo.test.ts +++ b/projects/subgraph-beanstalk/tests/Silo.test.ts @@ -8,7 +8,7 @@ import { GAUGE_BIP45_BLOCK, LUSD_3POOL, UNRIPE_BEAN, - UNRIPE_BEAN_3CRV + UNRIPE_LP } from "../../subgraph-core/utils/Constants"; import { createAddDepositV2Event, @@ -301,5 +301,5 @@ test("Legacy stem calculation", () => { assert.bigIntEquals(BigInt.fromI64(-5528000000), stemFromSeason(11446, BEAN_ERC20)); assert.bigIntEquals(BigInt.fromI64(-31556000000), stemFromSeason(6321, BEAN_3CRV)); assert.bigIntEquals(BigInt.fromI64(-16272000000), stemFromSeason(6074, UNRIPE_BEAN)); - assert.bigIntEquals(BigInt.fromI64(-32684000000), stemFromSeason(6039, UNRIPE_BEAN_3CRV)); + assert.bigIntEquals(BigInt.fromI64(-32684000000), stemFromSeason(6039, UNRIPE_LP)); }); diff --git a/projects/subgraph-beanstalk/tests/Yield.test.ts b/projects/subgraph-beanstalk/tests/Yield.test.ts index ccff8b89ea..088c92e434 100644 --- a/projects/subgraph-beanstalk/tests/Yield.test.ts +++ b/projects/subgraph-beanstalk/tests/Yield.test.ts @@ -8,7 +8,7 @@ import { BEAN_WETH_CP2_WELL, BEANSTALK, UNRIPE_BEAN, - UNRIPE_BEAN_3CRV, + UNRIPE_LP, LUSD_3POOL } from "../../subgraph-core/utils/Constants"; import { setSeason } from "./utils/Season"; @@ -152,7 +152,7 @@ describe("APY Calculations", () => { BEAN_ERC20.toHexString(), BEAN_WETH_CP2_WELL.toHexString(), UNRIPE_BEAN.toHexString(), - UNRIPE_BEAN_3CRV.toHexString() + UNRIPE_LP.toHexString() ]; silo.dewhitelistedTokens = [BEAN_3CRV.toHexString()]; silo.save(); @@ -175,7 +175,7 @@ describe("APY Calculations", () => { urbeanWhitelistSettings.stalkEarnedPerSeason = ZERO_BI; urbeanWhitelistSettings.save(); - let urlpWhitelistSettings = loadWhitelistTokenSetting(UNRIPE_BEAN_3CRV); + let urlpWhitelistSettings = loadWhitelistTokenSetting(UNRIPE_LP); urlpWhitelistSettings.stalkEarnedPerSeason = ZERO_BI; urlpWhitelistSettings.save(); @@ -196,7 +196,7 @@ describe("APY Calculations", () => { urbeanSiloAsset.depositedBDV = BigInt.fromString("19556945000000"); urbeanSiloAsset.save(); - let urlpSiloAsset = loadSiloAsset(BEANSTALK, UNRIPE_BEAN_3CRV); + let urlpSiloAsset = loadSiloAsset(BEANSTALK, UNRIPE_LP); urlpSiloAsset.depositedBDV = BigInt.fromString("24417908000000"); urlpSiloAsset.save(); diff --git a/projects/subgraph-core/utils/Constants.ts b/projects/subgraph-core/utils/Constants.ts index 77ab5ff2d4..c2b3da1dd3 100644 --- a/projects/subgraph-core/utils/Constants.ts +++ b/projects/subgraph-core/utils/Constants.ts @@ -7,8 +7,8 @@ export const ADDRESS_ZERO = Address.fromString("0x000000000000000000000000000000 export const BEAN_ERC20_V1 = Address.fromString("0xDC59ac4FeFa32293A95889Dc396682858d52e5Db"); export const BEAN_ERC20 = Address.fromString("0xBEA0000029AD1c77D3d5D23Ba2D8893dB9d1Efab"); export const UNRIPE_BEAN = Address.fromString("0x1bea0050e63e05fbb5d8ba2f10cf5800b6224449"); +export const UNRIPE_LP = Address.fromString("0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D"); export const BEAN_3CRV = Address.fromString("0xc9C32cd16Bf7eFB85Ff14e0c8603cc90F6F2eE49"); -export const UNRIPE_BEAN_3CRV = Address.fromString("0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D"); export const BEANSTALK_FARMS = Address.fromString("0x21de18b6a8f78ede6d16c50a167f6b222dc08df7"); export const WETH = Address.fromString("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); export const LUSD = Address.fromString("0x5f98805A4E8be255a32880FDeC7F6728C6568bA0"); From 6149dd397ed2375c8db7485848dcb8053b8ae0aa Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:06:05 -0700 Subject: [PATCH 35/59] unripe snapshots --- .../src/entities/snapshots/UnripeToken.ts | 148 ++++++++++++++++++ .../src/handlers/BarnHandler.ts | 3 +- 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts b/projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts new file mode 100644 index 0000000000..701d06cbd1 --- /dev/null +++ b/projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts @@ -0,0 +1,148 @@ +import { BigInt, Address, log } from "@graphprotocol/graph-ts"; +import { UnripeToken, UnripeTokenDailySnapshot, UnripeTokenHourlySnapshot } from "../../../generated/schema"; +import { getCurrentSeason } from "../Beanstalk"; +import { dayFromTimestamp, hourFromTimestamp } from "../../../../subgraph-core/utils/Dates"; + +export function takeUnripeTokenSnapshots(unripeToken: UnripeToken, protocol: Address, timestamp: BigInt): void { + const currentSeason = getCurrentSeason(protocol); + + const hour = BigInt.fromI32(hourFromTimestamp(timestamp)); + const day = BigInt.fromI32(dayFromTimestamp(timestamp)); + + // Load the snapshot for this season/day + const hourlyId = unripeToken.id + "-" + currentSeason.toString(); + const dailyId = unripeToken.id + "-" + day.toString(); + let baseHourly = UnripeTokenHourlySnapshot.load(hourlyId); + let baseDaily = UnripeTokenDailySnapshot.load(dailyId); + if (baseHourly == null && unripeToken.lastHourlySnapshotSeason !== 0) { + baseHourly = UnripeTokenHourlySnapshot.load(unripeToken.id + "-" + unripeToken.lastHourlySnapshotSeason.toString()); + } + if (baseDaily == null && unripeToken.lastDailySnapshotDay !== null) { + baseDaily = UnripeTokenDailySnapshot.load(unripeToken.id + "-" + unripeToken.lastDailySnapshotDay!.toString()); + } + const hourly = new UnripeTokenHourlySnapshot(hourlyId); + const daily = new UnripeTokenDailySnapshot(dailyId); + + // Set current values + hourly.season = currentSeason; + hourly.unripeToken = unripeToken.id; + hourly.underlyingToken = unripeToken.underlyingToken; + hourly.totalUnderlying = unripeToken.totalUnderlying; + hourly.amountUnderlyingOne = unripeToken.amountUnderlyingOne; + hourly.bdvUnderlyingOne = unripeToken.bdvUnderlyingOne; + hourly.choppableAmountOne = unripeToken.choppableAmountOne; + hourly.choppableBdvOne = unripeToken.choppableBdvOne; + hourly.chopRate = unripeToken.chopRate; + hourly.recapPercent = unripeToken.recapPercent; + hourly.totalChoppedAmount = unripeToken.totalChoppedAmount; + hourly.totalChoppedBdv = unripeToken.totalChoppedBdv; + hourly.totalChoppedBdvReceived = unripeToken.totalChoppedBdvReceived; + + // Set deltas + if (baseHourly !== null) { + hourly.deltaUnderlyingToken = hourly.underlyingToken != baseHourly.underlyingToken; + hourly.deltaTotalUnderlying = hourly.totalUnderlying.minus(baseHourly.totalUnderlying); + hourly.deltaAmountUnderlyingOne = hourly.amountUnderlyingOne.minus(baseHourly.amountUnderlyingOne); + hourly.deltaBdvUnderlyingOne = hourly.bdvUnderlyingOne.minus(baseHourly.bdvUnderlyingOne); + hourly.deltaChoppableAmountOne = hourly.choppableAmountOne.minus(baseHourly.choppableAmountOne); + hourly.deltaChoppableBdvOne = hourly.choppableBdvOne.minus(baseHourly.choppableBdvOne); + hourly.deltaChopRate = hourly.chopRate.minus(baseHourly.chopRate); + hourly.deltaRecapPercent = hourly.recapPercent.minus(baseHourly.recapPercent); + hourly.deltaTotalChoppedAmount = hourly.totalChoppedAmount.minus(baseHourly.totalChoppedAmount); + hourly.deltaTotalChoppedBdv = hourly.totalChoppedBdv.minus(baseHourly.totalChoppedBdv); + hourly.deltaTotalChoppedBdvReceived = hourly.totalChoppedBdvReceived.minus(baseHourly.totalChoppedBdvReceived); + + if (hourly.id == baseHourly.id) { + // Add existing deltas + hourly.deltaUnderlyingToken = hourly.deltaUnderlyingToken || baseHourly.deltaUnderlyingToken; + hourly.deltaTotalUnderlying = hourly.deltaTotalUnderlying.plus(baseHourly.deltaTotalUnderlying); + hourly.deltaAmountUnderlyingOne = hourly.deltaAmountUnderlyingOne.plus(baseHourly.deltaAmountUnderlyingOne); + hourly.deltaBdvUnderlyingOne = hourly.deltaBdvUnderlyingOne.plus(baseHourly.deltaBdvUnderlyingOne); + hourly.deltaChoppableAmountOne = hourly.deltaChoppableAmountOne.plus(baseHourly.deltaChoppableAmountOne); + hourly.deltaChoppableBdvOne = hourly.deltaChoppableBdvOne.plus(baseHourly.deltaChoppableBdvOne); + hourly.deltaChopRate = hourly.deltaChopRate.plus(baseHourly.deltaChopRate); + hourly.deltaRecapPercent = hourly.deltaRecapPercent.plus(baseHourly.deltaRecapPercent); + hourly.deltaTotalChoppedAmount = hourly.deltaTotalChoppedAmount.plus(baseHourly.deltaTotalChoppedAmount); + hourly.deltaTotalChoppedBdv = hourly.deltaTotalChoppedBdv.plus(baseHourly.deltaTotalChoppedBdv); + hourly.deltaTotalChoppedBdvReceived = hourly.deltaTotalChoppedBdvReceived.plus(baseHourly.deltaTotalChoppedBdvReceived); + } + } else { + hourly.deltaUnderlyingToken = false; + hourly.deltaTotalUnderlying = hourly.totalUnderlying; + hourly.deltaAmountUnderlyingOne = hourly.amountUnderlyingOne; + hourly.deltaBdvUnderlyingOne = hourly.bdvUnderlyingOne; + hourly.deltaChoppableAmountOne = hourly.choppableAmountOne; + hourly.deltaChoppableBdvOne = hourly.choppableBdvOne; + hourly.deltaChopRate = hourly.chopRate; + hourly.deltaRecapPercent = hourly.recapPercent; + hourly.deltaTotalChoppedAmount = hourly.totalChoppedAmount; + hourly.deltaTotalChoppedBdv = hourly.totalChoppedBdv; + hourly.deltaTotalChoppedBdvReceived = hourly.totalChoppedBdvReceived; + } + hourly.createdAt = hour; + hourly.updatedAt = timestamp; + hourly.save(); + + // Repeat for daily snapshot. + // Duplicate code is preferred to type coercion, the codegen doesnt provide a common interface. + + daily.season = currentSeason; + daily.unripeToken = unripeToken.id; + daily.underlyingToken = unripeToken.underlyingToken; + daily.totalUnderlying = unripeToken.totalUnderlying; + daily.amountUnderlyingOne = unripeToken.amountUnderlyingOne; + daily.bdvUnderlyingOne = unripeToken.bdvUnderlyingOne; + daily.choppableAmountOne = unripeToken.choppableAmountOne; + daily.choppableBdvOne = unripeToken.choppableBdvOne; + daily.chopRate = unripeToken.chopRate; + daily.recapPercent = unripeToken.recapPercent; + daily.totalChoppedAmount = unripeToken.totalChoppedAmount; + daily.totalChoppedBdv = unripeToken.totalChoppedBdv; + daily.totalChoppedBdvReceived = unripeToken.totalChoppedBdvReceived; + if (baseDaily !== null) { + daily.deltaUnderlyingToken = daily.underlyingToken != baseDaily.underlyingToken; + daily.deltaTotalUnderlying = daily.totalUnderlying.minus(baseDaily.totalUnderlying); + daily.deltaAmountUnderlyingOne = daily.amountUnderlyingOne.minus(baseDaily.amountUnderlyingOne); + daily.deltaBdvUnderlyingOne = daily.bdvUnderlyingOne.minus(baseDaily.bdvUnderlyingOne); + daily.deltaChoppableAmountOne = daily.choppableAmountOne.minus(baseDaily.choppableAmountOne); + daily.deltaChoppableBdvOne = daily.choppableBdvOne.minus(baseDaily.choppableBdvOne); + daily.deltaChopRate = daily.chopRate.minus(baseDaily.chopRate); + daily.deltaRecapPercent = daily.recapPercent.minus(baseDaily.recapPercent); + daily.deltaTotalChoppedAmount = daily.totalChoppedAmount.minus(baseDaily.totalChoppedAmount); + daily.deltaTotalChoppedBdv = daily.totalChoppedBdv.minus(baseDaily.totalChoppedBdv); + daily.deltaTotalChoppedBdvReceived = daily.totalChoppedBdvReceived.minus(baseDaily.totalChoppedBdvReceived); + + if (daily.id == baseDaily.id) { + // Add existing deltas + daily.deltaUnderlyingToken = daily.deltaUnderlyingToken || baseDaily.deltaUnderlyingToken; + daily.deltaTotalUnderlying = daily.deltaTotalUnderlying.plus(baseDaily.deltaTotalUnderlying); + daily.deltaAmountUnderlyingOne = daily.deltaAmountUnderlyingOne.plus(baseDaily.deltaAmountUnderlyingOne); + daily.deltaBdvUnderlyingOne = daily.deltaBdvUnderlyingOne.plus(baseDaily.deltaBdvUnderlyingOne); + daily.deltaChoppableAmountOne = daily.deltaChoppableAmountOne.plus(baseDaily.deltaChoppableAmountOne); + daily.deltaChoppableBdvOne = daily.deltaChoppableBdvOne.plus(baseDaily.deltaChoppableBdvOne); + daily.deltaChopRate = daily.deltaChopRate.plus(baseDaily.deltaChopRate); + daily.deltaRecapPercent = daily.deltaRecapPercent.plus(baseDaily.deltaRecapPercent); + daily.deltaTotalChoppedAmount = daily.deltaTotalChoppedAmount.plus(baseDaily.deltaTotalChoppedAmount); + daily.deltaTotalChoppedBdv = daily.deltaTotalChoppedBdv.plus(baseDaily.deltaTotalChoppedBdv); + daily.deltaTotalChoppedBdvReceived = daily.deltaTotalChoppedBdvReceived.plus(baseDaily.deltaTotalChoppedBdvReceived); + } + } else { + daily.deltaUnderlyingToken = false; + daily.deltaTotalUnderlying = daily.totalUnderlying; + daily.deltaAmountUnderlyingOne = daily.amountUnderlyingOne; + daily.deltaBdvUnderlyingOne = daily.bdvUnderlyingOne; + daily.deltaChoppableAmountOne = daily.choppableAmountOne; + daily.deltaChoppableBdvOne = daily.choppableBdvOne; + daily.deltaChopRate = daily.chopRate; + daily.deltaRecapPercent = daily.recapPercent; + daily.deltaTotalChoppedAmount = daily.totalChoppedAmount; + daily.deltaTotalChoppedBdv = daily.totalChoppedBdv; + daily.deltaTotalChoppedBdvReceived = daily.totalChoppedBdvReceived; + } + daily.createdAt = day; + daily.updatedAt = timestamp; + daily.save(); + + unripeToken.lastHourlySnapshotSeason = currentSeason; + unripeToken.lastDailySnapshotDay = day; +} diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 18aabbddd9..9620fa1ea9 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -6,6 +6,7 @@ import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; import { loadFarmer } from "../entities/Beanstalk"; import { loadUnripeToken } from "../entities/Silo"; +import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; export function handleTransferSingle(event: TransferSingle): void { handleTransfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); @@ -23,7 +24,7 @@ export function handleChangeUnderlying(event: ChangeUnderlying): void { const unripe = loadUnripeToken(event.params.token); unripe.totalUnderlying = unripe.totalUnderlying.plus(event.params.underlying); // TODO: investigate whether other things need to get calculated, such as recap/bdv/choppable etc. - // TODO: snapshot here + takeUnripeTokenSnapshots(unripe, event.address, event.block.timestamp); unripe.save(); } From 038aeb987ff06c4eb2e5a5791b9a9849964c7c58 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:31:01 -0700 Subject: [PATCH 36/59] add bdv to whitelist hourly/daily --- projects/subgraph-beanstalk/schema.graphql | 14 +++++++++ .../subgraph-beanstalk/src/entities/Silo.ts | 7 ++--- .../src/entities/snapshots/Field.ts | 10 +++---- .../src/entities/snapshots/Silo.ts | 5 ++-- .../snapshots/WhitelistTokenSetting.ts | 20 +++++++++++++ .../src/handlers/BarnHandler.ts | 29 ++----------------- .../src/handlers/GaugeHandler.ts | 2 +- .../src/handlers/SeasonHandler.ts | 2 +- projects/subgraph-beanstalk/src/utils/Barn.ts | 25 ++++++++++++++++ .../subgraph-beanstalk/src/utils/Constants.ts | 20 +++++++++++++ .../subgraph-beanstalk/src/utils/Field.ts | 4 +-- .../subgraph-beanstalk/src/utils/Season.ts | 29 ++++++++++++++++--- projects/subgraph-beanstalk/src/utils/Silo.ts | 2 ++ 13 files changed, 122 insertions(+), 47 deletions(-) create mode 100644 projects/subgraph-beanstalk/src/utils/Barn.ts diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 2f2d9c0c61..5ab03134c1 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -360,6 +360,10 @@ type WhitelistTokenSetting @entity { hourlySnapshots: [WhitelistTokenHourlySnapshot!]! @derivedFrom(field: "token") "Link to daily snapshot data" dailySnapshots: [WhitelistTokenDailySnapshot!]! @derivedFrom(field: "token") + + # Unique to the main entity, not on dailySnapshots + "Number of decimals in this token" + decimals: Int! } type WhitelistTokenHourlySnapshot @entity { @@ -396,6 +400,11 @@ type WhitelistTokenHourlySnapshot @entity { createdAt: BigInt! "Timestamp of last entity update" updatedAt: BigInt! + + # These are unique to the snapshot, and not on the main entity + "Point in time hourly bdv" + bdv: BigInt + deltaBdv: BigInt } type WhitelistTokenDailySnapshot @entity { @@ -432,6 +441,11 @@ type WhitelistTokenDailySnapshot @entity { createdAt: BigInt! "Timestamp of last entity update" updatedAt: BigInt! + + # These are unique to the snapshot, and not on the main entity + "Point in time daily bdv" + bdv: BigInt + deltaBdv: BigInt } type Field @entity { diff --git a/projects/subgraph-beanstalk/src/entities/Silo.ts b/projects/subgraph-beanstalk/src/entities/Silo.ts index f3c9848a7b..8900c919e5 100644 --- a/projects/subgraph-beanstalk/src/entities/Silo.ts +++ b/projects/subgraph-beanstalk/src/entities/Silo.ts @@ -11,7 +11,7 @@ import { } from "../../generated/schema"; import { BEANSTALK, UNRIPE_BEAN, UNRIPE_LP } from "../../../subgraph-core/utils/Constants"; import { ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { getUnripeUnderlying } from "../utils/Constants"; +import { getTokenDecimals, getUnripeUnderlying } from "../utils/Constants"; /* ===== Base Silo Entities ===== */ @@ -76,19 +76,18 @@ export function loadWhitelistTokenSetting(token: Address): WhitelistTokenSetting setting.stalkEarnedPerSeason = ZERO_BI; setting.stalkIssuedPerBdv = ZERO_BI; setting.milestoneSeason = 0; + setting.decimals = getTokenDecimals(token); setting.updatedAt = ZERO_BI; - setting.save(); // Check token addresses and set replant seeds/stalk for Unripe due to event timing. if (token == UNRIPE_BEAN) { setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); setting.stalkEarnedPerSeason = BigInt.fromI32(2000000); - setting.save(); } else if (token == UNRIPE_LP) { setting.stalkIssuedPerBdv = BigInt.fromString("10000000000"); setting.stalkEarnedPerSeason = BigInt.fromI32(4000000); - setting.save(); } + setting.save(); } return setting as WhitelistTokenSetting; } diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/Field.ts b/projects/subgraph-beanstalk/src/entities/snapshots/Field.ts index e94fd9f926..d33671c2ed 100644 --- a/projects/subgraph-beanstalk/src/entities/snapshots/Field.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/Field.ts @@ -182,17 +182,15 @@ export function takeFieldSnapshots(field: Field, protocol: Address, timestamp: B } // Set case id on hourly. Snapshot must have already been created. -export function setFieldHourlyCaseId(caseId: BigInt, field: Field, protocol: Address): void { - const currentSeason = getCurrentSeason(protocol); - const hourly = FieldHourlySnapshot.load(field.id + "-" + currentSeason.toString())!; +export function setFieldHourlyCaseId(caseId: BigInt, field: Field): void { + const hourly = FieldHourlySnapshot.load(field.id + "-" + field.lastHourlySnapshotSeason.toString())!; hourly.caseId = caseId; hourly.save(); } // Set soil sold out info on the hourly. Snapshot must have already been created. -export function setHourlySoilSoldOut(soldOutBlock: BigInt, field: Field, protocol: Address): void { - const currentSeason = getCurrentSeason(protocol); - const hourly = FieldHourlySnapshot.load(field.id + "-" + currentSeason.toString())!; +export function setHourlySoilSoldOut(soldOutBlock: BigInt, field: Field): void { + const hourly = FieldHourlySnapshot.load(field.id + "-" + field.lastHourlySnapshotSeason.toString())!; hourly.blocksToSoldOutSoil = soldOutBlock.minus(hourly.seasonBlock); hourly.soilSoldOut = true; hourly.save(); diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/Silo.ts b/projects/subgraph-beanstalk/src/entities/snapshots/Silo.ts index c9845b96bb..a0d06279f9 100644 --- a/projects/subgraph-beanstalk/src/entities/snapshots/Silo.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/Silo.ts @@ -134,9 +134,8 @@ export function takeSiloSnapshots(silo: Silo, protocol: Address, timestamp: BigI } // Set case id on hourly snapshot. Snapshot must have already been created. -export function setSiloHourlyCaseId(caseId: BigInt, silo: Silo, protocol: Address): void { - const currentSeason = getCurrentSeason(protocol); - const hourly = SiloHourlySnapshot.load(silo.id + "-" + currentSeason.toString())!; +export function setSiloHourlyCaseId(caseId: BigInt, silo: Silo): void { + const hourly = SiloHourlySnapshot.load(silo.id + "-" + silo.lastHourlySnapshotSeason.toString())!; hourly.caseId = caseId; hourly.save(); } diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts index e28a0ef88d..b7cebe6585 100644 --- a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts @@ -144,3 +144,23 @@ export function takeWhitelistTokenSettingSnapshots( whitelistTokenSetting.lastHourlySnapshotSeason = currentSeason; whitelistTokenSetting.lastDailySnapshotDay = day; } + +// Set bdv on hourly and daily. Snapshots must have already been created. +export function setBdv(bdv: BigInt, whitelistTokenSetting: WhitelistTokenSetting): void { + const hourly = WhitelistTokenHourlySnapshot.load( + whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() + )!; + const daily = WhitelistTokenDailySnapshot.load(whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastDailySnapshotDay!.toString())!; + hourly.bdv = bdv; + daily.bdv = bdv; + hourly.save(); + daily.save(); +} + +// Returns the latest hourly bdv for the requested token. Can be null if bdv function isnt implemented onchain yet. +export function getLatestBdv(whitelistTokenSetting: WhitelistTokenSetting): BigInt | null { + const hourly = WhitelistTokenHourlySnapshot.load( + whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() + )!; + return hourly.bdv; +} diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 9620fa1ea9..1e9386fba6 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -2,21 +2,19 @@ import { Address, BigInt, log } from "@graphprotocol/graph-ts"; import { Chop as ChopEntity } from "../../generated/schema"; import { ChangeUnderlying, Chop } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { TransferSingle, TransferBatch } from "../../generated/Beanstalk-ABIs/Fertilizer"; -import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; -import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; -import { loadFarmer } from "../entities/Beanstalk"; import { loadUnripeToken } from "../entities/Silo"; import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; +import { transfer } from "../utils/Barn"; export function handleTransferSingle(event: TransferSingle): void { - handleTransfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); + transfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); } export function handleTransferBatch(event: TransferBatch): void { for (let i = 0; i < event.params.ids.length; i++) { let id = event.params.ids[i]; let amount = event.params.values[i]; - handleTransfer(event.address, event.params.from, event.params.to, id, amount, event.block.number); + transfer(event.address, event.params.from, event.params.to, id, amount, event.block.number); } } @@ -42,24 +40,3 @@ export function handleChop(event: Chop): void { chop.createdAt = event.block.timestamp; chop.save(); } - -function handleTransfer(fertilizer1155: Address, from: Address, to: Address, id: BigInt, amount: BigInt, blockNumber: BigInt): void { - let fertilizer = loadFertilizer(fertilizer1155); - let fertilizerToken = loadFertilizerToken(fertilizer, id, blockNumber); - if (from != ADDRESS_ZERO) { - let fromFarmer = loadFarmer(from); - let fromFertilizerBalance = loadFertilizerBalance(fertilizerToken, fromFarmer); - fromFertilizerBalance.amount = fromFertilizerBalance.amount.minus(amount); - fromFertilizerBalance.save(); - } else { - fertilizerToken.supply = fertilizerToken.supply.plus(amount); - fertilizer.supply = fertilizer.supply.plus(amount); - fertilizer.save(); - fertilizerToken.save(); - } - - let toFarmer = loadFarmer(to); - let toFertilizerBalance = loadFertilizerBalance(fertilizerToken, toFarmer); - toFertilizerBalance.amount = toFertilizerBalance.amount.plus(amount); - toFertilizerBalance.save(); -} diff --git a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts index 7a0d5af7ba..30401b4dba 100644 --- a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts @@ -29,7 +29,7 @@ export function handleBeanToMaxLpGpPerBdvRatioChange(event: BeanToMaxLpGpPerBdvR silo.beanToMaxLpGpPerBdvRatio = silo.beanToMaxLpGpPerBdvRatio!.plus(event.params.absChange); } takeSiloSnapshots(silo, event.address, event.block.timestamp); - setSiloHourlyCaseId(event.params.caseId, silo, event.address); + setSiloHourlyCaseId(event.params.caseId, silo); silo.save(); } diff --git a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts index e97f3a1431..16f005acd2 100644 --- a/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SeasonHandler.ts @@ -1,7 +1,7 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; import { Reward, Soil, WellOracle, Sunrise, Incentivization, SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { BEANSTALK, GAUGE_BIP45_BLOCK, REPLANT_SEASON } from "../../../subgraph-core/utils/Constants"; -import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { toDecimal, ZERO_BD } from "../../../subgraph-core/utils/Decimals"; import { updateStalkWithCalls } from "../utils/legacy/LegacySilo"; import { loadBeanstalk, loadSeason } from "../entities/Beanstalk"; import { loadSilo } from "../entities/Silo"; diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts new file mode 100644 index 0000000000..c982786b25 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -0,0 +1,25 @@ +import { Address, BigInt, log } from "@graphprotocol/graph-ts"; +import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; +import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; +import { loadFarmer } from "../entities/Beanstalk"; + +export function transfer(fertilizer1155: Address, from: Address, to: Address, id: BigInt, amount: BigInt, blockNumber: BigInt): void { + let fertilizer = loadFertilizer(fertilizer1155); + let fertilizerToken = loadFertilizerToken(fertilizer, id, blockNumber); + if (from != ADDRESS_ZERO) { + let fromFarmer = loadFarmer(from); + let fromFertilizerBalance = loadFertilizerBalance(fertilizerToken, fromFarmer); + fromFertilizerBalance.amount = fromFertilizerBalance.amount.minus(amount); + fromFertilizerBalance.save(); + } else { + fertilizerToken.supply = fertilizerToken.supply.plus(amount); + fertilizer.supply = fertilizer.supply.plus(amount); + fertilizer.save(); + fertilizerToken.save(); + } + + let toFarmer = loadFarmer(to); + let toFertilizerBalance = loadFertilizerBalance(fertilizerToken, toFarmer); + toFertilizerBalance.amount = toFertilizerBalance.amount.plus(amount); + toFertilizerBalance.save(); +} diff --git a/projects/subgraph-beanstalk/src/utils/Constants.ts b/projects/subgraph-beanstalk/src/utils/Constants.ts index f811337a55..4ec609546f 100644 --- a/projects/subgraph-beanstalk/src/utils/Constants.ts +++ b/projects/subgraph-beanstalk/src/utils/Constants.ts @@ -1,9 +1,13 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; import { BEAN_3CRV, + BEAN_3CRV_V1, BEAN_ERC20, + BEAN_ERC20_V1, + BEAN_LUSD_V1, BEAN_WETH_CP2_WELL, BEAN_WETH_UNRIPE_MIGRATION_BLOCK, + BEAN_WETH_V1, BEAN_WSTETH_CP2_WELL, BEAN_WSTETH_UNRIPE_MIGRATION_BLOCK, BEANSTALK, @@ -47,3 +51,19 @@ export function getUnripeUnderlying(unripeToken: Address, blockNumber: BigInt): } throw new Error("Unsupported unripe token"); } + +// TODO: fill this in +export function getTokenDecimals(token: Address): i32 { + if (token == BEAN_ERC20) { + } else if (token == UNRIPE_BEAN) { + } else if (token == UNRIPE_LP) { + } else if (token == BEAN_3CRV) { + } else if (token == BEAN_WETH_CP2_WELL) { + } else if (token == BEAN_WSTETH_CP2_WELL) { + } else if (token == BEAN_ERC20_V1) { + } else if (token == BEAN_WETH_V1) { + } else if (token == BEAN_3CRV_V1) { + } else if (token == BEAN_LUSD_V1) { + } + throw new Error("Unsupported token"); +} diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index 373299830f..da920707d7 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -432,7 +432,7 @@ export function temperatureChanged(params: TemperatureChangedParams): void { field.save(); // Set caseId on the hourly snapshot - setFieldHourlyCaseId(params.caseId, field, protocol); + setFieldHourlyCaseId(params.caseId, field); } export function updateFieldTotals( @@ -477,7 +477,7 @@ export function updateFieldTotals( // Set extra info on the hourly snapshot if (field.soil == ZERO_BI) { - setHourlySoilSoldOut(blockNumber, field, protocol); + setHourlySoilSoldOut(blockNumber, field); } } diff --git a/projects/subgraph-beanstalk/src/utils/Season.ts b/projects/subgraph-beanstalk/src/utils/Season.ts index 3eb8109d82..e277d71cf5 100644 --- a/projects/subgraph-beanstalk/src/utils/Season.ts +++ b/projects/subgraph-beanstalk/src/utils/Season.ts @@ -3,11 +3,14 @@ import { loadSeason } from "../entities/Beanstalk"; import { loadPodMarketplace } from "../entities/PodMarketplace"; import { takeMarketSnapshots } from "../entities/snapshots/Marketplace"; import { takeSiloSnapshots } from "../entities/snapshots/Silo"; -import { loadSilo, loadSiloAsset } from "../entities/Silo"; +import { loadSilo, loadSiloAsset, loadWhitelistTokenSetting } from "../entities/Silo"; import { takeSiloAssetSnapshots } from "../entities/snapshots/SiloAsset"; import { takeFieldSnapshots } from "../entities/snapshots/Field"; -import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { BI_10, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { loadField } from "../entities/Field"; +import { setBdv, takeWhitelistTokenSettingSnapshots } from "../entities/snapshots/WhitelistTokenSetting"; +import { WhitelistTokenSetting } from "../../generated/schema"; +import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; export function sunrise(protocol: Address, season: BigInt, block: ethereum.Block): void { let currentSeason = season.toI32(); @@ -35,10 +38,28 @@ export function sunrise(protocol: Address, season: BigInt, block: ethereum.Block // Create silo entities for the protocol let silo = loadSilo(protocol); takeSiloSnapshots(silo, protocol, block.timestamp); + silo.save(); + // TODO: include dewhitelsited for (let i = 0; i < silo.whitelistedTokens.length; i++) { - let siloAsset = loadSiloAsset(protocol, Address.fromString(silo.whitelistedTokens[i])); + const token = Address.fromString(silo.whitelistedTokens[i]); + + let siloAsset = loadSiloAsset(protocol, token); takeSiloAssetSnapshots(siloAsset, protocol, block.timestamp); siloAsset.save(); + + let whitelistTokenSetting = loadWhitelistTokenSetting(token); + takeWhitelistTokenSettingSnapshots(whitelistTokenSetting, protocol, block.timestamp); + whitelistTokenSetting.save(); + setTokenBdv(token, protocol, whitelistTokenSetting); } - silo.save(); +} + +function setTokenBdv(token: Address, protocol: Address, whitelistTokenSetting: WhitelistTokenSetting): void { + // Get bdv if the bdv function is available onchain (not available prior to BIP-16) + const beanstalk_call = SeedGauge.bind(protocol); + const bdvResult = beanstalk_call.try_bdv(token, BI_10.pow(whitelistTokenSetting.decimals)); + if (bdvResult.reverted) { + return; + } + setBdv(bdvResult.value, whitelistTokenSetting); } diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index 35976decc0..ddf63728ac 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -200,3 +200,5 @@ export function updateSeedsBalances(protocol: Address, account: Address, seeds: takeSiloSnapshots(silo, protocol, timestamp); silo.save(); } + +export function updateWhitelistdBdvs(protocol: Address): void {} From c42e627f767e35804ccebfdc39c279fde143a2d7 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:39:21 -0700 Subject: [PATCH 37/59] add token decimals --- projects/subgraph-beanstalk/src/utils/Constants.ts | 11 ++++++++++- projects/subgraph-beanstalk/src/utils/Season.ts | 8 +++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/projects/subgraph-beanstalk/src/utils/Constants.ts b/projects/subgraph-beanstalk/src/utils/Constants.ts index 4ec609546f..78f3c2a295 100644 --- a/projects/subgraph-beanstalk/src/utils/Constants.ts +++ b/projects/subgraph-beanstalk/src/utils/Constants.ts @@ -52,18 +52,27 @@ export function getUnripeUnderlying(unripeToken: Address, blockNumber: BigInt): throw new Error("Unsupported unripe token"); } -// TODO: fill this in export function getTokenDecimals(token: Address): i32 { if (token == BEAN_ERC20) { + return 6; } else if (token == UNRIPE_BEAN) { + return 6; } else if (token == UNRIPE_LP) { + return 6; } else if (token == BEAN_3CRV) { + return 18; } else if (token == BEAN_WETH_CP2_WELL) { + return 18; } else if (token == BEAN_WSTETH_CP2_WELL) { + return 18; } else if (token == BEAN_ERC20_V1) { + return 6; } else if (token == BEAN_WETH_V1) { + return 18; } else if (token == BEAN_3CRV_V1) { + return 18; } else if (token == BEAN_LUSD_V1) { + return 18; } throw new Error("Unsupported token"); } diff --git a/projects/subgraph-beanstalk/src/utils/Season.ts b/projects/subgraph-beanstalk/src/utils/Season.ts index e277d71cf5..2789b3b7bb 100644 --- a/projects/subgraph-beanstalk/src/utils/Season.ts +++ b/projects/subgraph-beanstalk/src/utils/Season.ts @@ -39,9 +39,11 @@ export function sunrise(protocol: Address, season: BigInt, block: ethereum.Block let silo = loadSilo(protocol); takeSiloSnapshots(silo, protocol, block.timestamp); silo.save(); - // TODO: include dewhitelsited - for (let i = 0; i < silo.whitelistedTokens.length; i++) { - const token = Address.fromString(silo.whitelistedTokens[i]); + + // Update all whitelisted/dewhitelisted token info + const siloTokens = silo.whitelistedTokens.concat(silo.dewhitelistedTokens); + for (let i = 0; i < siloTokens.length; i++) { + const token = Address.fromString(siloTokens[i]); let siloAsset = loadSiloAsset(protocol, token); takeSiloAssetSnapshots(siloAsset, protocol, block.timestamp); From 850c778431d8dd1a318b3f9aed4797d5d9351fa3 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:54:03 -0700 Subject: [PATCH 38/59] hourly unripe stats --- .../src/handlers/BarnHandler.ts | 8 +++-- projects/subgraph-beanstalk/src/utils/Barn.ts | 30 ++++++++++++++++++- .../subgraph-beanstalk/src/utils/Constants.ts | 10 +++++++ .../subgraph-beanstalk/src/utils/Season.ts | 6 ++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 1e9386fba6..16d2a064e8 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -4,7 +4,7 @@ import { ChangeUnderlying, Chop } from "../../generated/Beanstalk-ABIs/SeedGauge import { TransferSingle, TransferBatch } from "../../generated/Beanstalk-ABIs/Fertilizer"; import { loadUnripeToken } from "../entities/Silo"; import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; -import { transfer } from "../utils/Barn"; +import { transfer, updateUnripeStats } from "../utils/Barn"; export function handleTransferSingle(event: TransferSingle): void { transfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); @@ -21,9 +21,11 @@ export function handleTransferBatch(event: TransferBatch): void { export function handleChangeUnderlying(event: ChangeUnderlying): void { const unripe = loadUnripeToken(event.params.token); unripe.totalUnderlying = unripe.totalUnderlying.plus(event.params.underlying); - // TODO: investigate whether other things need to get calculated, such as recap/bdv/choppable etc. - takeUnripeTokenSnapshots(unripe, event.address, event.block.timestamp); + // Snapshots are taken in the below method, updateUnripeStats unripe.save(); + + // Update other stats using protocol getters + updateUnripeStats(unripe.id, event.address, event.block); } export function handleChop(event: Chop): void { diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts index c982786b25..19f2413e1b 100644 --- a/projects/subgraph-beanstalk/src/utils/Barn.ts +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -1,7 +1,13 @@ -import { Address, BigInt, log } from "@graphprotocol/graph-ts"; +import { Address, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; import { loadFarmer } from "../entities/Beanstalk"; +import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { loadUnripeToken, loadWhitelistTokenSetting } from "../entities/Silo"; +import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; +import { getUnripeUnderlying } from "./Constants"; +import { toDecimal } from "../../../subgraph-core/utils/Decimals"; +import { getLatestBdv } from "../entities/snapshots/WhitelistTokenSetting"; export function transfer(fertilizer1155: Address, from: Address, to: Address, id: BigInt, amount: BigInt, blockNumber: BigInt): void { let fertilizer = loadFertilizer(fertilizer1155); @@ -23,3 +29,25 @@ export function transfer(fertilizer1155: Address, from: Address, to: Address, id toFertilizerBalance.amount = toFertilizerBalance.amount.plus(amount); toFertilizerBalance.save(); } + +// Update the status for this unripe token using protocol getters. These values fluctuate without related events. +export function updateUnripeStats(unripe: Address, protocol: Address, block: ethereum.Block): void { + const beanstalk_call = SeedGauge.bind(protocol); + let unripeToken = loadUnripeToken(unripe); + + // Contract values + unripeToken.amountUnderlyingOne = beanstalk_call.getUnderlyingPerUnripeToken(unripe); + unripeToken.choppableAmountOne = beanstalk_call.getPenalty(unripe); + unripeToken.chopRate = toDecimal(beanstalk_call.getPercentPenalty(unripe)); + unripeToken.recapPercent = toDecimal(beanstalk_call.getRecapFundedPercent(unripe)); + + // Further calculated values + unripeToken.underlyingToken = getUnripeUnderlying(unripe, block.number).toHexString(); + const whitelistSetting = loadWhitelistTokenSetting(Address.fromString(unripeToken.underlyingToken)); + const underlyingBdvOne = getLatestBdv(whitelistSetting)!; + unripeToken.bdvUnderlyingOne = unripeToken.amountUnderlyingOne.times(underlyingBdvOne); + unripeToken.choppableBdvOne = unripeToken.choppableAmountOne.times(underlyingBdvOne); + + takeUnripeTokenSnapshots(unripeToken, protocol, block.timestamp); + unripeToken.save(); +} diff --git a/projects/subgraph-beanstalk/src/utils/Constants.ts b/projects/subgraph-beanstalk/src/utils/Constants.ts index 78f3c2a295..f79e2e929e 100644 --- a/projects/subgraph-beanstalk/src/utils/Constants.ts +++ b/projects/subgraph-beanstalk/src/utils/Constants.ts @@ -76,3 +76,13 @@ export function getTokenDecimals(token: Address): i32 { } throw new Error("Unsupported token"); } + +export function isUnripe(token: Address): boolean { + const unripeTokens = [UNRIPE_BEAN, UNRIPE_LP]; + for (let i = 0; i < unripeTokens.length; ++i) { + if (unripeTokens[i] == token) { + return true; + } + } + return false; +} diff --git a/projects/subgraph-beanstalk/src/utils/Season.ts b/projects/subgraph-beanstalk/src/utils/Season.ts index 2789b3b7bb..4364da832d 100644 --- a/projects/subgraph-beanstalk/src/utils/Season.ts +++ b/projects/subgraph-beanstalk/src/utils/Season.ts @@ -11,6 +11,8 @@ import { loadField } from "../entities/Field"; import { setBdv, takeWhitelistTokenSettingSnapshots } from "../entities/snapshots/WhitelistTokenSetting"; import { WhitelistTokenSetting } from "../../generated/schema"; import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { isUnripe } from "./Constants"; +import { updateUnripeStats } from "./Barn"; export function sunrise(protocol: Address, season: BigInt, block: ethereum.Block): void { let currentSeason = season.toI32(); @@ -53,6 +55,10 @@ export function sunrise(protocol: Address, season: BigInt, block: ethereum.Block takeWhitelistTokenSettingSnapshots(whitelistTokenSetting, protocol, block.timestamp); whitelistTokenSetting.save(); setTokenBdv(token, protocol, whitelistTokenSetting); + + if (isUnripe(token)) { + updateUnripeStats(token, protocol, block); + } } } From fc5e2aa6997d08fdf57e0791d49c4df1faddc9c7 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:06:12 -0700 Subject: [PATCH 39/59] chop stats upon chop --- .../src/handlers/BarnHandler.ts | 19 ++++++++++++++++--- projects/subgraph-beanstalk/src/utils/Barn.ts | 3 +-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 16d2a064e8..4244e86083 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -2,9 +2,10 @@ import { Address, BigInt, log } from "@graphprotocol/graph-ts"; import { Chop as ChopEntity } from "../../generated/schema"; import { ChangeUnderlying, Chop } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { TransferSingle, TransferBatch } from "../../generated/Beanstalk-ABIs/Fertilizer"; -import { loadUnripeToken } from "../entities/Silo"; +import { loadUnripeToken, loadWhitelistTokenSetting } from "../entities/Silo"; import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; import { transfer, updateUnripeStats } from "../utils/Barn"; +import { getLatestBdv } from "../entities/snapshots/WhitelistTokenSetting"; export function handleTransferSingle(event: TransferSingle): void { transfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); @@ -21,14 +22,26 @@ export function handleTransferBatch(event: TransferBatch): void { export function handleChangeUnderlying(event: ChangeUnderlying): void { const unripe = loadUnripeToken(event.params.token); unripe.totalUnderlying = unripe.totalUnderlying.plus(event.params.underlying); - // Snapshots are taken in the below method, updateUnripeStats unripe.save(); - // Update other stats using protocol getters updateUnripeStats(unripe.id, event.address, event.block); } +// TODO: need to handle chop converts, which emit a different event. here are examples. +// When that is done, the chop entity should be abstracted also. +// https://etherscan.io/tx/0x22a568dcdcb52aa3f2d8a7e2d36fe4e9e25246fe2ebf3ebeee0d4096a0d18313 +// https://etherscan.io/tx/0xf40a95f6d7731e00806a24aaae3701a6496c482e5f301af9c7f865805836ea10 export function handleChop(event: Chop): void { + const unripe = loadUnripeToken(event.params.token); + const unripeBdv = getLatestBdv(loadWhitelistTokenSetting(unripe.id))!; + const underlyingBdv = getLatestBdv(loadWhitelistTokenSetting(Address.fromString(unripe.underlyingToken)))!; + unripe.totalChoppedAmount = unripe.totalChoppedAmount.plus(event.params.amount); + unripe.totalChoppedBdv = unripe.totalChoppedBdv.plus(event.params.amount.times(unripeBdv)); + unripe.totalChoppedBdvReceived = unripe.totalChoppedBdvReceived.plus(event.params.underlying.times(underlyingBdv)); + unripe.save(); + + updateUnripeStats(unripe.id, event.address, event.block); + let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); let chop = new ChopEntity(id); chop.hash = event.transaction.hash.toHexString(); diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts index 19f2413e1b..125b7e7bab 100644 --- a/projects/subgraph-beanstalk/src/utils/Barn.ts +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -43,8 +43,7 @@ export function updateUnripeStats(unripe: Address, protocol: Address, block: eth // Further calculated values unripeToken.underlyingToken = getUnripeUnderlying(unripe, block.number).toHexString(); - const whitelistSetting = loadWhitelistTokenSetting(Address.fromString(unripeToken.underlyingToken)); - const underlyingBdvOne = getLatestBdv(whitelistSetting)!; + const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromString(unripeToken.underlyingToken)))!; unripeToken.bdvUnderlyingOne = unripeToken.amountUnderlyingOne.times(underlyingBdvOne); unripeToken.choppableBdvOne = unripeToken.choppableAmountOne.times(underlyingBdvOne); From 39d34d8b2ae61167b92b04a0f74b27dcf840df3b Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:30:01 -0700 Subject: [PATCH 40/59] add convert handler --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 2 ++ .../subgraph-beanstalk/src/handlers/SiloHandler.ts | 10 +++++++++- projects/subgraph-beanstalk/src/utils/Barn.ts | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 77d2e0cd5c..2b6a981053 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -331,6 +331,8 @@ dataSources: handler: handleRemoveDeposit - event: RemoveDeposits(indexed address,indexed address,int96[],uint256[],uint256,uint256[]) handler: handleRemoveDeposits + - event: Convert(indexed address,address,address,uint256,uint256 + handler: handleConvert - event: StalkBalanceChanged(indexed address,int256,int256) handler: handleStalkBalanceChanged - event: SeedsBalanceChanged(indexed address,int256) diff --git a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts index 57198dddba..910b6cdaf0 100644 --- a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts @@ -6,6 +6,7 @@ import { takeWhitelistTokenSettingSnapshots } from "../entities/snapshots/Whitel import { Bytes4_emptyToNull } from "../../../subgraph-core/utils/Bytes"; import { AddDeposit, + Convert, DewhitelistToken, Plant, RemoveDeposit, @@ -18,7 +19,8 @@ import { WhitelistToken } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { updateClaimedWithdraw } from "../utils/legacy/LegacySilo"; -import { getProtocolToken } from "../utils/Constants"; +import { getProtocolToken, isUnripe } from "../utils/Constants"; +import { chopConvert } from "../utils/Barn"; export function handleAddDeposit(event: AddDeposit): void { addDeposits({ @@ -59,6 +61,12 @@ export function handleRemoveDeposits(event: RemoveDeposits): void { }); } +export function handleConvert(event: Convert): void { + if (isUnripe(event.params.fromToken) && !isUnripe(event.params.toToken)) { + chopConvert(event); + } +} + export function handleStalkBalanceChanged(event: StalkBalanceChanged): void { // Exclude BIP-24 emission of missed past events if (event.transaction.hash.toHexString() == "0xa89638aeb0d6c4afb4f367ea7a806a4c8b3b2a6eeac773e8cc4eda10bfa804fc") { diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts index 125b7e7bab..0bedcbd4b1 100644 --- a/projects/subgraph-beanstalk/src/utils/Barn.ts +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -2,7 +2,7 @@ import { Address, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; import { loadFarmer } from "../entities/Beanstalk"; -import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { Convert, SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { loadUnripeToken, loadWhitelistTokenSetting } from "../entities/Silo"; import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; import { getUnripeUnderlying } from "./Constants"; @@ -30,6 +30,8 @@ export function transfer(fertilizer1155: Address, from: Address, to: Address, id toFertilizerBalance.save(); } +export function chopConvert(event: Convert): void {} + // Update the status for this unripe token using protocol getters. These values fluctuate without related events. export function updateUnripeStats(unripe: Address, protocol: Address, block: ethereum.Block): void { const beanstalk_call = SeedGauge.bind(protocol); From f5e61759fae7bfd65b706c4f8844b80c2ca151b2 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:52:39 -0700 Subject: [PATCH 41/59] add price abi --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 822ee76521..3a7fe901ea 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -679,6 +679,8 @@ dataSources: abis: - name: SeedGauge file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - event: Reward(indexed uint32,uint256,uint256,uint256) handler: handleReward @@ -890,5 +892,5 @@ dataSources: features: - grafting graft: - base: QmaZ8zSaXfLAS7pTnXQLeWu1qhtRGu6cSPavGk7scJtnLH - block: 15289930 + base: QmRiA7YzTJA5wHXjJzE2ksTK88BTq1XHQCLBfWmumittVn + block: 19927660 From 669de1b9f0eac916542f365d36492e7633a452bd Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 13:45:09 -0700 Subject: [PATCH 42/59] delta bdv --- .../snapshots/WhitelistTokenSetting.ts | 23 +++++++++++++++++++ projects/subgraph-beanstalk/src/utils/Silo.ts | 2 -- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts index b7cebe6585..74aeb67fee 100644 --- a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts @@ -151,8 +151,31 @@ export function setBdv(bdv: BigInt, whitelistTokenSetting: WhitelistTokenSetting whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() )!; const daily = WhitelistTokenDailySnapshot.load(whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastDailySnapshotDay!.toString())!; + hourly.bdv = bdv; daily.bdv = bdv; + + // Delta cannot be managed by the default snapshot method because the bdv is unsuitable for calculation during that + // method (contract call). Previous season's snapshots can be accessed by subtracting one + // (the current season snapshots were already created) + const prevHourly = WhitelistTokenHourlySnapshot.load( + whitelistTokenSetting.id + "-" + (whitelistTokenSetting.lastHourlySnapshotSeason - 1).toString() + )!; + const prevDaily = WhitelistTokenDailySnapshot.load( + whitelistTokenSetting.id + "-" + (whitelistTokenSetting.lastDailySnapshotDay!.toI32() - 1).toString() + )!; + + if (prevHourly != null) { + hourly.deltaBdv = hourly.bdv.minus(prevHourly.bdv!); + } else { + hourly.deltaBdv = hourly.bdv; + } + if (prevDaily != null) { + daily.deltaBdv = daily.bdv.minus(prevDaily.bdv!); + } else { + daily.deltaBdv = daily.bdv; + } + hourly.save(); daily.save(); } diff --git a/projects/subgraph-beanstalk/src/utils/Silo.ts b/projects/subgraph-beanstalk/src/utils/Silo.ts index ddf63728ac..35976decc0 100644 --- a/projects/subgraph-beanstalk/src/utils/Silo.ts +++ b/projects/subgraph-beanstalk/src/utils/Silo.ts @@ -200,5 +200,3 @@ export function updateSeedsBalances(protocol: Address, account: Address, seeds: takeSiloSnapshots(silo, protocol, timestamp); silo.save(); } - -export function updateWhitelistdBdvs(protocol: Address): void {} From 6ef9f68f057e487a847dcc433910c53389879547 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:20:59 -0700 Subject: [PATCH 43/59] updated chop entity --- projects/subgraph-beanstalk/schema.graphql | 78 +++++-------------- .../subgraph-beanstalk/src/entities/Silo.ts | 2 +- .../src/handlers/BarnHandler.ts | 35 ++++----- projects/subgraph-beanstalk/src/utils/Barn.ts | 9 ++- 4 files changed, 46 insertions(+), 78 deletions(-) diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 5ab03134c1..8619b150d0 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -1226,46 +1226,6 @@ type FertilizerYield @entity { ##### Event-Level Data ##### ################################## -### We need to add these in - -""" -An event is any user action that occurs in a protocol. Generally, they are Ethereum events -emitted by a function in the smart contracts, stored in transaction receipts as event logs. -However, some user actions of interest are function calls that don't emit events. For example, -the deposit and withdraw functions in Yearn do not emit any events. In our subgraphs, we still -store them as events, although they are not technically Ethereum events emitted by smart -contracts. -""" -interface SiloEvent { - "{ Event type }-{ Transaction hash }-{ Log index }" - id: ID! - "Transaction hash of the transaction that emitted this event" - hash: String! - "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" - logIndex: Int! - "The protocol this transaction belongs to" - protocol: Beanstalk! - "Block number of this event" - blockNumber: BigInt! - "Timestamp of this event" - createdAt: BigInt! -} - -interface FieldEvent { - "{ Event type }-{ Transaction hash }-{ Log index }" - id: ID! - "Transaction hash of the transaction that emitted this event" - hash: String! - "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" - logIndex: Int! - "The protocol this transaction belongs to" - protocol: Beanstalk! - "Block number of this event" - blockNumber: BigInt! - "Timestamp of this event" - createdAt: BigInt! -} - interface MarketplaceEvent { "{ Event type }-{ Transaction hash }-{ Log index }" id: ID! @@ -1281,26 +1241,30 @@ interface MarketplaceEvent { createdAt: BigInt! } -type Chop implements SiloEvent @entity(immutable: true) { - "chop-{ Transaction hash }-{ Log index }" +type Chop @entity(immutable: true) { + "(chop|convert)-{ Transaction hash }-{ Log index }" id: ID! + "Account address" + farmer: Farmer! + "The unripe token which was chopped" + unripeToken: UnripeToken! + "Unripe token amount which was chopped" + unripeAmount: BigInt! + "Bdv of the unripe tokens which were chopped" + unripeBdv: BigInt! + "The underlying ERC20 token received by `farmer` as a result of this chop" + underlyingToken: WhitelistTokenSetting! + "Amount of underlying tokens `farmer` received" + underlyingAmount: BigInt! + "Amount of bdv `farmer` received" + underlyingBdv: BigInt! + "The effective chop rate for this chop" + chopRate: BigDecimal! "Transaction hash of the transaction that emitted this event" hash: String! - "Event log index. For transactions that don't emit event, create arbitrary index starting from 0" - logIndex: Int! - "The protocol this transaction belongs to" - protocol: Beanstalk! - "Address chopping" - farmer: String! - "Unripe token being chopped" - unripe: String! - "Amount being chopped" - amount: BigInt! - "Underlying token" - underlying: String! - "Block number of this event" + "The block number of this event" blockNumber: BigInt! - "Timestamp of this event" + "Timestamp of this chop" createdAt: BigInt! } @@ -1508,7 +1472,7 @@ type UnripeToken @entity { "Token Address" id: Bytes! "The ripe token underlying this unripe asset" - underlyingToken: String! + underlyingToken: WhitelistTokenSetting! "The total amount of `underlyingToken` for this unripe token (getTotalUnderlying)" totalUnderlying: BigInt! "The amount of `underlyingToken` corresponding to one of this unripe token (getUnderlyingPerUnripeToken)" diff --git a/projects/subgraph-beanstalk/src/entities/Silo.ts b/projects/subgraph-beanstalk/src/entities/Silo.ts index 8900c919e5..e53dd4769c 100644 --- a/projects/subgraph-beanstalk/src/entities/Silo.ts +++ b/projects/subgraph-beanstalk/src/entities/Silo.ts @@ -98,7 +98,7 @@ export function loadUnripeToken(token: Address): UnripeToken { let unripe = UnripeToken.load(token); if (unripe == null) { unripe = new UnripeToken(token); - unripe.underlyingToken = getUnripeUnderlying(token, ZERO_BI).toHexString(); + unripe.underlyingToken = getUnripeUnderlying(token, ZERO_BI); unripe.totalUnderlying = ZERO_BI; unripe.amountUnderlyingOne = ZERO_BI; unripe.bdvUnderlyingOne = ZERO_BI; diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 4244e86083..6496e771c1 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -27,31 +27,30 @@ export function handleChangeUnderlying(event: ChangeUnderlying): void { updateUnripeStats(unripe.id, event.address, event.block); } -// TODO: need to handle chop converts, which emit a different event. here are examples. -// When that is done, the chop entity should be abstracted also. -// https://etherscan.io/tx/0x22a568dcdcb52aa3f2d8a7e2d36fe4e9e25246fe2ebf3ebeee0d4096a0d18313 -// https://etherscan.io/tx/0xf40a95f6d7731e00806a24aaae3701a6496c482e5f301af9c7f865805836ea10 export function handleChop(event: Chop): void { const unripe = loadUnripeToken(event.params.token); - const unripeBdv = getLatestBdv(loadWhitelistTokenSetting(unripe.id))!; - const underlyingBdv = getLatestBdv(loadWhitelistTokenSetting(Address.fromString(unripe.underlyingToken)))!; - unripe.totalChoppedAmount = unripe.totalChoppedAmount.plus(event.params.amount); - unripe.totalChoppedBdv = unripe.totalChoppedBdv.plus(event.params.amount.times(unripeBdv)); - unripe.totalChoppedBdvReceived = unripe.totalChoppedBdvReceived.plus(event.params.underlying.times(underlyingBdv)); - unripe.save(); - - updateUnripeStats(unripe.id, event.address, event.block); + const unripeBdvOne = getLatestBdv(loadWhitelistTokenSetting(unripe.id))!; + const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(unripe.underlyingToken))!; let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); let chop = new ChopEntity(id); - chop.hash = event.transaction.hash.toHexString(); - chop.logIndex = event.transactionLogIndex.toI32(); - chop.protocol = event.address.toHexString(); chop.farmer = event.params.account.toHexString(); - chop.unripe = event.params.token.toHexString(); - chop.amount = event.params.amount; - chop.underlying = event.params.underlying.toHexString(); + chop.unripeToken = unripe.id; + chop.unripeAmount = event.params.amount; + chop.unripeBdv = event.params.amount.times(unripeBdvOne); + chop.underlyingToken = unripe.underlyingToken; + chop.underlyingAmount = event.params.underlying; + chop.underlyingBdv = event.params.underlying.times(underlyingBdvOne); + chop.chopRate = unripe.chopRate; + chop.hash = event.transaction.hash.toHexString(); chop.blockNumber = event.block.number; chop.createdAt = event.block.timestamp; chop.save(); + + unripe.totalChoppedAmount = unripe.totalChoppedAmount.plus(chop.unripeAmount); + unripe.totalChoppedBdv = unripe.totalChoppedBdv.plus(chop.unripeBdv); + unripe.totalChoppedBdvReceived = unripe.totalChoppedBdvReceived.plus(chop.underlyingBdv); + unripe.save(); + + updateUnripeStats(unripe.id, event.address, event.block); } diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts index 0bedcbd4b1..6aebf882d0 100644 --- a/projects/subgraph-beanstalk/src/utils/Barn.ts +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -29,8 +29,13 @@ export function transfer(fertilizer1155: Address, from: Address, to: Address, id toFertilizerBalance.amount = toFertilizerBalance.amount.plus(amount); toFertilizerBalance.save(); } - -export function chopConvert(event: Convert): void {} +// TODO: need to handle chop converts, which emit a different event. here are examples. +// When that is done, the chop entity should be abstracted also. +// https://etherscan.io/tx/0x22a568dcdcb52aa3f2d8a7e2d36fe4e9e25246fe2ebf3ebeee0d4096a0d18313 +// https://etherscan.io/tx/0xf40a95f6d7731e00806a24aaae3701a6496c482e5f301af9c7f865805836ea10 +export function chopConvert(event: Convert): void { + // +} // Update the status for this unripe token using protocol getters. These values fluctuate without related events. export function updateUnripeStats(unripe: Address, protocol: Address, block: ethereum.Block): void { From c95713668951abe4a85116b650e20fc973485a73 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:55:42 -0700 Subject: [PATCH 44/59] chop converts --- .../manifests/ethereum.yaml | 2 +- .../subgraph-beanstalk/manifests/no-apy.yaml | 8 +++ projects/subgraph-beanstalk/schema.graphql | 4 +- .../src/entities/snapshots/UnripeToken.ts | 8 +-- .../snapshots/WhitelistTokenSetting.ts | 16 +++--- .../src/handlers/BarnHandler.ts | 42 +++++----------- .../src/handlers/SiloHandler.ts | 11 ++++- projects/subgraph-beanstalk/src/utils/Barn.ts | 49 +++++++++++++++---- .../subgraph-beanstalk/src/utils/Season.ts | 2 +- 9 files changed, 85 insertions(+), 57 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 2b6a981053..45cafaa78e 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -331,7 +331,7 @@ dataSources: handler: handleRemoveDeposit - event: RemoveDeposits(indexed address,indexed address,int96[],uint256[],uint256,uint256[]) handler: handleRemoveDeposits - - event: Convert(indexed address,address,address,uint256,uint256 + - event: Convert(indexed address,address,address,uint256,uint256) handler: handleConvert - event: StalkBalanceChanged(indexed address,int256,int256) handler: handleStalkBalanceChanged diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml index 2d2a3d5815..7fe989b4c5 100644 --- a/projects/subgraph-beanstalk/manifests/no-apy.yaml +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -29,6 +29,8 @@ dataSources: handler: handleRemoveDeposit - event: RemoveDeposits(indexed address,indexed address,int96[],uint256[],uint256,uint256[]) handler: handleRemoveDeposits + - event: Convert(indexed address,address,address,uint256,uint256) + handler: handleConvert - event: StalkBalanceChanged(indexed address,int256,int256) handler: handleStalkBalanceChanged - event: SeedsBalanceChanged(indexed address,int256) @@ -357,6 +359,8 @@ dataSources: eventHandlers: - event: Chop(indexed address,indexed address,uint256,uint256) handler: handleChop + - event: ChangeUnderlying(indexed address,int256) + handler: handleChangeUnderlying file: ../src/handlers/BarnHandler.ts ### # SEASON @@ -425,6 +429,10 @@ dataSources: abis: - name: Replanted file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + - name: CurvePrice + file: ../../subgraph-core/abis/CurvePrice.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - event: MetapoolOracle(indexed uint32,int256,uint256[2]) handler: handleMetapoolOracle diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 8619b150d0..18d0c6cf0c 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -1512,7 +1512,7 @@ type UnripeTokenHourlySnapshot @entity { unripeToken: UnripeToken! "Point in time ripe token underlying this unripe asset" - underlyingToken: String! + underlyingToken: WhitelistTokenSetting! "Point in time total amount of `underlyingToken` for this unripe token (getTotalUnderlying)" totalUnderlying: BigInt! "Point in time amount of `underlyingToken` corresponding to one of this unripe token (getUnderlyingPerUnripeToken)" @@ -1564,7 +1564,7 @@ type UnripeTokenDailySnapshot @entity { unripeToken: UnripeToken! "Point in time ripe token underlying this unripe asset" - underlyingToken: String! + underlyingToken: WhitelistTokenSetting! "Point in time total amount of `underlyingToken` for this unripe token (getTotalUnderlying)" totalUnderlying: BigInt! "Point in time amount of `underlyingToken` corresponding to one of this unripe token (getUnderlyingPerUnripeToken)" diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts b/projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts index 701d06cbd1..084599bc06 100644 --- a/projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/UnripeToken.ts @@ -10,15 +10,15 @@ export function takeUnripeTokenSnapshots(unripeToken: UnripeToken, protocol: Add const day = BigInt.fromI32(dayFromTimestamp(timestamp)); // Load the snapshot for this season/day - const hourlyId = unripeToken.id + "-" + currentSeason.toString(); - const dailyId = unripeToken.id + "-" + day.toString(); + const hourlyId = unripeToken.id.toHexString() + "-" + currentSeason.toString(); + const dailyId = unripeToken.id.toHexString() + "-" + day.toString(); let baseHourly = UnripeTokenHourlySnapshot.load(hourlyId); let baseDaily = UnripeTokenDailySnapshot.load(dailyId); if (baseHourly == null && unripeToken.lastHourlySnapshotSeason !== 0) { - baseHourly = UnripeTokenHourlySnapshot.load(unripeToken.id + "-" + unripeToken.lastHourlySnapshotSeason.toString()); + baseHourly = UnripeTokenHourlySnapshot.load(unripeToken.id.toHexString() + "-" + unripeToken.lastHourlySnapshotSeason.toString()); } if (baseDaily == null && unripeToken.lastDailySnapshotDay !== null) { - baseDaily = UnripeTokenDailySnapshot.load(unripeToken.id + "-" + unripeToken.lastDailySnapshotDay!.toString()); + baseDaily = UnripeTokenDailySnapshot.load(unripeToken.id.toHexString() + "-" + unripeToken.lastDailySnapshotDay!.toString()); } const hourly = new UnripeTokenHourlySnapshot(hourlyId); const daily = new UnripeTokenDailySnapshot(dailyId); diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts index 74aeb67fee..6e99dc56a2 100644 --- a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts @@ -148,9 +148,11 @@ export function takeWhitelistTokenSettingSnapshots( // Set bdv on hourly and daily. Snapshots must have already been created. export function setBdv(bdv: BigInt, whitelistTokenSetting: WhitelistTokenSetting): void { const hourly = WhitelistTokenHourlySnapshot.load( - whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() + whitelistTokenSetting.id.toHexString() + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() + )!; + const daily = WhitelistTokenDailySnapshot.load( + whitelistTokenSetting.id.toHexString() + "-" + whitelistTokenSetting.lastDailySnapshotDay!.toString() )!; - const daily = WhitelistTokenDailySnapshot.load(whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastDailySnapshotDay!.toString())!; hourly.bdv = bdv; daily.bdv = bdv; @@ -159,19 +161,19 @@ export function setBdv(bdv: BigInt, whitelistTokenSetting: WhitelistTokenSetting // method (contract call). Previous season's snapshots can be accessed by subtracting one // (the current season snapshots were already created) const prevHourly = WhitelistTokenHourlySnapshot.load( - whitelistTokenSetting.id + "-" + (whitelistTokenSetting.lastHourlySnapshotSeason - 1).toString() + whitelistTokenSetting.id.toHexString() + "-" + (whitelistTokenSetting.lastHourlySnapshotSeason - 1).toString() )!; const prevDaily = WhitelistTokenDailySnapshot.load( - whitelistTokenSetting.id + "-" + (whitelistTokenSetting.lastDailySnapshotDay!.toI32() - 1).toString() + whitelistTokenSetting.id.toHexString() + "-" + (whitelistTokenSetting.lastDailySnapshotDay!.toI32() - 1).toString() )!; if (prevHourly != null) { - hourly.deltaBdv = hourly.bdv.minus(prevHourly.bdv!); + hourly.deltaBdv = hourly.bdv!.minus(prevHourly.bdv!); } else { hourly.deltaBdv = hourly.bdv; } if (prevDaily != null) { - daily.deltaBdv = daily.bdv.minus(prevDaily.bdv!); + daily.deltaBdv = daily.bdv!.minus(prevDaily.bdv!); } else { daily.deltaBdv = daily.bdv; } @@ -183,7 +185,7 @@ export function setBdv(bdv: BigInt, whitelistTokenSetting: WhitelistTokenSetting // Returns the latest hourly bdv for the requested token. Can be null if bdv function isnt implemented onchain yet. export function getLatestBdv(whitelistTokenSetting: WhitelistTokenSetting): BigInt | null { const hourly = WhitelistTokenHourlySnapshot.load( - whitelistTokenSetting.id + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() + whitelistTokenSetting.id.toHexString() + "-" + whitelistTokenSetting.lastHourlySnapshotSeason.toString() )!; return hourly.bdv; } diff --git a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts index 6496e771c1..c8f61efb89 100644 --- a/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BarnHandler.ts @@ -1,11 +1,8 @@ import { Address, BigInt, log } from "@graphprotocol/graph-ts"; -import { Chop as ChopEntity } from "../../generated/schema"; import { ChangeUnderlying, Chop } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { TransferSingle, TransferBatch } from "../../generated/Beanstalk-ABIs/Fertilizer"; -import { loadUnripeToken, loadWhitelistTokenSetting } from "../entities/Silo"; -import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; -import { transfer, updateUnripeStats } from "../utils/Barn"; -import { getLatestBdv } from "../entities/snapshots/WhitelistTokenSetting"; +import { loadUnripeToken } from "../entities/Silo"; +import { transfer, unripeChopped, updateUnripeStats } from "../utils/Barn"; export function handleTransferSingle(event: TransferSingle): void { transfer(event.address, event.params.from, event.params.to, event.params.id, event.params.value, event.block.number); @@ -24,33 +21,16 @@ export function handleChangeUnderlying(event: ChangeUnderlying): void { unripe.totalUnderlying = unripe.totalUnderlying.plus(event.params.underlying); unripe.save(); - updateUnripeStats(unripe.id, event.address, event.block); + updateUnripeStats(Address.fromBytes(unripe.id), event.address, event.block); } export function handleChop(event: Chop): void { - const unripe = loadUnripeToken(event.params.token); - const unripeBdvOne = getLatestBdv(loadWhitelistTokenSetting(unripe.id))!; - const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(unripe.underlyingToken))!; - - let id = "chop-" + event.transaction.hash.toHexString() + "-" + event.transactionLogIndex.toString(); - let chop = new ChopEntity(id); - chop.farmer = event.params.account.toHexString(); - chop.unripeToken = unripe.id; - chop.unripeAmount = event.params.amount; - chop.unripeBdv = event.params.amount.times(unripeBdvOne); - chop.underlyingToken = unripe.underlyingToken; - chop.underlyingAmount = event.params.underlying; - chop.underlyingBdv = event.params.underlying.times(underlyingBdvOne); - chop.chopRate = unripe.chopRate; - chop.hash = event.transaction.hash.toHexString(); - chop.blockNumber = event.block.number; - chop.createdAt = event.block.timestamp; - chop.save(); - - unripe.totalChoppedAmount = unripe.totalChoppedAmount.plus(chop.unripeAmount); - unripe.totalChoppedBdv = unripe.totalChoppedBdv.plus(chop.unripeBdv); - unripe.totalChoppedBdvReceived = unripe.totalChoppedBdvReceived.plus(chop.underlyingBdv); - unripe.save(); - - updateUnripeStats(unripe.id, event.address, event.block); + unripeChopped({ + event, + type: "chop", + account: event.params.account, + unripeToken: event.params.token, + unripeAmount: event.params.amount, + underlyingAmount: event.params.underlying + }); } diff --git a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts index 910b6cdaf0..2a2787c556 100644 --- a/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/SiloHandler.ts @@ -20,7 +20,7 @@ import { } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { updateClaimedWithdraw } from "../utils/legacy/LegacySilo"; import { getProtocolToken, isUnripe } from "../utils/Constants"; -import { chopConvert } from "../utils/Barn"; +import { unripeChopped } from "../utils/Barn"; export function handleAddDeposit(event: AddDeposit): void { addDeposits({ @@ -63,7 +63,14 @@ export function handleRemoveDeposits(event: RemoveDeposits): void { export function handleConvert(event: Convert): void { if (isUnripe(event.params.fromToken) && !isUnripe(event.params.toToken)) { - chopConvert(event); + unripeChopped({ + event, + type: "convert", + account: event.params.account, + unripeToken: event.params.fromToken, + unripeAmount: event.params.fromAmount, + underlyingAmount: event.params.toAmount + }); } } diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts index 6aebf882d0..eee1c82f50 100644 --- a/projects/subgraph-beanstalk/src/utils/Barn.ts +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -1,14 +1,24 @@ import { Address, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; +import { Chop as ChopEntity } from "../../generated/schema"; import { loadFertilizer, loadFertilizerBalance, loadFertilizerToken } from "../entities/Fertilizer"; import { ADDRESS_ZERO } from "../../../subgraph-core/utils/Constants"; import { loadFarmer } from "../entities/Beanstalk"; -import { Convert, SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; +import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { loadUnripeToken, loadWhitelistTokenSetting } from "../entities/Silo"; import { takeUnripeTokenSnapshots } from "../entities/snapshots/UnripeToken"; import { getUnripeUnderlying } from "./Constants"; import { toDecimal } from "../../../subgraph-core/utils/Decimals"; import { getLatestBdv } from "../entities/snapshots/WhitelistTokenSetting"; +class ChopParams { + event: ethereum.Event; + type: String; + account: Address; + unripeToken: Address; + unripeAmount: BigInt; + underlyingAmount: BigInt; +} + export function transfer(fertilizer1155: Address, from: Address, to: Address, id: BigInt, amount: BigInt, blockNumber: BigInt): void { let fertilizer = loadFertilizer(fertilizer1155); let fertilizerToken = loadFertilizerToken(fertilizer, id, blockNumber); @@ -29,12 +39,33 @@ export function transfer(fertilizer1155: Address, from: Address, to: Address, id toFertilizerBalance.amount = toFertilizerBalance.amount.plus(amount); toFertilizerBalance.save(); } -// TODO: need to handle chop converts, which emit a different event. here are examples. -// When that is done, the chop entity should be abstracted also. -// https://etherscan.io/tx/0x22a568dcdcb52aa3f2d8a7e2d36fe4e9e25246fe2ebf3ebeee0d4096a0d18313 -// https://etherscan.io/tx/0xf40a95f6d7731e00806a24aaae3701a6496c482e5f301af9c7f865805836ea10 -export function chopConvert(event: Convert): void { - // + +export function unripeChopped(params: ChopParams): void { + const unripe = loadUnripeToken(params.unripeToken); + const unripeBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromBytes(unripe.id)))!; + const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromBytes(unripe.underlyingToken)))!; + + let id = params.type + "-" + params.event.transaction.hash.toHexString() + "-" + params.event.transactionLogIndex.toString(); + let chop = new ChopEntity(id); + chop.farmer = params.account.toHexString(); + chop.unripeToken = unripe.id; + chop.unripeAmount = params.unripeAmount; + chop.unripeBdv = params.unripeAmount.times(unripeBdvOne); + chop.underlyingToken = unripe.underlyingToken; + chop.underlyingAmount = params.underlyingAmount; + chop.underlyingBdv = params.underlyingAmount.times(underlyingBdvOne); + chop.chopRate = unripe.chopRate; + chop.hash = params.event.transaction.hash.toHexString(); + chop.blockNumber = params.event.block.number; + chop.createdAt = params.event.block.timestamp; + chop.save(); + + unripe.totalChoppedAmount = unripe.totalChoppedAmount.plus(chop.unripeAmount); + unripe.totalChoppedBdv = unripe.totalChoppedBdv.plus(chop.unripeBdv); + unripe.totalChoppedBdvReceived = unripe.totalChoppedBdvReceived.plus(chop.underlyingBdv); + unripe.save(); + + updateUnripeStats(Address.fromBytes(unripe.id), params.event.address, params.event.block); } // Update the status for this unripe token using protocol getters. These values fluctuate without related events. @@ -49,8 +80,8 @@ export function updateUnripeStats(unripe: Address, protocol: Address, block: eth unripeToken.recapPercent = toDecimal(beanstalk_call.getRecapFundedPercent(unripe)); // Further calculated values - unripeToken.underlyingToken = getUnripeUnderlying(unripe, block.number).toHexString(); - const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromString(unripeToken.underlyingToken)))!; + unripeToken.underlyingToken = getUnripeUnderlying(unripe, block.number); + const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromBytes(unripeToken.underlyingToken)))!; unripeToken.bdvUnderlyingOne = unripeToken.amountUnderlyingOne.times(underlyingBdvOne); unripeToken.choppableBdvOne = unripeToken.choppableAmountOne.times(underlyingBdvOne); diff --git a/projects/subgraph-beanstalk/src/utils/Season.ts b/projects/subgraph-beanstalk/src/utils/Season.ts index 4364da832d..c8b2361836 100644 --- a/projects/subgraph-beanstalk/src/utils/Season.ts +++ b/projects/subgraph-beanstalk/src/utils/Season.ts @@ -65,7 +65,7 @@ export function sunrise(protocol: Address, season: BigInt, block: ethereum.Block function setTokenBdv(token: Address, protocol: Address, whitelistTokenSetting: WhitelistTokenSetting): void { // Get bdv if the bdv function is available onchain (not available prior to BIP-16) const beanstalk_call = SeedGauge.bind(protocol); - const bdvResult = beanstalk_call.try_bdv(token, BI_10.pow(whitelistTokenSetting.decimals)); + const bdvResult = beanstalk_call.try_bdv(token, BI_10.pow(whitelistTokenSetting.decimals)); if (bdvResult.reverted) { return; } From a05a56586c85539b41484e95a0689018d9f3a9e4 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:24:27 -0700 Subject: [PATCH 45/59] _version entity --- .../manifests/ethereum.yaml | 48 +++++++++--------- .../subgraph-beanstalk/manifests/no-apy.yaml | 50 ++++++++++--------- projects/subgraph-beanstalk/schema.graphql | 19 ++++--- .../src/entities/Beanstalk.ts | 4 -- .../src/handlers/DiamondHandler.ts | 8 --- projects/subgraph-beanstalk/src/utils/Init.ts | 25 ++++++++++ 6 files changed, 88 insertions(+), 66 deletions(-) delete mode 100644 projects/subgraph-beanstalk/src/handlers/DiamondHandler.ts create mode 100644 projects/subgraph-beanstalk/src/utils/Init.ts diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 6030dedf02..106dc3cbb2 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -306,6 +306,31 @@ dataSources: handler: handleLoadSilo3_3 file: ../src/utils/yield_cache/window_3/LoadSilo_3.ts ### + # INITIALIZATION + ### + - kind: ethereum/contract + name: Version + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + endBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - _Version + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts + ### # SILO ### - kind: ethereum/contract @@ -870,29 +895,6 @@ dataSources: - event: InternalBalanceChanged(indexed address,indexed address,int256) handler: handleInternalBalanceChanged file: ../src/handlers/FarmHandler.ts - ### - # DIAMOND - ### - - kind: ethereum/contract - name: Diamond - network: mainnet - source: - address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: SeedGauge - startBlock: 12974075 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Beanstalk - abis: - - name: SeedGauge - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleDiamondCut - file: ../src/handlers/DiamondHandler.ts features: - grafting graft: diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml index 7fe989b4c5..b210608536 100644 --- a/projects/subgraph-beanstalk/manifests/no-apy.yaml +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -4,6 +4,31 @@ schema: file: ../schema.graphql dataSources: ### + # INITIALIZATION + ### + - kind: ethereum/contract + name: Version + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: PreReplant + startBlock: 12974075 + endBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - _Version + abis: + - name: PreReplant + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts + ### # SILO ### - kind: ethereum/contract @@ -381,6 +406,8 @@ dataSources: abis: - name: SeedGauge file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + - name: BeanstalkPrice + file: ../../subgraph-core/abis/BeanstalkPrice.json eventHandlers: - event: Reward(indexed uint32,uint256,uint256,uint256) handler: handleReward @@ -566,26 +593,3 @@ dataSources: - event: InternalBalanceChanged(indexed address,indexed address,int256) handler: handleInternalBalanceChanged file: ../src/handlers/FarmHandler.ts - ### - # DIAMOND - ### - - kind: ethereum/contract - name: Diamond - network: mainnet - source: - address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: SeedGauge - startBlock: 12974075 - mapping: - kind: ethereum/events - apiVersion: 0.0.6 - language: wasm/assemblyscript - entities: - - Beanstalk - abis: - - name: SeedGauge - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleDiamondCut - file: ../src/handlers/DiamondHandler.ts diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 18d0c6cf0c..8109d142d0 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -21,6 +21,17 @@ enum EmaWindow { ROLLING_30_DAY } +type _Version @entity { + "= 'subgraph'" + id: ID! + "= 'beanstalk'" + protocolName: String! + "Verison number of the subgraph" + versionNumber: String! + "Which blockchain is being indexed, i.e. 'ethereum', 'arbitrum', etc." + chain: String! +} + type Beanstalk @entity { "Smart contract address of the protocol's main contract (Factory, Registry, etc) " id: ID! @@ -30,14 +41,6 @@ type Beanstalk @entity { token: String! "Address of the fertilizer contract" fertilizer1155: String - "Version of the subgraph schema, in SemVer format (e.g. 1.0.0) " - schemaVersion: String! - "Version of the subgraph implementation, in SemVer format (e.g. 1.0.0) " - subgraphVersion: String! - "Version of the methodology used to compute metrics, loosely based on SemVer format (e.g. 1.0.0) " - methodologyVersion: String! - "Timestamp of the latest DiamondCut call" - lastUpgrade: BigInt! "Season specific data" seasons: [Season!]! @derivedFrom(field: "beanstalk") "Silo level data" diff --git a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts index 51a0776d34..e1de2691d8 100644 --- a/projects/subgraph-beanstalk/src/entities/Beanstalk.ts +++ b/projects/subgraph-beanstalk/src/entities/Beanstalk.ts @@ -16,10 +16,6 @@ export function loadBeanstalk(protocol: Address): Beanstalk { if (fert !== null) { beanstalk.fertilizer1155 = fert.toHexString(); } - beanstalk.schemaVersion = "2.4.0"; - beanstalk.subgraphVersion = "2.4.0"; - beanstalk.methodologyVersion = "2.4.0"; - beanstalk.lastUpgrade = ZERO_BI; beanstalk.lastSeason = 1; beanstalk.activeFarmers = []; beanstalk.farmersToUpdate = []; diff --git a/projects/subgraph-beanstalk/src/handlers/DiamondHandler.ts b/projects/subgraph-beanstalk/src/handlers/DiamondHandler.ts deleted file mode 100644 index 933d4aaef7..0000000000 --- a/projects/subgraph-beanstalk/src/handlers/DiamondHandler.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { DiamondCut } from "../../generated/Beanstalk-ABIs/SeedGauge"; -import { loadBeanstalk } from "../entities/Beanstalk"; - -export function handleDiamondCut(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - beanstalk.lastUpgrade = event.block.timestamp; - beanstalk.save(); -} diff --git a/projects/subgraph-beanstalk/src/utils/Init.ts b/projects/subgraph-beanstalk/src/utils/Init.ts new file mode 100644 index 0000000000..8f73600ce8 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/Init.ts @@ -0,0 +1,25 @@ +import { BigInt, ethereum } from "@graphprotocol/graph-ts"; +import { _Version } from "../../generated/schema"; +import { BEANSTALK_BLOCK } from "../../../subgraph-core/utils/Constants"; + +export function handleInitVersion(block: ethereum.Block): void { + const versionEntity = new _Version("subgraph"); + versionEntity.versionNumber = "2.4.0"; + versionEntity.protocolName = protocolNameForBlockNumber(block.number); + versionEntity.chain = chainForBlockNumber(block.number); + versionEntity.save(); +} + +function protocolNameForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BEANSTALK_BLOCK) { + return "beanstalk"; + } + throw new Error("Unable to initialize protocol name for this block number"); +} + +function chainForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BEANSTALK_BLOCK) { + return "ethereum"; + } + throw new Error("Unable to initialize chain for this block number"); +} From c69423265ff45232742979cac5d8923f07a3e32b Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:59:35 -0700 Subject: [PATCH 46/59] update apy cache to use blockHandler init --- .../manifests/ethereum.yaml | 183 ++++++++++-------- .../utils/yield_cache/window_1/LoadSilo_1.ts | 13 +- .../utils/yield_cache/window_1/LoadSilo_2.ts | 13 +- .../utils/yield_cache/window_1/LoadSilo_3.ts | 13 +- .../utils/yield_cache/window_1/LoadToken_1.ts | 13 +- .../utils/yield_cache/window_1/LoadToken_2.ts | 13 +- .../utils/yield_cache/window_2/LoadSilo_1.ts | 13 +- .../utils/yield_cache/window_2/LoadSilo_2.ts | 13 +- .../utils/yield_cache/window_2/LoadSilo_3.ts | 13 +- .../utils/yield_cache/window_2/LoadToken_1.ts | 13 +- .../utils/yield_cache/window_2/LoadToken_2.ts | 13 +- .../utils/yield_cache/window_3/LoadSilo_1.ts | 13 +- .../utils/yield_cache/window_3/LoadSilo_2.ts | 13 +- .../utils/yield_cache/window_3/LoadSilo_3.ts | 13 +- .../utils/yield_cache/window_3/LoadToken_1.ts | 13 +- .../utils/yield_cache/window_3/LoadToken_2.ts | 13 +- 16 files changed, 152 insertions(+), 226 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 106dc3cbb2..64e312b9f8 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -3,7 +3,8 @@ schema: file: ../schema.graphql dataSources: ### - # HISTORICAL vAPY CACHE + # HISTORICAL vAPY CACHE. + # Set to occur one block after the rest of initialization steps, so that the Version entity is loaded. ### - kind: ethereum/contract name: TokenCacheWindow1_1 @@ -11,19 +12,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadToken1_1 + blockHandlers: + - handler: handleLoadToken1_1 + filter: + kind: once file: ../src/utils/yield_cache/window_1/LoadToken_1.ts - kind: ethereum/contract name: TokenCacheWindow1_2 @@ -31,19 +34,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadToken1_2 + blockHandlers: + - handler: handleLoadToken1_2 + filter: + kind: once file: ../src/utils/yield_cache/window_1/LoadToken_2.ts - kind: ethereum/contract name: SiloCacheWindow1_1 @@ -51,19 +56,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo1_1 + blockHandlers: + - handler: handleLoadSilo1_1 + filter: + kind: once file: ../src/utils/yield_cache/window_1/LoadSilo_1.ts - kind: ethereum/contract name: SiloCacheWindow1_2 @@ -71,19 +78,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo1_2 + blockHandlers: + - handler: handleLoadSilo1_2 + filter: + kind: once file: ../src/utils/yield_cache/window_1/LoadSilo_2.ts - kind: ethereum/contract name: SiloCacheWindow1_3 @@ -91,19 +100,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo1_3 + blockHandlers: + - handler: handleLoadSilo1_3 + filter: + kind: once file: ../src/utils/yield_cache/window_1/LoadSilo_3.ts - kind: ethereum/contract name: TokenCacheWindow2_1 @@ -111,19 +122,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadToken2_1 + blockHandlers: + - handler: handleLoadToken2_1 + filter: + kind: once file: ../src/utils/yield_cache/window_2/LoadToken_1.ts - kind: ethereum/contract name: TokenCacheWindow2_2 @@ -131,19 +144,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadToken2_2 + blockHandlers: + - handler: handleLoadToken2_2 + filter: + kind: once file: ../src/utils/yield_cache/window_2/LoadToken_2.ts - kind: ethereum/contract name: SiloCacheWindow2_1 @@ -151,19 +166,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo2_1 + blockHandlers: + - handler: handleLoadSilo2_1 + filter: + kind: once file: ../src/utils/yield_cache/window_2/LoadSilo_1.ts - kind: ethereum/contract name: SiloCacheWindow2_2 @@ -171,19 +188,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo2_2 + blockHandlers: + - handler: handleLoadSilo2_2 + filter: + kind: once file: ../src/utils/yield_cache/window_2/LoadSilo_2.ts - kind: ethereum/contract name: SiloCacheWindow2_3 @@ -191,19 +210,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo2_3 + blockHandlers: + - handler: handleLoadSilo2_3 + filter: + kind: once file: ../src/utils/yield_cache/window_2/LoadSilo_3.ts - kind: ethereum/contract name: TokenCacheWindow3_1 @@ -211,19 +232,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadToken3_1 + blockHandlers: + - handler: handleLoadToken3_1 + filter: + kind: once file: ../src/utils/yield_cache/window_3/LoadToken_1.ts - kind: ethereum/contract name: TokenCacheWindow3_2 @@ -231,19 +254,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadToken3_2 + blockHandlers: + - handler: handleLoadToken3_2 + filter: + kind: once file: ../src/utils/yield_cache/window_3/LoadToken_2.ts - kind: ethereum/contract name: SiloCacheWindow3_1 @@ -251,19 +276,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo3_1 + blockHandlers: + - handler: handleLoadSilo3_1 + filter: + kind: once file: ../src/utils/yield_cache/window_3/LoadSilo_1.ts - kind: ethereum/contract name: SiloCacheWindow3_2 @@ -271,19 +298,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo3_2 + blockHandlers: + - handler: handleLoadSilo3_2 + filter: + kind: once file: ../src/utils/yield_cache/window_3/LoadSilo_2.ts - kind: ethereum/contract name: SiloCacheWindow3_3 @@ -291,19 +320,21 @@ dataSources: source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" abi: PreReplant - startBlock: 12974075 + startBlock: 12974076 + endBlock: 12974076 mapping: kind: ethereum/events apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - Diamond + - SiloYield abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleLoadSilo3_3 + blockHandlers: + - handler: handleLoadSilo3_3 + filter: + kind: once file: ../src/utils/yield_cache/window_3/LoadSilo_3.ts ### # INITIALIZATION diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts index f1996cca4a..9e6f17d71d 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_1.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_10_000 } from "./HistoricSilo_10_000"; -export function handleLoadSilo1_1(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_24_HOUR_10_000); - } +export function handleLoadSilo1_1(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_24_HOUR_10_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts index dace728128..14b3c2a3ec 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_2.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_15_000 } from "./HistoricSilo_15_000"; -export function handleLoadSilo1_2(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_24_HOUR_15_000); - } +export function handleLoadSilo1_2(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_24_HOUR_15_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts index f1f4ab673c..fd11fdbdd6 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadSilo_3.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_24_HOUR_20_000 } from "./HistoricSilo_20_000"; -export function handleLoadSilo1_3(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_24_HOUR_20_000); - } +export function handleLoadSilo1_3(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_24_HOUR_20_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts index 113b2cc924..5551144985 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_1.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_24_HOUR_12_000 } from "./HistoricToken_12_000"; -export function handleLoadToken1_1(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadTokenCache(TOKEN_YIELD_24_HOUR_12_000); - } +export function handleLoadToken1_1(block: ethereum.Block): void { + loadTokenCache(TOKEN_YIELD_24_HOUR_12_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts index deb60e1658..a89ad04008 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_1/LoadToken_2.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_24_HOUR_20_000 } from "./HistoricToken_20_000"; -export function handleLoadToken1_2(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadTokenCache(TOKEN_YIELD_24_HOUR_20_000); - } +export function handleLoadToken1_2(block: ethereum.Block): void { + loadTokenCache(TOKEN_YIELD_24_HOUR_20_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts index 07629f51aa..13724f84d2 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_1.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_10_000 } from "./HistoricSilo_10_000"; -export function handleLoadSilo2_1(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_7_DAY_10_000); - } +export function handleLoadSilo2_1(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_7_DAY_10_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts index df6e94890d..8633a11905 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_2.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_15_000 } from "./HistoricSilo_15_000"; -export function handleLoadSilo2_2(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_7_DAY_15_000); - } +export function handleLoadSilo2_2(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_7_DAY_15_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts index d2a21e83c8..28bc4fad74 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadSilo_3.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_7_DAY_20_000 } from "./HistoricSilo_20_000"; -export function handleLoadSilo2_3(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_7_DAY_20_000); - } +export function handleLoadSilo2_3(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_7_DAY_20_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts index 0eb4fb6ed7..06dfd4e555 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_1.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_7_DAY_12_000 } from "./HistoricToken_12_000"; -export function handleLoadToken2_1(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadTokenCache(TOKEN_YIELD_7_DAY_12_000); - } +export function handleLoadToken2_1(block: ethereum.Block): void { + loadTokenCache(TOKEN_YIELD_7_DAY_12_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts index 30705ca2ec..9ffebca8d1 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_2/LoadToken_2.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_7_DAY_20_000 } from "./HistoricToken_20_000"; -export function handleLoadToken2_2(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadTokenCache(TOKEN_YIELD_7_DAY_20_000); - } +export function handleLoadToken2_2(block: ethereum.Block): void { + loadTokenCache(TOKEN_YIELD_7_DAY_20_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts index b1e709b1d7..1d6d3ff8fc 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_1.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_10_000 } from "./HistoricSilo_10_000"; -export function handleLoadSilo3_1(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_30_DAY_10_000); - } +export function handleLoadSilo3_1(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_30_DAY_10_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts index af708cd1f4..22b63f0075 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_2.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_15_000 } from "./HistoricSilo_15_000"; -export function handleLoadSilo3_2(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_30_DAY_15_000); - } +export function handleLoadSilo3_2(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_30_DAY_15_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts index 09f84f73f4..14d2a83034 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadSilo_3.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadSiloCache } from "../CacheLoader"; import { SILO_YIELD_30_DAY_20_000 } from "./HistoricSilo_20_000"; -export function handleLoadSilo3_3(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadSiloCache(SILO_YIELD_30_DAY_20_000); - } +export function handleLoadSilo3_3(block: ethereum.Block): void { + loadSiloCache(SILO_YIELD_30_DAY_20_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts index e3f2942af5..709f1485e5 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_1.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_30_DAY_12_000 } from "./HistoricToken_12_000"; -export function handleLoadToken3_1(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadTokenCache(TOKEN_YIELD_30_DAY_12_000); - } +export function handleLoadToken3_1(block: ethereum.Block): void { + loadTokenCache(TOKEN_YIELD_30_DAY_12_000); } diff --git a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts index 1f2d548e38..8e1d177840 100644 --- a/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts +++ b/projects/subgraph-beanstalk/src/utils/yield_cache/window_3/LoadToken_2.ts @@ -1,14 +1,7 @@ -import { ZERO_BI } from "../../../../../subgraph-core/utils/Decimals"; -import { DiamondCut } from "../../../../generated/Beanstalk-ABIs/PreReplant"; -import { loadBeanstalk } from "../../../entities/Beanstalk"; +import { ethereum } from "@graphprotocol/graph-ts"; import { loadTokenCache } from "../CacheLoader"; import { TOKEN_YIELD_30_DAY_20_000 } from "./HistoricToken_20_000"; -export function handleLoadToken3_2(event: DiamondCut): void { - let beanstalk = loadBeanstalk(event.address); - - // Load the historical vAPY figures in bulk at start - if (beanstalk.lastUpgrade == ZERO_BI) { - loadTokenCache(TOKEN_YIELD_30_DAY_20_000); - } +export function handleLoadToken3_2(block: ethereum.Block): void { + loadTokenCache(TOKEN_YIELD_30_DAY_20_000); } From f9aad96d72e4112f9fa4c3e7a12d67f052585517 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:18:06 -0700 Subject: [PATCH 47/59] remove ineffective underscore --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 12 ++++++------ projects/subgraph-beanstalk/manifests/no-apy.yaml | 2 +- projects/subgraph-beanstalk/schema.graphql | 3 ++- projects/subgraph-beanstalk/src/utils/Init.ts | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 64e312b9f8..6062875059 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -352,7 +352,7 @@ dataSources: apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - _Version + - Version abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json @@ -926,8 +926,8 @@ dataSources: - event: InternalBalanceChanged(indexed address,indexed address,int256) handler: handleInternalBalanceChanged file: ../src/handlers/FarmHandler.ts -features: - - grafting -graft: - base: QmRiA7YzTJA5wHXjJzE2ksTK88BTq1XHQCLBfWmumittVn - block: 19927660 +# features: +# - grafting +# graft: +# base: QmRiA7YzTJA5wHXjJzE2ksTK88BTq1XHQCLBfWmumittVn +# block: 19927660 diff --git a/projects/subgraph-beanstalk/manifests/no-apy.yaml b/projects/subgraph-beanstalk/manifests/no-apy.yaml index b210608536..b3b188e95c 100644 --- a/projects/subgraph-beanstalk/manifests/no-apy.yaml +++ b/projects/subgraph-beanstalk/manifests/no-apy.yaml @@ -19,7 +19,7 @@ dataSources: apiVersion: 0.0.6 language: wasm/assemblyscript entities: - - _Version + - Version abis: - name: PreReplant file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 8109d142d0..7d98946ba9 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -21,7 +21,8 @@ enum EmaWindow { ROLLING_30_DAY } -type _Version @entity { +# This same entity schema is intended for use across the subgraphs +type Version @entity { "= 'subgraph'" id: ID! "= 'beanstalk'" diff --git a/projects/subgraph-beanstalk/src/utils/Init.ts b/projects/subgraph-beanstalk/src/utils/Init.ts index 8f73600ce8..f142e1dbe7 100644 --- a/projects/subgraph-beanstalk/src/utils/Init.ts +++ b/projects/subgraph-beanstalk/src/utils/Init.ts @@ -1,9 +1,9 @@ import { BigInt, ethereum } from "@graphprotocol/graph-ts"; -import { _Version } from "../../generated/schema"; +import { Version } from "../../generated/schema"; import { BEANSTALK_BLOCK } from "../../../subgraph-core/utils/Constants"; export function handleInitVersion(block: ethereum.Block): void { - const versionEntity = new _Version("subgraph"); + const versionEntity = new Version("subgraph"); versionEntity.versionNumber = "2.4.0"; versionEntity.protocolName = protocolNameForBlockNumber(block.number); versionEntity.chain = chainForBlockNumber(block.number); From 2c7512819a594cbbcc2c7455b624870efd96713f Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:43:21 -0700 Subject: [PATCH 48/59] add version entity to all subgraphs --- .../manifests/codegen-abis.yaml | 18 +++++++------ .../subgraph-basin/manifests/ethereum.yaml | 25 +++++++++++++++++++ projects/subgraph-basin/schema.graphql | 12 +++++++++ projects/subgraph-basin/src/utils/Init.ts | 24 ++++++++++++++++++ .../subgraph-bean/manifests/codegen-abis.yaml | 9 ++++--- .../subgraph-bean/manifests/ethereum.yaml | 25 +++++++++++++++++++ projects/subgraph-bean/schema.graphql | 12 +++++++++ projects/subgraph-bean/src/utils/Init.ts | 24 ++++++++++++++++++ .../manifests/codegen-abis.yaml | 9 ++++--- .../subgraph-beanft/manifests/ethereum.yaml | 25 +++++++++++++++++++ projects/subgraph-beanft/schema.graphql | 16 ++++++++++-- projects/subgraph-beanft/src/utils/Init.ts | 24 ++++++++++++++++++ .../manifests/codegen-abis.yaml | 9 ++++--- projects/subgraph-beanstalk/schema.graphql | 2 +- projects/subgraph-beanstalk/src/utils/Init.ts | 11 ++++---- 15 files changed, 216 insertions(+), 29 deletions(-) create mode 100644 projects/subgraph-basin/src/utils/Init.ts create mode 100644 projects/subgraph-bean/src/utils/Init.ts create mode 100644 projects/subgraph-beanft/src/utils/Init.ts diff --git a/projects/subgraph-basin/manifests/codegen-abis.yaml b/projects/subgraph-basin/manifests/codegen-abis.yaml index 491eab9455..d40bdf01c4 100644 --- a/projects/subgraph-basin/manifests/codegen-abis.yaml +++ b/projects/subgraph-basin/manifests/codegen-abis.yaml @@ -33,10 +33,11 @@ dataSources: file: ../../subgraph-core/abis/CurvePrice.json - name: BeanstalkPrice file: ../../subgraph-core/abis/BeanstalkPrice.json - eventHandlers: - - event: BoreWell(address,address,address[],(address,bytes),(address,bytes)[],bytes) - handler: handleBoreWell - file: ../src/templates/AquiferHandler.ts + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts templates: - kind: ethereum/contract name: Well @@ -52,7 +53,8 @@ templates: abis: - name: Well file: ../../subgraph-core/abis/Well.json - eventHandlers: - - event: Sync(uint256[],uint256,address) - handler: handleSync - file: ../src/WellHandler.ts + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts diff --git a/projects/subgraph-basin/manifests/ethereum.yaml b/projects/subgraph-basin/manifests/ethereum.yaml index 332c1b9393..5633136603 100644 --- a/projects/subgraph-basin/manifests/ethereum.yaml +++ b/projects/subgraph-basin/manifests/ethereum.yaml @@ -2,6 +2,31 @@ specVersion: 0.0.4 schema: file: ../schema.graphql dataSources: + ### + # INITIALIZATION + ### + - kind: ethereum/contract + name: Version + network: mainnet + source: + address: "0xBA51AAAA95aeEFc1292515b36D86C51dC7877773" + abi: Aquifer + startBlock: 17977922 + endBlock: 17977922 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Version + abis: + - name: Aquifer + file: ../../subgraph-core/abis/Aquifer.json + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts - kind: ethereum/contract name: Aquifer network: mainnet diff --git a/projects/subgraph-basin/schema.graphql b/projects/subgraph-basin/schema.graphql index 80d545cd04..688f00497d 100644 --- a/projects/subgraph-basin/schema.graphql +++ b/projects/subgraph-basin/schema.graphql @@ -17,6 +17,18 @@ enum SwapEvent { SHIFT } +# This same entity schema is intended for use across the subgraphs +type Version @entity { + "= 'subgraph'" + id: ID! + "= 'beanstalk'" + subgraphName: String! + "Verison number of the subgraph" + versionNumber: String! + "Which blockchain is being indexed, i.e. 'ethereum', 'arbitrum', etc." + chain: String! +} + type Token @entity { " Smart contract address of the token " id: Bytes! diff --git a/projects/subgraph-basin/src/utils/Init.ts b/projects/subgraph-basin/src/utils/Init.ts new file mode 100644 index 0000000000..630642264e --- /dev/null +++ b/projects/subgraph-basin/src/utils/Init.ts @@ -0,0 +1,24 @@ +import { BigInt, ethereum } from "@graphprotocol/graph-ts"; +import { Version } from "../../generated/schema"; + +export function handleInitVersion(block: ethereum.Block): void { + const versionEntity = new Version("subgraph"); + versionEntity.versionNumber = "2.2.2"; + versionEntity.subgraphName = subgraphNameForBlockNumber(block.number); + versionEntity.chain = chainForBlockNumber(block.number); + versionEntity.save(); +} + +function subgraphNameForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BigInt.fromU32(17977922)) { + return "basin"; + } + throw new Error("Unable to initialize subgraph name for this block number"); +} + +function chainForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BigInt.fromU32(17977922)) { + return "ethereum"; + } + throw new Error("Unable to initialize chain for this block number"); +} diff --git a/projects/subgraph-bean/manifests/codegen-abis.yaml b/projects/subgraph-bean/manifests/codegen-abis.yaml index 5a690c0445..5865dadba4 100644 --- a/projects/subgraph-bean/manifests/codegen-abis.yaml +++ b/projects/subgraph-bean/manifests/codegen-abis.yaml @@ -43,7 +43,8 @@ dataSources: file: ../../subgraph-core/abis/CurvePrice.json - name: CalculationsCurve file: ../../subgraph-core/abis/CalculationsCurve.json - eventHandlers: - - event: Transfer(indexed address,indexed address,uint256) - handler: handleTransfer - file: ../src/BeanHandler.ts + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts diff --git a/projects/subgraph-bean/manifests/ethereum.yaml b/projects/subgraph-bean/manifests/ethereum.yaml index 156bc5b6d2..98f72df93d 100644 --- a/projects/subgraph-bean/manifests/ethereum.yaml +++ b/projects/subgraph-bean/manifests/ethereum.yaml @@ -2,6 +2,31 @@ specVersion: 0.0.4 schema: file: ../schema.graphql dataSources: + ### + # INITIALIZATION + ### + - kind: ethereum/contract + name: Version + network: mainnet + source: + address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" + abi: Beanstalk + startBlock: 12974075 + endBlock: 12974075 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Version + abis: + - name: Beanstalk + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts - kind: ethereum/contract name: BeanV1 network: mainnet diff --git a/projects/subgraph-bean/schema.graphql b/projects/subgraph-bean/schema.graphql index f740f8b026..9392462efa 100644 --- a/projects/subgraph-bean/schema.graphql +++ b/projects/subgraph-bean/schema.graphql @@ -1,3 +1,15 @@ +# This same entity schema is intended for use across the subgraphs +type Version @entity { + "= 'subgraph'" + id: ID! + "= 'beanstalk'" + subgraphName: String! + "Verison number of the subgraph" + versionNumber: String! + "Which blockchain is being indexed, i.e. 'ethereum', 'arbitrum', etc." + chain: String! +} + type Token @entity { "Smart contract address of the token" id: ID! diff --git a/projects/subgraph-bean/src/utils/Init.ts b/projects/subgraph-bean/src/utils/Init.ts new file mode 100644 index 0000000000..3ca88c6450 --- /dev/null +++ b/projects/subgraph-bean/src/utils/Init.ts @@ -0,0 +1,24 @@ +import { BigInt, ethereum } from "@graphprotocol/graph-ts"; +import { Version } from "../../generated/schema"; + +export function handleInitVersion(block: ethereum.Block): void { + const versionEntity = new Version("subgraph"); + versionEntity.versionNumber = "2.3.1"; + versionEntity.subgraphName = subgraphNameForBlockNumber(block.number); + versionEntity.chain = chainForBlockNumber(block.number); + versionEntity.save(); +} + +function subgraphNameForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BigInt.fromU32(12974075)) { + return "bean"; + } + throw new Error("Unable to initialize subgraph name for this block number"); +} + +function chainForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BigInt.fromU32(12974075)) { + return "ethereum"; + } + throw new Error("Unable to initialize chain for this block number"); +} diff --git a/projects/subgraph-beanft/manifests/codegen-abis.yaml b/projects/subgraph-beanft/manifests/codegen-abis.yaml index 5a09f00b7c..de84539fe9 100644 --- a/projects/subgraph-beanft/manifests/codegen-abis.yaml +++ b/projects/subgraph-beanft/manifests/codegen-abis.yaml @@ -30,7 +30,8 @@ dataSources: file: ../abis/barnraise.json - name: basin file: ../abis/basin.json - eventHandlers: - - event: Transfer(indexed address,indexed address,indexed uint256) - handler: handleTransferGenesis - file: ../src/mappings.ts + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts diff --git a/projects/subgraph-beanft/manifests/ethereum.yaml b/projects/subgraph-beanft/manifests/ethereum.yaml index 54b3b8fa7f..ad0af5a2bd 100644 --- a/projects/subgraph-beanft/manifests/ethereum.yaml +++ b/projects/subgraph-beanft/manifests/ethereum.yaml @@ -2,6 +2,31 @@ specVersion: 0.0.5 schema: file: ../schema.graphql dataSources: + ### + # INITIALIZATION + ### + - kind: ethereum/contract + name: Version + network: mainnet + source: + address: "0xa755A670Aaf1FeCeF2bea56115E65e03F7722A79" + abi: genesis + startBlock: 13323594 + endBlock: 13323594 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Version + abis: + - name: genesis + file: ../abis/genesis.json + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts - kind: ethereum name: genesis network: mainnet diff --git a/projects/subgraph-beanft/schema.graphql b/projects/subgraph-beanft/schema.graphql index 0a25b889fe..4b842617ce 100644 --- a/projects/subgraph-beanft/schema.graphql +++ b/projects/subgraph-beanft/schema.graphql @@ -1,11 +1,23 @@ +# This same entity schema is intended for use across the subgraphs +type Version @entity { + "= 'subgraph'" + id: ID! + "= 'beanstalk'" + subgraphName: String! + "Verison number of the subgraph" + versionNumber: String! + "Which blockchain is being indexed, i.e. 'ethereum', 'arbitrum', etc." + chain: String! +} + type BeaNFTUser @entity { id: ID! barnRaise: [Int!] genesis: [Int!] winter: [Int!] basin: [Int!] -}, +} type CollectionData @entity { id: ID! minted: [Int!] -} \ No newline at end of file +} diff --git a/projects/subgraph-beanft/src/utils/Init.ts b/projects/subgraph-beanft/src/utils/Init.ts new file mode 100644 index 0000000000..19e683964b --- /dev/null +++ b/projects/subgraph-beanft/src/utils/Init.ts @@ -0,0 +1,24 @@ +import { BigInt, ethereum } from "@graphprotocol/graph-ts"; +import { Version } from "../../generated/schema"; + +export function handleInitVersion(block: ethereum.Block): void { + const versionEntity = new Version("subgraph"); + versionEntity.versionNumber = "1.0.2"; + versionEntity.subgraphName = subgraphNameForBlockNumber(block.number); + versionEntity.chain = chainForBlockNumber(block.number); + versionEntity.save(); +} + +function subgraphNameForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BigInt.fromU32(13323594)) { + return "beanft"; + } + throw new Error("Unable to initialize subgraph name for this block number"); +} + +function chainForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BigInt.fromU32(13323594)) { + return "ethereum"; + } + throw new Error("Unable to initialize chain for this block number"); +} diff --git a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml index 036ca0643b..613d8aaefc 100644 --- a/projects/subgraph-beanstalk/manifests/codegen-abis.yaml +++ b/projects/subgraph-beanstalk/manifests/codegen-abis.yaml @@ -44,7 +44,8 @@ dataSources: file: ../../subgraph-core/abis/CurvePrice.json - name: Fertilizer file: ../../subgraph-core/abis/Fertilizer.json - eventHandlers: - - event: DiamondCut((address,uint8,bytes4[])[],address,bytes) - handler: handleDiamondCut - file: ../src/handlers/DiamondHandler.ts + blockHandlers: + - handler: handleInitVersion + filter: + kind: once + file: ../src/utils/Init.ts diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 7d98946ba9..2fed33dd22 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -26,7 +26,7 @@ type Version @entity { "= 'subgraph'" id: ID! "= 'beanstalk'" - protocolName: String! + subgraphName: String! "Verison number of the subgraph" versionNumber: String! "Which blockchain is being indexed, i.e. 'ethereum', 'arbitrum', etc." diff --git a/projects/subgraph-beanstalk/src/utils/Init.ts b/projects/subgraph-beanstalk/src/utils/Init.ts index f142e1dbe7..44cef48257 100644 --- a/projects/subgraph-beanstalk/src/utils/Init.ts +++ b/projects/subgraph-beanstalk/src/utils/Init.ts @@ -1,24 +1,23 @@ import { BigInt, ethereum } from "@graphprotocol/graph-ts"; import { Version } from "../../generated/schema"; -import { BEANSTALK_BLOCK } from "../../../subgraph-core/utils/Constants"; export function handleInitVersion(block: ethereum.Block): void { const versionEntity = new Version("subgraph"); versionEntity.versionNumber = "2.4.0"; - versionEntity.protocolName = protocolNameForBlockNumber(block.number); + versionEntity.subgraphName = subgraphNameForBlockNumber(block.number); versionEntity.chain = chainForBlockNumber(block.number); versionEntity.save(); } -function protocolNameForBlockNumber(blockNumber: BigInt): string { - if (blockNumber == BEANSTALK_BLOCK) { +function subgraphNameForBlockNumber(blockNumber: BigInt): string { + if (blockNumber == BigInt.fromU32(12974075)) { return "beanstalk"; } - throw new Error("Unable to initialize protocol name for this block number"); + throw new Error("Unable to initialize subgraph name for this block number"); } function chainForBlockNumber(blockNumber: BigInt): string { - if (blockNumber == BEANSTALK_BLOCK) { + if (blockNumber == BigInt.fromU32(12974075)) { return "ethereum"; } throw new Error("Unable to initialize chain for this block number"); From 37cc738a0e9f7023292f0dd030eb69eea21f6624 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:52:22 -0700 Subject: [PATCH 49/59] upgrade manifest specVersion --- projects/subgraph-basin/manifests/codegen-abis.yaml | 2 +- projects/subgraph-basin/manifests/ethereum.yaml | 2 +- projects/subgraph-bean/manifests/codegen-abis.yaml | 2 +- projects/subgraph-bean/manifests/ethereum.yaml | 2 +- projects/subgraph-beanft/manifests/codegen-abis.yaml | 2 +- projects/subgraph-beanft/manifests/ethereum.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/subgraph-basin/manifests/codegen-abis.yaml b/projects/subgraph-basin/manifests/codegen-abis.yaml index d40bdf01c4..fa6c273743 100644 --- a/projects/subgraph-basin/manifests/codegen-abis.yaml +++ b/projects/subgraph-basin/manifests/codegen-abis.yaml @@ -3,7 +3,7 @@ # the only important part is in the `abis` and `templates` sections. # - For abis, its only the list of abis that is relevant. The name of the dataSource is also visible. # - For templates, it is only the name of the template that is relevant. -specVersion: 0.0.4 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-basin/manifests/ethereum.yaml b/projects/subgraph-basin/manifests/ethereum.yaml index 5633136603..4a6ff8445d 100644 --- a/projects/subgraph-basin/manifests/ethereum.yaml +++ b/projects/subgraph-basin/manifests/ethereum.yaml @@ -1,4 +1,4 @@ -specVersion: 0.0.4 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-bean/manifests/codegen-abis.yaml b/projects/subgraph-bean/manifests/codegen-abis.yaml index 5865dadba4..1ab42fdf24 100644 --- a/projects/subgraph-bean/manifests/codegen-abis.yaml +++ b/projects/subgraph-bean/manifests/codegen-abis.yaml @@ -3,7 +3,7 @@ # the only important part is in the `abis` and `templates` sections. # - For abis, its only the list of abis that is relevant. The name of the dataSource is also visible. # - For templates, it is only the name of the template that is relevant. -specVersion: 0.0.4 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-bean/manifests/ethereum.yaml b/projects/subgraph-bean/manifests/ethereum.yaml index 98f72df93d..c4884d028e 100644 --- a/projects/subgraph-bean/manifests/ethereum.yaml +++ b/projects/subgraph-bean/manifests/ethereum.yaml @@ -1,4 +1,4 @@ -specVersion: 0.0.4 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-beanft/manifests/codegen-abis.yaml b/projects/subgraph-beanft/manifests/codegen-abis.yaml index de84539fe9..0cbc6ef2a0 100644 --- a/projects/subgraph-beanft/manifests/codegen-abis.yaml +++ b/projects/subgraph-beanft/manifests/codegen-abis.yaml @@ -3,7 +3,7 @@ # the only important part is in the `abis` and `templates` sections. # - For abis, its only the list of abis that is relevant. The name of the dataSource is also visible. # - For templates, it is only the name of the template that is relevant. -specVersion: 0.0.5 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: diff --git a/projects/subgraph-beanft/manifests/ethereum.yaml b/projects/subgraph-beanft/manifests/ethereum.yaml index ad0af5a2bd..c0b92b9bd5 100644 --- a/projects/subgraph-beanft/manifests/ethereum.yaml +++ b/projects/subgraph-beanft/manifests/ethereum.yaml @@ -1,4 +1,4 @@ -specVersion: 0.0.5 +specVersion: 0.0.9 schema: file: ../schema.graphql dataSources: From bd197a8f177c0670b2c0b2d065c4b970814d2dbf Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:58:11 -0700 Subject: [PATCH 50/59] update apiVersion and deploy ci --- .github/workflows/deploy.subgraph.yaml | 2 +- projects/subgraph-basin/manifests/ethereum.yaml | 2 +- projects/subgraph-bean/manifests/ethereum.yaml | 2 +- projects/subgraph-beanft/manifests/ethereum.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.subgraph.yaml b/.github/workflows/deploy.subgraph.yaml index 6583a64381..95c88ee5ed 100644 --- a/.github/workflows/deploy.subgraph.yaml +++ b/.github/workflows/deploy.subgraph.yaml @@ -28,7 +28,7 @@ jobs: exit 1 fi # Check if the subgraph is a valid selection - if [[ "${{ github.event.inputs.subgraph }}" != "beanstalk" && "${{ github.event.inputs.subgraph }}" != "bean" && "${{ github.event.inputs.subgraph }}" != "basin" && "${{ github.event.inputs.subgraph }}" != "beanft" ]]; then + if [[ ! "${{ github.event.inputs.subgraph }}" =~ ^(beanstalk|bean|basin|beanft) ]]; then echo "Error: Subgraph must be one of 'beanstalk', 'bean', 'basin', 'beanft'." exit 1 fi diff --git a/projects/subgraph-basin/manifests/ethereum.yaml b/projects/subgraph-basin/manifests/ethereum.yaml index 4a6ff8445d..64b5112c0c 100644 --- a/projects/subgraph-basin/manifests/ethereum.yaml +++ b/projects/subgraph-basin/manifests/ethereum.yaml @@ -15,7 +15,7 @@ dataSources: endBlock: 17977922 mapping: kind: ethereum/events - apiVersion: 0.0.6 + apiVersion: 0.0.7 language: wasm/assemblyscript entities: - Version diff --git a/projects/subgraph-bean/manifests/ethereum.yaml b/projects/subgraph-bean/manifests/ethereum.yaml index c4884d028e..f42e9afb87 100644 --- a/projects/subgraph-bean/manifests/ethereum.yaml +++ b/projects/subgraph-bean/manifests/ethereum.yaml @@ -15,7 +15,7 @@ dataSources: endBlock: 12974075 mapping: kind: ethereum/events - apiVersion: 0.0.6 + apiVersion: 0.0.7 language: wasm/assemblyscript entities: - Version diff --git a/projects/subgraph-beanft/manifests/ethereum.yaml b/projects/subgraph-beanft/manifests/ethereum.yaml index c0b92b9bd5..2cc798c09b 100644 --- a/projects/subgraph-beanft/manifests/ethereum.yaml +++ b/projects/subgraph-beanft/manifests/ethereum.yaml @@ -15,7 +15,7 @@ dataSources: endBlock: 13323594 mapping: kind: ethereum/events - apiVersion: 0.0.6 + apiVersion: 0.0.7 language: wasm/assemblyscript entities: - Version From 05784397f81ea12b6cd24331c8516e30b337c2e6 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 17:31:08 -0700 Subject: [PATCH 51/59] fix import of wrong file --- .../src/handlers/legacy/LegacyMarketplaceHandler.ts | 2 -- projects/subgraph-beanstalk/src/utils/Yield.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts index 32505673ee..a14326439b 100644 --- a/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/legacy/LegacyMarketplaceHandler.ts @@ -6,12 +6,10 @@ import { PodOrderFilled as PodOrderFilled_v1, PodListingCancelled as PodListingCancelled_indexed } from "../../../generated/Beanstalk-ABIs/PreReplant"; -import { PodListingCancelled } from "../../../../subgraph-bean/generated/Bean-ABIs/SeedGauge"; import { PodListingCreated as PodListingCreated_v1_1 } from "../../../generated/Beanstalk-ABIs/Replanted"; import { podListingCancelled, podListingCreated, podListingFilled, podOrderCreated, podOrderFilled } from "../../utils/Marketplace"; import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; import { loadPodListing, loadPodOrder } from "../../entities/PodMarketplace"; -import { handlePodListingCancelled } from "../MarketplaceHandler"; // PreReplant -> Replanted export function handlePodListingCreated_v1(event: PodListingCreated_v1): void { diff --git a/projects/subgraph-beanstalk/src/utils/Yield.ts b/projects/subgraph-beanstalk/src/utils/Yield.ts index 8c667ff478..2244eda32c 100644 --- a/projects/subgraph-beanstalk/src/utils/Yield.ts +++ b/projects/subgraph-beanstalk/src/utils/Yield.ts @@ -16,7 +16,7 @@ import { getCurrentSeason, getRewardMinted, loadBeanstalk } from "../entities/Be import { loadFertilizer, loadFertilizerYield } from "../entities/Fertilizer"; import { getProtocolFertilizer } from "./Constants"; import { REPLANT_SEASON } from "../../../subgraph-core/utils/Constants"; -import { SeedGauge } from "../../../subgraph-bean/generated/Bean-ABIs/SeedGauge"; +import { SeedGauge } from "../../generated/Beanstalk-ABIs/SeedGauge"; const ROLLING_24_WINDOW = 24; const ROLLING_7_DAY_WINDOW = 168; From 7923ab5bb67ec8a6bbdd15a4a78c40939c6f8aba Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 17:58:31 -0700 Subject: [PATCH 52/59] null check for bdv of unripe tokens prior to replant --- projects/subgraph-beanstalk/src/utils/Barn.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts index eee1c82f50..80c12ff191 100644 --- a/projects/subgraph-beanstalk/src/utils/Barn.ts +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -81,9 +81,11 @@ export function updateUnripeStats(unripe: Address, protocol: Address, block: eth // Further calculated values unripeToken.underlyingToken = getUnripeUnderlying(unripe, block.number); - const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromBytes(unripeToken.underlyingToken)))!; - unripeToken.bdvUnderlyingOne = unripeToken.amountUnderlyingOne.times(underlyingBdvOne); - unripeToken.choppableBdvOne = unripeToken.choppableAmountOne.times(underlyingBdvOne); + const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromBytes(unripeToken.underlyingToken))); + if (underlyingBdvOne != null) { + unripeToken.bdvUnderlyingOne = unripeToken.amountUnderlyingOne.times(underlyingBdvOne); + unripeToken.choppableBdvOne = unripeToken.choppableAmountOne.times(underlyingBdvOne); + } takeUnripeTokenSnapshots(unripeToken, protocol, block.timestamp); unripeToken.save(); From c96592c6b2d78304a9bce49b5764f210f1640364 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:10:21 -0700 Subject: [PATCH 53/59] fix comparison --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 4 ++-- projects/subgraph-beanstalk/src/utils/Barn.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 6062875059..0b78a3e4cb 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -929,5 +929,5 @@ dataSources: # features: # - grafting # graft: -# base: QmRiA7YzTJA5wHXjJzE2ksTK88BTq1XHQCLBfWmumittVn -# block: 19927660 +# base: QmfJpxvEjd4BdhtGr42MVtjbgnz9PPUmJ35wf7XtCJXeaC +# block: 15279870 diff --git a/projects/subgraph-beanstalk/src/utils/Barn.ts b/projects/subgraph-beanstalk/src/utils/Barn.ts index 80c12ff191..cbd7528c52 100644 --- a/projects/subgraph-beanstalk/src/utils/Barn.ts +++ b/projects/subgraph-beanstalk/src/utils/Barn.ts @@ -82,7 +82,7 @@ export function updateUnripeStats(unripe: Address, protocol: Address, block: eth // Further calculated values unripeToken.underlyingToken = getUnripeUnderlying(unripe, block.number); const underlyingBdvOne = getLatestBdv(loadWhitelistTokenSetting(Address.fromBytes(unripeToken.underlyingToken))); - if (underlyingBdvOne != null) { + if (underlyingBdvOne !== null) { unripeToken.bdvUnderlyingOne = unripeToken.amountUnderlyingOne.times(underlyingBdvOne); unripeToken.choppableBdvOne = unripeToken.choppableAmountOne.times(underlyingBdvOne); } From a2a71fc775b7c74dab11a7118048a523e01e9497 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:55:56 -0700 Subject: [PATCH 54/59] change abi for pre-replant sunrise --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 0b78a3e4cb..6d254ea214 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -802,7 +802,7 @@ dataSources: network: mainnet source: address: "0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5" - abi: PreReplant + abi: SeedGauge startBlock: 12974075 endBlock: 15277986 # Replanted mapping: @@ -812,8 +812,8 @@ dataSources: entities: - Season abis: - - name: PreReplant - file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Pre-Replant.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - event: Sunrise(indexed uint256) handler: handleSunrise From 82c5e492771f06df09e6bdf1952cf707034428c3 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:24:36 -0700 Subject: [PATCH 55/59] fix nullable issues --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 6 ++++-- .../src/entities/snapshots/WhitelistTokenSetting.ts | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 6d254ea214..a4f9bfc833 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -835,6 +835,8 @@ dataSources: abis: - name: Replanted file: ../../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + - name: SeedGauge + file: ../../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json eventHandlers: - event: Sunrise(indexed uint256) handler: handleReplantSunrise @@ -929,5 +931,5 @@ dataSources: # features: # - grafting # graft: -# base: QmfJpxvEjd4BdhtGr42MVtjbgnz9PPUmJ35wf7XtCJXeaC -# block: 15279870 +# base: QmRJCKP5nLjUNtR2ZZ9F62iBGiKLdkGPX7GzBZLgVfnz3c +# block: 15289930 diff --git a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts index 6e99dc56a2..2b08a6831e 100644 --- a/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts +++ b/projects/subgraph-beanstalk/src/entities/snapshots/WhitelistTokenSetting.ts @@ -162,17 +162,17 @@ export function setBdv(bdv: BigInt, whitelistTokenSetting: WhitelistTokenSetting // (the current season snapshots were already created) const prevHourly = WhitelistTokenHourlySnapshot.load( whitelistTokenSetting.id.toHexString() + "-" + (whitelistTokenSetting.lastHourlySnapshotSeason - 1).toString() - )!; + ); const prevDaily = WhitelistTokenDailySnapshot.load( whitelistTokenSetting.id.toHexString() + "-" + (whitelistTokenSetting.lastDailySnapshotDay!.toI32() - 1).toString() - )!; + ); - if (prevHourly != null) { + if (prevHourly != null && prevHourly.bdv !== null) { hourly.deltaBdv = hourly.bdv!.minus(prevHourly.bdv!); } else { hourly.deltaBdv = hourly.bdv; } - if (prevDaily != null) { + if (prevDaily != null && prevDaily.bdv !== null) { daily.deltaBdv = daily.bdv!.minus(prevDaily.bdv!); } else { daily.deltaBdv = daily.bdv; From 7a98b22c2cfa66b0e7ee7ec6ceedb51fe423df3a Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:48:12 -0700 Subject: [PATCH 56/59] FarmerGerminatingStalkBalanceChanged adjust for event bug --- projects/subgraph-beanstalk/schema.graphql | 13 +++++++ .../src/entities/Germinating.ts | 37 +++++++++++++++++-- .../src/handlers/GaugeHandler.ts | 19 ++++++++-- 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/projects/subgraph-beanstalk/schema.graphql b/projects/subgraph-beanstalk/schema.graphql index 2fed33dd22..e486ed70c7 100644 --- a/projects/subgraph-beanstalk/schema.graphql +++ b/projects/subgraph-beanstalk/schema.graphql @@ -1472,6 +1472,19 @@ type Germinating @entity { bdv: BigInt! } +# This entity exists solely for resolving the issue in LibGerminate when deposits from multiple seasons +# complete their germination (the event emission itself has a bug) +type PrevFarmerGerminatingEvent @entity { + "Farmer address" + id: Bytes! + "The `block.number` of the `FarmerGerminatingStalkBalanceChanged` event" + eventBlock: BigInt! + "The `logIndex` of the `FarmerGerminatingStalkBalanceChanged` event" + logIndex: BigInt! + "The value for `deltaGerminatingStalk` from this previous `FarmerGerminatingStalkBalanceChanged` event." + deltaGerminatingStalk: BigInt! +} + type UnripeToken @entity { "Token Address" id: Bytes! diff --git a/projects/subgraph-beanstalk/src/entities/Germinating.ts b/projects/subgraph-beanstalk/src/entities/Germinating.ts index 32912d0149..8939dd6682 100644 --- a/projects/subgraph-beanstalk/src/entities/Germinating.ts +++ b/projects/subgraph-beanstalk/src/entities/Germinating.ts @@ -1,6 +1,6 @@ -import { Address, BigDecimal, BigInt, store } from "@graphprotocol/graph-ts"; -import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { Germinating } from "../../generated/schema"; +import { Address, BigDecimal, BigInt, ethereum, store } from "@graphprotocol/graph-ts"; +import { ONE_BI, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { Germinating, PrevFarmerGerminatingEvent } from "../../generated/schema"; export function loadOrCreateGerminating(address: Address, season: i32, isFarmer: boolean): Germinating { const type = germinationSeasonCategory(season); @@ -42,6 +42,37 @@ export function deleteGerminating(germinating: Germinating): void { store.remove("Germinating", germinating.id); } +// This is the entity that exists to resolve the issue in LibGerminate when deposits from multiple seasons +// complete their germination (the event emission itself has a bug) +export function loadPrevFarmerGerminatingEvent(account: Address): PrevFarmerGerminatingEvent { + let savedEvent = PrevFarmerGerminatingEvent.load(account); + if (savedEvent == null) { + savedEvent = new PrevFarmerGerminatingEvent(account); + savedEvent.eventBlock = ZERO_BI; + savedEvent.logIndex = ZERO_BI; + savedEvent.deltaGerminatingStalk = ZERO_BI; + // No point in saving it + } + return savedEvent as PrevFarmerGerminatingEvent; +} + +export function savePrevFarmerGerminatingEvent(account: Address, event: ethereum.Event, deltaGerminatingStalk: BigInt): void { + const savedEvent = new PrevFarmerGerminatingEvent(account); + savedEvent.eventBlock = event.block.number; + savedEvent.logIndex = event.logIndex; + savedEvent.deltaGerminatingStalk = deltaGerminatingStalk; + savedEvent.save(); +} + +// Returns the stalk offset that should be applied to the encountered FarmerGerminatingStalkBalanceChanged event. +export function getFarmerGerminatingBugOffset(account: Address, event: ethereum.Event): BigInt { + const prevEvent = loadPrevFarmerGerminatingEvent(account); + if (prevEvent.eventBlock == event.block.number && prevEvent.logIndex == event.logIndex.minus(ONE_BI)) { + return prevEvent.deltaGerminatingStalk.neg(); + } + return ZERO_BI; +} + function germinationSeasonCategory(season: i32): string { return season % 2 == 0 ? "EVEN" : "ODD"; } diff --git a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts index 30401b4dba..72038a6886 100644 --- a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts @@ -8,7 +8,13 @@ import { TotalGerminatingStalkChanged, TotalStalkChangedFromGermination } from "../../generated/Beanstalk-ABIs/SeedGauge"; -import { deleteGerminating, loadGerminating, loadOrCreateGerminating } from "../entities/Germinating"; +import { + deleteGerminating, + getFarmerGerminatingBugOffset, + loadGerminating, + loadOrCreateGerminating, + savePrevFarmerGerminatingEvent +} from "../entities/Germinating"; import { BI_10, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; import { BEAN_WETH_CP2_WELL } from "../../../subgraph-core/utils/Constants"; import { Bytes4_emptyToNull } from "../../../subgraph-core/utils/Bytes"; @@ -71,9 +77,13 @@ export function handleFarmerGerminatingStalkBalanceChanged(event: FarmerGerminat farmerGerminating.stalk = farmerGerminating.stalk.plus(event.params.deltaGerminatingStalk); farmerGerminating.save(); } else { + // Adjusts for the event's inherent bug when both even/odd germination complete in the same txn + const bugfixStalkOffset = getFarmerGerminatingBugOffset(event.params.account, event); + const actualDeltaGerminatingStalk = event.params.deltaGerminatingStalk.plus(bugfixStalkOffset); + // Germinating stalk is being removed. It therefore must have created the entity already let farmerGerminating = loadGerminating(event.params.account, event.params.germinationState); - farmerGerminating.stalk = farmerGerminating.stalk.plus(event.params.deltaGerminatingStalk); + farmerGerminating.stalk = farmerGerminating.stalk.plus(actualDeltaGerminatingStalk); if (farmerGerminating.stalk == ZERO_BI) { deleteGerminating(farmerGerminating); } else { @@ -84,10 +94,13 @@ export function handleFarmerGerminatingStalkBalanceChanged(event: FarmerGerminat // If germination finished, need to subtract stalk from system silo. This stalk was already added // into system stalk upon sunrise for season - 2. let systemSilo = loadSilo(event.address); - systemSilo.stalk = systemSilo.stalk.plus(event.params.deltaGerminatingStalk); + systemSilo.stalk = systemSilo.stalk.plus(actualDeltaGerminatingStalk); takeSiloSnapshots(systemSilo, event.address, event.block.timestamp); systemSilo.save(); } + + // Also for the event bug adjustment + savePrevFarmerGerminatingEvent(event.params.account, event, event.params.deltaGerminatingStalk); } let farmerSilo = loadSilo(event.params.account); From 17ee34b64d425dbc502528dda04f4b344cdadfe5 Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:41:28 -0700 Subject: [PATCH 57/59] Fix for germinating starting on the prior season upon certain converts --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 10 +++++----- .../subgraph-beanstalk/src/entities/Germinating.ts | 4 ++-- .../subgraph-beanstalk/src/handlers/GaugeHandler.ts | 13 +++++++++++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index a4f9bfc833..0fa68b49b4 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -928,8 +928,8 @@ dataSources: - event: InternalBalanceChanged(indexed address,indexed address,int256) handler: handleInternalBalanceChanged file: ../src/handlers/FarmHandler.ts -# features: -# - grafting -# graft: -# base: QmRJCKP5nLjUNtR2ZZ9F62iBGiKLdkGPX7GzBZLgVfnz3c -# block: 15289930 +features: + - grafting +graft: + base: QmUqT47H7o3gcZ2mHRJf2J5hpitWDYxsMmacGeuvo1wKU7 + block: 19927630 diff --git a/projects/subgraph-beanstalk/src/entities/Germinating.ts b/projects/subgraph-beanstalk/src/entities/Germinating.ts index 8939dd6682..ddb2c0b490 100644 --- a/projects/subgraph-beanstalk/src/entities/Germinating.ts +++ b/projects/subgraph-beanstalk/src/entities/Germinating.ts @@ -73,10 +73,10 @@ export function getFarmerGerminatingBugOffset(account: Address, event: ethereum. return ZERO_BI; } -function germinationSeasonCategory(season: i32): string { +export function germinationSeasonCategory(season: i32): string { return season % 2 == 0 ? "EVEN" : "ODD"; } -function germinationEnumCategory(enumValue: i32): string { +export function germinationEnumCategory(enumValue: i32): string { return enumValue == 0 ? "ODD" : "EVEN"; } diff --git a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts index 72038a6886..a40d231f0c 100644 --- a/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/GaugeHandler.ts @@ -10,6 +10,8 @@ import { } from "../../generated/Beanstalk-ABIs/SeedGauge"; import { deleteGerminating, + germinationEnumCategory, + germinationSeasonCategory, getFarmerGerminatingBugOffset, loadGerminating, loadOrCreateGerminating, @@ -72,8 +74,15 @@ export function handleFarmerGerminatingStalkBalanceChanged(event: FarmerGerminat const currentSeason = getCurrentSeason(event.address); if (event.params.deltaGerminatingStalk > ZERO_BI) { - // Germinating stalk is being added in the current season - let farmerGerminating = loadOrCreateGerminating(event.params.account, currentSeason, true); + // Germinating stalk is added. It is possible to begin germination in the prior season rather than the + // current season when converting. See ConvertFacet._depositTokensForConvert for more information. + // If the event's germinationState doesnt match with the current season, use the prior season. + const germinatingSeason = + germinationSeasonCategory(currentSeason) === germinationEnumCategory(event.params.germinationState) + ? currentSeason + : currentSeason - 1; + + let farmerGerminating = loadOrCreateGerminating(event.params.account, germinatingSeason, true); farmerGerminating.stalk = farmerGerminating.stalk.plus(event.params.deltaGerminatingStalk); farmerGerminating.save(); } else { From 510aa88558e7819ff0f4c4d872d48509a0c1576c Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:18:17 -0700 Subject: [PATCH 58/59] remove graft --- projects/subgraph-beanstalk/manifests/ethereum.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 0fa68b49b4..740990494a 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -928,8 +928,8 @@ dataSources: - event: InternalBalanceChanged(indexed address,indexed address,int256) handler: handleInternalBalanceChanged file: ../src/handlers/FarmHandler.ts -features: - - grafting -graft: - base: QmUqT47H7o3gcZ2mHRJf2J5hpitWDYxsMmacGeuvo1wKU7 - block: 19927630 +# features: +# - grafting +# graft: +# base: QmUqT47H7o3gcZ2mHRJf2J5hpitWDYxsMmacGeuvo1wKU7 +# block: 19927630 From e395207a23aad14e3ea500292a6c38df0acffded Mon Sep 17 00:00:00 2001 From: Soil King <157099073+soilking@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:47:29 -0700 Subject: [PATCH 59/59] handle bean supply exploit correction --- .../manifests/ethereum.yaml | 25 +++++++++++++++++++ .../src/handlers/BeanHandler.ts | 18 ++++++++++--- .../subgraph-beanstalk/src/utils/Constants.ts | 9 +++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/projects/subgraph-beanstalk/manifests/ethereum.yaml b/projects/subgraph-beanstalk/manifests/ethereum.yaml index 740990494a..16b7b9fae1 100644 --- a/projects/subgraph-beanstalk/manifests/ethereum.yaml +++ b/projects/subgraph-beanstalk/manifests/ethereum.yaml @@ -362,6 +362,31 @@ dataSources: kind: once file: ../src/utils/Init.ts ### + # EXPLOIT + ### + - kind: ethereum/contract + name: Exploit + network: mainnet + source: + address: "0xDC59ac4FeFa32293A95889Dc396682858d52e5Db" + abi: ERC20 + startBlock: 14602789 # Exploit + endBlock: 14602789 # Exploit + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Version + abis: + - name: ERC20 + file: ../../subgraph-core/abis/ERC20.json + blockHandlers: + - handler: handleExploit + filter: + kind: once + file: ../src/handlers/BeanHandler.ts + ### # SILO ### - kind: ethereum/contract diff --git a/projects/subgraph-beanstalk/src/handlers/BeanHandler.ts b/projects/subgraph-beanstalk/src/handlers/BeanHandler.ts index 5017fe9fe0..1569946103 100644 --- a/projects/subgraph-beanstalk/src/handlers/BeanHandler.ts +++ b/projects/subgraph-beanstalk/src/handlers/BeanHandler.ts @@ -1,12 +1,14 @@ -import { BigInt, log } from "@graphprotocol/graph-ts"; +import { BigDecimal, BigInt, ethereum, log } from "@graphprotocol/graph-ts"; import { Transfer } from "../../generated/Beanstalk-ABIs/ERC20"; import { ADDRESS_ZERO, BEANSTALK } from "../../../subgraph-core/utils/Constants"; import { loadBeanstalk, loadSeason } from "../entities/Beanstalk"; +import { getTokenProtocol } from "../utils/Constants"; +import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; export function handleTransfer(event: Transfer): void { if (event.params.from == ADDRESS_ZERO || event.params.to == ADDRESS_ZERO) { - let beanstalk = loadBeanstalk(BEANSTALK); - let season = loadSeason(BEANSTALK, BigInt.fromI32(beanstalk.lastSeason)); + let beanstalk = loadBeanstalk(getTokenProtocol(event.address)); + let season = loadSeason(getTokenProtocol(event.address), BigInt.fromI32(beanstalk.lastSeason)); if (event.params.from == ADDRESS_ZERO) { season.deltaBeans = season.deltaBeans.plus(event.params.value); @@ -18,3 +20,13 @@ export function handleTransfer(event: Transfer): void { season.save(); } } + +export function handleExploit(block: ethereum.Block): void { + let beanstalk = loadBeanstalk(BEANSTALK); + let season = loadSeason(BEANSTALK, BigInt.fromI32(beanstalk.lastSeason)); + season.deltaBeans = ZERO_BI; + season.beans = ZERO_BI; + season.price = BigDecimal.fromString("1.022"); + season.save(); + return; +} diff --git a/projects/subgraph-beanstalk/src/utils/Constants.ts b/projects/subgraph-beanstalk/src/utils/Constants.ts index f79e2e929e..182a1d6806 100644 --- a/projects/subgraph-beanstalk/src/utils/Constants.ts +++ b/projects/subgraph-beanstalk/src/utils/Constants.ts @@ -23,6 +23,15 @@ export function getProtocolToken(protocol: Address): Address { throw new Error("Unsupported protocol"); } +export function getTokenProtocol(token: Address): Address { + if (token == BEAN_ERC20) { + return BEANSTALK; + } else if (token == BEAN_ERC20_V1) { + return BEANSTALK; + } + throw new Error("Unsupported protocol token"); +} + export function getProtocolFertilizer(protocol: Address): Address | null { if (protocol == BEANSTALK) { return FERTILIZER;