Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into bip39-seedGauge-rem…
Browse files Browse the repository at this point in the history
…ediations
  • Loading branch information
Brean0 committed Apr 8, 2024
2 parents c7e118c + 6c8538f commit 14271ca
Show file tree
Hide file tree
Showing 138 changed files with 226,452 additions and 41,696 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.ui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ jobs:
run: yarn ui:test
env:
VITE_ALCHEMY_API_KEY: ${{ secrets.VITE_ALCHEMY_API_KEY }}
VITE_WALLETCONNECT_PROJECT_ID: ${{ secrets.VITE_WALLETCONNECT_PROJECT_ID }}
1 change: 1 addition & 0 deletions projects/dev-graph-node/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.data
graph-node
seed
1 change: 1 addition & 0 deletions projects/subgraph-beanstalk/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ generated
# matchstick binary download info
tests/.latest.json
tests/.bin
tests/.docker
14 changes: 9 additions & 5 deletions projects/subgraph-beanstalk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@

### Subgraphs

All currently used subgraphs live on the graph protocol's centralized host.
All currently used subgraphs live on the graph protocol's centralized host.

- [Testing Subgraph](https://graph.node.bean.money/subgraphs/name/beanstalk-testing)
- Used during local development for debugging and rapid iteration.
- 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.
- 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.
- Stable deployment and current source of truth for UI and other production processes.
- 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.
- All changes pushed to the canonical subgraph are prototyped on the testing subgraph, tested on the dev subgraph, then made canonical once verified.

### 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.
1 change: 1 addition & 0 deletions projects/subgraph-beanstalk/matchstick.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
libsFolder: ../../node_modules
6 changes: 6 additions & 0 deletions projects/subgraph-beanstalk/matchstick.yaml.docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This configuration is needed when running the matchstick tests in docker.
# This is because the root project directory is bind mounted to the container, as the
# subgraph has some dependencies on other projects in the repo.
testsFolder: repo-mounted/projects/subgraph-beanstalk/tests
libsFolder: repo-mounted/node_modules
manifestPath: repo-mounted/projects/subgraph-beanstalk/subgraph.yaml
8 changes: 5 additions & 3 deletions projects/subgraph-beanstalk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"codegen": "graph codegen",
"build": "graph build",
"test": "graph test",
"testd": "docker run -it --rm --mount type=bind,source=\"$(pwd)\"/matchstick.yaml.docker,target=/matchstick/matchstick.yaml --mount type=bind,source=\"$(pwd)\"/../../,target=/matchstick/repo-mounted/ matchstick",
"testd-named": "./tests/scripts/docker-run-named.sh",
"deploy": "graph deploy --node https://api.studio.thegraph.com/deploy/ beanstalk",
"create-local": "graph create --node http://127.0.0.1:8020/ beanstalk",
"deploy-local": "graph deploy --node http://127.0.0.1:8020/ --ipfs http://127.0.0.1:5001 beanstalk",
Expand All @@ -25,9 +27,9 @@
"deploy-hosted-test": "graph deploy --node http://graph.node.bean.money:8020/ --ipfs http://graph.node.bean.money:5001 beanstalk-testing"
},
"dependencies": {
"@graphprotocol/graph-cli": "0.56.0",
"@graphprotocol/graph-ts": "0.31.0",
"matchstick-as": "^0.5.0"
"@graphprotocol/graph-cli": "0.69.0",
"@graphprotocol/graph-ts": "0.34.0",
"matchstick-as": "^0.6.0"
},
"private": true
}
14 changes: 12 additions & 2 deletions projects/subgraph-beanstalk/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ enum PlotSource {
TRANSFER
}

enum EmaWindow {
ROLLING_24_HOUR
ROLLING_7_DAY
ROLLING_30_DAY
}

