diff --git a/projects/subgraph-basin/README.md b/projects/subgraph-basin/README.md index a7135a0b7b..c6ea6f1565 100644 --- a/projects/subgraph-basin/README.md +++ b/projects/subgraph-basin/README.md @@ -9,4 +9,15 @@ ### Subgraphs -All subgraphs are currently in development in the anticipation of the Wells release. +All currently used subgraphs live on a centralized host controlled by beanstalk farms. + +- [Testing Subgraph](https://graph.node.bean.money/subgraphs/name/basin-testing) + - Used during local development for debugging and rapid iteration. +- [Dev Subgraph](https://graph.node.bean.money/subgraphs/name/basin-dev) + - Used for testing fixes or improvements made in the testing subgraph. +- [Canonical Subgraph](https://graph.node.bean.money/subgraphs/name/basin) + - Stable deployment and current source of truth for UI and other production processes. + +### Testing + +To test with Docker, the first time you will need to run `yarn run graph test -d`. This will build the `matchstick` Docker image. Then, you can use the `yarn testd` script to run all tests. Alternatively, use `yarn testd-named ...` to run specific tests. I have found running in Docker to be preferred since otherwise there can be issues with console output and some test cases fail silently. diff --git a/projects/subgraph-basin/src/utils/BeanstalkPrice.ts b/projects/subgraph-basin/src/utils/BeanstalkPrice.ts new file mode 100644 index 0000000000..320cdaf4ee --- /dev/null +++ b/projects/subgraph-basin/src/utils/BeanstalkPrice.ts @@ -0,0 +1,17 @@ +// Unfortunately this file must be copied across the various subgraph projects. This is due to the codegen +import { Address, BigInt } from "@graphprotocol/graph-ts"; +import { BeanstalkPrice } from "../../generated/templates/Well/BeanstalkPrice"; +import { BEANSTALK_PRICE_1, BEANSTALK_PRICE_2, PRICE_2_BLOCK } from "../../../subgraph-core/utils/Constants"; + +// Gets the BeanstalkPrice contract, bound to the appropriate instance of the contract. +// Note: Will bind to PRICE_1 even if that contract has not been deployed yet +// Thus the caller still needs to check for reverts. +export function getBeanstalkPrice(blockNumber: BigInt): BeanstalkPrice { + let contractAddress: Address; + if (blockNumber < PRICE_2_BLOCK) { + contractAddress = BEANSTALK_PRICE_1; + } else { + contractAddress = BEANSTALK_PRICE_2; + } + return BeanstalkPrice.bind(contractAddress); +} diff --git a/projects/subgraph-basin/src/utils/Token.ts b/projects/subgraph-basin/src/utils/Token.ts index 79fa5a4403..0c8b95bc3b 100644 --- a/projects/subgraph-basin/src/utils/Token.ts +++ b/projects/subgraph-basin/src/utils/Token.ts @@ -2,9 +2,9 @@ import { Address, BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; import { ERC20 } from "../../generated/Aquifer/ERC20"; import { Token } from "../../generated/schema"; import { CurvePrice } from "../../generated/templates/Well/CurvePrice"; -import { BEANSTALK_PRICE, BEAN_ERC20, BEAN_WETH_CP2_WELL, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; +import { BEAN_ERC20, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { BeanstalkPrice } from "../../generated/templates/Well/BeanstalkPrice"; +import { getBeanstalkPrice } from "./BeanstalkPrice"; export function loadOrCreateToken(tokenAddress: Address): Token { let token = Token.load(tokenAddress); @@ -59,8 +59,8 @@ export function updateTokenUSD(tokenAddress: Address, blockNumber: BigInt, beanP if (tokenAddress == BEAN_ERC20) { // Attempt to use Beanstalk price contract first - let beanstalkPrice = BeanstalkPrice.bind(BEANSTALK_PRICE); - let price = beanstalkPrice.try_getConstantProductWell(BEAN_WETH_CP2_WELL); + let beanstalkPrice = getBeanstalkPrice(blockNumber); + let price = beanstalkPrice.try_price(); if (!price.reverted) { token.lastPriceUSD = toDecimal(price.value.price); } else { diff --git a/projects/subgraph-basin/tests/helpers/Functions.ts b/projects/subgraph-basin/tests/helpers/Functions.ts index f68dab29fd..c4feab1ca1 100644 --- a/projects/subgraph-basin/tests/helpers/Functions.ts +++ b/projects/subgraph-basin/tests/helpers/Functions.ts @@ -1,8 +1,8 @@ import { BigDecimal, BigInt, ethereum } from "@graphprotocol/graph-ts"; import { createMockedFunction } from "matchstick-as/assembly/index"; -import { BEAN_3CRV, BEAN_ERC20, BEAN_WETH_CP2_WELL, CRV3_TOKEN, WETH } from "../../../subgraph-core/utils/Constants"; +import { BEAN_3CRV, BEAN_ERC20, BEAN_WETH_CP2_WELL, BEANSTALK_PRICE_1, CRV3_TOKEN, WETH } from "../../../subgraph-core/utils/Constants"; import { BEAN_USD_PRICE, WELL } from "./Constants"; -import { setMockCurvePrice, setMockWellPrice } from "../../../subgraph-core/tests/event-mocking/Price"; +import { setMockBeanPrice } from "../../../subgraph-core/tests/event-mocking/Price"; import { ONE_BD, ZERO_BD } from "../../../subgraph-core/utils/Decimals"; let prevMocked = ZERO_BD; @@ -15,26 +15,32 @@ export function createContractCallMocks(priceMultiple: BigDecimal = ONE_BD): voi const price = BigInt.fromString(new BigDecimal(BEAN_USD_PRICE).times(priceMultiple).truncate(0).toString()); - setMockCurvePrice({ - contract: BEAN_3CRV, - tokens: [BEAN_ERC20, CRV3_TOKEN], - balances: [BigInt.fromString("14306013160240"), BigInt.fromString("12306817594155799426763734")], + setMockBeanPrice({ price: price, - liquidity: BigInt.fromString("26025239751318"), - deltaB: BigInt.fromString("-866349934591"), - lpUsd: BigInt.fromString("969328"), - lpBdv: BigInt.fromString("1032515") - }); - - setMockWellPrice({ - contract: BEAN_WETH_CP2_WELL, - tokens: [BEAN_ERC20, WETH], - balances: [BigInt.fromString("2000000000"), BigInt.fromString("1500000000000000000")], - price: price, - liquidity: BigInt.fromString("26025239751318"), - deltaB: BigInt.fromString("-866349934591"), - lpUsd: BigInt.fromString("969328"), - lpBdv: BigInt.fromString("1032515") + liquidity: BigInt.fromString("26025239751318").times(BigInt.fromU32(2)), + deltaB: BigInt.fromString("-866349934591").times(BigInt.fromU32(2)), + ps: [ + { + contract: BEAN_3CRV, + tokens: [BEAN_ERC20, CRV3_TOKEN], + balances: [BigInt.fromString("14306013160240"), BigInt.fromString("12306817594155799426763734")], + price: price, + liquidity: BigInt.fromString("26025239751318"), + deltaB: BigInt.fromString("-866349934591"), + lpUsd: BigInt.fromString("969328"), + lpBdv: BigInt.fromString("1032515") + }, + { + contract: BEAN_WETH_CP2_WELL, + tokens: [BEAN_ERC20, WETH], + balances: [BigInt.fromString("2000000000"), BigInt.fromString("1500000000000000000")], + price: price, + liquidity: BigInt.fromString("26025239751318"), + deltaB: BigInt.fromString("-866349934591"), + lpUsd: BigInt.fromString("969328"), + lpBdv: BigInt.fromString("1032515") + } + ] }); createMockedFunction(BEAN_ERC20, "name", "name():(string)") diff --git a/projects/subgraph-bean/README.md b/projects/subgraph-bean/README.md index 84d90bc223..272a96a7a1 100644 --- a/projects/subgraph-bean/README.md +++ b/projects/subgraph-bean/README.md @@ -1,6 +1,25 @@ Beanstalk logo -# Bean Subgraph +## Beanstalk Subgraph -The Bean subgraph can be found here: -https://thegraph.com/explorer/subgraph?id=0x925753106fcdb6d2f30c3db295328a0a1c5fd1d1-1 +[![Discord][discord-badge]][discord-url] + +[discord-badge]: https://img.shields.io/discord/880413392916054098?label=Beanstalk +[discord-url]: https://discord.gg/beanstalk + +**Indexes events emitted by [Beanstalk](https://etherscan.io/address/0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5) and its trading pools.** + +### Subgraphs + +All currently used subgraphs live on a centralized host controlled by beanstalk farms. + +- [Testing Subgraph](https://graph.node.bean.money/subgraphs/name/bean-testing) + - Used during local development for debugging and rapid iteration. +- [Dev Subgraph](https://graph.node.bean.money/subgraphs/name/bean-dev) + - Used for testing fixes or improvements made in the testing subgraph. +- [Canonical Subgraph](https://graph.node.bean.money/subgraphs/name/bean) + - Stable deployment and current source of truth for UI and other production processes. + +### Testing + +To test with Docker, the first time you will need to run `yarn run graph test -d`. This will build the `matchstick` Docker image. Then, you can use the `yarn testd` script to run all tests. Alternatively, use `yarn testd-named ...` to run specific tests. I have found running in Docker to be preferred since otherwise there can be issues with console output and some test cases fail silently. diff --git a/projects/subgraph-bean/src/BeanWellHandler.ts b/projects/subgraph-bean/src/BeanWellHandler.ts index e09be16f99..0c7b91c0fc 100644 --- a/projects/subgraph-bean/src/BeanWellHandler.ts +++ b/projects/subgraph-bean/src/BeanWellHandler.ts @@ -86,7 +86,10 @@ function handleLiquidityChange( if (beanPrice.reverted) { return; } - let wellPrice = getPoolPrice(beanPrice, Address.fromString(poolAddress))!; + let wellPrice = getPoolPrice(beanPrice, Address.fromString(poolAddress)); + if (wellPrice == null) { + return; + } let startingLiquidity = getPoolLiquidityUSD(poolAddress, blockNumber); @@ -142,7 +145,10 @@ function handleSwapEvent( if (beanPrice.reverted) { return; } - let wellPrice = getPoolPrice(beanPrice, Address.fromString(poolAddress))!; + let wellPrice = getPoolPrice(beanPrice, Address.fromString(poolAddress)); + if (wellPrice == null) { + return; + } let startingLiquidity = getPoolLiquidityUSD(poolAddress, blockNumber); diff --git a/projects/subgraph-bean/src/BeanstalkHandler.ts b/projects/subgraph-bean/src/BeanstalkHandler.ts index 2bcb75863a..ebc4cd1686 100644 --- a/projects/subgraph-bean/src/BeanstalkHandler.ts +++ b/projects/subgraph-bean/src/BeanstalkHandler.ts @@ -2,16 +2,7 @@ import { Address, BigInt } from "@graphprotocol/graph-ts"; import { Chop, DewhitelistToken, Reward, Sunrise } from "../generated/Beanstalk/Beanstalk"; import { getBeanTokenAddress, loadBean, updateBeanSeason, updateBeanSupplyPegPercent, updateBeanTwa, updateBeanValues } from "./utils/Bean"; import { loadOrCreatePool, updatePoolPrice, updatePoolSeason, updatePoolValues } from "./utils/Pool"; -import { BeanstalkPrice } from "../generated/Beanstalk/BeanstalkPrice"; -import { - BEANSTALK_PRICE, - BEAN_3CRV, - BEAN_ERC20, - BEAN_ERC20_V1, - BEAN_WETH_CP2_WELL, - BEAN_WETH_V1, - CURVE_PRICE -} from "../../subgraph-core/utils/Constants"; +import { BEAN_3CRV, BEAN_ERC20, BEAN_ERC20_V1, BEAN_WETH_V1, CURVE_PRICE } from "../../subgraph-core/utils/Constants"; import { ZERO_BD, ZERO_BI, toDecimal } from "../../subgraph-core/utils/Decimals"; import { CurvePrice } from "../generated/Beanstalk/CurvePrice"; import { checkBeanCross } from "./utils/Cross"; diff --git a/projects/subgraph-bean/src/BlockHandler.ts b/projects/subgraph-bean/src/BlockHandler.ts index 308febd162..84c64471e2 100644 --- a/projects/subgraph-bean/src/BlockHandler.ts +++ b/projects/subgraph-bean/src/BlockHandler.ts @@ -1,5 +1,5 @@ import { ethereum } from "@graphprotocol/graph-ts"; -import { BEAN_ERC20, BEAN_WETH_CP2_WELL_BLOCK, BEANSTALK_PRICE, EXPLOIT_BLOCK } from "../../subgraph-core/utils/Constants"; +import { BEAN_ERC20, BEAN_WETH_CP2_WELL_BLOCK, EXPLOIT_BLOCK } from "../../subgraph-core/utils/Constants"; import { checkPegCrossEth as univ2_checkPegCrossEth } from "./UniswapV2Handler"; import { loadBean, updateBeanValues } from "./utils/Bean"; import { toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; @@ -38,8 +38,6 @@ export function beanstalkPrice_updatePoolPrices(priceOnlyOnCross: boolean, block const prevPrice = bean.price; const newPrice = toDecimal(priceResult.value.price); - // log.debug("Prev/New bean price {} / {}", [prevPrice.toString(), newPrice.toString()]); - // Check for overall peg cross const beanCrossed = checkBeanCross(BEAN_ERC20.toHexString(), block.timestamp, block.number, prevPrice, newPrice); diff --git a/projects/subgraph-bean/src/constants/PooledTokens.ts b/projects/subgraph-bean/src/constants/PooledTokens.ts index 6937a83187..5ef138c463 100644 --- a/projects/subgraph-bean/src/constants/PooledTokens.ts +++ b/projects/subgraph-bean/src/constants/PooledTokens.ts @@ -9,7 +9,9 @@ import { BEAN_3CRV_V1, BEAN_LUSD_V1, BEAN_3CRV, - BEAN_WETH_CP2_WELL + BEAN_WETH_CP2_WELL, + BEAN_WSTETH_CP2_WELL, + WSTETH } from "../../../subgraph-core/utils/Constants"; // Use this mapping to determine which tokens are in each pool. Pools may each follow a distinct interface, @@ -58,6 +60,10 @@ const poolTokens: PoolTokens[] = [ { pool: BEAN_WETH_CP2_WELL.toHexString(), tokens: [BEAN_ERC20.toHexString(), WETH.toHexString()] + }, + { + pool: BEAN_WSTETH_CP2_WELL.toHexString(), + tokens: [BEAN_ERC20.toHexString(), WSTETH.toHexString()] } ]; @@ -92,5 +98,9 @@ const tokens: Token[] = [ { address: LUSD.toHexString(), info: { name: "LUSD", decimals: BigInt.fromU32(18) } + }, + { + address: WSTETH.toHexString(), + info: { name: "wstETH", decimals: BigInt.fromU32(18) } } ]; diff --git a/projects/subgraph-bean/src/utils/Bean.ts b/projects/subgraph-bean/src/utils/Bean.ts index cd3c7e70bf..33c74a2477 100644 --- a/projects/subgraph-bean/src/utils/Bean.ts +++ b/projects/subgraph-bean/src/utils/Bean.ts @@ -1,15 +1,6 @@ -import { BigDecimal, BigInt, log } from "@graphprotocol/graph-ts"; +import { BigDecimal, BigInt } from "@graphprotocol/graph-ts"; import { Bean, BeanDailySnapshot, BeanHourlySnapshot, Pool } from "../../generated/schema"; -import { - BEAN_3CRV, - BEAN_ERC20_V1, - BEAN_ERC20, - BEAN_WETH_V1, - BEAN_WETH_CP2_WELL, - 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 } 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"; diff --git a/projects/subgraph-bean/src/utils/BeanWells.ts b/projects/subgraph-bean/src/utils/BeanWells.ts index 8c2c7a9949..5cc72a0121 100644 --- a/projects/subgraph-bean/src/utils/BeanWells.ts +++ b/projects/subgraph-bean/src/utils/BeanWells.ts @@ -1,5 +1,10 @@ import { BigInt, Address } from "@graphprotocol/graph-ts"; -import { BEAN_WETH_CP2_WELL, BEAN_WETH_CP2_WELL_BLOCK } from "../../../subgraph-core/utils/Constants"; +import { + BEAN_WETH_CP2_WELL, + BEAN_WETH_CP2_WELL_BLOCK, + BEAN_WSTETH_CP2_WELL, + BEAN_WSTETH_CP2_WELL_BLOCK +} from "../../../subgraph-core/utils/Constants"; export enum WellFunction { ConstantProduct @@ -16,5 +21,10 @@ export const BEAN_WELLS: BeanWell[] = [ address: BEAN_WETH_CP2_WELL, startBlock: BEAN_WETH_CP2_WELL_BLOCK, wellFunction: WellFunction.ConstantProduct + }, + { + address: BEAN_WSTETH_CP2_WELL, + startBlock: BEAN_WSTETH_CP2_WELL_BLOCK, + wellFunction: WellFunction.ConstantProduct } ]; diff --git a/projects/subgraph-bean/src/utils/LockedBeans.ts b/projects/subgraph-bean/src/utils/LockedBeans.ts index 5ba95b6fa0..a0f2064081 100644 --- a/projects/subgraph-bean/src/utils/LockedBeans.ts +++ b/projects/subgraph-bean/src/utils/LockedBeans.ts @@ -3,6 +3,8 @@ import { BEAN_3CRV, BEAN_WETH_CP2_WELL, BEAN_WETH_UNRIPE_MIGRATION_BLOCK, + BEAN_WSTETH_CP2_WELL, + BEAN_WSTETH_UNRIPE_MIGRATION_BLOCK, BEANSTALK, GAUGE_BIP45_BLOCK, UNRIPE_BEAN, @@ -58,8 +60,10 @@ export function calcLockedBeans(blockNumber: BigInt): BigInt { function getUnderlyingUnripe(blockNumber: BigInt): Address { if (blockNumber < BEAN_WETH_UNRIPE_MIGRATION_BLOCK) { return BEAN_3CRV; - } else { + } else if (blockNumber < BEAN_WSTETH_UNRIPE_MIGRATION_BLOCK) { return BEAN_WETH_CP2_WELL; + } else { + return BEAN_WSTETH_CP2_WELL; } } diff --git a/projects/subgraph-bean/src/utils/price/BeanstalkPrice.ts b/projects/subgraph-bean/src/utils/price/BeanstalkPrice.ts index 0b76a296ff..e74fd5c2ac 100644 --- a/projects/subgraph-bean/src/utils/price/BeanstalkPrice.ts +++ b/projects/subgraph-bean/src/utils/price/BeanstalkPrice.ts @@ -1,11 +1,12 @@ -import { Address, BigInt, log } from "@graphprotocol/graph-ts"; +// Unfortunately this file must be copied across the various subgraph projects. This is due to the codegen +import { Address, BigInt } from "@graphprotocol/graph-ts"; import { BeanstalkPrice, BeanstalkPrice__priceResultPPsStruct, BeanstalkPrice__priceResultPStruct } from "../../../generated/Beanstalk/BeanstalkPrice"; import { loadBean } from "../Bean"; -import { BEANSTALK_PRICE } from "../../../../subgraph-core/utils/Constants"; +import { BEANSTALK_PRICE_1, BEANSTALK_PRICE_2, PRICE_1_BLOCK, PRICE_2_BLOCK } from "../../../../subgraph-core/utils/Constants"; import { ZERO_BI } from "../../../../subgraph-core/utils/Decimals"; // Can't use the autogenerated one because the fields need to be updateable @@ -55,18 +56,19 @@ export class BeanstalkPriceResult { constructor(value: BeanstalkPrice__priceResultPStruct | null, whitelistedPools: string[]) { if (value !== null) { this._value = new PriceOverallStruct(value); - let anyDewhitelisted = false; + let poolsCount = this._value!.ps.length; + let dewhitelistCount = 0; for (let i = 0; i < this._value!.ps.length; ++i) { const index = whitelistedPools.indexOf(this._value!.ps[i].pool.toHexString()); if (index == -1) { // The pool was dewhitelisted this._dewhitelistedPools.push(this._value!.ps.splice(i--, 1)[0]); - anyDewhitelisted = true; + ++dewhitelistCount; } } - // Recalculate overall price/liquidity/delta - if (anyDewhitelisted) { + // Recalculate overall price/liquidity/delta if some but not all pools got dewhitelisted + if (dewhitelistCount > 0 && dewhitelistCount < poolsCount) { this._value!.price = ZERO_BI; this._value!.liquidity = ZERO_BI; this._value!.deltaB = ZERO_BI; @@ -76,6 +78,8 @@ export class BeanstalkPriceResult { this._value!.deltaB = this._value!.deltaB.plus(this._value!.ps[i].deltaB); } this._value!.price = this._value!.price.div(this._value!.liquidity); + } else if (dewhitelistCount == poolsCount) { + this._value!.ps = this._dewhitelistedPools; } } } @@ -100,7 +104,7 @@ export class BeanstalkPriceResult { // (1) Only including whitelisted tokens in the final price calculation and the prices list // (2) Which contract to call (in anticipation of new BeanstalkPrice contract deployments) export function BeanstalkPrice_try_price(beanAddr: Address, blockNumber: BigInt): BeanstalkPriceResult { - let beanstalkPrice = BeanstalkPrice.bind(BEANSTALK_PRICE); + let beanstalkPrice = getBeanstalkPrice(blockNumber); let beanPrice = beanstalkPrice.try_price(); if (beanPrice.reverted) { @@ -129,3 +133,16 @@ export function getPoolPrice(priceResult: BeanstalkPriceResult, pool: Address): } return null; } + +// Gets the BeanstalkPrice contract, bound to the appropriate instance of the contract. +// Note: Will bind to PRICE_1 even if that contract has not been deployed yet +// Thus the caller still needs to check for reverts. +export function getBeanstalkPrice(blockNumber: BigInt): BeanstalkPrice { + let contractAddress: Address; + if (blockNumber < PRICE_2_BLOCK) { + contractAddress = BEANSTALK_PRICE_1; + } else { + contractAddress = BEANSTALK_PRICE_2; + } + return BeanstalkPrice.bind(contractAddress); +} diff --git a/projects/subgraph-bean/subgraph.yaml b/projects/subgraph-bean/subgraph.yaml index bd3b67976c..bfb57dbb3e 100644 --- a/projects/subgraph-bean/subgraph.yaml +++ b/projects/subgraph-bean/subgraph.yaml @@ -249,7 +249,45 @@ dataSources: apiVersion: 0.0.7 language: wasm/assemblyscript entities: - - Bean3CRV + - Pool + abis: + - name: Well + file: ../subgraph-core/abis/Well.json + - name: BeanstalkPrice + file: ../subgraph-core/abis/BeanstalkPrice.json + - name: ERC20 + file: ../subgraph-core/abis/ERC20.json + - name: Beanstalk + file: ../subgraph-core/abis/Beanstalk/Beanstalk-Replanted.json + - name: SeedGauge + file: ../subgraph-core/abis/Beanstalk/Beanstalk-BIP45.json + eventHandlers: + - event: AddLiquidity(uint256[],uint256,address) + handler: handleAddLiquidity + - event: RemoveLiquidity(uint256,uint256[],address) + handler: handleRemoveLiquidity + - event: RemoveLiquidityOneToken(uint256,address,uint256,address) + handler: handleRemoveLiquidityOneToken + - event: Swap(address,address,uint256,uint256,address) + handler: handleSwap + - event: Shift(uint256[],address,uint256,address) + handler: handleShift + - event: Sync(uint256[],uint256,address) + handler: handleSync + file: ./src/BeanWellHandler.ts + - kind: ethereum/contract + name: BEANwstETHCP2w + network: mainnet + source: + address: "0xBeA0000113B0d182f4064C86B71c315389E4715D" + abi: Well + startBlock: 20264128 + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - Pool abis: - name: Well file: ../subgraph-core/abis/Well.json @@ -335,3 +373,8 @@ dataSources: blockHandlers: - handler: handleBlock file: ./src/BlockHandler.ts +# features: +# - grafting +# graft: +# base: QmYnY2GzZbwTqot3H4jAV83mPbGTnBavdbB8bVXYxJzLUd +# block: 20291520 diff --git a/projects/subgraph-bean/tests/BeanstalkPrice.test.ts b/projects/subgraph-bean/tests/BeanstalkPrice.test.ts index 13ec8e54e6..69c6de0a98 100644 --- a/projects/subgraph-bean/tests/BeanstalkPrice.test.ts +++ b/projects/subgraph-bean/tests/BeanstalkPrice.test.ts @@ -1,6 +1,15 @@ import { beforeEach, beforeAll, afterEach, assert, clearStore, describe, test, log } from "matchstick-as/assembly/index"; import { loadBean } from "../src/utils/Bean"; -import { BEAN_3CRV, BEAN_ERC20, BEAN_WETH_CP2_WELL, BEAN_WETH_CP2_WELL_BLOCK, CRV3_TOKEN, WETH } from "../../subgraph-core/utils/Constants"; +import { + BEAN_3CRV, + BEAN_ERC20, + BEAN_WETH_CP2_WELL, + BEANSTALK_PRICE_2, + CRV3_TOKEN, + PRICE_1_BLOCK, + PRICE_2_BLOCK, + WETH +} from "../../subgraph-core/utils/Constants"; import { handleDewhitelistToken } from "../src/BeanstalkHandler"; import { createDewhitelistTokenEvent } from "./event-mocking/Beanstalk"; import { setMockBeanPrice } from "../../subgraph-core/tests/event-mocking/Price"; @@ -15,6 +24,7 @@ const curveLiquidity = BigInt.fromU32(1000000).times(BI_10.pow(6)); const beanEthLiquidity = BigInt.fromU32(5000000).times(BI_10.pow(6)); const curveDelta = BigInt.fromI32(500).times(BI_10.pow(6)); const beanEthDelta = BigInt.fromI32(7500).times(BI_10.pow(6)); +const contract2Price = BigInt.fromU32(1522833); describe("BeanstalkPrice", () => { beforeAll(() => { @@ -45,6 +55,16 @@ describe("BeanstalkPrice", () => { } ] }); + + setMockBeanPrice( + { + price: contract2Price, + liquidity: beanEthLiquidity.plus(curveLiquidity), + deltaB: curveDelta.plus(beanEthDelta), + ps: [] + }, + BEANSTALK_PRICE_2 + ); }); beforeEach(() => { @@ -59,14 +79,14 @@ describe("BeanstalkPrice", () => { }); test("Can set the price", () => { - const priceResult = BeanstalkPrice_try_price(BEAN_ERC20, BEAN_WETH_CP2_WELL_BLOCK); + const priceResult = BeanstalkPrice_try_price(BEAN_ERC20, PRICE_1_BLOCK); assert.assertTrue(priceResult.value.price.equals(overallPrice)); assert.assertTrue(priceResult.value.ps.length == 2); assert.assertTrue(priceResult.dewhitelistedPools.length == 0); }); test("Extract pool price", () => { - const priceResult = BeanstalkPrice_try_price(BEAN_ERC20, BEAN_WETH_CP2_WELL_BLOCK); + const priceResult = BeanstalkPrice_try_price(BEAN_ERC20, PRICE_1_BLOCK); const curvePriceResult = getPoolPrice(priceResult, BEAN_3CRV)!; assert.assertTrue(curvePriceResult.price.equals(curvePrice)); @@ -76,14 +96,22 @@ describe("BeanstalkPrice", () => { test("Price response only includes whitelisted tokens", () => { const event = createDewhitelistTokenEvent(BEAN_3CRV.toHexString()); - event.block.number = BEAN_WETH_CP2_WELL_BLOCK; + event.block.number = PRICE_1_BLOCK; handleDewhitelistToken(event); - const priceResult = BeanstalkPrice_try_price(BEAN_ERC20, BEAN_WETH_CP2_WELL_BLOCK); + const priceResult = BeanstalkPrice_try_price(BEAN_ERC20, PRICE_1_BLOCK); const curvePriceResult = getPoolPrice(priceResult, BEAN_3CRV); assert.assertTrue(priceResult.value.ps.length == 1); assert.assertTrue(priceResult.dewhitelistedPools.length == 1); assert.assertTrue(curvePriceResult !== null); assert.assertTrue(priceResult.value.price.equals(beanEthPrice)); }); + + test("Calls correct price contract by block", () => { + const price1 = BeanstalkPrice_try_price(BEAN_ERC20, PRICE_1_BLOCK); + assert.assertTrue(price1.value.price.equals(overallPrice)); + + const price2 = BeanstalkPrice_try_price(BEAN_ERC20, PRICE_2_BLOCK); + assert.assertTrue(price2.value.price.equals(contract2Price)); + }); }); diff --git a/projects/subgraph-beanstalk/README.md b/projects/subgraph-beanstalk/README.md index f067648712..32bc5b4a25 100644 --- a/projects/subgraph-beanstalk/README.md +++ b/projects/subgraph-beanstalk/README.md @@ -11,17 +11,14 @@ ### Subgraphs -All currently used subgraphs live on the graph protocol's centralized host. +All currently used subgraphs live on a centralized host controlled by beanstalk farms. - [Testing Subgraph](https://graph.node.bean.money/subgraphs/name/beanstalk-testing) - Used during local development for debugging and rapid iteration. - [Dev Subgraph](https://graph.node.bean.money/subgraphs/name/beanstalk-dev) - Used for testing fixes or improvements made in the testing subgraph. -- [Canonical Subgraph](https://thegraph.com/explorer/subgraphs/R9rnzRuiyDybfDsZfoM7eA9w8WuHtZKbroGrgWwDw1d?view=Overview) - - Decentralized deployment to the Graph network. +- [Canonical Subgraph](https://graph.node.bean.money/subgraphs/name/beanstalk) - Stable deployment and current source of truth for UI and other production processes. - - The `master` branch is updated when a new deployment is ready to be indexed. - - All changes pushed to the canonical subgraph are prototyped on the testing subgraph, tested on the dev subgraph, then made canonical once verified. ### Testing diff --git a/projects/subgraph-beanstalk/src/GaugeHandler.ts b/projects/subgraph-beanstalk/src/GaugeHandler.ts index b2913395ef..1ddb53077b 100644 --- a/projects/subgraph-beanstalk/src/GaugeHandler.ts +++ b/projects/subgraph-beanstalk/src/GaugeHandler.ts @@ -24,7 +24,6 @@ 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 { BigInt } from "@graphprotocol/graph-ts"; import { BEAN_WETH_CP2_WELL } from "../../subgraph-core/utils/Constants"; import { Bytes4_emptyToNull } from "../../subgraph-core/utils/Bytes"; diff --git a/projects/subgraph-beanstalk/src/SeasonHandler.ts b/projects/subgraph-beanstalk/src/SeasonHandler.ts index 27b5389ba7..2713041219 100644 --- a/projects/subgraph-beanstalk/src/SeasonHandler.ts +++ b/projects/subgraph-beanstalk/src/SeasonHandler.ts @@ -6,7 +6,7 @@ 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, BEANSTALK_PRICE, BEAN_ERC20, CURVE_PRICE, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; +import { BEANSTALK, BEANSTALK_PRICE_1, BEAN_ERC20, CURVE_PRICE, GAUGE_BIP45_BLOCK } from "../../subgraph-core/utils/Constants"; import { ONE_BI, toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals"; import { loadField, loadFieldDaily, loadFieldHourly } from "./utils/Field"; import { @@ -26,6 +26,7 @@ import { loadSiloAssetHourlySnapshot } from "./utils/SiloEntities"; import { BeanstalkPrice } from "../generated/Season-Replanted/BeanstalkPrice"; +import { BeanstalkPrice_try_price, getBeanstalkPrice } from "./utils/BeanstalkPrice"; export function handleSunrise(event: Sunrise): void { let currentSeason = event.params.season.toI32(); @@ -161,8 +162,7 @@ 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 beanstalkPrice = BeanstalkPrice.bind(BEANSTALK_PRICE); - let beanstalkQuery = beanstalkPrice.try_price(); + 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); @@ -189,10 +189,8 @@ export function handleWellOracle(event: WellOracle): void { let season = loadSeason(event.address, event.params.season); season.deltaB = season.deltaB.plus(event.params.deltaB); - // FIXME: will not be accurate when there are multiple whitelisted wells. - // This information should be pulled from the Bean subgraph instead, and removed here. if (event.block.number >= GAUGE_BIP45_BLOCK && season.price == ZERO_BD) { - let beanstalkPrice = BeanstalkPrice.bind(BEANSTALK_PRICE); + let beanstalkPrice = getBeanstalkPrice(event.block.number); let beanstalkQuery = beanstalkPrice.getConstantProductWell(event.params.well); season.price = toDecimal(beanstalkQuery.price); } diff --git a/projects/subgraph-beanstalk/src/utils/Beanstalk.ts b/projects/subgraph-beanstalk/src/utils/Beanstalk.ts index f291ba5861..185ef0f0d7 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.0"; - beanstalk.subgraphVersion = "2.3.0"; - beanstalk.methodologyVersion = "2.3.0"; + beanstalk.schemaVersion = "2.3.1"; + beanstalk.subgraphVersion = "2.3.1"; + beanstalk.methodologyVersion = "2.3.1"; beanstalk.lastUpgrade = ZERO_BI; beanstalk.lastSeason = 1; beanstalk.activeFarmers = []; diff --git a/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts b/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts new file mode 100644 index 0000000000..dde78e9c95 --- /dev/null +++ b/projects/subgraph-beanstalk/src/utils/BeanstalkPrice.ts @@ -0,0 +1,148 @@ +// Unfortunately this file must be copied across the various subgraph projects. This is due to the codegen +import { Address, BigInt } from "@graphprotocol/graph-ts"; +import { + BeanstalkPrice, + BeanstalkPrice__priceResultPPsStruct, + BeanstalkPrice__priceResultPStruct +} from "../../generated/Field/BeanstalkPrice"; +import { BEANSTALK_PRICE_1, BEANSTALK_PRICE_2, PRICE_1_BLOCK, PRICE_2_BLOCK } from "../../../subgraph-core/utils/Constants"; +import { ZERO_BI } from "../../../subgraph-core/utils/Decimals"; +import { loadSilo } from "./SiloEntities"; + +// Can't use the autogenerated one because the fields need to be updateable +class PriceOverallStruct { + price: BigInt; + liquidity: BigInt; + deltaB: BigInt; + ps: PricePoolStruct[]; + + constructor(value: BeanstalkPrice__priceResultPStruct) { + this.price = value.price; + this.liquidity = value.liquidity; + this.deltaB = value.deltaB; + this.ps = []; + for (let i = 0; i < value.ps.length; ++i) { + this.ps.push(new PricePoolStruct(value.ps[i])); + } + } +} + +class PricePoolStruct { + pool: Address; + tokens: Address[]; + balances: BigInt[]; + price: BigInt; + liquidity: BigInt; + deltaB: BigInt; + lpUsd: BigInt; + lpBdv: BigInt; + + constructor(value: BeanstalkPrice__priceResultPPsStruct) { + this.pool = value.pool; + this.tokens = value.tokens; + this.balances = value.balances; + this.price = value.price; + this.liquidity = value.liquidity; + this.deltaB = value.deltaB; + this.lpUsd = value.lpUsd; + this.lpBdv = value.lpBdv; + } +} + +export class BeanstalkPriceResult { + private _value: PriceOverallStruct | null = null; + private _dewhitelistedPools: Array = []; + + constructor(value: BeanstalkPrice__priceResultPStruct | null, whitelistedPools: string[]) { + if (value !== null) { + this._value = new PriceOverallStruct(value); + let poolsCount = this._value!.ps.length; + let dewhitelistCount = 0; + for (let i = 0; i < this._value!.ps.length; ++i) { + const index = whitelistedPools.indexOf(this._value!.ps[i].pool.toHexString()); + if (index == -1) { + // The pool was dewhitelisted + this._dewhitelistedPools.push(this._value!.ps.splice(i--, 1)[0]); + ++dewhitelistCount; + } + } + + // Recalculate overall price/liquidity/delta if some but not all pools got dewhitelisted + if (dewhitelistCount > 0 && dewhitelistCount < poolsCount) { + this._value!.price = ZERO_BI; + this._value!.liquidity = ZERO_BI; + this._value!.deltaB = ZERO_BI; + for (let i = 0; i < this._value!.ps.length; ++i) { + this._value!.price = this._value!.price.plus(this._value!.ps[i].price.times(this._value!.ps[i].liquidity)); + this._value!.liquidity = this._value!.liquidity.plus(this._value!.ps[i].liquidity); + this._value!.deltaB = this._value!.deltaB.plus(this._value!.ps[i].deltaB); + } + this._value!.price = this._value!.price.div(this._value!.liquidity); + } else if (dewhitelistCount == poolsCount) { + this._value!.ps = this._dewhitelistedPools; + } + } + } + + get reverted(): boolean { + return this._value == null; + } + + get value(): PriceOverallStruct { + assert(!this.reverted, "accessed value of a reverted call, please check the `reverted` field before accessing the `value` field"); + return this._value!; + } + + // Dewhitelsited pools are remvoed from value struct and placed here. + get dewhitelistedPools(): Array { + assert(!this.reverted, "accessed value of a reverted call, please check the `reverted` field before accessing the `value` field"); + return this._dewhitelistedPools; + } +} + +// Wrapper for BeanstalkPrice contract that handles a few things: +// (1) Only including whitelisted tokens in the final price calculation and the prices list +// (2) Which contract to call (in anticipation of new BeanstalkPrice contract deployments) +export function BeanstalkPrice_try_price(beanstalkAddr: Address, blockNumber: BigInt): BeanstalkPriceResult { + let beanstalkPrice = getBeanstalkPrice(blockNumber); + let beanPrice = beanstalkPrice.try_price(); + + if (beanPrice.reverted) { + return new BeanstalkPriceResult(null, []); + } + + let silo = loadSilo(beanstalkAddr); + + // changetype is necessary as there are identical responses from different generated contract objects. + // If the response structure changes in the future, this will need to be revisited. + return new BeanstalkPriceResult(changetype(beanPrice.value), silo.whitelistedTokens); +} + +// Extracts the pool price from the larger result +export function getPoolPrice(priceResult: BeanstalkPriceResult, pool: Address): PricePoolStruct | null { + for (let i = 0; i < priceResult.value.ps.length; ++i) { + if (priceResult.value.ps[i].pool == pool) { + return priceResult.value.ps[i]; + } + } + + for (let i = 0; i < priceResult.dewhitelistedPools.length; ++i) { + if (priceResult.dewhitelistedPools[i].pool == pool) { + return priceResult.dewhitelistedPools[i]; + } + } + return null; +} + +// Gets the BeanstalkPrice contract, bound to the appropriate instance of the contract. +// Note: Will bind to PRICE_1 even if that contract has not been deployed yet +// Thus the caller still needs to check for reverts. +export function getBeanstalkPrice(blockNumber: BigInt): BeanstalkPrice { + let contractAddress: Address; + if (blockNumber < PRICE_2_BLOCK) { + contractAddress = BEANSTALK_PRICE_1; + } else { + contractAddress = BEANSTALK_PRICE_2; + } + return BeanstalkPrice.bind(contractAddress); +} diff --git a/projects/subgraph-beanstalk/src/utils/Field.ts b/projects/subgraph-beanstalk/src/utils/Field.ts index ea7ad15f94..beb409477f 100644 --- a/projects/subgraph-beanstalk/src/utils/Field.ts +++ b/projects/subgraph-beanstalk/src/utils/Field.ts @@ -2,10 +2,11 @@ import { Address, BigInt, BigDecimal, ethereum } from "@graphprotocol/graph-ts"; import { Field, FieldDailySnapshot, FieldHourlySnapshot } from "../../generated/schema"; import { dayFromTimestamp } from "./Dates"; import { BI_MAX, ONE_BD, toDecimal, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils/Decimals"; -import { BEANSTALK, BEANSTALK_PRICE, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; +import { BEANSTALK, BEANSTALK_PRICE_1, CURVE_PRICE } from "../../../subgraph-core/utils/Constants"; import { loadSeason } from "./Season"; import { CurvePrice } from "../../generated/Field/CurvePrice"; import { BeanstalkPrice } from "../../generated/Field/BeanstalkPrice"; +import { BeanstalkPrice_try_price } from "./BeanstalkPrice"; // 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. @@ -29,8 +30,7 @@ export function handleRateChange(evtAddress: Address, evtBlock: ethereum.Block, currentPrice = seasonEntity.price; } else { // Attempt to pull from Beanstalk Price contract first - let beanstalkPrice = BeanstalkPrice.bind(BEANSTALK_PRICE); - let beanstalkQuery = beanstalkPrice.try_price(); + let beanstalkQuery = BeanstalkPrice_try_price(evtAddress, evtBlock.number); if (beanstalkQuery.reverted) { let curvePrice = CurvePrice.bind(CURVE_PRICE); currentPrice = toDecimal(curvePrice.getCurve().price); diff --git a/projects/subgraph-beanstalk/subgraph.yaml b/projects/subgraph-beanstalk/subgraph.yaml index d07347d039..ed61fb7904 100644 --- a/projects/subgraph-beanstalk/subgraph.yaml +++ b/projects/subgraph-beanstalk/subgraph.yaml @@ -776,3 +776,8 @@ dataSources: - event: UpdateGaugeSettings(indexed address,bytes4,bytes4,uint64) handler: handleUpdateGaugeSettings file: ./src/GaugeHandler.ts +# features: +# - grafting +# graft: +# base: QmWHi6hu2wXnyxBHHmQHwCQLoq5KkoTX2qLm8MdyVXTyTu +# block: 20216425 diff --git a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts index efca899cf0..5035dde5fa 100644 --- a/projects/subgraph-beanstalk/tests/SeedGauge.test.ts +++ b/projects/subgraph-beanstalk/tests/SeedGauge.test.ts @@ -15,7 +15,7 @@ import { handleTotalStalkChangedFromGermination } from "../src/GaugeHandler"; -import { BEAN_ERC20, BEANSTALK } from "../../subgraph-core/utils/Constants"; +import { BEAN_ERC20, BEAN_WETH_CP2_WELL, BEANSTALK, UNRIPE_BEAN, UNRIPE_BEAN_3CRV } from "../../subgraph-core/utils/Constants"; import { createBeanToMaxLpGpPerBdvRatioChangeEvent, createFarmerGerminatingStalkBalanceChangedEvent, @@ -28,7 +28,7 @@ import { } from "./event-mocking/SeedGauge"; import { createWhitelistTokenV4Event } from "./event-mocking/Whitelist"; import { createTemperatureChangeEvent } from "./event-mocking/Field"; -import { simpleMockPrice } from "../../subgraph-core/tests/event-mocking/Prices"; +import { simpleMockPrice } from "../../subgraph-core/tests/event-mocking/Price"; import { loadSilo } from "../src/utils/SiloEntities"; import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block"; import { dayFromTimestamp } from "../src/utils/Dates"; diff --git a/projects/subgraph-core/tests/event-mocking/Price.ts b/projects/subgraph-core/tests/event-mocking/Price.ts index b1cb9e07c9..06ecef4114 100644 --- a/projects/subgraph-core/tests/event-mocking/Price.ts +++ b/projects/subgraph-core/tests/event-mocking/Price.ts @@ -5,7 +5,7 @@ import { BEAN_ERC20, BEAN_WETH_CP2_WELL, BEAN_WETH_V1, - BEANSTALK_PRICE, + BEANSTALK_PRICE_1, CURVE_PRICE, WETH, WETH_USDC_PAIR @@ -36,11 +36,11 @@ class Pool { * @param prices - the Prices struct that the contract will return * @param mockPools - when true, mocks the return values from the individual pools' price call also */ -export function setMockBeanPrice(prices: Prices, mockPools: boolean = true): void { +export function setMockBeanPrice(prices: Prices, contract: Address = BEANSTALK_PRICE_1, mockPools: boolean = true): void { const pricesReturn = toPricesStruct(prices); createMockedFunction( - BEANSTALK_PRICE, + contract, "price", "price():((uint256,uint256,int256,(address,address[2],uint256[2],uint256,uint256,int256,uint256,uint256)[]))" ) @@ -70,7 +70,7 @@ export function setMockWellPrice(pool: Pool): void { const wellPriceReturn = toPoolStruct(pool); createMockedFunction( - BEANSTALK_PRICE, + BEANSTALK_PRICE_1, "getConstantProductWell", "getConstantProductWell(address):((address,address[2],uint256[2],uint256,uint256,int256,uint256,uint256))" ) diff --git a/projects/subgraph-core/tests/event-mocking/Prices.ts b/projects/subgraph-core/tests/event-mocking/Prices.ts deleted file mode 100644 index 053a478ccc..0000000000 --- a/projects/subgraph-core/tests/event-mocking/Prices.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { BigInt, ethereum, Address } from "@graphprotocol/graph-ts"; -import { createMockedFunction } from "matchstick-as/assembly/index"; -import { BEAN_3CRV, BEAN_ERC20, BEAN_WETH_CP2_WELL, BEANSTALK_PRICE, CURVE_PRICE, WETH } from "../../utils/Constants"; - -// These 2 classes are analagous to structs used by BeanstalkPrice contract -class Prices { - price: BigInt; - liquidity: BigInt; - deltaB: BigInt; - ps: Pool[]; -} - -class Pool { - contract: Address; - tokens: Address[]; - balances: BigInt[]; - price: BigInt; - liquidity: BigInt; - deltaB: BigInt; - lpUsd: BigInt; - lpBdv: BigInt; -} - -/** - * Mocks the return values from BeanstalkPrice contract - * @param prices - the Prices struct that the contract will return - * @param mockPools - when true, mocks the return values from the individual pools' price call also - */ -export function setMockBeanPrice(prices: Prices, mockPools: boolean = true): void { - const pricesReturn = toPricesStruct(prices); - - createMockedFunction( - BEANSTALK_PRICE, - "price", - "price():((uint256,uint256,int256,(address,address[2],uint256[2],uint256,uint256,int256,uint256,uint256)[]))" - ) - // @ts-expect-error:2322 - .returns([ethereum.Value.fromTuple(pricesReturn)]); - - if (mockPools) { - for (let i = 0; i < prices.ps.length; ++i) { - if (prices.ps[i].contract == BEAN_3CRV) { - setMockCurvePrice(prices.ps[i]); - } else { - setMockWellPrice(prices.ps[i]); - } - } - } -} - -export function setMockCurvePrice(pool: Pool): void { - const curvePriceReturn = toPoolStruct(pool); - - createMockedFunction(CURVE_PRICE, "getCurve", "getCurve():((address,address[2],uint256[2],uint256,uint256,int256,uint256,uint256))") - .withArgs([]) - .returns([ethereum.Value.fromTuple(curvePriceReturn)]); -} - -export function setMockWellPrice(pool: Pool): void { - const wellPriceReturn = toPoolStruct(pool); - - createMockedFunction( - BEANSTALK_PRICE, - "getConstantProductWell", - "getConstantProductWell(address):((address,address[2],uint256[2],uint256,uint256,int256,uint256,uint256))" - ) - .withArgs([ethereum.Value.fromAddress(pool.contract)]) - .returns([ethereum.Value.fromTuple(wellPriceReturn)]); -} - -const price = (p: number): BigInt => BigInt.fromU32((p * Math.pow(10, 6))); - -export const simpleMockPrice = (overall: number, beanEth: number): void => { - setMockBeanPrice({ - price: price(overall), - liquidity: BigInt.zero(), - deltaB: BigInt.zero(), - ps: [ - { - contract: BEAN_WETH_CP2_WELL, - tokens: [BEAN_ERC20, WETH], - balances: [BigInt.fromString("10"), BigInt.fromString("10")], - price: price(beanEth), - liquidity: BigInt.fromString("10"), - deltaB: BigInt.fromString("10"), - lpUsd: BigInt.fromString("10"), - lpBdv: BigInt.fromString("10") - } - ] - }); -}; - -function toPricesStruct(prices: Prices): ethereum.Tuple { - let retval = new ethereum.Tuple(); - - retval.push(ethereum.Value.fromUnsignedBigInt(prices.price)); - retval.push(ethereum.Value.fromUnsignedBigInt(prices.liquidity)); - retval.push(ethereum.Value.fromSignedBigInt(prices.deltaB)); - - const pools: ethereum.Tuple[] = []; - for (let i = 0; i < prices.ps.length; ++i) { - pools.push(toPoolStruct(prices.ps[i])); - } - retval.push(ethereum.Value.fromTupleArray(pools)); - - return retval; -} - -function toPoolStruct(pool: Pool): ethereum.Tuple { - const ethereumTokens: ethereum.Value[] = []; - for (let i = 0; i < pool.tokens.length; ++i) { - ethereumTokens.push(ethereum.Value.fromAddress(pool.tokens[i])); - } - - let retval = new ethereum.Tuple(); - - retval.push(ethereum.Value.fromAddress(pool.contract)); - retval.push(ethereum.Value.fromArray(ethereumTokens)); - retval.push(ethereum.Value.fromUnsignedBigIntArray(pool.balances)); - retval.push(ethereum.Value.fromUnsignedBigInt(pool.price)); - retval.push(ethereum.Value.fromUnsignedBigInt(pool.liquidity)); - retval.push(ethereum.Value.fromSignedBigInt(pool.deltaB)); - retval.push(ethereum.Value.fromUnsignedBigInt(pool.lpUsd)); - retval.push(ethereum.Value.fromUnsignedBigInt(pool.lpBdv)); - - return retval; -} diff --git a/projects/subgraph-core/utils/Constants.ts b/projects/subgraph-core/utils/Constants.ts index 5ab7004339..5c6f9cb042 100644 --- a/projects/subgraph-core/utils/Constants.ts +++ b/projects/subgraph-core/utils/Constants.ts @@ -12,6 +12,7 @@ export const UNRIPE_BEAN_3CRV = Address.fromString("0x1BEA3CcD22F4EBd3d37d731BA3 export const BEANSTALK_FARMS = Address.fromString("0x21de18b6a8f78ede6d16c50a167f6b222dc08df7"); export const WETH = Address.fromString("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); export const LUSD = Address.fromString("0x5f98805A4E8be255a32880FDeC7F6728C6568bA0"); +export const WSTETH = Address.fromString("0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"); // Protocol Addresses export const BEANSTALK = Address.fromString("0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5"); @@ -19,7 +20,8 @@ export const FERTILIZER = Address.fromString("0x402c84De2Ce49aF88f5e2eF3710ff89b export const AQUIFER = Address.fromString("0xBA51AAAA95aeEFc1292515b36D86C51dC7877773"); export const CURVE_PRICE = Address.fromString("0xA57289161FF18D67A68841922264B317170b0b81"); -export const BEANSTALK_PRICE = Address.fromString("0xb01CE0008CaD90104651d6A84b6B11e182a9B62A"); +export const BEANSTALK_PRICE_1 = Address.fromString("0xb01CE0008CaD90104651d6A84b6B11e182a9B62A"); +export const BEANSTALK_PRICE_2 = Address.fromString("0x4bed6cb142b7d474242d87f4796387deb9e1e1b4"); // LP Addresses export const BEAN_3CRV_V1 = Address.fromString("0x3a70DfA7d2262988064A2D051dd47521E43c9BdD"); @@ -30,6 +32,7 @@ export const WETH_USDC_PAIR = Address.fromString("0xB4e16d0168e52d35CaCD2c6185b4 export const BEAN_LUSD_V1 = Address.fromString("0xD652c40fBb3f06d6B58Cb9aa9CFF063eE63d465D"); export const LUSD_3POOL = Address.fromString("0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA"); export const BEAN_WETH_CP2_WELL = Address.fromString("0xBEA0e11282e2bB5893bEcE110cF199501e872bAd"); +export const BEAN_WSTETH_CP2_WELL = Address.fromString("0xBeA0000113B0d182f4064C86B71c315389E4715D"); // Other Constants export const BEAN_DECIMALS = 6; @@ -44,7 +47,13 @@ export const CALCULATIONS_CURVE = Address.fromString("0x25BF7b72815476Dd515044F9 export const BEANSTALK_BLOCK = BigInt.fromU32(12974075); export const EXPLOIT_BLOCK = BigInt.fromU32(14602790); export const REPLANT_SUNRISE_BLOCK = BigInt.fromU32(15289934); -export const BEANSTALK_PRICE_BLOCK = BigInt.fromU32(17978222); +export const GAUGE_BIP45_BLOCK = BigInt.fromU32(19927634); + export const BEAN_WETH_CP2_WELL_BLOCK = BigInt.fromU32(17978134); +export const BEAN_WSTETH_CP2_WELL_BLOCK = BigInt.fromU32(20264128); + export const BEAN_WETH_UNRIPE_MIGRATION_BLOCK = BigInt.fromU32(18392690); -export const GAUGE_BIP45_BLOCK = BigInt.fromU32(19927634); +export const BEAN_WSTETH_UNRIPE_MIGRATION_BLOCK = BigInt.fromU32(20389706); + +export const PRICE_1_BLOCK = BigInt.fromU32(17978222); +export const PRICE_2_BLOCK = BigInt.fromU32(20298142);