Skip to content

Commit

Permalink
Add misc metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
soilking committed Jun 18, 2024
1 parent 0435bfb commit bce460c
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 46 deletions.
9 changes: 9 additions & 0 deletions projects/subgraph-bean/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ type Token @entity {
"Smart contract address of the token"
id: ID!

"Name of the token, i.e. BEAN, WETH"
name: String!

"Number of decimals"
decimals: BigInt!

Expand All @@ -13,6 +16,9 @@ type Bean @entity {
"Contract address of the Bean token"
id: ID!

"Which chain this Bean is from"
chain: String!

"Current supply"
supply: BigInt!

Expand Down Expand Up @@ -187,7 +193,10 @@ type PoolCross @entity {

type Pool @entity {
id: ID!
"The Bean token that is in this pool"
bean: Bean!
"All tokens in this pool"
tokens: [Token!]!
reserves: [BigInt!]!
lastSeason: Int!
lastPrice: BigDecimal!
Expand Down
1 change: 0 additions & 1 deletion projects/subgraph-bean/src/BeanstalkHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { MetapoolOracle, WellOracle } from "../generated/TWAPOracles/BIP37";
import { DeltaBPriceLiquidity } from "./utils/price/Types";
import { setRawWellReserves, setTwaLast } from "./utils/price/TwaOracle";
import { decodeCumulativeWellReserves, setWellTwa } from "./utils/price/WellPrice";
import { BeanstalkPrice_try_price, getPoolPrice } from "./utils/price/BeanstalkPrice";
import { beanstalkPrice_updatePoolPrices } from "./BlockHandler";

export function handleSunrise(event: Sunrise): void {
Expand Down
96 changes: 96 additions & 0 deletions projects/subgraph-bean/src/constants/PooledTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { BigInt, log } from "@graphprotocol/graph-ts";
import {
BEAN_ERC20,
BEAN_ERC20_V1,
WETH,
CRV3_TOKEN,
LUSD,
BEAN_WETH_V1,
BEAN_3CRV_V1,
BEAN_LUSD_V1,
BEAN_3CRV,
BEAN_WETH_CP2_WELL
} from "../../../subgraph-core/utils/Constants";

// Use this mapping to determine which tokens are in each pool. Pools may each follow a distinct interface,
// so a view function shouldn't be used, and a new subgraph build is already required to track a newly whitelisted asset.
export function getTokensForPool(pool: string): string[] {
for (let i = 0; i < poolTokens.length; ++i) {
if (poolTokens[i].pool == pool) {
return poolTokens[i].tokens;
}
}
throw new Error("Pool has not been configured");
}

// Name/Decimals are not guaranteed as part of the ERC20 interface, so predefined values are necessary
export function getTokenInfo(token: string): TokenInfo {
for (let i = 0; i < tokens.length; ++i) {
if (tokens[i].address == token) {
return tokens[i].info;
}
}
throw new Error("Token has not been configured");
}

class PoolTokens {
pool: string;
tokens: string[];
}
// WHITELIST: Add new pools here
const poolTokens: PoolTokens[] = [
{
pool: BEAN_WETH_V1.toHexString(),
tokens: [BEAN_ERC20_V1.toHexString(), WETH.toHexString()]
},
{
pool: BEAN_3CRV_V1.toHexString(),
tokens: [BEAN_ERC20_V1.toHexString(), CRV3_TOKEN.toHexString()]
},
{
pool: BEAN_LUSD_V1.toHexString(),
tokens: [BEAN_ERC20_V1.toHexString(), LUSD.toHexString()]
},
{
pool: BEAN_3CRV.toHexString(),
tokens: [BEAN_ERC20.toHexString(), CRV3_TOKEN.toHexString()]
},
{
pool: BEAN_WETH_CP2_WELL.toHexString(),
tokens: [BEAN_ERC20.toHexString(), WETH.toHexString()]
}
];

class Token {
address: string;
info: TokenInfo;
}

class TokenInfo {
name: string;
decimals: BigInt;
}

// WHITELIST: Add new tokens here
const tokens: Token[] = [
{
address: BEAN_ERC20_V1.toHexString(),
info: { name: "BEAN", decimals: BigInt.fromU32(6) }
},
{
address: BEAN_ERC20.toHexString(),
info: { name: "BEAN", decimals: BigInt.fromU32(6) }
},
{
address: WETH.toHexString(),
info: { name: "WETH", decimals: BigInt.fromU32(18) }
},
{
address: CRV3_TOKEN.toHexString(),
info: { name: "3CRV", decimals: BigInt.fromU32(18) }
},
{
address: LUSD.toHexString(),
info: { name: "LUSD", decimals: BigInt.fromU32(18) }
}
];
21 changes: 4 additions & 17 deletions projects/subgraph-bean/src/utils/Bean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function loadBean(token: string): Bean {
let bean = Bean.load(token);
if (bean == null) {
bean = new Bean(token);
bean.chain = "ethereum";
bean.supply = ZERO_BI;
bean.marketCap = ZERO_BD;
bean.lockedBeans = ZERO_BI;
Expand All @@ -38,11 +39,7 @@ export function loadBean(token: string): Bean {
return bean as Bean;
}

export function loadOrCreateBeanHourlySnapshot(
token: string,
timestamp: BigInt,
season: i32
): BeanHourlySnapshot {
export function loadOrCreateBeanHourlySnapshot(token: string, timestamp: BigInt, season: i32): BeanHourlySnapshot {
let id = token + "-" + season.toString();
let snapshot = BeanHourlySnapshot.load(id);
if (snapshot == null) {
Expand Down Expand Up @@ -188,9 +185,7 @@ 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 < BigInt.fromString("15278082") ? BEAN_ERC20_V1.toHexString() : BEAN_ERC20.toHexString();
}

export function updateBeanSupplyPegPercent(blockNumber: BigInt): void {
Expand Down Expand Up @@ -254,15 +249,7 @@ export function updateBeanAfterPoolSwap(
}

updateBeanSupplyPegPercent(blockNumber);
updateBeanValues(
BEAN_ERC20.toHexString(),
timestamp,
beanPrice,
ZERO_BI,
volumeBean,
volumeUSD,
deltaLiquidityUSD
);
updateBeanValues(BEAN_ERC20.toHexString(), timestamp, beanPrice, ZERO_BI, volumeBean, volumeUSD, deltaLiquidityUSD);
checkBeanCross(BEAN_ERC20.toHexString(), timestamp, blockNumber, oldBeanPrice, beanPrice);
}
}
Expand Down
6 changes: 6 additions & 0 deletions projects/subgraph-bean/src/utils/Pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { emptyBigIntArray, ZERO_BD, ZERO_BI } from "../../../subgraph-core/utils
import { getBeanTokenAddress, loadBean, updateInstDeltaB } from "./Bean";
import { checkPoolCross } from "./Cross";
import { DeltaBAndPrice } from "./price/Types";
import { getTokensForPool } from "../constants/PooledTokens";
import { loadOrCreateToken } from "./Token";

export function loadOrCreatePool(poolAddress: string, blockNumber: BigInt): Pool {
let pool = Pool.load(poolAddress);
Expand All @@ -13,6 +15,10 @@ export function loadOrCreatePool(poolAddress: string, blockNumber: BigInt): Pool
let bean = loadBean(beanAddress);

pool = new Pool(poolAddress);
pool.tokens = getTokensForPool(poolAddress);
for (let i = 0; i < pool.tokens.length; ++i) {
loadOrCreateToken(pool.tokens[i]);
}
pool.bean = beanAddress;
pool.reserves = emptyBigIntArray(2);
pool.lastSeason = bean.lastSeason;
Expand Down
7 changes: 5 additions & 2 deletions projects/subgraph-bean/src/utils/Token.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { BigDecimal, BigInt } from "@graphprotocol/graph-ts";
import { BigDecimal } from "@graphprotocol/graph-ts";
import { Token } from "../../generated/schema";
import { ZERO_BD } from "../../../subgraph-core/utils/Decimals";
import { getTokenInfo } from "../constants/PooledTokens";

export function loadOrCreateToken(address: string): Token {
let token = Token.load(address);
if (token == null) {
const tokenInfo = getTokenInfo(address);
token = new Token(address);
token.decimals = BigInt.fromString("18");
token.name = tokenInfo.name;
token.decimals = tokenInfo.decimals;
token.lastPriceUSD = ZERO_BD;
token.save();
}
Expand Down
14 changes: 7 additions & 7 deletions projects/subgraph-bean/tests/Cross.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { mockBlock } from "../../subgraph-core/tests/event-mocking/Block";
import { mockPreReplantETHPrice, simpleMockPrice } from "../../subgraph-core/tests/event-mocking/Price";

import { BEAN_3CRV_V1, BEAN_ERC20, BEAN_ERC20_V1, BEAN_WETH_CP2_WELL, BEAN_WETH_V1 } from "../../subgraph-core/utils/Constants";
import { BD_10, ONE_BD, ONE_BI, toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals";
import { BD_10, BigDecimal_round, ONE_BD, ONE_BI, toDecimal, ZERO_BD, ZERO_BI } from "../../subgraph-core/utils/Decimals";

import { loadBean } from "../src/utils/Bean";
import { getPreReplantPriceETH, constantProductPrice, uniswapV2Reserves } from "../src/utils/price/UniswapPrice";
Expand Down Expand Up @@ -75,8 +75,8 @@ describe("Peg Crosses", () => {
const reserves = uniswapV2Reserves(BEAN_WETH_V1);
const ethPriceNow = getPreReplantPriceETH();
const newPrice = constantProductPrice(toDecimal(reserves[1]), toDecimal(reserves[0], 18), ethPriceNow);
log.info("expected | actual {} | {}", [beanPrice.toString(), newPrice.truncate(4).toString()]);
assert.assertTrue(beanPrice.equals(newPrice));
// log.info("expected | actual {} | {}", [beanPrice.toString(), newPrice.truncate(4).toString()]);
assert.assertTrue(beanPrice.equals(newPrice.truncate(4)));

const beanPrice2 = BigDecimal.fromString("0.7652");
const liquidity2 = BigDecimal.fromString("1234567");
Expand All @@ -86,10 +86,10 @@ describe("Peg Crosses", () => {
const ethPriceNow2 = getPreReplantPriceETH();
const newPrice2 = constantProductPrice(toDecimal(reserves2[1]), toDecimal(reserves2[0], 18), ethPriceNow2);
const newLiquidity2 = toDecimal(reserves2[0], 18).times(ethPriceNow2).times(BigDecimal.fromString("2"));
log.info("expected | actual {} | {}", [beanPrice2.toString(), newPrice2.truncate(4).toString()]);
assert.assertTrue(beanPrice2.equals(newPrice2));
log.info("expected | actual {} | {}", [liquidity2.truncate(0).toString(), newLiquidity2.truncate(0).toString()]);
// assert.assertTrue(liquidity2.truncate(0).equals(newLiquidity2.truncate(0)));
// log.info("expected | actual {} | {}", [beanPrice2.toString(), newPrice2.truncate(4).toString()]);
assert.assertTrue(beanPrice2.equals(newPrice2.truncate(4)));
// log.info("expected | actual {} | {}", [liquidity2.truncate(2).toString(), newLiquidity2.truncate(2).toString()]);
assert.assertTrue(BigDecimal_round(liquidity2).equals(BigDecimal_round(newLiquidity2)));
});

test("UniswapV2/Bean cross above", () => {
Expand Down
27 changes: 27 additions & 0 deletions projects/subgraph-bean/tests/Pool.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { afterEach, clearStore, describe, assert, test } from "matchstick-as/assembly/index";
import { loadOrCreateToken } from "../src/utils/Token";
import { BEAN_3CRV, BEAN_ERC20, BEAN_ERC20_V1, BEAN_WETH_V1, CRV3_TOKEN, WETH } from "../../subgraph-core/utils/Constants";
import { BigInt } from "@graphprotocol/graph-ts";
import { loadOrCreatePool } from "../src/utils/Pool";

describe("Token", () => {
afterEach(() => {
clearStore();
});

test("Pool and its tokens are assigned appropriate metadata", () => {
const pool = loadOrCreatePool(BEAN_WETH_V1.toHexString(), BigInt.fromU32(14500000));
assert.stringEquals(BEAN_ERC20_V1.toHexString(), pool.tokens[0]);
assert.stringEquals(WETH.toHexString(), pool.tokens[1]);

assert.fieldEquals("Token", BEAN_ERC20_V1.toHexString(), "decimals", "6");
assert.fieldEquals("Token", WETH.toHexString(), "decimals", "18");

const pool2 = loadOrCreatePool(BEAN_3CRV.toHexString(), BigInt.fromU32(17500000));
assert.stringEquals(BEAN_ERC20.toHexString(), pool2.tokens[0]);
assert.stringEquals(CRV3_TOKEN.toHexString(), pool2.tokens[1]);

assert.fieldEquals("Token", BEAN_ERC20.toHexString(), "decimals", "6");
assert.fieldEquals("Token", CRV3_TOKEN.toHexString(), "decimals", "18");
});
});
29 changes: 10 additions & 19 deletions projects/subgraph-core/utils/Decimals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ export const ZERO_BI = BigInt.fromI32(0);
export const ONE_BI = BigInt.fromI32(1);
export const BI_6 = BigInt.fromI32(6);
export const BI_10 = BigInt.fromI32(10);
export const BI_MAX = BigInt.fromUnsignedBytes(
Bytes.fromHexString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
);
export const BI_MAX = BigInt.fromUnsignedBytes(Bytes.fromHexString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
export const ZERO_BD = BigDecimal.fromString("0");
export const ONE_BD = BigDecimal.fromString("1");
export const BD_10 = BigDecimal.fromString("10");
Expand All @@ -27,10 +25,7 @@ export function pow(base: BigDecimal, exponent: number): BigDecimal {
return result;
}

export function sqrt(
value: BigDecimal,
tolerance: BigDecimal = BigDecimal.fromString("0.0000001")
): BigDecimal {
export function sqrt(value: BigDecimal, tolerance: BigDecimal = BigDecimal.fromString("0.0000001")): BigDecimal {
if (value.equals(ZERO_BD)) {
return ZERO_BD;
}
Expand All @@ -46,10 +41,8 @@ export function sqrt(
// Check if the difference is within the tolerance level
if (
lastX.minus(x).equals(ZERO_BD) ||
(lastX.minus(x).toString().startsWith("-") &&
lastX.minus(x).toString().substring(1) < tolerance.toString()) ||
(!lastX.minus(x).toString().startsWith("-") &&
lastX.minus(x).toString() < tolerance.toString())
(lastX.minus(x).toString().startsWith("-") && lastX.minus(x).toString().substring(1) < tolerance.toString()) ||
(!lastX.minus(x).toString().startsWith("-") && lastX.minus(x).toString() < tolerance.toString())
) {
break;
}
Expand All @@ -68,9 +61,7 @@ export function toDecimal(value: BigInt, decimals: number = DEFAULT_DECIMALS): B

export function toBigInt(value: BigDecimal, decimals: number = DEFAULT_DECIMALS): BigInt {
let precision = 10 ** decimals;
return BigInt.fromString(
value.times(BigDecimal.fromString(precision.toString())).truncate(0).toString()
);
return BigInt.fromString(value.times(BigDecimal.fromString(precision.toString())).truncate(0).toString());
}

export function emptyBigIntArray(length: i32): BigInt[] {
Expand Down Expand Up @@ -107,10 +98,10 @@ export function getBigDecimalArrayTotal(detail: BigDecimal[]): BigDecimal {
return total;
}

export function BigDecimal_isClose(
value: BigDecimal,
target: BigDecimal,
window: BigDecimal
): boolean {
export function BigDecimal_isClose(value: BigDecimal, target: BigDecimal, window: BigDecimal): boolean {
return target.minus(window) < value && value < target.plus(window);
}

export function BigDecimal_round(value: BigDecimal): BigDecimal {
return value.plus(BigDecimal.fromString("0.5")).truncate(0);
}

0 comments on commit bce460c

Please sign in to comment.