type Beanstalk @entity {
" Smart contract address of the protocol's main contract (Factory, Registry, etc) "
id: ID!
Expand Down Expand Up @@ -294,10 +300,12 @@ type SiloAssetDailySnapshot @entity {
}

type SiloYield @entity {
"Season of data points"
"Season of data points - EMA window"
id: ID!
"Sortable int field for season"
season: Int!
"Window used for vAPY calc"
window: EmaWindow!
"Beta used for EMA"
beta: BigDecimal!
"u used for EMA"
Expand All @@ -313,7 +321,7 @@ type SiloYield @entity {
}

type TokenYield @entity {
"Token address - season"
"Token address - season - EMA window"
id: Bytes!
"Token being calculated"
token: Bytes!
Expand Down Expand Up @@ -1110,6 +1118,8 @@ type FertilizerYield @entity {
id: ID!
"Current season"
season: Int!
"Bean EMA Window"
window: EmaWindow!
"Current humidity"
humidity: BigDecimal!
"Current outstanding fert"
Expand Down
15 changes: 0 additions & 15 deletions projects/subgraph-beanstalk/src/DiamondHandler.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts";
import { ZERO_BI } from "../../subgraph-core/utils/Decimals";
import { DiamondCut } from "../generated/Diamond/Beanstalk";
import { loadBeanstalk } from "./utils/Beanstalk";
import { TOKEN_YIELD_14_000 } from "./utils/HistoricYield";
import { loadTokenYield } from "./utils/SiloEntities";

export function handleDiamondCut(event: DiamondCut): void {
let beanstalk = loadBeanstalk(event.address);

// Load the historical vAPY figures in bulk at start
if (beanstalk.lastUpgrade == ZERO_BI) {
for (let i = 0; i < TOKEN_YIELD_14_000.length; i++) {
let tokenYield = loadTokenYield(Address.fromString(TOKEN_YIELD_14_000[i][0]), <i32>parseInt(TOKEN_YIELD_14_000[i][1]));
tokenYield.beanAPY = BigDecimal.fromString(TOKEN_YIELD_14_000[i][2]);
tokenYield.stalkAPY = BigDecimal.fromString(TOKEN_YIELD_14_000[i][3]);
tokenYield.createdAt = BigInt.fromString(TOKEN_YIELD_14_000[i][4]);
tokenYield.save();
}
}

beanstalk.lastUpgrade = event.block.timestamp;
beanstalk.save();
}
49 changes: 48 additions & 1 deletion projects/subgraph-beanstalk/src/FieldHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,27 @@ export function handlePlotTransfer(event: PlotTransfer): void {
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, season.harvestableIndex);

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
Expand All @@ -338,6 +352,7 @@ export function handlePlotTransfer(event: PlotTransfer): void {
sourcePlot.farmer = event.params.to.toHexString();
sourcePlot.updatedAt = event.block.timestamp;
sourcePlot.pods = event.params.pods;
sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, season.harvestableIndex);
sourcePlot.save();

remainderPlot.farmer = event.params.from.toHexString();
Expand All @@ -348,6 +363,7 @@ export function handlePlotTransfer(event: PlotTransfer): void {
remainderPlot.updatedAt = event.block.timestamp;
remainderPlot.index = remainderIndex;
remainderPlot.pods = sourceEndIndex.minus(transferEndIndex);
remainderPlot.harvestablePods = calcHarvestable(remainderPlot.index, remainderPlot.pods, season.harvestableIndex);
remainderPlot.temperature = sourcePlot.temperature;
remainderPlot.save();

Expand All @@ -363,6 +379,7 @@ export function handlePlotTransfer(event: PlotTransfer): void {

sourcePlot.updatedAt = event.block.timestamp;
sourcePlot.pods = sourcePlot.pods.minus(event.params.pods);
sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, season.harvestableIndex);
sourcePlot.save();

toPlot.farmer = event.params.to.toHexString();
Expand All @@ -373,6 +390,7 @@ export function handlePlotTransfer(event: PlotTransfer): void {
toPlot.updatedAt = event.block.timestamp;
toPlot.index = event.params.id;
toPlot.pods = event.params.pods;
toPlot.harvestablePods = calcHarvestable(toPlot.index, toPlot.pods, season.harvestableIndex);
toPlot.temperature = sourcePlot.temperature;
toPlot.save();

Expand All @@ -389,6 +407,7 @@ export function handlePlotTransfer(event: PlotTransfer): void {

sourcePlot.updatedAt = event.block.timestamp;
sourcePlot.pods = event.params.id.minus(sourcePlot.index);
sourcePlot.harvestablePods = calcHarvestable(sourcePlot.index, sourcePlot.pods, season.harvestableIndex);
sourcePlot.save();

toPlot.farmer = event.params.to.toHexString();
Expand All @@ -399,6 +418,7 @@ export function handlePlotTransfer(event: PlotTransfer): void {
toPlot.updatedAt = event.block.timestamp;
toPlot.index = event.params.id;
toPlot.pods = event.params.pods;
toPlot.harvestablePods = calcHarvestable(toPlot.index, toPlot.pods, season.harvestableIndex);
toPlot.temperature = sourcePlot.temperature;
toPlot.save();

Expand All @@ -410,6 +430,7 @@ export function handlePlotTransfer(event: PlotTransfer): void {
remainderPlot.updatedAt = event.block.timestamp;
remainderPlot.index = remainderIndex;
remainderPlot.pods = sourceEndIndex.minus(transferEndIndex);
remainderPlot.harvestablePods = calcHarvestable(remainderPlot.index, remainderPlot.pods, season.harvestableIndex);
remainderPlot.temperature = sourcePlot.temperature;
remainderPlot.save();

Expand All @@ -423,7 +444,33 @@ export function handlePlotTransfer(event: PlotTransfer): void {
field.save();

// Update any harvestable pod amounts
updateHarvestablePlots(season.harvestableIndex, event.block.timestamp, event.block.number);
// No need to shift beanstalk field, only the farmer fields.
if (transferredHarvestable != ZERO_BI) {
updateFieldTotals(
event.params.from,
beanstalk.lastSeason,
ZERO_BI,
ZERO_BI,
ZERO_BI,
ZERO_BI,
ZERO_BI.minus(transferredHarvestable),
ZERO_BI,
event.block.timestamp,
event.block.number
);
updateFieldTotals(
event.params.to,
beanstalk.lastSeason,
ZERO_BI,
ZERO_BI,
ZERO_BI,
ZERO_BI,
transferredHarvestable,
ZERO_BI,
event.block.timestamp,
event.block.number
);
}

// Save the raw event data
savePodTransfer(event);
Expand Down
56 changes: 33 additions & 23 deletions projects/subgraph-beanstalk/src/YieldHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,42 @@ import { toDecimal, ZERO_BD } from "../../subgraph-core/utils/Decimals";
import { loadFertilizer } from "./utils/Fertilizer";
import { loadFertilizerYield } from "./utils/FertilizerYield";
import { loadSilo, loadSiloHourlySnapshot, loadSiloYield, loadTokenYield, loadWhitelistTokenSetting } from "./utils/SiloEntities";
import { SILO_YIELD_14_000 } from "./utils/HistoricYield";

const MAX_WINDOW = 720;
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 {
let silo = loadSilo(BEANSTALK);
let siloYield = loadSiloYield(t);

// Check for cached info
if (t <= 14_000) {
let cacheIndex = t - 6075;
siloYield.beta = BigDecimal.fromString(SILO_YIELD_14_000[cacheIndex][1]);
siloYield.u = <i32>parseInt(SILO_YIELD_14_000[cacheIndex][2]);
siloYield.beansPerSeasonEMA = BigDecimal.fromString(SILO_YIELD_14_000[cacheIndex][3]);
updateWindowEMA(t, timestamp, ROLLING_24_WINDOW);
updateWindowEMA(t, timestamp, ROLLING_7_DAY_WINDOW);
updateWindowEMA(t, timestamp, ROLLING_30_DAY_WINDOW);
}

/**
*
*
*/
function updateWindowEMA(t: i32, timestamp: BigInt, window: i32): void {
// 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.createdAt = BigInt.fromString(SILO_YIELD_14_000[cacheIndex][4]);
siloYield.save();

updateFertAPY(t, timestamp);
updateFertAPY(t, timestamp, window);

return;
}

// When less then MAX_WINDOW data points are available,
// smooth over whatever is available. Otherwise use MAX_WINDOW.
siloYield.u = t - 6074 < MAX_WINDOW ? t - 6074 : MAX_WINDOW;
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;
siloYield.whitelistedTokens = silo.whitelistedTokens;

// Calculate the current beta value
Expand All @@ -41,7 +50,7 @@ export function updateBeanEMA(t: i32, timestamp: BigInt): void {
let currentEMA = ZERO_BD;
let priorEMA = ZERO_BD;

if (siloYield.u < MAX_WINDOW) {
if (siloYield.u < window) {
// Recalculate EMA from initial season since beta has changed
for (let i = 6075; i <= t; i++) {
let season = loadSiloHourlySnapshot(BEANSTALK, i, timestamp);
Expand All @@ -50,7 +59,7 @@ export function updateBeanEMA(t: i32, timestamp: BigInt): void {
}
} else {
// Calculate EMA for the prior 720 seasons
for (let i = t - MAX_WINDOW + 1; i <= t; i++) {
for (let i = t - window + 1; i <= t; i++) {
let season = loadSiloHourlySnapshot(BEANSTALK, i, timestamp);
currentEMA = toDecimal(season.deltaBeanMints).minus(priorEMA).times(siloYield.beta).plus(priorEMA);
priorEMA = currentEMA;
Expand All @@ -68,7 +77,7 @@ export function updateBeanEMA(t: i32, timestamp: BigInt): void {
for (let i = 0; i < siloYield.whitelistedTokens.length; i++) {
let token = Address.fromString(siloYield.whitelistedTokens[i]);
let siloSettings = loadWhitelistTokenSetting(token);
let tokenYield = loadTokenYield(token, t);
let tokenYield = loadTokenYield(token, t, window);

let tokenAPY = calculateAPY(
currentEMA,
Expand All @@ -83,7 +92,7 @@ export function updateBeanEMA(t: i32, timestamp: BigInt): void {
tokenYield.save();
}

updateFertAPY(t, timestamp);
updateFertAPY(t, timestamp, window);
}

/**
Expand Down Expand Up @@ -156,9 +165,10 @@ export function calculateAPY(

return apys;
}
function updateFertAPY(t: i32, timestamp: BigInt): void {
let siloYield = loadSiloYield(t);
let fertilizerYield = loadFertilizerYield(t);

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 = Beanstalk.bind(BEANSTALK);
let currentFertHumidity = beanstalk.try_getCurrentHumidity();
Expand Down
6 changes: 3 additions & 3 deletions projects/subgraph-beanstalk/src/utils/Beanstalk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export function loadBeanstalk(protocol: Address): Beanstalk {
beanstalk = new Beanstalk(protocol.toHexString());
beanstalk.name = "Beanstalk";
beanstalk.slug = "beanstalk";
beanstalk.schemaVersion = "2.0.0";
beanstalk.subgraphVersion = "2.0.0";
beanstalk.methodologyVersion = "2.0.0";
beanstalk.schemaVersion = "2.1.1";
beanstalk.subgraphVersion = "2.1.1";
beanstalk.methodologyVersion = "2.1.1";
beanstalk.lastUpgrade = ZERO_BI;
beanstalk.lastSeason = 1;
beanstalk.activeFarmers = [];
Expand Down
Loading

0 comments on commit 14271ca

Please sign in to comment.