Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subgraph updates for BIP-48 wstETH Migration #964

Merged
merged 21 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8586a44
BeanstalkPrice wrapper to support new contract
soilking Jul 16, 2024
3b70b01
separate binding function for price contract
soilking Jul 16, 2024
235581f
Price contract wrapper for each subgraph
soilking Jul 16, 2024
78921ce
Add wsteth datasource and pool config
soilking Jul 16, 2024
d6cbe59
switch underlying on wsteth block
soilking Jul 16, 2024
2c96af5
Merge branch 'feat/sk/beanstalkprice' into subgraph-bean2.3.0
soilking Jul 16, 2024
492c230
bump version
soilking Jul 16, 2024
bd7d5aa
bump version
soilking Jul 16, 2024
af22402
ignore wsteth events prior to updated price contract
soilking Jul 18, 2024
cabdbf6
switch price function
soilking Jul 19, 2024
4944e3b
Merge branch 'subgraph-basin1.2.3' into feat/sk/subgraphs-wsteth
soilking Jul 23, 2024
c7c98ce
Merge branch 'subgraph-beanstalk2.3.1' into feat/sk/subgraphs-wsteth
soilking Jul 23, 2024
d30b9a7
Merge branch 'subgraph-bean2.3.0' into feat/sk/subgraphs-wsteth
soilking Jul 23, 2024
f354830
disable graft
soilking Jul 23, 2024
38a68fd
refactor price mocking
soilking Jul 23, 2024
2b01db5
Merge branch 'subgraph-basin1.2.3' into feat/sk/subgraphs-wsteth
soilking Jul 23, 2024
65edc7c
remove reference to wrong folder
soilking Jul 23, 2024
e1ab1e9
Merge branch 'subgraph-basin1.2.3' into feat/sk/subgraphs-wsteth
soilking Jul 23, 2024
9e16c64
update subgraph readme and links
soilking Jul 25, 2024
9b47fb7
set wsteth migration block
soilking Jul 26, 2024
83df316
Merge branch 'master' into feat/sk/subgraphs-wsteth
soilking Jul 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion projects/subgraph-basin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <TestName1> ...` 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.
17 changes: 17 additions & 0 deletions projects/subgraph-basin/src/utils/BeanstalkPrice.ts
Original file line number Diff line number Diff line change
@@ -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);
}
8 changes: 4 additions & 4 deletions projects/subgraph-basin/src/utils/Token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
48 changes: 27 additions & 21 deletions projects/subgraph-basin/tests/helpers/Functions.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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)")
Expand Down
25 changes: 22 additions & 3 deletions projects/subgraph-bean/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
<img src="https://github.com/BeanstalkFarms/Beanstalk-Brand-Assets/blob/main/BEAN/bean-128x128.png" alt="Beanstalk logo" align="right" width="120" />

# 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 <TestName1> ...` 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.
10 changes: 8 additions & 2 deletions projects/subgraph-bean/src/BeanWellHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
11 changes: 1 addition & 10 deletions projects/subgraph-bean/src/BeanstalkHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
4 changes: 1 addition & 3 deletions projects/subgraph-bean/src/BlockHandler.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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);

Expand Down
12 changes: 11 additions & 1 deletion projects/subgraph-bean/src/constants/PooledTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()]
}
];

Expand Down Expand Up @@ -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) }
}
];
13 changes: 2 additions & 11 deletions projects/subgraph-bean/src/utils/Bean.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
12 changes: 11 additions & 1 deletion projects/subgraph-bean/src/utils/BeanWells.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
}
];
6 changes: 5 additions & 1 deletion projects/subgraph-bean/src/utils/LockedBeans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
}

Expand Down
31 changes: 24 additions & 7 deletions projects/subgraph-bean/src/utils/price/BeanstalkPrice.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
}
Loading
Loading