From 6a899bb903693b04fb062f75e63c7b2c98211e0c Mon Sep 17 00:00:00 2001 From: mendesfabio Date: Tue, 27 Aug 2024 09:53:10 -0300 Subject: [PATCH] add hourly snapshots and raw metrics amounts --- networks.yaml | 8 ++-- schema.graphql | 22 +++++++++++ src/mappings/helpers/assets.ts | 60 +++++++++--------------------- src/mappings/helpers/misc.ts | 68 ++++++++++++++++++++++++++++++++++ src/mappings/poolController.ts | 2 + src/mappings/pricing.ts | 4 +- src/mappings/vault.ts | 4 ++ 7 files changed, 120 insertions(+), 48 deletions(-) diff --git a/networks.yaml b/networks.yaml index ad434574..f087b5d1 100644 --- a/networks.yaml +++ b/networks.yaml @@ -241,15 +241,15 @@ polygon: network: matic graft: # FXPoolDeployerTracker start block - block: 54559455 + # block: 54559455 # this will be the base of the unpruned deployment, so make sure it has not been pruned # it should be possible to run time travel queries on it going back to the vault's startBlock - base: QmUqS6BAVQgvstEsVrxuwsu1DwQdfAdj3Q6gz2j3DbUYQ9 + # base: QmUqS6BAVQgvstEsVrxuwsu1DwQdfAdj3Q6gz2j3DbUYQ9 graft_pruned: # FXPoolDeployerTracker start block - block: 54559455 + # block: 54559455 # this will be the base of the pruned deployment, so it is ok if it is a pruned subgraph - base: QmUqS6BAVQgvstEsVrxuwsu1DwQdfAdj3Q6gz2j3DbUYQ9 + # base: QmUqS6BAVQgvstEsVrxuwsu1DwQdfAdj3Q6gz2j3DbUYQ9 EventEmitter: address: "0xcdcECFa416EE3022030E707dC3EA13a8997D74c8" startBlock: 38152461 diff --git a/schema.graphql b/schema.graphql index 7e8243f6..7a57a99e 100644 --- a/schema.graphql +++ b/schema.graphql @@ -158,6 +158,8 @@ type PoolToken @entity { oldPriceRate: BigDecimal # TODO: make mandatory at next full sync priceRate: BigDecimal! balance: BigDecimal! + volume: BigDecimal! + swapFees: BigDecimal! paidProtocolFees: BigDecimal # TODO: make mandatory at next full sync cashBalance: BigDecimal! managedBalance: BigDecimal! @@ -333,6 +335,26 @@ type PoolSnapshot @entity { totalShares: BigDecimal! swapVolume: BigDecimal! protocolFee: BigDecimal # TODO: make mandatory at next full sync + totalSwapFees: [BigDecimal!]! + totalSwapVolumes: [BigDecimal!]! + totalProtocolFees: [BigDecimal!]! + swapFees: BigDecimal! + liquidity: BigDecimal! + swapsCount: BigInt! + holdersCount: BigInt! + timestamp: Int! +} + +type PoolSnapshotHourly @entity { + id: ID! + pool: Pool! + amounts: [BigDecimal!]! + totalShares: BigDecimal! + swapVolume: BigDecimal! + protocolFee: BigDecimal # TODO: make mandatory at next full sync + totalSwapFees: [BigDecimal!]! + totalSwapVolumes: [BigDecimal!]! + totalProtocolFees: [BigDecimal!]! swapFees: BigDecimal! liquidity: BigDecimal! swapsCount: BigInt! diff --git a/src/mappings/helpers/assets.ts b/src/mappings/helpers/assets.ts index 45891304..3213d608 100644 --- a/src/mappings/helpers/assets.ts +++ b/src/mappings/helpers/assets.ts @@ -1,4 +1,4 @@ -// This file is automatically generated and contains assets from mainnet. +// This file is automatically generated and contains assets from gnosis. // Generate for other networks by running: yarn generate-assets [network]. // Supported networks are: arbitrum, goerli, mainnet, and polygon. @@ -10,54 +10,28 @@ class Assets { public fxAssetAggregators: Address[][]; } -export const USDC_ADDRESS = Address.fromString('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'); -export const DAI_ADDRESS = Address.fromString('0x6B175474E89094C44Da98b954EedeAC495271d0F'); -export const USDT_ADDRESS = Address.fromString('0xdAC17F958D2ee523a2206206994597C13D831ec7'); +export const WXDAI_ADDRESS = Address.fromString('0xe91d153e0b41518a2ce8dd3d7944fa863463a97d'); +export const USDC_ADDRESS = Address.fromString('0xddafbb505ad214d7b80b1f830fccc89b60fb7a83'); +export const USDT_ADDRESS = Address.fromString('0x4ecaba5870353805a9f068101a40e0f32ed605c6'); export const assets: Assets = { stableAssets: [ - Address.fromString('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), // USDC - Address.fromString('0x6B175474E89094C44Da98b954EedeAC495271d0F'), // DAI - Address.fromString('0xdAC17F958D2ee523a2206206994597C13D831ec7'), // USDT + Address.fromString('0xe91d153e0b41518a2ce8dd3d7944fa863463a97d'), // WXDAI + Address.fromString('0xddafbb505ad214d7b80b1f830fccc89b60fb7a83'), // USDC + Address.fromString('0x4ecaba5870353805a9f068101a40e0f32ed605c6'), // USDT ], pricingAssets: [ - Address.fromString('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'), // WETH - Address.fromString('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'), // wstETH - Address.fromString('0x804CdB9116a10bB78768D3252355a1b18067bF8f'), // bb-a-DAI-V1 - Address.fromString('0x9210F1204b5a24742Eba12f710636D76240dF3d0'), // bb-a-USDC-V1 - Address.fromString('0x2BBf681cC4eb09218BEe85EA2a5d3D13Fa40fC0C'), // bb-a-USDT-V1 - Address.fromString('0xae37D54Ae477268B9997d4161B96b8200755935c'), // bb-a-DAI-V2 - Address.fromString('0x82698aeCc9E28e9Bb27608Bd52cF57f704BD1B83'), // bb-a-USDC-V2 - Address.fromString('0x2F4eb100552ef93840d5aDC30560E5513DFfFACb'), // bb-a-USDT-V2 - Address.fromString('0x6667c6fa9f2b3Fc1Cc8D85320b62703d938E4385'), // bb-a-DAI-V3 - Address.fromString('0xcbFA4532D8B2ade2C261D3DD5ef2A2284f792692'), // bb-a-USDC-V3 - Address.fromString('0xA1697F9Af0875B63DdC472d6EeBADa8C1fAB8568'), // bb-a-USDT-V3 - Address.fromString('0xfeBb0bbf162E64fb9D0dfe186E517d84C395f016'), // bb-a-USD-V3 - Address.fromString('0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599'), // WBTC - Address.fromString('0xba100000625a3754423978a60c9317c58a424e3D'), // BAL - Address.fromString('0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2'), // MKR - Address.fromString('0x6810e776880C02933D47DB1b9fc05908e5386b96'), // GNO - Address.fromString('0x5c6ee304399dbdb9c8ef030ab642b10820db8f56'), // B-80BAL-20WETH - Address.fromString('0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0'), // MATIC - Address.fromString('0xA13a9247ea42D743238089903570127DdA72fE44'), // bb-a-USD - Address.fromString('0x60D604890feaa0b5460B28A424407c24fe89374a'), // bb-a-WETH-V3 + Address.fromString('0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1'), // WETH + Address.fromString('0x8e5bBbb09Ed1ebdE8674Cda39A0c169401db4252'), // WBTC + Address.fromString('0x9c58bacc331c9aa871afd802db6379a98e80cedb'), // GNO + Address.fromString('0xd4015683b8153666190e0b2bec352580ebc4caca'), // bb-ag-WBTC + Address.fromString('0xbb9cd48d33033f5effbedec9dd700c7d7e1dcf50'), // bb-ag-WETH + Address.fromString('0xfedb19ec000d38d92af4b21436870f115db22725'), // bb-ag-USD + Address.fromString('0x41211bba6d37f5a74b22e667533f080c7c7f3f13'), // bb-ag-WXDAI + Address.fromString('0xd16f72b02da5f51231fde542a8b9e2777a478c88'), // bb-ag-USDT + Address.fromString('0xe7f88d7d4ef2eb18fcf9dd7216ba7da1c46f3dd6'), // bb-ag-USDC + Address.fromString('0xffff76a3280e95dc855696111c2562da09db2ac0'), // bb-ag-GNO ], fxAssetAggregators: [ - [ - Address.fromString('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), // USDC - Address.fromString('0x789190466E21a8b78b8027866CBBDc151542A26C'), // USDC/USD - ], - [ - Address.fromString('0x70e8dE73cE538DA2bEEd35d14187F6959a8ecA96'), // XSGD - Address.fromString('0xc96129C796F03bb21AC947EfC5329CD1F560305B'), // SGD/USD - ], - [ - Address.fromString('0x6B175474E89094C44Da98b954EedeAC495271d0F'), // DAI - Address.fromString('0xDEc0a100eaD1fAa37407f0Edc76033426CF90b82'), // DAI/USD - ], - [ - Address.fromString('0xdB25f211AB05b1c97D595516F45794528a807ad8'), // EURS - Address.fromString('0x02F878A94a1AE1B15705aCD65b5519A46fe3517e'), // EUR/USD - ], ], }; diff --git a/src/mappings/helpers/misc.ts b/src/mappings/helpers/misc.ts index d1bc84a6..ca103572 100644 --- a/src/mappings/helpers/misc.ts +++ b/src/mappings/helpers/misc.ts @@ -13,6 +13,8 @@ import { BalancerSnapshot, Balancer, FXOracle, + HourlyPoolSnapshot, + PoolSnapshotHourly, } from '../../types/schema'; import { ERC20 } from '../../types/Vault/ERC20'; import { WeightedPool } from '../../types/Vault/WeightedPool'; @@ -248,13 +250,24 @@ export function createPoolSnapshot(pool: Pool, timestamp: i32): void { let tokens = pool.tokensList; let amounts = new Array(tokens.length); + let protocolFees = new Array(tokens.length); + let volumes = new Array(tokens.length); + let swapFees = new Array(tokens.length); for (let i = 0; i < tokens.length; i++) { let token = tokens[i]; let tokenAddress = Address.fromString(token.toHexString()); let poolToken = loadPoolToken(poolId, tokenAddress); if (poolToken == null) continue; + volumes[i] = poolToken.volume; amounts[i] = poolToken.balance; + swapFees[i] = poolToken.swapFees; + + if (poolToken.address == pool.address.toHex()) { + protocolFees[i] = pool.totalProtocolFeePaidInBPT ? pool.totalProtocolFeePaidInBPT : ZERO_BD; + } else { + protocolFees[i] = poolToken.paidProtocolFees ? poolToken.paidProtocolFees : ZERO_BD; + } } snapshot.pool = poolId; @@ -264,12 +277,67 @@ export function createPoolSnapshot(pool: Pool, timestamp: i32): void { snapshot.swapFees = pool.totalSwapFee; snapshot.liquidity = pool.totalLiquidity; snapshot.protocolFee = pool.totalProtocolFee; + snapshot.totalProtocolFees = protocolFees; + snapshot.totalSwapVolumes = volumes; + snapshot.totalSwapFees = swapFees; snapshot.swapsCount = pool.swapsCount; snapshot.holdersCount = pool.holdersCount; snapshot.timestamp = dayTimestamp; snapshot.save(); } +export function createPoolSnapshotHourly(pool: Pool, timestamp: i32): void { + const hourIndex = timestamp / 3600; // get unique hour within unix history + const hourStartUnix = hourIndex * 3600; // want the rounded effect + + let poolId = pool.id; + if (pool == null || !pool.tokensList) return; + + let snapshotId = poolId + '-' + hourIndex.toString(); + let snapshot = PoolSnapshotHourly.load(snapshotId); + + if (!snapshot) { + snapshot = new PoolSnapshotHourly(snapshotId); + } + + let tokens = pool.tokensList; + let amounts = new Array(tokens.length); + let protocolFees = new Array(tokens.length); + let volumes = new Array(tokens.length); + let swapFees = new Array(tokens.length); + for (let i = 0; i < tokens.length; i++) { + let token = tokens[i]; + let tokenAddress = Address.fromString(token.toHexString()); + let poolToken = loadPoolToken(poolId, tokenAddress); + if (poolToken == null) continue; + + volumes[i] = poolToken.volume; + amounts[i] = poolToken.balance; + swapFees[i] = poolToken.swapFees; + + if (poolToken.address == pool.address.toHex()) { + protocolFees[i] = pool.totalProtocolFeePaidInBPT ? pool.totalProtocolFeePaidInBPT : ZERO_BD; + } else { + protocolFees[i] = poolToken.paidProtocolFees ? poolToken.paidProtocolFees : ZERO_BD; + } + } + + snapshot.pool = poolId; + snapshot.amounts = amounts; + snapshot.totalShares = pool.totalShares; + snapshot.swapVolume = pool.totalSwapVolume; + snapshot.swapFees = pool.totalSwapFee; + snapshot.liquidity = pool.totalLiquidity; + snapshot.protocolFee = pool.totalProtocolFee; + snapshot.totalProtocolFees = protocolFees; + snapshot.totalSwapVolumes = volumes; + snapshot.totalSwapFees = swapFees; + snapshot.swapsCount = pool.swapsCount; + snapshot.holdersCount = pool.holdersCount; + snapshot.timestamp = hourStartUnix; + snapshot.save(); +} + export function createUserEntity(address: Address): void { let addressHex = address.toHex(); if (User.load(addressHex) == null) { diff --git a/src/mappings/poolController.ts b/src/mappings/poolController.ts index cf82d536..c6e48aee 100644 --- a/src/mappings/poolController.ts +++ b/src/mappings/poolController.ts @@ -55,6 +55,7 @@ import { createPoolSnapshot, hexToBigInt, getBalancerSnapshot, + createPoolSnapshotHourly, } from './helpers/misc'; import { ONE_BD, ProtocolFeeType, VAULT_ADDRESS, ZERO_ADDRESS, ZERO_BD } from './helpers/constants'; import { updateAmpFactor } from './helpers/stable'; @@ -657,6 +658,7 @@ export function handleTransfer(event: Transfer): void { // create or update pool's snapshot createPoolSnapshot(pool, event.block.timestamp.toI32()); + createPoolSnapshotHourly(pool, event.block.timestamp.toI32()); let vault = Balancer.load('2') as Balancer; let vaultProtocolFee = vault.totalProtocolFee ? vault.totalProtocolFee : ZERO_BD; diff --git a/src/mappings/pricing.ts b/src/mappings/pricing.ts index 87098c43..f704bc2d 100644 --- a/src/mappings/pricing.ts +++ b/src/mappings/pricing.ts @@ -12,6 +12,7 @@ import { hasVirtualSupply, isComposableStablePool, isLinearPool, isFXPool, PoolT import { bytesToAddress, createPoolSnapshot, + createPoolSnapshotHourly, getBalancerSnapshot, getToken, getTokenPriceId, @@ -179,8 +180,9 @@ export function updatePoolLiquidity(poolId: string, block_number: BigInt, timest updateBptPrice(pool); } - // Create or update pool daily snapshot + // Create or update pool snapshots createPoolSnapshot(pool, timestamp.toI32()); + createPoolSnapshotHourly(pool, timestamp.toI32()); // Update global stats let vault = Balancer.load('2') as Balancer; diff --git a/src/mappings/vault.ts b/src/mappings/vault.ts index 3d4b78f4..4caa3076 100644 --- a/src/mappings/vault.ts +++ b/src/mappings/vault.ts @@ -558,10 +558,14 @@ export function handleSwapEvent(event: SwapEvent): void { let newInAmount = poolTokenIn.balance.plus(tokenAmountIn); poolTokenIn.balance = newInAmount; + poolTokenIn.volume = poolTokenIn.volume.plus(tokenAmountIn); + poolTokenIn.swapFees = poolTokenIn.swapFees.plus(tokenAmountIn.times(pool.swapFee)); poolTokenIn.save(); let newOutAmount = poolTokenOut.balance.minus(tokenAmountOut); poolTokenOut.balance = newOutAmount; + poolTokenOut.volume = poolTokenOut.volume.plus(tokenAmountOut); + poolTokenOut.swapFees = poolTokenOut.swapFees.plus(tokenAmountOut.times(pool.swapFee)); poolTokenOut.save(); let swapId = transactionHash.toHexString().concat(logIndex.toString());