From a76698c86ed4c67bfb44e71e27cf5f5717d022f9 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 12:32:21 +0100 Subject: [PATCH 01/23] start v3 integration --- modules/network/arbitrum.ts | 21 ++++++++++------ modules/network/avalanche.ts | 21 ++++++++++------ modules/network/base.ts | 19 ++++++++++----- modules/network/fantom.ts | 21 ++++++++++------ modules/network/gnosis.ts | 21 ++++++++++------ modules/network/mainnet.ts | 24 ++++++++++++------- modules/network/network-config-types.ts | 16 +++++++++---- modules/network/optimism.ts | 21 ++++++++++------ modules/network/polygon.ts | 21 ++++++++++------ modules/network/zkevm.ts | 21 ++++++++++------ modules/pool/lib/pool-gql-loader.service.ts | 3 +++ modules/pool/pool.gql | 17 +++++++++---- modules/pool/pool.prisma | 2 ++ .../migration.sql | 2 ++ prisma/schema.prisma | 2 ++ 15 files changed, 160 insertions(+), 72 deletions(-) create mode 100644 prisma/migrations/20240119112613_add_vault_version/migration.sql diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 5e5b8f475..39b379629 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -68,9 +68,16 @@ export const arbitrumNetworkData: NetworkData = { delegationProxy: '0x81cfae226343b24ba12ec6521db2c79e7aeeb310', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, multicall: '0x80c7dd17b01855a6d2347444a0fcc36136a314de', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -237,15 +244,15 @@ export const arbitrumNetworkConfig: NetworkConfig = { new YbTokensAprService( arbitrumNetworkData.ybAprConfig, arbitrumNetworkData.chain.prismaId, - arbitrumNetworkData.balancer.yieldProtocolFeePercentage, - arbitrumNetworkData.balancer.swapProtocolFeePercentage, + arbitrumNetworkData.balancer.v2.yieldProtocolFeePercentage, + arbitrumNetworkData.balancer.v2.swapProtocolFeePercentage, ), new PhantomStableAprService( arbitrumNetworkData.chain.prismaId, - arbitrumNetworkData.balancer.yieldProtocolFeePercentage, + arbitrumNetworkData.balancer.v2.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(arbitrumNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(arbitrumNetworkData.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [arbitrumNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, arbitrumNetworkData.bal!.address)], diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index d00e1b3e8..2190c8039 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -66,9 +66,16 @@ const avalancheNetworkData: NetworkData = { delegationProxy: '0x0c6052254551eae3ecac77b01dfcf1025418828f', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -208,15 +215,15 @@ export const avalancheNetworkConfig: NetworkConfig = { new YbTokensAprService( avalancheNetworkData.ybAprConfig, avalancheNetworkData.chain.prismaId, - avalancheNetworkData.balancer.yieldProtocolFeePercentage, - avalancheNetworkData.balancer.swapProtocolFeePercentage, + avalancheNetworkData.balancer.v2.yieldProtocolFeePercentage, + avalancheNetworkData.balancer.v2.swapProtocolFeePercentage, ), new PhantomStableAprService( avalancheNetworkData.chain.prismaId, - avalancheNetworkData.balancer.yieldProtocolFeePercentage, + avalancheNetworkData.balancer.v2.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(avalancheNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(avalancheNetworkData.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [avalancheNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, avalancheNetworkData.bal!.address)], diff --git a/modules/network/base.ts b/modules/network/base.ts index 28c6a7f64..fe71e6aea 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -62,9 +62,16 @@ const baseNetworkData: NetworkData = { delegationProxy: '0xd87f44df0159dc78029ab9ca7d7e57e7249f5acd', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, ybAprConfig: { defaultHandlers: { @@ -132,11 +139,11 @@ export const baseNetworkConfig: NetworkConfig = { new YbTokensAprService( baseNetworkData.ybAprConfig, baseNetworkData.chain.prismaId, - baseNetworkData.balancer.yieldProtocolFeePercentage, - baseNetworkData.balancer.swapProtocolFeePercentage, + baseNetworkData.balancer.v2.yieldProtocolFeePercentage, + baseNetworkData.balancer.v2.swapProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(baseNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(baseNetworkData.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [baseNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, baseNetworkData.bal!.address)], diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 36549c936..ea2805bfb 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -114,9 +114,16 @@ const fantomNetworkData: NetworkData = { poolAddress: '0xcde5a11a4acb4ee4c805352cec57e236bdbc3837', }, balancer: { - vault: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', - swapProtocolFeePercentage: 0.25, - yieldProtocolFeePercentage: 0.25, + v2: { + vault: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', + swapProtocolFeePercentage: 0.25, + yieldProtocolFeePercentage: 0.25, + }, + v3: { + vault: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', + swapProtocolFeePercentage: 0.25, + yieldProtocolFeePercentage: 0.25, + }, }, multicall: '0x66335d7ad8011f6aa3f48aadcb523b62b38ed961', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -292,16 +299,16 @@ export const fantomNetworkConfig: NetworkConfig = { new YbTokensAprService( fantomNetworkData.ybAprConfig, fantomNetworkData.chain.prismaId, - fantomNetworkData.balancer.yieldProtocolFeePercentage, - fantomNetworkData.balancer.swapProtocolFeePercentage, + fantomNetworkData.balancer.v2.yieldProtocolFeePercentage, + fantomNetworkData.balancer.v2.swapProtocolFeePercentage, ), // new SpookySwapAprService(tokenService, fantomNetworkData.spooky!.xBooContract), new PhantomStableAprService( fantomNetworkData.chain.prismaId, - fantomNetworkData.balancer.yieldProtocolFeePercentage, + fantomNetworkData.balancer.v2.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(fantomNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(fantomNetworkData.balancer.v2.swapProtocolFeePercentage), new MasterchefFarmAprService(fantomNetworkData.beets!.address), new ReliquaryFarmAprService(fantomNetworkData.beets!.address), new BeetswarsGaugeVotingAprService(), diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 85462a672..f340e23bb 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -64,9 +64,16 @@ const gnosisNetworkData: NetworkData = { delegationProxy: '0x7a2535f5fb47b8e44c02ef5d9990588313fe8f05', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, multicall: '0xbb6fab6b627947dae0a75808250d8b2652952cb5', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -136,15 +143,15 @@ export const gnosisNetworkConfig: NetworkConfig = { new YbTokensAprService( gnosisNetworkData.ybAprConfig, gnosisNetworkData.chain.prismaId, - gnosisNetworkData.balancer.yieldProtocolFeePercentage, - gnosisNetworkData.balancer.swapProtocolFeePercentage, + gnosisNetworkData.balancer.v2.yieldProtocolFeePercentage, + gnosisNetworkData.balancer.v2.swapProtocolFeePercentage, ), new PhantomStableAprService( gnosisNetworkData.chain.prismaId, - gnosisNetworkData.balancer.yieldProtocolFeePercentage, + gnosisNetworkData.balancer.v2.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(gnosisNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(gnosisNetworkData.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [gnosisNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, gnosisNetworkData.bal!.address)], diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index b862ed02f..61f7188c8 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -82,10 +82,18 @@ const data: NetworkData = { config: '0xac89cc9d78bbad7eb3a02601b4d65daa1f908aa6', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, multicall: '0x5ba1e12693dc8f9c48aad8770482f4739beed696', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -368,12 +376,12 @@ export const mainnetNetworkConfig: NetworkConfig = { new YbTokensAprService( data.ybAprConfig, data.chain.prismaId, - data.balancer.yieldProtocolFeePercentage, - data.balancer.swapProtocolFeePercentage, + data.balancer.v2.yieldProtocolFeePercentage, + data.balancer.v2.swapProtocolFeePercentage, ), - new PhantomStableAprService(data.chain.prismaId, data.balancer.yieldProtocolFeePercentage), + new PhantomStableAprService(data.chain.prismaId, data.balancer.v2.yieldProtocolFeePercentage), new BoostedPoolAprService(), - new SwapFeeAprService(data.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(data.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [data.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, data.bal!.address)], diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index efeaabc08..421fa36b4 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -102,10 +102,18 @@ export interface NetworkData { config: string; }; balancer: { - vault: string; - tokenAdmin?: string; - yieldProtocolFeePercentage: number; - swapProtocolFeePercentage: number; + v2: { + vault: string; + tokenAdmin?: string; + yieldProtocolFeePercentage: number; + swapProtocolFeePercentage: number; + }; + v3: { + vault: string; + tokenAdmin?: string; + yieldProtocolFeePercentage: number; + swapProtocolFeePercentage: number; + }; }; multicall: string; multicall3: string; diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 2faa94d8f..f996ee7c3 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -73,9 +73,16 @@ const optimismNetworkData: NetworkData = { config: '0x32acb44fc929339b9f16f0449525cc590d2a23f3', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, multicall: '0x2dc0e2aa608532da689e89e237df582b783e552c', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -265,15 +272,15 @@ export const optimismNetworkConfig: NetworkConfig = { new YbTokensAprService( optimismNetworkData.ybAprConfig, optimismNetworkData.chain.prismaId, - optimismNetworkData.balancer.yieldProtocolFeePercentage, - optimismNetworkData.balancer.swapProtocolFeePercentage, + optimismNetworkData.balancer.v2.yieldProtocolFeePercentage, + optimismNetworkData.balancer.v2.swapProtocolFeePercentage, ), new PhantomStableAprService( optimismNetworkData.chain.prismaId, - optimismNetworkData.balancer.yieldProtocolFeePercentage, + optimismNetworkData.balancer.v2.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(optimismNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(optimismNetworkData.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [optimismNetworkData.beets!.address, optimismNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, optimismNetworkData.bal!.address)], diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index ae8f88d55..ee2a6d1ae 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -68,9 +68,16 @@ const polygonNetworkData: NetworkData = { config: '0xfdc2e9e03f515804744a40d0f8d25c16e93fbe67', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, multicall: '0x275617327c958bd06b5d6b871e7f491d76113dd8', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -253,15 +260,15 @@ export const polygonNetworkConfig: NetworkConfig = { new YbTokensAprService( polygonNetworkData.ybAprConfig, polygonNetworkData.chain.prismaId, - polygonNetworkData.balancer.yieldProtocolFeePercentage, - polygonNetworkData.balancer.swapProtocolFeePercentage, + polygonNetworkData.balancer.v2.yieldProtocolFeePercentage, + polygonNetworkData.balancer.v2.swapProtocolFeePercentage, ), new PhantomStableAprService( polygonNetworkData.chain.prismaId, - polygonNetworkData.balancer.yieldProtocolFeePercentage, + polygonNetworkData.balancer.v2.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(polygonNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(polygonNetworkData.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [polygonNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, polygonNetworkData.bal!.address)], diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 2e118fc60..43998e28e 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -66,9 +66,16 @@ const zkevmNetworkData: NetworkData = { delegationProxy: '0xc7e5ed1054a24ef31d827e6f86caa58b3bc168d7', }, balancer: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, + v2: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, + v3: { + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + swapProtocolFeePercentage: 0.5, + yieldProtocolFeePercentage: 0.5, + }, }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -166,15 +173,15 @@ export const zkevmNetworkConfig: NetworkConfig = { new YbTokensAprService( zkevmNetworkData.ybAprConfig, zkevmNetworkData.chain.prismaId, - zkevmNetworkData.balancer.yieldProtocolFeePercentage, - zkevmNetworkData.balancer.swapProtocolFeePercentage, + zkevmNetworkData.balancer.v2.yieldProtocolFeePercentage, + zkevmNetworkData.balancer.v2.swapProtocolFeePercentage, ), new PhantomStableAprService( zkevmNetworkData.chain.prismaId, - zkevmNetworkData.balancer.yieldProtocolFeePercentage, + zkevmNetworkData.balancer.v2.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(zkevmNetworkData.balancer.swapProtocolFeePercentage), + new SwapFeeAprService(zkevmNetworkData.balancer.v2.swapProtocolFeePercentage), new GaugeAprService(tokenService, [zkevmNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, zkevmNetworkData.bal!.address)], diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index de731f980..1f947b197 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -356,6 +356,9 @@ export class PoolGqlLoaderService { in: where?.chainIn || undefined, notIn: where?.chainNotIn || undefined, }, + vaultVersion: { + in: where?.vaultVersionIn || undefined, + }, type: { in: where?.poolTypeIn || undefined, notIn: where?.poolTypeNotIn || undefined, diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index de96f2c52..e7f73bf3c 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -60,6 +60,7 @@ extend type Mutation { type GqlPoolMinimal { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -107,6 +108,7 @@ interface GqlPoolBase { #fields that never change after creation id: ID! chain: GqlChain! + vaultVersion: Int! type: GqlPoolType! version: Int! name: String! @@ -213,6 +215,7 @@ enum GqlPoolNestingType { type GqlPoolWeighted implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -238,6 +241,7 @@ type GqlPoolWeighted implements GqlPoolBase { type GqlPoolGyro implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! type: GqlPoolType! symbol: String! @@ -288,6 +292,7 @@ type GqlPoolFx implements GqlPoolBase { # Base pool id: ID! chain: GqlChain! + vaultVersion: Int! type: GqlPoolType! version: Int! name: String! @@ -310,6 +315,7 @@ type GqlPoolFx implements GqlPoolBase { type GqlPoolLiquidityBootstrapping implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -335,6 +341,7 @@ type GqlPoolLiquidityBootstrapping implements GqlPoolBase { type GqlPoolStable implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -360,6 +367,7 @@ type GqlPoolStable implements GqlPoolBase { type GqlPoolMetaStable implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -385,6 +393,7 @@ type GqlPoolMetaStable implements GqlPoolBase { type GqlPoolComposableStable implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -411,6 +420,7 @@ type GqlPoolComposableStable implements GqlPoolBase { type GqlPoolElement implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -439,6 +449,7 @@ type GqlPoolElement implements GqlPoolBase { type GqlPoolLinear implements GqlPoolBase { id: ID! chain: GqlChain! + vaultVersion: Int! name: String! symbol: String! address: Bytes! @@ -694,6 +705,7 @@ input GqlPoolFilter { chainNotIn: [GqlChain!] createTime: GqlPoolTimePeriod userAddress: String + vaultVersionIn: [Int!] } enum GqlPoolFilterCategory { @@ -713,11 +725,6 @@ type GqlPoolTokenExpanded { isMainToken: Boolean! } -type GqlPoolFilterDefinition { - id: ID! - title: String! -} - type GqlPoolSwap { id: ID! chain: GqlChain! diff --git a/modules/pool/pool.prisma b/modules/pool/pool.prisma index e9189664e..3023c7bc6 100644 --- a/modules/pool/pool.prisma +++ b/modules/pool/pool.prisma @@ -15,6 +15,8 @@ model PrismaPool { owner String factory String? + vaultVersion Int @default(2) + linearData PrismaPoolLinearData? elementData PrismaPoolElementData? gyroData PrismaPoolGyroData? diff --git a/prisma/migrations/20240119112613_add_vault_version/migration.sql b/prisma/migrations/20240119112613_add_vault_version/migration.sql new file mode 100644 index 000000000..14d210abd --- /dev/null +++ b/prisma/migrations/20240119112613_add_vault_version/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "PrismaPool" ADD COLUMN "vaultVersion" INTEGER NOT NULL DEFAULT 2; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c3e363422..b533bbfa9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -61,6 +61,8 @@ model PrismaPool { owner String factory String? + vaultVersion Int @default(2) + linearData PrismaPoolLinearData? elementData PrismaPoolElementData? gyroData PrismaPoolGyroData? From 4d58bd4c52ed327a363394b3e020b2e350f84415 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 13:46:23 +0100 Subject: [PATCH 02/23] remove unsued --- modules/beethoven/beets.resolvers.ts | 22 - modules/user/lib/user-snapshot.service.ts | 746 ---------- modules/user/user-snapshot.service.test.ts | 1564 -------------------- modules/user/user.service.ts | 38 +- worker/job-handlers.ts | 12 - 5 files changed, 1 insertion(+), 2381 deletions(-) delete mode 100644 modules/user/lib/user-snapshot.service.ts delete mode 100644 modules/user/user-snapshot.service.test.ts diff --git a/modules/beethoven/beets.resolvers.ts b/modules/beethoven/beets.resolvers.ts index 87e705789..540131d85 100644 --- a/modules/beethoven/beets.resolvers.ts +++ b/modules/beethoven/beets.resolvers.ts @@ -36,21 +36,6 @@ const beetsResolvers: Resolvers = { ...balance, }; }, - userGetPoolSnapshots: async (parent, { poolId, chain, range }, context) => { - const accountAddress = getRequiredAccountAddress(context); - - return userService.getUserBalanceSnapshotsForPool( - accountAddress.toLowerCase(), - poolId.toLowerCase(), - chain, - range, - ); - }, - userGetRelicSnapshots: async (parent, { farmId, range }, context) => { - const accountAddress = getRequiredAccountAddress(context); - - return userService.getUserRelicSnapshots(accountAddress.toLowerCase(), farmId, range); - }, }, Mutation: { beetsSyncFbeetsRatio: async (parent, {}, context) => { @@ -65,13 +50,6 @@ const beetsResolvers: Resolvers = { await poolService.loadReliquarySnapshotsForAllFarms(); - return 'success'; - }, - userLoadAllRelicSnapshots: async (parent, {}, context) => { - isAdminRoute(context); - - await userService.loadAllUserRelicSnapshots(); - return 'success'; }, }, diff --git a/modules/user/lib/user-snapshot.service.ts b/modules/user/lib/user-snapshot.service.ts deleted file mode 100644 index dfc1a3e93..000000000 --- a/modules/user/lib/user-snapshot.service.ts +++ /dev/null @@ -1,746 +0,0 @@ -import { UserSnapshotSubgraphService } from '../../subgraphs/user-snapshot-subgraph/user-snapshot-subgraph.service'; -import { prisma } from '../../../prisma/prisma-client'; -import moment from 'moment-timezone'; -import { UserPoolSnapshot, UserRelicSnapshot } from '../user-types'; -import { GqlUserSnapshotDataRange } from '../../../schema'; -import { PoolSnapshotService } from '../../pool/lib/pool-snapshot.service'; -import { - Chain, - Prisma, - PrismaPool, - PrismaPoolSnapshot, - PrismaPoolStaking, - PrismaUserRelicSnapshot, -} from '@prisma/client'; -import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; -import { oneDayInSeconds, secondsPerDay } from '../../common/time'; -import { UserBalanceSnapshotFragment } from '../../subgraphs/user-snapshot-subgraph/generated/user-snapshot-subgraph-types'; -import { ReliquarySubgraphService } from '../../subgraphs/reliquary-subgraph/reliquary.service'; -import { ReliquaryRelicSnapshotFragment } from '../../subgraphs/reliquary-subgraph/generated/reliquary-subgraph-types'; -import _ from 'lodash'; -import { networkContext } from '../../network/network-context.service'; - -export class UserSnapshotService { - private readonly FBEETS_BPT_RATIO: number = 1.0271; - - constructor( - private readonly userSnapshotSubgraphService: UserSnapshotSubgraphService, - private readonly reliquarySubgraphService: ReliquarySubgraphService, - private readonly poolSnapshotService: PoolSnapshotService, - ) {} - - // problem: user can have multiple relics in the same farm with different snapshots - public async getUserRelicSnapshotsForFarm(userAddress: string, farmId: string, range: GqlUserSnapshotDataRange) { - const userSnapshots: UserRelicSnapshot[] = []; - - const firstTimestamp = this.getTimestampForRange(range); - const allSnapshots = await prisma.prismaUserRelicSnapshot.findMany({ - where: { userAddress: userAddress, farmId: farmId, chain: networkContext.chain }, - orderBy: { timestamp: 'asc' }, - }); - - const allRelicIds = _.uniq(allSnapshots.map((snapshot) => snapshot.relicId)); - - for (const relicId of allRelicIds) { - const relicSnapshots = allSnapshots.filter( - (snapshot) => snapshot.relicId === relicId && snapshot.timestamp >= firstTimestamp, - ); - - let firstSnapshot = relicSnapshots.shift(); - - /* - if the firstSnapshot is not available (because it's older) or if it is younger than what is requested, - we try to find an older one to derive from - if we can't find and older one, then if we found a younger snapshot before it will be used, - otherwise we don't have any snapshots for this relic - */ - if (!firstSnapshot || firstSnapshot.timestamp > firstTimestamp) { - const snapshotBeforeFirstTimestamp = await prisma.prismaUserRelicSnapshot.findFirst({ - where: { relicId: relicId, timestamp: { lt: firstTimestamp }, chain: networkContext.chain }, - orderBy: { timestamp: 'desc' }, - }); - if (snapshotBeforeFirstTimestamp) { - firstSnapshot = { - ...snapshotBeforeFirstTimestamp, - timestamp: firstTimestamp, - }; - } - } - if (!firstSnapshot) { - continue; - } - // fill in the gaps to return a complete set - const completeSnapshots: PrismaUserRelicSnapshot[] = [firstSnapshot]; - // this.addToUserSnapshots(userSnapshots, firstSnapshot); - for (const snapshot of relicSnapshots) { - // if the previous snapshot is older than 1 day, manually derive a snapshot - let previousSnapshot = completeSnapshots[completeSnapshots.length - 1]; - while (previousSnapshot.timestamp + oneDayInSeconds < snapshot.timestamp) { - completeSnapshots.push({ - ...previousSnapshot, - id: `${snapshot.id}-${previousSnapshot.timestamp + oneDayInSeconds}`, - timestamp: previousSnapshot.timestamp + oneDayInSeconds, - }); - previousSnapshot = completeSnapshots[completeSnapshots.length - 1]; - } - - completeSnapshots.push(snapshot); - } - // fill gaps until today - const lastRealSnapshot = completeSnapshots[completeSnapshots.length - 1]; - let previousSnapshot = completeSnapshots[completeSnapshots.length - 1]; - while (previousSnapshot.timestamp < moment().startOf('day').unix()) { - completeSnapshots.push({ - ...lastRealSnapshot, - id: `${lastRealSnapshot.id}-${previousSnapshot.timestamp + oneDayInSeconds}`, - timestamp: previousSnapshot.timestamp + oneDayInSeconds, - }); - previousSnapshot = completeSnapshots[completeSnapshots.length - 1]; - } - this.addToUserSnapshots(userSnapshots, completeSnapshots); - } - - return userSnapshots; - } - - private addToUserSnapshots(userSnapshots: UserRelicSnapshot[], relicSnapshots: PrismaUserRelicSnapshot[]) { - for (const relicSnapshot of relicSnapshots) { - let userSnapshotForTimestampIndex = userSnapshots.findIndex( - (userSnapshot) => userSnapshot.timestamp === relicSnapshot.timestamp, - ); - if (userSnapshotForTimestampIndex === -1) { - userSnapshots.push({ - timestamp: relicSnapshot.timestamp, - totalBalance: `0`, - relicCount: 0, - relicSnapshots: [], - }); - userSnapshotForTimestampIndex = userSnapshots.length - 1; - } - userSnapshots[userSnapshotForTimestampIndex].relicSnapshots.push({ - relicId: relicSnapshot.relicId, - farmId: relicSnapshot.farmId, - balance: relicSnapshot.balance, - entryTimestamp: relicSnapshot.entryTimestamp, - level: relicSnapshot.level, - }); - - userSnapshots[userSnapshotForTimestampIndex].relicCount++; - userSnapshots[userSnapshotForTimestampIndex].totalBalance = `${ - parseFloat(userSnapshots[userSnapshotForTimestampIndex].totalBalance) + - parseFloat(relicSnapshot.balance) - }`; - } - } - - public async syncLatestUserRelicSnapshots(numDays = 1) { - const yesterdayMorning = moment().utc().subtract(numDays, 'days').startOf('day').unix(); - const relicSnapshots = await this.reliquarySubgraphService.getAllRelicSnapshotsSince(yesterdayMorning); - const filteredSnapshots = relicSnapshots.filter( - (snapshot) => !networkContext.data.reliquary!.excludedFarmIds.includes(snapshot.poolId.toString()), - ); - await this.upsertRelicSnapshots(filteredSnapshots); - } - - public async loadAllUserRelicSnapshots() { - const relicSnapshots = await this.reliquarySubgraphService.getAllRelicSnapshotsSince(); - const filteredSnapshots = relicSnapshots.filter( - (snapshot) => !networkContext.data.reliquary!.excludedFarmIds.includes(snapshot.poolId.toString()), - ); - await this.upsertRelicSnapshots(filteredSnapshots); - } - - private async upsertRelicSnapshots(relicSnapshots: ReliquaryRelicSnapshotFragment[]) { - let operations: any[] = []; - for (const snapshot of relicSnapshots) { - const data: PrismaUserRelicSnapshot = { - farmId: `${snapshot.poolId}`, - chain: networkContext.chain, - timestamp: snapshot.snapshotTimestamp, - userAddress: snapshot.userAddress.toLowerCase(), - balance: snapshot.balance, - entryTimestamp: snapshot.entryTimestamp, - id: snapshot.id, - level: snapshot.level, - relicId: snapshot.relicId, - }; - operations.push( - prisma.prismaUserRelicSnapshot.upsert({ - where: { id_chain: { id: snapshot.id, chain: networkContext.chain } }, - create: data, - update: data, - }), - ); - } - await prismaBulkExecuteOperations(operations); - } - - public async syncUserPoolBalanceSnapshots() { - // sync all snapshots that we have stored - - let operations: any[] = []; - - // get all unique users which have a snapshot stored - const users = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - distinct: ['userAddress'], - select: { - userAddress: true, - }, - where: { chain: networkContext.chain }, - }); - - for (const user of users) { - const userAddress = user.userAddress; - const userSnapshotsFromSubgraph = - await this.userSnapshotSubgraphService.getUserBalanceSnapshotsForUserAndRange( - 0, - moment().unix(), - userAddress, - ); - // no snapshots for the user in the requested timerange - if (!userSnapshotsFromSubgraph) { - continue; - } - - // get the latest snapshot for each unique user/pool pair - const latestStoredPoolSnapshotsOfUser = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { userAddress: userAddress, chain: networkContext.chain }, - orderBy: { timestamp: 'desc' }, - distinct: ['userAddress', 'poolId'], - }); - - /* - For each latest stored user pool snapshot, we need to sync from subgraph. We only store user snapshots for pools with an existing snapshot if they meet one of the following criteria: - - total balance of subgraph snapshot is not 0 - - total balance of subgraph snapshot is 0, but the total balance of the previous stored user pool snapshot was > 0, meaning the user has left the pool. - - A snapshot reflects always the state by the end of the day (UTC). Snapshots for the current day are gradually updated to reflect the current state. - Therefore we have to handle those snapshots different than the ones for already closed days. - - */ - for (const latestStoredUserPoolSnapshot of latestStoredPoolSnapshotsOfUser) { - let previousStoredUserPoolSnapshotHasBalance = - parseFloat(latestStoredUserPoolSnapshot.totalBalance) > 0; - for (const userSubgraphSnapshot of userSnapshotsFromSubgraph.snapshots) { - if (!userSubgraphSnapshot || !latestStoredUserPoolSnapshot.poolId) { - continue; - } - if (userSubgraphSnapshot.timestamp >= latestStoredUserPoolSnapshot.timestamp) { - // subgraph snapshot is newer or from today. If it is > 0 balance, we need to enrich and persist. - const pool = await prisma.prismaPool.findUniqueOrThrow({ - where: { - id_chain: { - id: latestStoredUserPoolSnapshot.poolId, - chain: latestStoredUserPoolSnapshot.chain, - }, - }, - include: { - staking: true, - }, - }); - - // extract data from snapshot for the requested pool - const { totalBalance, walletBalance, gaugeBalance, farmBalance } = - this.extractBalancesFromSnapshot(userSubgraphSnapshot, pool); - - if (totalBalance > 0) { - //enrich with poolsnapshot data and save - const poolSnapshot = await this.poolSnapshotService.getSnapshotForPool( - pool.id, - userSubgraphSnapshot.timestamp, - pool.chain, - ); - - /* - Could be that the poolsnapshot is delayed (beethoven subgraph is much slower than bpt subgraph), - so we will persist 0 $ value if there is a totalBalance > 0 and try to get the when we serve the data - */ - const userPoolBalanceSnapshotData = this.createUserPoolSnapshotData( - poolSnapshot, - pool, - networkContext.chain, - userSubgraphSnapshot, - totalBalance, - walletBalance, - gaugeBalance, - farmBalance, - ); - - operations.push( - prisma.prismaUserPoolBalanceSnapshot.upsert({ - where: { - id_chain: { - id: userPoolBalanceSnapshotData.id, - chain: userPoolBalanceSnapshotData.chain, - }, - }, - create: userPoolBalanceSnapshotData, - update: userPoolBalanceSnapshotData, - }), - ); - previousStoredUserPoolSnapshotHasBalance = true; - } else if (previousStoredUserPoolSnapshotHasBalance) { - // if the snapshot has total balance of 0, we store it if the previously stored snapshot had a balance. This is to indicate that the user has left the pool. - const userPoolBalanceSnapshotData = { - id: `${pool.id}-${userSubgraphSnapshot.user.id.toLowerCase()}-${ - userSubgraphSnapshot.timestamp - }`, - chain: pool.chain, - timestamp: userSubgraphSnapshot.timestamp, - userAddress: userSubgraphSnapshot.user.id.toLowerCase(), - poolId: pool.id, - poolToken: pool.address, - walletBalance, - gaugeBalance, - farmBalance, - percentShare: `0`, - totalBalance: '0', - totalValueUSD: `0`, - fees24h: `0`, - }; - - operations.push( - prisma.prismaUserPoolBalanceSnapshot.upsert({ - where: { - id_chain: { - id: userPoolBalanceSnapshotData.id, - chain: userPoolBalanceSnapshotData.chain, - }, - }, - create: userPoolBalanceSnapshotData, - update: userPoolBalanceSnapshotData, - }), - ); - previousStoredUserPoolSnapshotHasBalance = false; - } - } - } - } - } - - await prismaBulkExecuteOperations(operations, false); - } - - public async getUserPoolBalanceSnapshotsForPool( - userAddress: string, - poolId: string, - chain: Chain, - range: GqlUserSnapshotDataRange, - ): Promise { - const oldestRequestedSnapshotTimestamp = this.getTimestampForRange(range); - - userAddress = userAddress.toLowerCase(); - poolId = poolId.toLowerCase(); - - const storedUserSnapshotsForPool = await this.getStoredSnapshotsForUserForPoolFromTimestamp( - userAddress, - 0, - poolId, - chain, - ); - - let storedUserSnapshotsInRangeForPool = storedUserSnapshotsForPool.filter( - (snapshot) => snapshot.timestamp >= oldestRequestedSnapshotTimestamp, - ); - - let poolSnapshots: PrismaPoolSnapshot[] = []; - - // no stored snapshots, retrieve from subgraph and store all - if (storedUserSnapshotsForPool.length === 0) { - const userSnapshotsFromSubgraph = - await this.userSnapshotSubgraphService.getUserBalanceSnapshotsForUserAndRange( - 0, - moment().unix(), - userAddress, - ); - - const pool = await prisma.prismaPool.findUniqueOrThrow({ - where: { - id_chain: { id: poolId, chain: chain }, - }, - include: { - staking: true, - }, - }); - - // Check if any of the retrieved subgraph snapshots contain the requested pool, no need to go further if there are no snapshots - if ( - !userSnapshotsFromSubgraph.snapshots.find((snapshot) => { - if (snapshot.walletTokens.includes(pool.address)) { - return snapshot; - } - - if (pool.staking.length > 0) { - if ( - pool.staking.some((stake) => snapshot.farms.includes(stake.id)) || - pool.staking.some((stake) => snapshot.gauges.includes(stake.id)) - ) - return snapshot; - } - }) - ) { - return []; - } - - // make sure users exists - await prisma.prismaUser.upsert({ - where: { address: userAddress }, - update: {}, - create: { address: userAddress }, - }); - - const prismaInput: Prisma.PrismaUserPoolBalanceSnapshotCreateManyInput[] = []; - - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); - - /* - For each snapshot from the subgraph, this will get the poolSnapshot for the same timestamp and enrich with $ value data - If there is no poolSnapshot for that timestamp, we persist a 0 $ totalUSD snapshot because it could become available at a later time - If there are consecutive 0 total balance snapshots, only the first one is persisted. This is to avoid unnecessary 0 value - snapshots in the database. These 0 balance gaps must be filled when serving the request. - */ - for (const userSubgraphSnapshot of userSnapshotsFromSubgraph.snapshots) { - const poolSnapshotForTimestamp = poolSnapshots.find( - (poolSnapshot) => userSubgraphSnapshot.timestamp === poolSnapshot.timestamp, - ); - - // extract data from snapshot for the requested pool - const { totalBalance, walletBalance, gaugeBalance, farmBalance } = this.extractBalancesFromSnapshot( - userSubgraphSnapshot, - pool, - ); - - /* - We get ALL snapshots from the subgraph for the user. Total balance will be 0 until he joined the pool we need. - Therefore we want to skip all 0 total balance snapshot at the beginning. - */ - if (prismaInput.length === 0 && totalBalance === 0) { - continue; - } - - /* - If a user left a pool, the snapshot from the subgraph won't list the pool balance with '0'. - In fact, the pool address (or farm or gage id) won't show up in the array. We therefore need to store the FIRST - 0 total balance snapshot to show that he left the pool, but want to skip any consecutive 0 total value - snapshots to avoid unnecessary 0 total balance snapshots in the database. - */ - if (totalBalance === 0 && prismaInput[prismaInput.length - 1].totalBalance === '0') { - continue; - } - - const userPoolBalanceSnapshotData = this.createUserPoolSnapshotData( - poolSnapshotForTimestamp, - pool, - chain, - userSubgraphSnapshot, - totalBalance, - walletBalance, - gaugeBalance, - farmBalance, - ); - - prismaInput.push(userPoolBalanceSnapshotData); - } - await prisma.prismaUserPoolBalanceSnapshot.createMany({ - data: prismaInput, - }); - - storedUserSnapshotsInRangeForPool = await this.getStoredSnapshotsForUserForPoolFromTimestamp( - userAddress, - oldestRequestedSnapshotTimestamp, - poolId, - chain, - ); - } - - // Only get them if we didn't get them above - if (poolSnapshots.length === 0) { - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); - } - - /* - - - If a user joined a pool and did not interact with the pool (or any other pool) for a few days, those snapshots - will be missing from the subgraph and also in the database. When the user requests his snapshots for a given pool - we need to find and fill the gaps between the first and the last snapshot we have in the database. - - 1st) If there is no snapshot for the oldestRequestedTimestamp but there is an older one, we need to infer from the older one to the oldestRequestedTimestamp - 2nd) We need to find and fill the gaps between the oldestRequestedTimestamp and the latest stored snapshot we have in the database. - 3rd) If the latest stored snapshot is not a 0 total balance snapshot (which would mean the user left the pool) we will also - need to fill the gaps from the latest stored snapshot until today. - */ - - // The first snapshot in the database must be >0 total value, push that - const userPoolSnapshots: UserPoolSnapshot[] = []; - - // 1st) if we either have no stored snapshots for the range or only newer ones, we need to check if we have an older and infer - if ( - storedUserSnapshotsInRangeForPool.length === 0 || - storedUserSnapshotsInRangeForPool[0].timestamp > oldestRequestedSnapshotTimestamp - ) { - const olderSnapshot = await prisma.prismaUserPoolBalanceSnapshot.findFirst({ - where: { - userAddress: userAddress, - timestamp: { - lt: oldestRequestedSnapshotTimestamp, - }, - poolId: poolId, - chain: chain, - }, - orderBy: { timestamp: 'desc' }, - }); - if (olderSnapshot) { - const poolSnapshot = poolSnapshots.find( - (snapshot) => snapshot.timestamp === oldestRequestedSnapshotTimestamp, - ); - const percentShare = poolSnapshot - ? parseFloat(olderSnapshot.totalBalance) / poolSnapshot.totalSharesNum - : 0; - userPoolSnapshots.push({ - timestamp: oldestRequestedSnapshotTimestamp, - walletBalance: olderSnapshot.walletBalance, - farmBalance: olderSnapshot.farmBalance, - gaugeBalance: olderSnapshot.gaugeBalance, - totalBalance: olderSnapshot.totalBalance, - percentShare: percentShare, - totalValueUSD: `${parseFloat(olderSnapshot.totalBalance) * (poolSnapshot?.sharePrice || 0)}`, - fees24h: `${ - percentShare * - (poolSnapshot?.fees24h || 0) * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - }); - } - } - - // We need the fist snapshot already in the userPoolSnapshots array because we are accessing previous indexes below. - // We only need to do this here if we didn't already push one snapshot above. - if (userPoolSnapshots.length === 0) { - const firstSnapshot = storedUserSnapshotsInRangeForPool.shift(); - if (firstSnapshot) { - // check - userPoolSnapshots.push({ - timestamp: firstSnapshot.timestamp, - walletBalance: firstSnapshot.walletBalance, - farmBalance: firstSnapshot.farmBalance, - gaugeBalance: firstSnapshot.gaugeBalance, - totalBalance: firstSnapshot.totalBalance, - totalValueUSD: firstSnapshot.totalValueUSD, - fees24h: firstSnapshot.fees24h, - percentShare: parseFloat(firstSnapshot.percentShare), - }); - } - } - for (const currentSnapshot of storedUserSnapshotsInRangeForPool) { - /* 2nd) - as long as the currentSnapshot is newer than (timestamp + 1 day) of the last snapshot in userPoolSnapshots, it means there is a gap that we need to fill. - E.g. we have snapshots for day 1 and 4 -> currentSnapshot.timestamp=4 (day 1 already stored above), which is newer than 1+1, so we fill the gap for day 2. - currentSnapshot.timestamp=4 is newer than 2+1, need to fill gap for day 3. - currentSnapshot.timestamp=4 is not newer than 3+1, no gap, persist currentSnapshot - etc. - */ - while ( - currentSnapshot.timestamp > - userPoolSnapshots[userPoolSnapshots.length - 1].timestamp + secondsPerDay - ) { - //need to fill the gap from last snapshot - const previousUserSnapshot = userPoolSnapshots[userPoolSnapshots.length - 1]; - const currentTimestamp = previousUserSnapshot.timestamp + secondsPerDay; - const poolSnapshot = poolSnapshots.find((snapshot) => snapshot.timestamp === currentTimestamp); - const percentShare = poolSnapshot - ? parseFloat(previousUserSnapshot.totalBalance) / poolSnapshot.totalSharesNum - : 0; - userPoolSnapshots.push({ - timestamp: currentTimestamp, - walletBalance: previousUserSnapshot.walletBalance, - farmBalance: previousUserSnapshot.farmBalance, - gaugeBalance: previousUserSnapshot.gaugeBalance, - totalBalance: previousUserSnapshot.totalBalance, - percentShare: percentShare, - totalValueUSD: `${parseFloat(previousUserSnapshot.totalBalance) * (poolSnapshot?.sharePrice || 0)}`, - fees24h: `${ - percentShare * - (poolSnapshot?.fees24h || 0) * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - }); - } - - if (parseFloat(currentSnapshot.totalBalance) > 0 && parseFloat(currentSnapshot.totalValueUSD) === 0) { - // We didn't have a poolsnapshot at the time of persistance, let's see if we have one now and persist - const poolSnapshot = poolSnapshots.find( - (poolSnapshot) => poolSnapshot.timestamp === currentSnapshot.timestamp, - ); - if (poolSnapshot) { - const percentShare = parseFloat(currentSnapshot.totalBalance) / poolSnapshot.totalSharesNum; - currentSnapshot.percentShare = percentShare.toString(); - currentSnapshot.totalValueUSD = `${ - parseFloat(currentSnapshot.totalBalance) * (poolSnapshot.sharePrice || 0) - }`; - currentSnapshot.fees24h = `${ - percentShare * - (poolSnapshot.fees24h || 0) * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`; - await prisma.prismaUserPoolBalanceSnapshot.update({ - where: { id_chain: { id: currentSnapshot.id, chain: chain } }, - data: currentSnapshot, - }); - } - } - userPoolSnapshots.push({ - timestamp: currentSnapshot.timestamp, - walletBalance: currentSnapshot.walletBalance, - farmBalance: currentSnapshot.farmBalance, - gaugeBalance: currentSnapshot.gaugeBalance, - totalBalance: currentSnapshot.totalBalance, - totalValueUSD: currentSnapshot.totalValueUSD, - fees24h: currentSnapshot.fees24h, - percentShare: parseFloat(currentSnapshot.percentShare), - }); - } - - // 3rd) we have to check if there are missing snapshots from the last snapshot until today and fill in those gaps (if the latest balance is > 0) - if (parseFloat(userPoolSnapshots[userPoolSnapshots.length - 1].totalBalance) > 0) { - while (userPoolSnapshots[userPoolSnapshots.length - 1].timestamp < moment().startOf('day').unix()) { - const previousUserSnapshot = userPoolSnapshots[userPoolSnapshots.length - 1]; - const currentTimestamp = previousUserSnapshot.timestamp + secondsPerDay; - const poolSnapshot = poolSnapshots.find((snapshot) => snapshot.timestamp === currentTimestamp); - const percentShare = poolSnapshot - ? parseFloat(previousUserSnapshot.totalBalance) / poolSnapshot.totalSharesNum - : 0; - userPoolSnapshots.push({ - timestamp: currentTimestamp, - walletBalance: previousUserSnapshot.walletBalance, - farmBalance: previousUserSnapshot.farmBalance, - gaugeBalance: previousUserSnapshot.gaugeBalance, - totalBalance: previousUserSnapshot.totalBalance, - percentShare: percentShare, - totalValueUSD: `${parseFloat(previousUserSnapshot.totalBalance) * (poolSnapshot?.sharePrice || 0)}`, - fees24h: `${ - percentShare * - (poolSnapshot?.fees24h || 0) * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - }); - } - } - return userPoolSnapshots; - } - - private createUserPoolSnapshotData( - poolSnapshot: PrismaPoolSnapshot | undefined | null, - pool: PrismaPool & { staking: PrismaPoolStaking[] }, - chain: Chain, - subgraphSnapshot: UserBalanceSnapshotFragment, - totalBalance: number, - walletBalance: string, - gaugeBalance: string, - farmBalance: string, - ) { - const percentShare = poolSnapshot ? totalBalance / poolSnapshot?.totalSharesNum : 0; - - const userPoolBalanceSnapshotData = { - id: `${pool.id}-${subgraphSnapshot.user.id.toLowerCase()}-${subgraphSnapshot.timestamp}`, - chain: chain, - timestamp: subgraphSnapshot.timestamp, - userAddress: subgraphSnapshot.user.id.toLowerCase(), - poolId: pool.id, - poolToken: pool.address, - walletBalance, - gaugeBalance, - farmBalance, - percentShare: `${percentShare}`, - totalBalance: `${totalBalance}`, - totalValueUSD: `${totalBalance * (poolSnapshot?.sharePrice || 0)}`, - fees24h: `${ - percentShare * - (poolSnapshot?.fees24h || 0) * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - }; - return userPoolBalanceSnapshotData; - } - - /* - The snapshot consists of 6 arrays which follow the same structure. For each type (wallet, farm, gauge) it has a "index" array and a "balance" array: - - walletTokens -> walletBalances - - Gauges -> GaugeBalances - - Farms -> FarmBalances - - The index array indicates the position of the walletToken, gauge or farm in the balance array. e.g.: - - walletTokens: ["token1", "token2"] - - walletBalances: ["200", "100"] - This means the user has 200 of token1 and 100 of token2 in his wallet. - */ - private extractBalancesFromSnapshot( - userSnapshot: UserBalanceSnapshotFragment, - pool: PrismaPool & { staking: PrismaPoolStaking[] }, - ) { - const walletIdx = userSnapshot.walletTokens.indexOf(pool.address); - let walletBalance = walletIdx !== -1 ? userSnapshot.walletBalances[walletIdx] : '0'; - let gaugeBalance = '0'; - let farmBalance = '0'; - for (const stake of pool.staking) { - const gaugeIdx = userSnapshot.gauges.indexOf(stake.id || ''); - gaugeBalance = - gaugeIdx !== -1 - ? `${parseFloat(userSnapshot.gaugeBalances[gaugeIdx]) + parseFloat(gaugeBalance)}` - : gaugeBalance; - const farmIdx = userSnapshot.farms.indexOf(stake.id || ''); - farmBalance = - farmIdx !== -1 ? `${parseFloat(userSnapshot.farmBalances[farmIdx]) + parseFloat(farmBalance)}` : '0'; - } - - // if the pool is fbeets (fidelio duetto), we need to also add fbeets wallet balance (multiplied by bpt ratio) to the bpt wallet balance - // we also need to multiply the staked amount by the fbeets->bpt ratio - if (pool.id === networkContext.data.fbeets?.poolId) { - const fBeetsWalletIdx = userSnapshot.walletTokens.indexOf(networkContext.data.fbeets?.address || ''); - const fBeetsWalletBalance = fBeetsWalletIdx !== -1 ? userSnapshot.walletBalances[fBeetsWalletIdx] : '0'; - walletBalance = ( - parseFloat(walletBalance) + - parseFloat(fBeetsWalletBalance) * this.FBEETS_BPT_RATIO - ).toString(); - - farmBalance = (parseFloat(farmBalance) * this.FBEETS_BPT_RATIO).toString(); - } - - const totalBalance = parseFloat(walletBalance) + parseFloat(gaugeBalance) + parseFloat(farmBalance); - return { totalBalance, walletBalance, gaugeBalance, farmBalance }; - } - - private async getStoredSnapshotsForUserForPoolFromTimestamp( - userAddress: string, - oldestRequestedSnapshotTimestamp: number, - poolId: string, - chain: Chain, - ) { - return await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - timestamp: { - gte: oldestRequestedSnapshotTimestamp, - }, - poolId: poolId, - chain: chain, - }, - orderBy: { timestamp: 'asc' }, - }); - } - - private getTimestampForRange(range: GqlUserSnapshotDataRange): number { - switch (range) { - case 'THIRTY_DAYS': - return moment().startOf('day').subtract(30, 'days').unix(); - case 'NINETY_DAYS': - return moment().startOf('day').subtract(90, 'days').unix(); - case 'ONE_HUNDRED_EIGHTY_DAYS': - return moment().startOf('day').subtract(180, 'days').unix(); - case 'ONE_YEAR': - return moment().startOf('day').subtract(365, 'days').unix(); - case 'ALL_TIME': - return 0; - } - } -} diff --git a/modules/user/user-snapshot.service.test.ts b/modules/user/user-snapshot.service.test.ts deleted file mode 100644 index f97fc4d57..000000000 --- a/modules/user/user-snapshot.service.test.ts +++ /dev/null @@ -1,1564 +0,0 @@ -import moment from 'moment'; -import { graphql } from 'msw'; -import { prisma } from '../../prisma/prisma-client'; -import { - createRandomSnapshotsForPool, - createRandomSnapshotsForPoolForTimestamp, - createUserPoolBalanceSnapshot, - createWeightedPoolFromDefault, - defaultTokens, -} from '../tests-helper/poolTestdataHelpers'; -import { createIndividualDatabaseSchemaForTest as createDedicatedSchemaForTest } from '../tests-helper/setupTestDatabase'; -import { mockServer } from '../tests-helper/mocks/mockHttpServer'; -import { userService } from './user.service'; -import { secondsPerDay } from '../common/time'; -import { networkContext } from '../network/network-context.service'; -import { Chain } from '@prisma/client'; - -/* -TEST SETUP: -- Two different weighted pools, one with 30 random snapshots (complete, one spanshot per day) one with only 2 snapshots -- pool1 has also a farm specified -- One user -- fidelio pool - -*/ -const poolId1 = '0x001a'; -const poolName1 = 'Test pool 1'; -const poolAddress1 = '0x001'; -const farmId1 = '0x001a-stake'; - -const pool2Id = '0x002a'; -const poolName2 = 'Test pool 2'; -const poolAddress2 = '0x002'; - -const userAddress = '0x0000000000000000000000000000000000000001'; - -const FBEETS_BPT_RATIO: number = 1.0271; - -const today = moment().startOf('day').unix(); -const sevenDaysAgo = today - 7 * secondsPerDay; -const sixDaysAgo = today - 6 * secondsPerDay; -const fiveDaysAgo = today - 5 * secondsPerDay; -const fourDaysAgo = today - 4 * secondsPerDay; -const threeDaysAgo = today - 3 * secondsPerDay; -const twoDaysAgo = today - 2 * secondsPerDay; -const oneDayAgo = today - 1 * secondsPerDay; - -beforeAll(async () => { - await createDedicatedSchemaForTest(); - const pool1 = await createWeightedPoolFromDefault( - { - id: poolId1, - name: poolName1, - address: poolAddress1, - staking: { - create: { - id: farmId1, - }, - }, - }, - [defaultTokens.usdc, defaultTokens.wftm, defaultTokens.wbtc, defaultTokens.beets], - ); - - // create 30 snapshotsfor pool1 - await createRandomSnapshotsForPool(pool1.id, pool1.tokens.length, 30); - - const fidelio = await createWeightedPoolFromDefault( - { - id: networkContext.data.fbeets!.poolId, - name: 'Fidelio Duetto', - address: networkContext.data.fbeets!.poolAddress, - staking: { - create: { - id: networkContext.data.fbeets!.farmId, - }, - }, - }, - [defaultTokens.wftm, defaultTokens.beets], - ); - - // create 30 snapshotsfor pool1 - await createRandomSnapshotsForPool(fidelio.id, fidelio.tokens.length, 365); - - // create user - await prisma.prismaUser.create({ - data: { - address: userAddress, - }, - }); -}, 60000); - -afterEach(async () => { - mockServer.resetHandlers(); - await prisma.prismaUserPoolBalanceSnapshot.deleteMany({}); -}); - -// Clean up after the tests are finished. -afterAll(async () => { - await prisma.$disconnect(); -}); - -test('The user requests the user stats for the first time, requesting from subgraph, persiting to db.', async () => { - /* - Scenario: - - The user requests the user stats for the first time - - The user joined pool1 three days ago, joined again one day ago, added some to farm and joined another pool one day ago - - Behaviour under test: - - Snapshot inference that a fourth snapshot is created for missing day two days ago - - Snapshots are retrieved from subgraph and persisted in DB - - Only snapshots for requested pool and without inferred snapshot are persisted in DB (three snapshots) - - Balances are correctly returned and summarized (farmbalance + walletbalance = totalbalance) - - USD values are correctly calculated based on pool snapshot values - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create three snapshots for user - - First snapshot from three days ago, where he only has 1 bpts from pool1 in his wallet - - Seconds snapshot from one day ago, where he has 0.5 bpt from pool1 and 1 bpt from pool2 in his wallet and 1 bpt from pool1 in the farm - - Third snapshot from today, where he has only 1 bpt from pool2 in his wallet - - */ - - const timestampOfLastReturnedSnapshot = today; - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > timestampOfLastReturnedSnapshot) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [poolAddress1], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${oneDayAgo}`, - user: { - id: userAddress, - }, - timestamp: oneDayAgo, - walletTokens: [poolAddress1, poolAddress2], - walletBalances: ['0.5', '1'], - gauges: [], - gaugeBalances: [], - farms: [farmId1], - farmBalances: ['1'], - }, - { - id: `${userAddress}-${today}`, - user: { - id: userAddress, - }, - timestamp: today, - walletTokens: [poolAddress2], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - ], - }), - ); - }), - ], - ); - - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - //check if 4th snapshot has been inferred from three present ones - expect(snapshotsFromService.length).toBe(4); - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - include: { pool: true }, - }); - - // check if the 3 snapshots have been persisted - expect(snapshotsFromDb.length).toBe(3); - - // check if balances are calculated correctly - expect(snapshotsFromService[0].walletBalance).toBe('1'); - expect(snapshotsFromService[0].timestamp).toBe(today - 3 * secondsPerDay); - expect(snapshotsFromService[1].walletBalance).toBe('1'); - expect(snapshotsFromService[1].timestamp).toBe(today - 2 * secondsPerDay); - - expect(snapshotsFromService[2].walletBalance).toBe('0.5'); - expect(snapshotsFromService[2].farmBalance).toBe('1'); - expect(snapshotsFromService[2].totalBalance).toBe('1.5'); - expect(snapshotsFromService[2].timestamp).toBe(today - 1 * secondsPerDay); - - expect(snapshotsFromService[3].walletBalance).toBe('0'); - expect(snapshotsFromService[3].timestamp).toBe(today - 0 * secondsPerDay); - - const poolSnapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: poolId1 }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of snapshotsFromService) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshots) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.percentShare).toBe( - parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - userBalanceSnapshot.percentShare * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } -}); - -test('User in in the pool for a very long time, requests various different time ranges.', async () => { - /* - Scenario: - - The user joined pool1 one year ago and is in there ever since, never changed position. - - Requests different time ranges - - Behaviour under test: - - If the various time ranges return correct number of snapshots - - Only one snapshot a year ago, all other snapshots should be inferred up to today - - Only one year old snapshot, make sure that also snapshots are returned for shorter timeframes - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create 1 snapshot one year ago for the user in the subgraph - - Also create 365 Snapshots for the pool. - - */ - - const oneYearAgo = today - 365 * secondsPerDay; - const timestampOfLastReturnedSnapshot = oneYearAgo; - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > timestampOfLastReturnedSnapshot) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${oneYearAgo}`, - user: { - id: userAddress, - }, - timestamp: oneYearAgo, - walletTokens: [poolAddress1], - walletBalances: ['10'], - gauges: [], - gaugeBalances: [], - farms: [farmId1], - farmBalances: ['5'], - }, - ], - }), - ); - }), - ], - ); - - const thirtySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - - //also includes the one from today - expect(thirtySnapshotsFromService.length).toBe(31); - const thirtySnapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - include: { pool: true }, - }); - - // check if the 3 snapshots have been persisted - expect(thirtySnapshotsFromDb.length).toBe(1); - - const ninetySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'NINETY_DAYS', - ); - //also includes the one from today - expect(ninetySnapshotsFromService.length).toBe(91); - const ninetySnapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - include: { pool: true }, - }); - - // check if the 3 snapshots have been persisted - expect(ninetySnapshotsFromDb.length).toBe(1); -}); - -test('user leaves pool and joins pool again', async () => { - /* -Scenario: -- The user requests the user stats for the first time -- The user joined pool1 three days ago, left the pool two days ago and joined again one day ago - -Behaviour under test: -- Snapshot inference that he has the same amount today as yesterday -- 0 balance snapshots are correctly returned - -Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): -- Create three snapshots for user -- First snapshot from three days ago, where he only has 1 bpts from pool1 in his wallet -- Seconds snapshot from two days ago, where he has no balance -- Third snapshot from yesterday, where he has 1 bpt from pool1 in his wallet - -*/ - - const timestampOfLastReturnedSnapshot = oneDayAgo; - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > timestampOfLastReturnedSnapshot) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [poolAddress1], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${twoDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: twoDaysAgo, - walletTokens: [], - walletBalances: [], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${oneDayAgo}`, - user: { - id: userAddress, - }, - timestamp: oneDayAgo, - walletTokens: [poolAddress1], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - ], - }), - ); - }), - ], - ); - - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - //check if 4th snapshot has been inferred from three present ones - expect(snapshotsFromService.length).toBe(4); - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - include: { pool: true }, - }); - - // check if the 3 snapshots have been persisted - expect(snapshotsFromDb.length).toBe(3); - - // check if balances are calculated correctly - expect(snapshotsFromService[0].timestamp).toBe(threeDaysAgo); - expect(snapshotsFromService[0].walletBalance).toBe('1'); - expect(snapshotsFromService[1].timestamp).toBe(twoDaysAgo); - expect(snapshotsFromService[1].walletBalance).toBe('0'); - expect(snapshotsFromService[1].totalValueUSD).toBe('0'); - expect(snapshotsFromService[1].fees24h).toBe('0'); - expect(snapshotsFromService[1].percentShare).toBe(0); - - expect(snapshotsFromService[2].timestamp).toBe(oneDayAgo); - expect(snapshotsFromService[2].walletBalance).toBe('1'); - - expect(snapshotsFromService[3].timestamp).toBe(today); - expect(snapshotsFromService[3].walletBalance).toBe('1'); - - const poolSnapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: poolId1 }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of snapshotsFromService) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshots) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.percentShare).toBe( - parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - userBalanceSnapshot.percentShare * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } -}); - -test('When user left pool, no more snapshots are returned', async () => { - /* -Scenario: -- The user requests the user stats for the first time -- The user joined pool1 three days ago, left the pool two days ago - -Behaviour under test: -- That once he leaves, those 0 balance snapshots are neither persisted nor returned - -Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): -- Create two snapshots for user -- First snapshot from three days ago, where he only has 1 bpts from pool1 in his wallet -- Seconds snapshot from two days ago, where he has no balance - -*/ - const timestampOfLastReturnedSnapshot = secondsPerDay; - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > timestampOfLastReturnedSnapshot) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [poolAddress1], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${twoDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: twoDaysAgo, - walletTokens: [], - walletBalances: [], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - ], - }), - ); - }), - ], - ); - - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - //check if 4th snapshot has been inferred from three present ones - expect(snapshotsFromService.length).toBe(2); - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - include: { pool: true }, - }); - - // check if the 3 snapshots have been persisted - expect(snapshotsFromDb.length).toBe(2); - - // check if balances are calculated correctly - expect(snapshotsFromService[0].timestamp).toBe(threeDaysAgo); - expect(snapshotsFromService[0].walletBalance).toBe('1'); - expect(snapshotsFromService[1].timestamp).toBe(twoDaysAgo); - expect(snapshotsFromService[1].walletBalance).toBe('0'); - expect(snapshotsFromService[1].totalValueUSD).toBe('0'); - expect(snapshotsFromService[1].fees24h).toBe('0'); - expect(snapshotsFromService[1].percentShare).toBe(0); -}); - -test('Return a snapshot with 0 valueUSD if there is no pool snapshot for the given day. When pool snapshot becomes present, return and persist correct valueUSD for the given day.', async () => { - /* - Scenario: - - The user requests the user stats for the first time - - The user joined pool2 three days ago and is still in the pool - - Poolsnapshots are only available for two days, therefore only two valueUSD > 0 snapshots are present - - Adding another "delayed" poolSnapshot after the frist query for today, which changes the valueUSD of the user snapshot for today - - Behaviour under test: - - Pool2 has only two snapshots for three days ago and two days ago. - - We should have 4 usersnapshots but only the ones from three and two days ago should have USD values. - - We then create another pool snapshot for today - - We should now have 3 usersnapshots with $ values - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create one snapshots for user - - First snapshot from three days ago, where he has 1 bpts from pool1 in his wallet - - create two pool snapshots for pool2 for three days ago and two days ago - */ - - const timestampOfLastReturnedSnapshot = threeDaysAgo; - - // setup mock data in DB - const pool2 = await createWeightedPoolFromDefault( - { - id: pool2Id, - name: poolName2, - address: poolAddress2, - }, - [defaultTokens.usdc, defaultTokens.beets], - ); - await createRandomSnapshotsForPoolForTimestamp(pool2.id, pool2.tokens.length, threeDaysAgo); - await createRandomSnapshotsForPoolForTimestamp(pool2.id, pool2.tokens.length, twoDaysAgo); - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > timestampOfLastReturnedSnapshot) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [pool2.address], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - ], - }), - ); - }), - ], - ); - - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - pool2Id, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - // should get all 4 snapshots - expect(snapshotsFromService.length).toBe(4); - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - include: { pool: true }, - }); - - // check if the 1 snapshots have been persisted (others are inferred on query) - expect(snapshotsFromDb.length).toBe(1); - - // check if balances are calculated correctly - expect(snapshotsFromService[0].timestamp).toBe(threeDaysAgo); - expect(snapshotsFromService[0].walletBalance).toBe('1'); - expect(parseFloat(snapshotsFromService[0].totalValueUSD)).toBeGreaterThan(0); - expect(snapshotsFromService[1].timestamp).toBe(twoDaysAgo); - expect(snapshotsFromService[1].walletBalance).toBe('1'); - expect(parseFloat(snapshotsFromService[1].totalValueUSD)).toBeGreaterThan(0); - - expect(snapshotsFromService[2].timestamp).toBe(oneDayAgo); - expect(snapshotsFromService[2].walletBalance).toBe('1'); - expect(parseFloat(snapshotsFromService[2].totalValueUSD)).toBe(0); - - expect(snapshotsFromService[3].timestamp).toBe(today); - expect(snapshotsFromService[3].walletBalance).toBe('1'); - expect(parseFloat(snapshotsFromService[3].totalValueUSD)).toBe(0); - - await createRandomSnapshotsForPoolForTimestamp(pool2.id, pool2.tokens.length, today); - - const snapshotsAfterAdditionalPoolSnapshot = await userService.getUserBalanceSnapshotsForPool( - userAddress, - pool2Id, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - //expect still the same results here as above - expect(snapshotsFromService[0].timestamp).toBe(threeDaysAgo); - expect(snapshotsFromService[0].walletBalance).toBe('1'); - expect(parseFloat(snapshotsFromService[0].totalValueUSD)).toBeGreaterThan(0); - expect(snapshotsFromService[1].timestamp).toBe(twoDaysAgo); - expect(snapshotsFromService[1].walletBalance).toBe('1'); - expect(parseFloat(snapshotsFromService[1].totalValueUSD)).toBeGreaterThan(0); - - expect(snapshotsFromService[2].timestamp).toBe(oneDayAgo); - expect(snapshotsFromService[2].walletBalance).toBe('1'); - expect(parseFloat(snapshotsFromService[2].totalValueUSD)).toBe(0); - - // expecting a >0 value here since now a poolsnapshot was created - expect(snapshotsAfterAdditionalPoolSnapshot[3].timestamp).toBe(today); - expect(snapshotsAfterAdditionalPoolSnapshot[3].walletBalance).toBe('1'); - expect(parseFloat(snapshotsAfterAdditionalPoolSnapshot[3].totalValueUSD)).toBeGreaterThan(0); -}); - -test('User snapshots in the database must be picked up and synced by the sync process.', async () => { - /* - Scenario: - - The user has once requested the user stats for pool1 - - We manually add a user pool snapshot to simulate that user stats on this pool have already been requested once - - Since one user snapshot is in the database, the userBalanceSync should query the subgraph and sync all missing snapshots until now - - Behaviour under test: - - The oldest user snapshot from three days ago for pool1 is already persisted in the db from a previous run (here mocked) - - Sync finds that snapshot and will sync ALL from the latest until today - - Sync will only sync snapshots of pool1, not of pool2 - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create three snapshots for user - - First snapshot from three days ago, where he only has 1 bpts from pool1 in his wallet - - Seconds snapshot from one day ago, where he has 0.5 bpt from pool1 and 1 bpt from pool2 in his wallet and 1 bpt from pool1 in the farm - - Third snapshot from today, where he has only 1 bpt from pool2 in his wallet - - Mock data in data base: - - Create one userbalance snapshot for three days ago for the user and pool1 - - */ - - const newestSnapshotTimestamp = today; - - await createUserPoolBalanceSnapshot({ - id: `${poolId1}-${userAddress}-${threeDaysAgo}`, - timestamp: threeDaysAgo, - user: { connect: { address: userAddress } }, - pool: { - connect: { - id: poolId1, - }, - }, - poolToken: poolAddress1, - walletBalance: '1', - farmBalance: '0', - gaugeBalance: '0', - totalBalance: '1', - }); - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > newestSnapshotTimestamp) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [poolAddress1], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${oneDayAgo}`, - user: { - id: userAddress, - }, - timestamp: oneDayAgo, - walletTokens: [poolAddress1, poolAddress2], - walletBalances: ['0.5', '1'], - gauges: [], - gaugeBalances: [], - farms: [farmId1], - farmBalances: ['1'], - }, - { - id: `${userAddress}-${today}`, - user: { - id: userAddress, - }, - timestamp: today, - walletTokens: [poolAddress1, poolAddress2], - walletBalances: ['0', '1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - ], - }), - ); - }), - ], - ); - - // before the sync is called, this should only return one snapshot that was manually added to the DB in this test - const snapshotsInDbBeforeSync = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - }); - expect(snapshotsInDbBeforeSync.length).toBe(1); - - // sync - await userService.syncUserBalanceSnapshots(); - - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - }); - - // check if snapshots have been persisted (only three, one is inferred at query) - expect(snapshotsFromDb.length).toBe(3); - - // after the sync, all 4 snapshots should be present - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - expect(snapshotsAfterSync.length).toBe(4); - - // check if balances are calculated correctly - expect(snapshotsAfterSync[0].walletBalance).toBe('1'); - expect(snapshotsAfterSync[0].timestamp).toBe(threeDaysAgo); - expect(snapshotsAfterSync[1].walletBalance).toBe('1'); - expect(snapshotsAfterSync[1].timestamp).toBe(twoDaysAgo); - - expect(snapshotsAfterSync[2].walletBalance).toBe('0.5'); - expect(snapshotsAfterSync[2].farmBalance).toBe('1'); - expect(snapshotsAfterSync[2].totalBalance).toBe('1.5'); - expect(snapshotsAfterSync[2].timestamp).toBe(oneDayAgo); - - expect(snapshotsAfterSync[3].walletBalance).toBe('0'); - expect(snapshotsAfterSync[3].timestamp).toBe(today); - - const poolSnapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: poolId1 }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of snapshotsAfterSync) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshots) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.percentShare).toBe( - parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - userBalanceSnapshot.percentShare * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } -}); - -test('User has left and re-entered the pool. Make sure the sync does not persist the 0 total value snapshots in the gaps.', async () => { - /* - Scenario: - - The user has once requested the user stats for pool1 - - We manually add a user pool snapshot to simulate that user stats on this pool have already been requested once - - Since one user snapshot is in the database, the userBalanceSync should query the subgraph and sync all missing snapshots until now - - user joined pool seven days ago, left again five days ago, joined pool and farm again three days ago, left both two days ago - - Behaviour under test: - - The oldest user snapshot from seven days ago for pool1 is already persisted in the db from a previous run (here mocked) - - Sync finds that snapshot and will sync ALL from the latest until today - - Sync will not persist the 0 balance gap from four days ago and one day ago and today - - Sync will not persist >0 balance gap from six days ago - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create five snapshots for user representing the above scenario - - Mock data in data base: - - Create one userbalance snapshot for seven days ago for the user and pool1 - - */ - - const newestSnapshotTimestamp = oneDayAgo; - - await createUserPoolBalanceSnapshot({ - id: `${poolId1}-${userAddress}-${sevenDaysAgo}`, - timestamp: sevenDaysAgo, - user: { connect: { address: userAddress } }, - pool: { - connect: { - id: poolId1, - }, - }, - poolToken: poolAddress1, - walletBalance: '1', - farmBalance: '0', - gaugeBalance: '0', - totalBalance: '1', - }); - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > newestSnapshotTimestamp) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${sevenDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: sevenDaysAgo, - walletTokens: [poolAddress1], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${fiveDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: fiveDaysAgo, - walletTokens: [], - walletBalances: [], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [poolAddress1], - walletBalances: ['0.5'], - gauges: [], - gaugeBalances: [], - farms: [farmId1], - farmBalances: ['1'], - }, - { - id: `${userAddress}-${twoDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: twoDaysAgo, - walletTokens: [], - walletBalances: [], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${oneDayAgo}`, - user: { - id: userAddress, - }, - timestamp: oneDayAgo, - walletTokens: [], - walletBalances: [], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - ], - }), - ); - }), - ], - ); - - // before the sync is called, this should only return one snapshot that was manually added to the DB in this test - const snapshotsInDbBeforeSync = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - }); - expect(snapshotsInDbBeforeSync.length).toBe(1); - - // sync - await userService.syncUserBalanceSnapshots(); - - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - }); - - // check if snapshots have been persisted (only four, rest is inferred at query or consecutive 0 balance) - expect(snapshotsFromDb.length).toBe(4); - - // after the sync, 5 snapshots should be present. - //Sevendaysago, sixdaysago (inferred), fivedaysago (0 balance), fourdays ago (0 balance), threedaysago and twodaysago (0 balance) - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - expect(snapshotsAfterSync.length).toBe(6); - - const snapshotsFromDbAfterGet = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - }); - - // check if snapshots are still 4 on db (no new added because of get) - expect(snapshotsFromDbAfterGet.length).toBe(4); - - // check if balances are calculated correctly - expect(snapshotsAfterSync[0].timestamp).toBe(sevenDaysAgo); - expect(snapshotsAfterSync[0].walletBalance).toBe('1'); - expect(snapshotsAfterSync[0].totalBalance).toBe('1'); - expect(snapshotsAfterSync[1].timestamp).toBe(sixDaysAgo); - expect(snapshotsAfterSync[1].walletBalance).toBe('1'); - expect(snapshotsAfterSync[1].totalBalance).toBe('1'); - - expect(snapshotsAfterSync[2].timestamp).toBe(fiveDaysAgo); - expect(snapshotsAfterSync[2].walletBalance).toBe('0'); - expect(snapshotsAfterSync[2].totalBalance).toBe('0'); - - expect(snapshotsAfterSync[3].timestamp).toBe(fourDaysAgo); - expect(snapshotsAfterSync[3].walletBalance).toBe('0'); - expect(snapshotsAfterSync[3].farmBalance).toBe('0'); - expect(snapshotsAfterSync[3].totalBalance).toBe('0'); - - expect(snapshotsAfterSync[4].timestamp).toBe(threeDaysAgo); - expect(snapshotsAfterSync[4].walletBalance).toBe('0.5'); - expect(snapshotsAfterSync[4].farmBalance).toBe('1'); - expect(snapshotsAfterSync[4].totalBalance).toBe('1.5'); - - expect(snapshotsAfterSync[5].timestamp).toBe(twoDaysAgo); - expect(snapshotsAfterSync[5].walletBalance).toBe('0'); - expect(snapshotsAfterSync[5].totalBalance).toBe('0'); - - const poolSnapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: poolId1 }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of snapshotsAfterSync) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshots) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.percentShare).toBe( - parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - userBalanceSnapshot.percentShare * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } -}); - -test('Todays user snapshot must be gradually updated based on an updated pool snapshot.', async () => { - /* - Behaviour under test: - - The user has once requested the user stats for pool1 - - Poolsnapshots are updated regularly for fees/volume, if we request user snapshot again and the poolsnapshot has changed, these changes should be reflected in the user snapshot - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create one snapshot for user for today where he has only 1 bpt from pool1 in his wallet - */ - - const newestSnapshotTimestamp = today; - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > newestSnapshotTimestamp) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${today}`, - user: { - id: userAddress, - }, - timestamp: today, - walletTokens: [poolAddress1], - walletBalances: ['1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - ], - }), - ); - }), - ], - ); - - const userSnapshotsBefore = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - expect(userSnapshotsBefore.length).toBe(1); - - // check if balances are calculated correctly - expect(userSnapshotsBefore[0].walletBalance).toBe('1'); - expect(userSnapshotsBefore[0].timestamp).toBe(today); - - const poolSnapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: poolId1 }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of userSnapshotsBefore) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshots) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.percentShare).toBe( - parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - userBalanceSnapshot.percentShare * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } - - // update poolsnapshot of today - await prisma.prismaPoolSnapshot.update({ - where: { id_chain: { id: `${poolId1}-${today}`, chain: 'FANTOM' } }, - data: { - totalLiquidity: 1000, - volume24h: 500, - fees24h: 5000, - sharePrice: 10, - }, - }); - - // sync - await userService.syncUserBalanceSnapshots(); - - // check numbers again - const userSnapshotsAfter = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - expect(userSnapshotsBefore.length).toBe(1); - - // check if balances are calculated correctly - expect(userSnapshotsAfter[0].walletBalance).toBe('1'); - expect(userSnapshotsAfter[0].timestamp).toBe(today); - - const poolSnapshotsAfter = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: poolId1 }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of userSnapshotsAfter) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshotsAfter) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - if (poolSnapshot.timestamp === today) { - expect(poolSnapshot.totalLiquidity).toBe(1000); - expect(poolSnapshot.volume24h).toBe(500); - expect(poolSnapshot.fees24h).toBe(5000); - expect(poolSnapshot.sharePrice).toBe(10); - } - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.percentShare).toBe( - parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - userBalanceSnapshot.percentShare * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } -}); - -test('User requests pool snapshots for Fidelio Duetto Pool. Make sure fBeets are correctly accounted for.', async () => { - /* - Scenario: - - Request snapshots for the fidelio duetto pool - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create three snapshots for user, one with only bpt, one with btp and fbeets, and one with bpt, fbeets and staked fbeets - - Behaviour under test: - - For fidelio duetto, we must also add fbeets wallet balance to the fidelio bpt wallet balance (adjusted with the correct BPT->fbeets ratio) - */ - - const newestSnapshotTimestamp = oneDayAgo; - - const fidelioPoolId = networkContext.data.fbeets!.poolId; - const fidelioPoolAddress = networkContext.data.fbeets!.poolAddress; - const fbeets = networkContext.data.fbeets!.address; - const fbeetsFarm = networkContext.data.fbeets!.farmId; - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > newestSnapshotTimestamp) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [fidelioPoolAddress], - walletBalances: ['0.5'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${twoDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: twoDaysAgo, - walletTokens: [fidelioPoolAddress, fbeets], - walletBalances: ['0.5', '1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${oneDayAgo}`, - user: { - id: userAddress, - }, - timestamp: oneDayAgo, - walletTokens: [fidelioPoolAddress, fbeets], - walletBalances: ['1', '2'], - gauges: [], - gaugeBalances: [], - farms: [fbeetsFarm], - farmBalances: ['2'], - }, - ], - }), - ); - }), - ], - ); - - const userBalanceSnapshots = await userService.getUserBalanceSnapshotsForPool( - userAddress, - fidelioPoolId, - Chain.FANTOM, - 'THIRTY_DAYS', - ); - expect(userBalanceSnapshots.length).toBe(4); - - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - }); - - // check if snapshots have been persisted (last one in inferred) - expect(snapshotsFromDb.length).toBe(3); - - // check if balances are calculated correctly - expect(userBalanceSnapshots[0].timestamp).toBe(threeDaysAgo); - expect(userBalanceSnapshots[0].walletBalance).toBe('0.5'); - expect(userBalanceSnapshots[0].totalBalance).toBe('0.5'); - - expect(userBalanceSnapshots[1].timestamp).toBe(twoDaysAgo); - expect(userBalanceSnapshots[1].walletBalance).toBe(`${FBEETS_BPT_RATIO * 1 + 0.5}`); - expect(userBalanceSnapshots[1].totalBalance).toBe(`${FBEETS_BPT_RATIO * 1 + 0.5}`); - - expect(userBalanceSnapshots[2].timestamp).toBe(oneDayAgo); - expect(userBalanceSnapshots[2].walletBalance).toBe(`${FBEETS_BPT_RATIO * 2 + 1}`); - expect(userBalanceSnapshots[2].farmBalance).toBe(`${FBEETS_BPT_RATIO * 2}`); - expect(userBalanceSnapshots[2].totalBalance).toBe(`${FBEETS_BPT_RATIO * 2 + 1 + FBEETS_BPT_RATIO * 2}`); - - expect(userBalanceSnapshots[3].timestamp).toBe(today); - expect(userBalanceSnapshots[3].walletBalance).toBe(`${FBEETS_BPT_RATIO * 2 + 1}`); - expect(userBalanceSnapshots[3].farmBalance).toBe(`${FBEETS_BPT_RATIO * 2}`); - expect(userBalanceSnapshots[3].totalBalance).toBe(`${FBEETS_BPT_RATIO * 2 + 1 + FBEETS_BPT_RATIO * 2}`); - - const poolSnapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: fidelioPoolId }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of userBalanceSnapshots) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshots) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - expect(userBalanceSnapshot.percentShare).toBe( - parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum, - ); - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - userBalanceSnapshot.percentShare * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } -}); - -test('Sync user snapshots for Fidelio Duetto pool. Make sure fBeets are correctly accounted for when persisting.', async () => { - /* - Scenario: - - sync snapshots for fidelio pool - - Mock data for user-balance-subgraph (important that timestamps are ASC, as this is requested like this form the function under test): - - Create three snapshots for user - - Mock data in data base: - - Create one userbalance snapshot for three days ago for the user and fidelio pool - - Behaviour under test: - - For fidelio duetto, we must also add fbeets wallet balance to the fidelio bpt wallet balance (adjusted with the correct BPT->fbeets ratio). The sync needs to account for that. - */ - - const newestSnapshotTimestamp = oneDayAgo; - - const fidelioPoolId = networkContext.data.fbeets!.poolId; - const fidelioPoolAddress = networkContext.data.fbeets!.poolAddress; - const fbeets = networkContext.data.fbeets!.address; - const fbeetsFarm = networkContext.data.fbeets!.farmId; - - await createUserPoolBalanceSnapshot({ - id: `${fidelioPoolId}-${userAddress}-${threeDaysAgo}`, - timestamp: threeDaysAgo, - user: { connect: { address: userAddress } }, - pool: { - connect: { - id: fidelioPoolId, - }, - }, - poolToken: fidelioPoolAddress, - walletBalance: '1', - farmBalance: '0', - gaugeBalance: '0', - totalBalance: '1', - }); - - mockServer.use( - ...[ - graphql.query('UserBalanceSnapshots', async (req, res, ctx) => { - const requestJson = await req.json(); - if (requestJson.variables.where.timestamp_gte > newestSnapshotTimestamp) { - return res( - ctx.data({ - snapshots: [], - }), - ); - } - // important, sort snapshots ASC - return res( - ctx.data({ - snapshots: [ - { - id: `${userAddress}-${threeDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: threeDaysAgo, - walletTokens: [fidelioPoolAddress], - walletBalances: ['0.5'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${twoDaysAgo}`, - user: { - id: userAddress, - }, - timestamp: twoDaysAgo, - walletTokens: [fidelioPoolAddress, fbeets], - walletBalances: ['0.5', '1'], - gauges: [], - gaugeBalances: [], - farms: [], - farmBalances: [], - }, - { - id: `${userAddress}-${oneDayAgo}`, - user: { - id: userAddress, - }, - timestamp: oneDayAgo, - walletTokens: [fidelioPoolAddress, fbeets], - walletBalances: ['1', '2'], - gauges: [], - gaugeBalances: [], - farms: [fbeetsFarm], - farmBalances: ['2'], - }, - ], - }), - ); - }), - ], - ); - - const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - }); - - expect(snapshotsFromDb.length).toBe(1); - - // sync - await userService.syncUserBalanceSnapshots(); - - const snapshotsFromDbAfterSync = await prisma.prismaUserPoolBalanceSnapshot.findMany({ - where: { - userAddress: userAddress, - }, - orderBy: { timestamp: 'asc' }, - }); - - // check if snapshots have been persisted (last one is inferred) - expect(snapshotsFromDbAfterSync.length).toBe(3); - - // check if balances are calculated correctly - expect(snapshotsFromDbAfterSync[0].timestamp).toBe(threeDaysAgo); - expect(snapshotsFromDbAfterSync[0].walletBalance).toBe('0.5'); - expect(snapshotsFromDbAfterSync[0].totalBalance).toBe('0.5'); - - expect(snapshotsFromDbAfterSync[1].timestamp).toBe(twoDaysAgo); - expect(snapshotsFromDbAfterSync[1].walletBalance).toBe(`${FBEETS_BPT_RATIO * 1 + 0.5}`); - expect(snapshotsFromDbAfterSync[1].totalBalance).toBe(`${FBEETS_BPT_RATIO * 1 + 0.5}`); - - expect(snapshotsFromDbAfterSync[2].timestamp).toBe(oneDayAgo); - expect(snapshotsFromDbAfterSync[2].walletBalance).toBe(`${FBEETS_BPT_RATIO * 2 + 1}`); - expect(snapshotsFromDbAfterSync[2].farmBalance).toBe(`${FBEETS_BPT_RATIO * 2}`); - expect(snapshotsFromDbAfterSync[2].totalBalance).toBe(`${FBEETS_BPT_RATIO * 2 + 1 + FBEETS_BPT_RATIO * 2}`); - - const poolSnapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: fidelioPoolId }, - }); - - // check if usd value, percent share of the pool and fees are correctly calculated based on poolsnapshots - for (const userBalanceSnapshot of snapshotsFromDbAfterSync) { - let foundPoolSnapshot = false; - for (const poolSnapshot of poolSnapshots) { - if (poolSnapshot.timestamp === userBalanceSnapshot.timestamp) { - expect(userBalanceSnapshot.percentShare).toBe( - `${parseFloat(userBalanceSnapshot.totalBalance) / poolSnapshot.totalSharesNum}`, - ); - expect(userBalanceSnapshot.totalValueUSD).toBe( - `${poolSnapshot.sharePrice * parseFloat(userBalanceSnapshot.totalBalance)}`, - ); - expect(userBalanceSnapshot.fees24h).toBe( - `${ - parseFloat(userBalanceSnapshot.percentShare) * - poolSnapshot.fees24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }`, - ); - foundPoolSnapshot = true; - } - } - //make sure we have a pool snapshot for each user snapshot - expect(foundPoolSnapshot).toBe(true); - } -}); diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index 872e3c505..638ebe5dd 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -1,16 +1,11 @@ import { Chain, PrismaPoolStaking, PrismaPoolStakingType } from '@prisma/client'; import { prisma } from '../../prisma/prisma-client'; import { GqlPoolJoinExit, GqlPoolSwap, GqlUserSnapshotDataRange } from '../../schema'; -import { coingeckoService } from '../coingecko/coingecko.service'; -import { PoolSnapshotService } from '../pool/lib/pool-snapshot.service'; import { PoolSwapService } from '../pool/lib/pool-swap.service'; -import { reliquarySubgraphService } from '../subgraphs/reliquary-subgraph/reliquary.service'; -import { userSnapshotSubgraphService } from '../subgraphs/user-snapshot-subgraph/user-snapshot-subgraph.service'; import { tokenService } from '../token/token.service'; import { UserBalanceService } from './lib/user-balance.service'; -import { UserSnapshotService } from './lib/user-snapshot.service'; import { UserSyncWalletBalanceService } from './lib/user-sync-wallet-balance.service'; -import { UserPoolBalance, UserPoolSnapshot, UserStakedBalanceService } from './user-types'; +import { UserPoolBalance, UserStakedBalanceService } from './user-types'; import { networkContext } from '../network/network-context.service'; export class UserService { @@ -18,7 +13,6 @@ export class UserService { private readonly userBalanceService: UserBalanceService, private readonly walletSyncService: UserSyncWalletBalanceService, private readonly poolSwapService: PoolSwapService, - private readonly userSnapshotService: UserSnapshotService, ) {} private get stakedSyncServices(): UserStakedBalanceService[] { @@ -57,19 +51,6 @@ export class UserService { return this.userBalanceService.getUserStaking(address, chains); } - public async getUserBalanceSnapshotsForPool( - accountAddress: string, - poolId: string, - chain: Chain, - days: GqlUserSnapshotDataRange, - ): Promise { - return this.userSnapshotService.getUserPoolBalanceSnapshotsForPool(accountAddress, poolId, chain, days); - } - - public async getUserRelicSnapshots(accountAddress: string, farmId: string, days: GqlUserSnapshotDataRange) { - return this.userSnapshotService.getUserRelicSnapshotsForFarm(accountAddress, farmId, days); - } - public async initWalletBalancesForAllPools() { await this.walletSyncService.initBalancesForPools(); } @@ -125,27 +106,10 @@ export class UserService { ); } } - - public async syncUserBalanceSnapshots() { - await this.userSnapshotService.syncUserPoolBalanceSnapshots(); - } - - public async syncUserRelicSnapshots() { - await this.userSnapshotService.syncLatestUserRelicSnapshots(); - } - - public async loadAllUserRelicSnapshots() { - await this.userSnapshotService.loadAllUserRelicSnapshots(); - } } export const userService = new UserService( new UserBalanceService(), new UserSyncWalletBalanceService(), new PoolSwapService(tokenService), - new UserSnapshotService( - userSnapshotSubgraphService, - reliquarySubgraphService, - new PoolSnapshotService(coingeckoService), - ), ); diff --git a/worker/job-handlers.ts b/worker/job-handlers.ts index aa91a476a..82ee33dbf 100644 --- a/worker/job-handlers.ts +++ b/worker/job-handlers.ts @@ -227,15 +227,6 @@ export function configureWorkerRoutes(app: Express) { next, ); break; - case 'sync-user-snapshots': - await runIfNotAlreadyRunning( - job.name, - chainId, - () => userService.syncUserBalanceSnapshots(), - res, - next, - ); - break; case 'feed-data-to-datastudio': await runIfNotAlreadyRunning(job.name, chainId, () => datastudioService.feedPoolData(), res, next); break; @@ -248,9 +239,6 @@ export function configureWorkerRoutes(app: Express) { next, ); break; - case 'sync-latest-relic-snapshots': - await runIfNotAlreadyRunning(job.name, chainId, () => userService.syncUserRelicSnapshots(), res, next); - break; case 'global-purge-old-tokenprices': await runIfNotAlreadyRunning( job.name, From 221c71c5ac3cca0f3d0a3f0069570d142a924a3c Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 13:47:03 +0100 Subject: [PATCH 03/23] add vault v3 settings and per pool swap fee --- modules/datastudio/datastudio.service.ts | 17 ++++------- modules/network/arbitrum.ts | 30 ++++++------------- modules/network/avalanche.ts | 30 ++++++------------- modules/network/base.ts | 25 +++++----------- modules/network/fantom.ts | 30 ++++++------------- modules/network/gnosis.ts | 30 ++++++------------- modules/network/mainnet.ts | 30 +++++++------------ modules/network/network-config-types.ts | 19 +++++------- modules/network/optimism.ts | 30 ++++++------------- modules/network/polygon.ts | 30 ++++++------------- modules/network/zkevm.ts | 30 ++++++------------- .../boosted-pool-apr.service.ts | 4 +-- .../phantom-stable-apr.service.ts | 6 ++-- .../apr-data-sources/swap-fee-apr.service.ts | 4 +-- .../apr-data-sources/yb-tokens-apr.service.ts | 14 +++------ .../pool/lib/pool-on-chain-data.service.ts | 14 +++++++-- modules/pool/lib/pool-onchain-data.ts | 5 ++++ modules/pool/lib/pool-sync.service.ts | 2 +- modules/pool/lib/pool-usd-data.service.ts | 9 +++--- modules/pool/pool.prisma | 3 +- .../sor/sorV1Beets/balancer-sor.service.ts | 6 +++- .../lib/user-sync-wallet-balance.service.ts | 2 +- prisma/schema.prisma | 3 +- 23 files changed, 133 insertions(+), 240 deletions(-) diff --git a/modules/datastudio/datastudio.service.ts b/modules/datastudio/datastudio.service.ts index 8ec97703e..e214c41d9 100644 --- a/modules/datastudio/datastudio.service.ts +++ b/modules/datastudio/datastudio.service.ts @@ -26,7 +26,6 @@ export class DatastudioService { networkContext.data.datastudio![env.DEPLOYMENT_ENV as DeploymentEnv].compositionTabName; const emissionDataTabName = networkContext.data.datastudio![env.DEPLOYMENT_ENV as DeploymentEnv].emissionDataTabName; - const swapProtocolFeePercentage = networkContext.data.balancer.swapProtocolFeePercentage; const chainSlug = networkContext.data.chain.slug; const sheets = google.sheets({ version: 'v4' }); @@ -136,27 +135,23 @@ export class DatastudioService { } if (pool.dynamicData) { - const protocolYieldFeePercentage = pool.dynamicData.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; + const protocolYieldFeePercentage = parseFloat(pool.dynamicData.protocolYieldFee); + const protocolSwapFeePercentage = parseFloat(pool.dynamicData.protocolSwapFee); sharesChange = `${ parseFloat(pool.dynamicData.totalShares) - parseFloat(pool.dynamicData.totalShares24hAgo) }`; tvlChange = `${pool.dynamicData.totalLiquidity - pool.dynamicData.totalLiquidity24hAgo}`; - lpSwapFee = `${pool.dynamicData.fees24h * (1 - swapProtocolFeePercentage)}`; - protocolSwapFee = `${pool.dynamicData.fees24h * swapProtocolFeePercentage}`; + lpSwapFee = `${pool.dynamicData.fees24h * (1 - protocolSwapFeePercentage)}`; + protocolSwapFee = `${pool.dynamicData.fees24h * protocolSwapFeePercentage}`; lpYieldCapture = pool.type === 'META_STABLE' - ? `${ - pool.dynamicData.yieldCapture24h * - (1 - networkContext.data.balancer.swapProtocolFeePercentage) - }` + ? `${pool.dynamicData.yieldCapture24h * (1 - protocolSwapFeePercentage)}` : `${pool.dynamicData.yieldCapture24h * (1 - protocolYieldFeePercentage)}`; protocolYieldCapture = pool.type === 'META_STABLE' - ? `${pool.dynamicData.yieldCapture24h * networkContext.data.balancer.swapProtocolFeePercentage}` + ? `${pool.dynamicData.yieldCapture24h * protocolSwapFeePercentage}` : `${pool.dynamicData.yieldCapture24h * protocolYieldFeePercentage}`; if (pool.dynamicData.isInRecoveryMode || pool.type === 'LIQUIDITY_BOOTSTRAPPING') { diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 39b379629..02c702870 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -68,16 +68,12 @@ export const arbitrumNetworkData: NetworkData = { delegationProxy: '0x81cfae226343b24ba12ec6521db2c79e7aeeb310', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, multicall: '0x80c7dd17b01855a6d2347444a0fcc36136a314de', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -241,18 +237,10 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: arbitrumNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - arbitrumNetworkData.ybAprConfig, - arbitrumNetworkData.chain.prismaId, - arbitrumNetworkData.balancer.v2.yieldProtocolFeePercentage, - arbitrumNetworkData.balancer.v2.swapProtocolFeePercentage, - ), - new PhantomStableAprService( - arbitrumNetworkData.chain.prismaId, - arbitrumNetworkData.balancer.v2.yieldProtocolFeePercentage, - ), + new YbTokensAprService(arbitrumNetworkData.ybAprConfig, arbitrumNetworkData.chain.prismaId), + new PhantomStableAprService(arbitrumNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(arbitrumNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [arbitrumNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, arbitrumNetworkData.bal!.address)], diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index 2190c8039..e8907b37f 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -66,16 +66,12 @@ const avalancheNetworkData: NetworkData = { delegationProxy: '0x0c6052254551eae3ecac77b01dfcf1025418828f', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -212,18 +208,10 @@ export const avalancheNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: avalancheNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - avalancheNetworkData.ybAprConfig, - avalancheNetworkData.chain.prismaId, - avalancheNetworkData.balancer.v2.yieldProtocolFeePercentage, - avalancheNetworkData.balancer.v2.swapProtocolFeePercentage, - ), - new PhantomStableAprService( - avalancheNetworkData.chain.prismaId, - avalancheNetworkData.balancer.v2.yieldProtocolFeePercentage, - ), + new YbTokensAprService(avalancheNetworkData.ybAprConfig, avalancheNetworkData.chain.prismaId), + new PhantomStableAprService(avalancheNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(avalancheNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [avalancheNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, avalancheNetworkData.bal!.address)], diff --git a/modules/network/base.ts b/modules/network/base.ts index fe71e6aea..efe5a1250 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -62,16 +62,12 @@ const baseNetworkData: NetworkData = { delegationProxy: '0xd87f44df0159dc78029ab9ca7d7e57e7249f5acd', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, ybAprConfig: { defaultHandlers: { @@ -136,14 +132,9 @@ export const baseNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: baseNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - baseNetworkData.ybAprConfig, - baseNetworkData.chain.prismaId, - baseNetworkData.balancer.v2.yieldProtocolFeePercentage, - baseNetworkData.balancer.v2.swapProtocolFeePercentage, - ), + new YbTokensAprService(baseNetworkData.ybAprConfig, baseNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(baseNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [baseNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, baseNetworkData.bal!.address)], diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index ea2805bfb..718bd50b1 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -114,16 +114,12 @@ const fantomNetworkData: NetworkData = { poolAddress: '0xcde5a11a4acb4ee4c805352cec57e236bdbc3837', }, balancer: { - v2: { - vault: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', - swapProtocolFeePercentage: 0.25, - yieldProtocolFeePercentage: 0.25, - }, - v3: { - vault: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', - swapProtocolFeePercentage: 0.25, - yieldProtocolFeePercentage: 0.25, - }, + vaultV2Address: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', + v2DefaultSwapFeePercentage: '0.25', + v2DefaultYieldFeePercentage: '0.25', + vaultV3Address: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', + v3DefaultSwapFeePercentage: '0.25', + v3DefaultYieldFeePercentage: '0.25', }, multicall: '0x66335d7ad8011f6aa3f48aadcb523b62b38ed961', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -296,19 +292,11 @@ export const fantomNetworkConfig: NetworkConfig = { contentService: new SanityContentService(fantomNetworkData.chain.prismaId), provider: new ethers.providers.JsonRpcProvider({ url: fantomNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - fantomNetworkData.ybAprConfig, - fantomNetworkData.chain.prismaId, - fantomNetworkData.balancer.v2.yieldProtocolFeePercentage, - fantomNetworkData.balancer.v2.swapProtocolFeePercentage, - ), + new YbTokensAprService(fantomNetworkData.ybAprConfig, fantomNetworkData.chain.prismaId), // new SpookySwapAprService(tokenService, fantomNetworkData.spooky!.xBooContract), - new PhantomStableAprService( - fantomNetworkData.chain.prismaId, - fantomNetworkData.balancer.v2.yieldProtocolFeePercentage, - ), + new PhantomStableAprService(fantomNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(fantomNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new MasterchefFarmAprService(fantomNetworkData.beets!.address), new ReliquaryFarmAprService(fantomNetworkData.beets!.address), new BeetswarsGaugeVotingAprService(), diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index f340e23bb..e0f7a6f16 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -64,16 +64,12 @@ const gnosisNetworkData: NetworkData = { delegationProxy: '0x7a2535f5fb47b8e44c02ef5d9990588313fe8f05', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, multicall: '0xbb6fab6b627947dae0a75808250d8b2652952cb5', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -140,18 +136,10 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: gnosisNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - gnosisNetworkData.ybAprConfig, - gnosisNetworkData.chain.prismaId, - gnosisNetworkData.balancer.v2.yieldProtocolFeePercentage, - gnosisNetworkData.balancer.v2.swapProtocolFeePercentage, - ), - new PhantomStableAprService( - gnosisNetworkData.chain.prismaId, - gnosisNetworkData.balancer.v2.yieldProtocolFeePercentage, - ), + new YbTokensAprService(gnosisNetworkData.ybAprConfig, gnosisNetworkData.chain.prismaId), + new PhantomStableAprService(gnosisNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(gnosisNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [gnosisNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, gnosisNetworkData.bal!.address)], diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 61f7188c8..dbd2a0578 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -82,18 +82,13 @@ const data: NetworkData = { config: '0xac89cc9d78bbad7eb3a02601b4d65daa1f908aa6', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, multicall: '0x5ba1e12693dc8f9c48aad8770482f4739beed696', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -373,15 +368,10 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: data.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - data.ybAprConfig, - data.chain.prismaId, - data.balancer.v2.yieldProtocolFeePercentage, - data.balancer.v2.swapProtocolFeePercentage, - ), - new PhantomStableAprService(data.chain.prismaId, data.balancer.v2.yieldProtocolFeePercentage), + new YbTokensAprService(data.ybAprConfig, data.chain.prismaId), + new PhantomStableAprService(data.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(data.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [data.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, data.bal!.address)], diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 421fa36b4..653739708 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -102,18 +102,13 @@ export interface NetworkData { config: string; }; balancer: { - v2: { - vault: string; - tokenAdmin?: string; - yieldProtocolFeePercentage: number; - swapProtocolFeePercentage: number; - }; - v3: { - vault: string; - tokenAdmin?: string; - yieldProtocolFeePercentage: number; - swapProtocolFeePercentage: number; - }; + vaultV2Address: string; + v2DefaultSwapFeePercentage: string; + v2DefaultYieldFeePercentage: string; + vaultV3Address: string; + v3DefaultSwapFeePercentage: string; + v3DefaultYieldFeePercentage: string; + tokenAdmin?: string; }; multicall: string; multicall3: string; diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index f996ee7c3..68c567cc2 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -73,16 +73,12 @@ const optimismNetworkData: NetworkData = { config: '0x32acb44fc929339b9f16f0449525cc590d2a23f3', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, multicall: '0x2dc0e2aa608532da689e89e237df582b783e552c', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -269,18 +265,10 @@ export const optimismNetworkConfig: NetworkConfig = { contentService: new SanityContentService(optimismNetworkData.chain.prismaId), provider: new ethers.providers.JsonRpcProvider({ url: optimismNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - optimismNetworkData.ybAprConfig, - optimismNetworkData.chain.prismaId, - optimismNetworkData.balancer.v2.yieldProtocolFeePercentage, - optimismNetworkData.balancer.v2.swapProtocolFeePercentage, - ), - new PhantomStableAprService( - optimismNetworkData.chain.prismaId, - optimismNetworkData.balancer.v2.yieldProtocolFeePercentage, - ), + new YbTokensAprService(optimismNetworkData.ybAprConfig, optimismNetworkData.chain.prismaId), + new PhantomStableAprService(optimismNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(optimismNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [optimismNetworkData.beets!.address, optimismNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, optimismNetworkData.bal!.address)], diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index ee2a6d1ae..9f97bb7e6 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -68,16 +68,12 @@ const polygonNetworkData: NetworkData = { config: '0xfdc2e9e03f515804744a40d0f8d25c16e93fbe67', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, multicall: '0x275617327c958bd06b5d6b871e7f491d76113dd8', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -257,18 +253,10 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: polygonNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - polygonNetworkData.ybAprConfig, - polygonNetworkData.chain.prismaId, - polygonNetworkData.balancer.v2.yieldProtocolFeePercentage, - polygonNetworkData.balancer.v2.swapProtocolFeePercentage, - ), - new PhantomStableAprService( - polygonNetworkData.chain.prismaId, - polygonNetworkData.balancer.v2.yieldProtocolFeePercentage, - ), + new YbTokensAprService(polygonNetworkData.ybAprConfig, polygonNetworkData.chain.prismaId), + new PhantomStableAprService(polygonNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(polygonNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [polygonNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, polygonNetworkData.bal!.address)], diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 43998e28e..2732e83f2 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -66,16 +66,12 @@ const zkevmNetworkData: NetworkData = { delegationProxy: '0xc7e5ed1054a24ef31d827e6f86caa58b3bc168d7', }, balancer: { - v2: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, - v3: { - vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', - swapProtocolFeePercentage: 0.5, - yieldProtocolFeePercentage: 0.5, - }, + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', @@ -170,18 +166,10 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: zkevmNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new YbTokensAprService( - zkevmNetworkData.ybAprConfig, - zkevmNetworkData.chain.prismaId, - zkevmNetworkData.balancer.v2.yieldProtocolFeePercentage, - zkevmNetworkData.balancer.v2.swapProtocolFeePercentage, - ), - new PhantomStableAprService( - zkevmNetworkData.chain.prismaId, - zkevmNetworkData.balancer.v2.yieldProtocolFeePercentage, - ), + new YbTokensAprService(zkevmNetworkData.ybAprConfig, zkevmNetworkData.chain.prismaId), + new PhantomStableAprService(zkevmNetworkData.chain.prismaId), new BoostedPoolAprService(), - new SwapFeeAprService(zkevmNetworkData.balancer.v2.swapProtocolFeePercentage), + new SwapFeeAprService(), new GaugeAprService(tokenService, [zkevmNetworkData.bal!.address]), ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, zkevmNetworkData.bal!.address)], diff --git a/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts b/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts index c0e93d27f..de14694e7 100644 --- a/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts @@ -45,9 +45,7 @@ export class BoostedPoolAprService implements PoolAprService { }); for (const pool of filteredBoostedPoolsExpanded) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; + const protocolYieldFeePercentage = parseFloat(pool.dynamicData?.protocolYieldFee || '0'); const tokens = pool.tokens.filter((token) => { if (token.address === pool.address) { return false; diff --git a/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts b/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts index de75b1b46..98cb1e8b0 100644 --- a/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts @@ -5,7 +5,7 @@ import { collectsYieldFee } from '../pool-utils'; import { Chain } from '@prisma/client'; export class PhantomStableAprService implements PoolAprService { - constructor(private chain: Chain, private defaultProtocolFee: number) {} + constructor(private chain: Chain) {} public getAprServiceName(): string { return 'PhantomStableAprService'; @@ -20,9 +20,7 @@ export class PhantomStableAprService implements PoolAprService { }); for (const pool of phantomStablePoolsExpanded) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : this.defaultProtocolFee; + const protocolYieldFeePercentage = parseFloat(pool.dynamicData?.protocolYieldFee || '0'); const linearPoolTokens = pool.tokens.filter((token) => token.nestedPool?.type === 'LINEAR'); const linearPoolIds = linearPoolTokens.map((token) => token.nestedPool?.id || ''); const aprItems = await prisma.prismaPoolAprItem.findMany({ diff --git a/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts b/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts index 2b0eaa6e6..ea155fdba 100644 --- a/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts @@ -6,8 +6,6 @@ import { networkContext } from '../../../network/network-context.service'; const MAX_DB_INT = 9223372036854775807; export class SwapFeeAprService implements PoolAprService { - constructor(private readonly swapProtocolFeePercentage: number) {} - public getAprServiceName(): string { return 'SwapFeeAprService'; } @@ -29,7 +27,7 @@ export class SwapFeeAprService implements PoolAprService { ? (pool.dynamicData.fees24h * 365) / pool.dynamicData.totalLiquidity : 0; - let protocolFee = this.swapProtocolFeePercentage; + let protocolFee = parseFloat(pool.dynamicData.protocolSwapFee); if (pool.type === 'GYROE') { // Gyro has custom protocol fee structure protocolFee = parseFloat(pool.dynamicData.protocolYieldFee || '0'); diff --git a/modules/pool/lib/apr-data-sources/yb-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/yb-tokens-apr.service.ts index d7ad92276..18d171d54 100644 --- a/modules/pool/lib/apr-data-sources/yb-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/yb-tokens-apr.service.ts @@ -11,12 +11,7 @@ import { YbAprConfig } from '../../../network/apr-config-types'; export class YbTokensAprService implements PoolAprService { private ybTokensAprHandlers: YbAprHandlers; - constructor( - aprConfig: YbAprConfig, - private chain: Chain, - private defaultYieldFee: number, - private defaultSwapFee: number, - ) { + constructor(aprConfig: YbAprConfig, private chain: Chain) { this.ybTokensAprHandlers = new YbAprHandlers(aprConfig, chain); } @@ -78,12 +73,11 @@ export class YbTokensAprService implements PoolAprService { let aprInPoolAfterFees = tokenApr.apr * tokenPercentageInPool; if (collectsYieldFee(pool) && token.dynamicData && token.dynamicData.priceRate !== '1.0') { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : this.defaultYieldFee; + const protocolYieldFeePercentage = parseFloat(pool.dynamicData.protocolYieldFee || '0'); + const protocolSwapFeePercentage = parseFloat(pool.dynamicData.protocolSwapFee || '0'); aprInPoolAfterFees = pool.type === 'META_STABLE' - ? aprInPoolAfterFees * (1 - this.defaultSwapFee) + ? aprInPoolAfterFees * (1 - protocolSwapFeePercentage) : aprInPoolAfterFees * (1 - protocolYieldFeePercentage); } diff --git a/modules/pool/lib/pool-on-chain-data.service.ts b/modules/pool/lib/pool-on-chain-data.service.ts index 3957329eb..40603d2ac 100644 --- a/modules/pool/lib/pool-on-chain-data.service.ts +++ b/modules/pool/lib/pool-on-chain-data.service.ts @@ -31,8 +31,9 @@ export class PoolOnChainDataService { private get options() { return { chain: networkContext.chain, - vaultAddress: networkContext.data.balancer.vault, - yieldProtocolFeePercentage: networkContext.data.balancer.yieldProtocolFeePercentage, + vaultAddress: networkContext.data.balancer.vaultV2Address, + yieldProtocolFeePercentage: networkContext.data.balancer.v2DefaultYieldFeePercentage, + swapProtocolFeePercentage: networkContext.data.balancer.v2DefaultSwapFeePercentage, gyroConfig: networkContext.data.gyro?.config, }; } @@ -168,12 +169,18 @@ export class PoolOnChainDataService { onchainData.protocolYieldFeePercentageCache || String(this.options.yieldProtocolFeePercentage); + const swapProtocolFeePercentage = + gyroFees[pool.id] || + onchainData.protocolSwapFeePercentageCache || + String(this.options.swapProtocolFeePercentage); + if ( pool.dynamicData && (pool.dynamicData.swapFee !== swapFee || pool.dynamicData.totalShares !== totalShares || pool.dynamicData.swapEnabled !== swapEnabled || - pool.dynamicData.protocolYieldFee !== yieldProtocolFeePercentage) + pool.dynamicData.protocolYieldFee !== yieldProtocolFeePercentage || + pool.dynamicData.protocolSwapFee !== swapProtocolFeePercentage) ) { operations.push( prisma.prismaPoolDynamicData.update({ @@ -184,6 +191,7 @@ export class PoolOnChainDataService { totalSharesNum: parseFloat(totalShares), swapEnabled: typeof swapEnabled !== 'undefined' ? swapEnabled : true, protocolYieldFee: yieldProtocolFeePercentage, + protocolSwapFee: swapProtocolFeePercentage blockNumber, }, }), diff --git a/modules/pool/lib/pool-onchain-data.ts b/modules/pool/lib/pool-onchain-data.ts index f5ca25b41..9b7f1e499 100644 --- a/modules/pool/lib/pool-onchain-data.ts +++ b/modules/pool/lib/pool-onchain-data.ts @@ -35,6 +35,7 @@ interface OnchainData { swapFee: BigNumber; swapEnabled?: boolean; protocolYieldFeePercentageCache?: BigNumber; + protocolSwapFeePercentageCache?: BigNumber; rate?: BigNumber; weights?: BigNumber[]; targets?: [BigNumber, BigNumber]; @@ -100,6 +101,7 @@ const addDefaultCallsToMulticaller = ( multicaller.call(`${id}.totalSupply`, address, getTotalSupplyFn(type, version)); multicaller.call(`${id}.swapFee`, address, getSwapFeeFn(type)); multicaller.call(`${id}.rate`, address, 'getRate'); + multicaller.call(`${id}.protocolSwapFeePercentageCache`, address, 'getProtocolFeePercentageCache', [0]); multicaller.call(`${id}.protocolYieldFeePercentageCache`, address, 'getProtocolFeePercentageCache', [2]); }; @@ -193,6 +195,9 @@ const parse = (result: OnchainData, decimalsLookup: { [address: string]: number protocolYieldFeePercentageCache: result.protocolYieldFeePercentageCache ? formatEther(result.protocolYieldFeePercentageCache) : undefined, + protocolSwapFeePercentageCache: result.protocolSwapFeePercentageCache + ? formatEther(result.protocolSwapFeePercentageCache) + : undefined, }); export const fetchOnChainPoolData = async (pools: PoolInput[], vaultAddress: string, batchSize = 1024) => { diff --git a/modules/pool/lib/pool-sync.service.ts b/modules/pool/lib/pool-sync.service.ts index e1163fa7e..31615575a 100644 --- a/modules/pool/lib/pool-sync.service.ts +++ b/modules/pool/lib/pool-sync.service.ts @@ -20,7 +20,7 @@ export class PoolSyncService { } get vaultAddress() { - return networkContext.data.balancer.vault; + return networkContext.data.balancer.vaultV2Address; } get rpcUrl() { diff --git a/modules/pool/lib/pool-usd-data.service.ts b/modules/pool/lib/pool-usd-data.service.ts index bc4f81952..5bdcf946a 100644 --- a/modules/pool/lib/pool-usd-data.service.ts +++ b/modules/pool/lib/pool-usd-data.service.ts @@ -233,18 +233,17 @@ export class PoolUsdDataService { const yieldForUser48h = ((totalLiquidity24hAgo * userYieldApr) / 365) * 2; const yieldForUser24h = (liquidityAverage24h * userYieldApr) / 365; - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; + const protocolYieldFeePercentage = parseFloat(pool.dynamicData.protocolYieldFee || '0'); + const protocolSwapFeePercentage = parseFloat(pool.dynamicData.protocolSwapFee || '0'); let yieldCapture24h = pool.type === 'META_STABLE' - ? yieldForUser24h / (1 - networkContext.data.balancer.swapProtocolFeePercentage) + ? yieldForUser24h / (1 - protocolSwapFeePercentage) : yieldForUser24h / (1 - protocolYieldFeePercentage); let yieldCapture48h = pool.type === 'META_STABLE' - ? yieldForUser48h / (1 - networkContext.data.balancer.swapProtocolFeePercentage) + ? yieldForUser48h / (1 - protocolSwapFeePercentage) : yieldForUser48h / (1 - protocolYieldFeePercentage); // if the pool is in recovery mode, the protocol does not take any fee and therefore the user takes all yield captured diff --git a/modules/pool/pool.prisma b/modules/pool/pool.prisma index 3023c7bc6..d14e977c0 100644 --- a/modules/pool/pool.prisma +++ b/modules/pool/pool.prisma @@ -128,7 +128,8 @@ model PrismaPoolDynamicData { blockNumber Int updatedAt DateTime @updatedAt - protocolYieldFee String? + protocolYieldFee String @default("0") + protocolSwapFee String @default("0") swapFee String swapEnabled Boolean isPaused Boolean @default(false) diff --git a/modules/sor/sorV1Beets/balancer-sor.service.ts b/modules/sor/sorV1Beets/balancer-sor.service.ts index 7825abfbb..7c2960993 100644 --- a/modules/sor/sorV1Beets/balancer-sor.service.ts +++ b/modules/sor/sorV1Beets/balancer-sor.service.ts @@ -319,7 +319,11 @@ export class BalancerSorService { } private queryBatchSwap(swapType: SwapTypes, swaps: SwapV2[], assets: string[]): Promise { - const vaultContract = new Contract(networkContext.data.balancer.vault, VaultAbi, networkContext.provider); + const vaultContract = new Contract( + networkContext.data.balancer.vaultV2Address, + VaultAbi, + networkContext.provider, + ); const funds: FundManagement = { sender: AddressZero, recipient: AddressZero, diff --git a/modules/user/lib/user-sync-wallet-balance.service.ts b/modules/user/lib/user-sync-wallet-balance.service.ts index d971d87e4..1a5ec9fd0 100644 --- a/modules/user/lib/user-sync-wallet-balance.service.ts +++ b/modules/user/lib/user-sync-wallet-balance.service.ts @@ -42,7 +42,7 @@ export class UserSyncWalletBalanceService { } get vaultAddress() { - return AllNetworkConfigs[this.chainId].data.balancer.vault; + return AllNetworkConfigs[this.chainId].data.balancer.vaultV2Address; } get fbeetsAddress() { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b533bbfa9..0b6a6ed16 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -174,7 +174,8 @@ model PrismaPoolDynamicData { blockNumber Int updatedAt DateTime @updatedAt - protocolYieldFee String? + protocolYieldFee String @default("0") + protocolSwapFee String @default("0") swapFee String swapEnabled Boolean isPaused Boolean @default(false) From fb42519707d0681d5987537ce2e3503b54da64c0 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 13:48:14 +0100 Subject: [PATCH 04/23] typo --- modules/pool/lib/pool-on-chain-data.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pool/lib/pool-on-chain-data.service.ts b/modules/pool/lib/pool-on-chain-data.service.ts index 40603d2ac..11e43a46d 100644 --- a/modules/pool/lib/pool-on-chain-data.service.ts +++ b/modules/pool/lib/pool-on-chain-data.service.ts @@ -191,7 +191,7 @@ export class PoolOnChainDataService { totalSharesNum: parseFloat(totalShares), swapEnabled: typeof swapEnabled !== 'undefined' ? swapEnabled : true, protocolYieldFee: yieldProtocolFeePercentage, - protocolSwapFee: swapProtocolFeePercentage + protocolSwapFee: swapProtocolFeePercentage, blockNumber, }, }), From b554970967e35bb1981ba9876c8b17f167fccf27 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 14:28:25 +0100 Subject: [PATCH 05/23] unused --- modules/beethoven/beets.gql | 53 ------------------------------------- 1 file changed, 53 deletions(-) diff --git a/modules/beethoven/beets.gql b/modules/beethoven/beets.gql index caa15efbb..683660869 100644 --- a/modules/beethoven/beets.gql +++ b/modules/beethoven/beets.gql @@ -4,58 +4,12 @@ extend type Query { beetsPoolGetReliquaryFarmSnapshots(id: String!, range: GqlPoolSnapshotDataRange!): [GqlReliquaryFarmSnapshot!]! userGetFbeetsBalance: GqlUserFbeetsBalance! - - userGetPoolSnapshots(poolId: String!, chain: GqlChain!, range: GqlUserSnapshotDataRange!): [GqlUserPoolSnapshot!]! - userGetRelicSnapshots(farmId: String!, range: GqlUserSnapshotDataRange!): [GqlUserRelicSnapshot!]! - - userGetPortfolioSnapshots(days: Int!): [GqlUserPortfolioSnapshot!]! } extend type Mutation { beetsSyncFbeetsRatio: String! beetsPoolLoadReliquarySnapshotsForAllFarms: String! - - userLoadAllRelicSnapshots: String! -} - -type GqlUserPortfolioSnapshot { - timestamp: Int! - walletBalance: AmountHumanReadable! - gaugeBalance: AmountHumanReadable! - farmBalance: AmountHumanReadable! - totalBalance: AmountHumanReadable! - totalValueUSD: AmountHumanReadable! - fees24h: AmountHumanReadable! - totalFees: AmountHumanReadable! - pools: [GqlUserPoolSnapshot!]! -} - -enum GqlUserSnapshotDataRange { - THIRTY_DAYS - NINETY_DAYS - ONE_HUNDRED_EIGHTY_DAYS - ONE_YEAR - ALL_TIME -} - -type GqlUserPoolSnapshot { - # id: ID! - timestamp: Int! - # poolId: String! - # poolAddress: String! - # poolName: String! - percentShare: Float! - walletBalance: AmountHumanReadable! - gaugeBalance: AmountHumanReadable! - farmBalance: AmountHumanReadable! - totalBalance: AmountHumanReadable! - totalValueUSD: AmountHumanReadable! - fees24h: AmountHumanReadable! - # totalFees: AmountHumanReadable! - # percentageOfPortfolio: Float! - # priceChange24h: AmountHumanReadable! - # priceChangePercent24h: Float! } type GqlUserFbeetsBalance { @@ -135,13 +89,6 @@ type GqlPoolStakingFarmRewarder { rewardPerSecond: String! } -type GqlUserRelicSnapshot { - timestamp: Int! - totalBalance: String! - relicCount: Int! - relicSnapshots: [GqlRelicSnapshot!]! -} - type GqlRelicSnapshot { relicId: Int! farmId: String! From 7d6f342eeee7d4d1ec0e83fa5f3c0f2b418cd093 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 14:42:56 +0100 Subject: [PATCH 06/23] unused --- modules/network/arbitrum.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 02c702870..2cc40b63c 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -202,10 +202,6 @@ export const arbitrumNetworkData: NetworkData = { beefy: { linearPools: [''], }, - lido: { - wstEthAprEndpoint: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - wstEthContract: '0x5979d7b546e38e414f7e9822514be443a4800529', - }, datastudio: { main: { user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', From 4ce5355666a09585c77e5759860b1a5b62c5ca31 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 14:52:05 +0100 Subject: [PATCH 07/23] adding sepolia --- app/env.ts | 4 - modules/common/Base.gql | 1 + modules/datastudio/datastudio.service.ts | 2 +- modules/network/network-config-types.ts | 4 - modules/network/network-config.ts | 6 +- modules/network/sepolia.ts | 245 ++++++++++++++++++ modules/pool/pool.prisma | 2 +- modules/user/user.service.ts | 2 +- prisma/base.prisma | 1 + .../migration.sql | 5 + prisma/schema.prisma | 3 +- worker/scheduler.ts | 10 +- 12 files changed, 271 insertions(+), 14 deletions(-) create mode 100644 modules/network/sepolia.ts create mode 100644 prisma/migrations/20240119135136_add_swapfee_and_sepolia/migration.sql diff --git a/app/env.ts b/app/env.ts index a782dd24c..7860eccea 100644 --- a/app/env.ts +++ b/app/env.ts @@ -29,10 +29,6 @@ export const schema = { optional: true, type: String, }, - SUPPORTED_NETWORKS: { - optional: true, - type: String, - }, WORKER_QUEUE_URL: { optional: true, type: String, diff --git a/modules/common/Base.gql b/modules/common/Base.gql index 45d473aab..9bd61ba5f 100644 --- a/modules/common/Base.gql +++ b/modules/common/Base.gql @@ -11,4 +11,5 @@ enum GqlChain { OPTIMISM POLYGON ZKEVM + SEPOLIA } diff --git a/modules/datastudio/datastudio.service.ts b/modules/datastudio/datastudio.service.ts index e214c41d9..dcb0397f8 100644 --- a/modules/datastudio/datastudio.service.ts +++ b/modules/datastudio/datastudio.service.ts @@ -135,7 +135,7 @@ export class DatastudioService { } if (pool.dynamicData) { - const protocolYieldFeePercentage = parseFloat(pool.dynamicData.protocolYieldFee); + const protocolYieldFeePercentage = parseFloat(pool.dynamicData.protocolYieldFee || ''); const protocolSwapFeePercentage = parseFloat(pool.dynamicData.protocolSwapFee); sharesChange = `${ parseFloat(pool.dynamicData.totalShares) - parseFloat(pool.dynamicData.totalShares24hAgo) diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 653739708..fac23e02d 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -127,10 +127,6 @@ export interface NetworkData { beefy?: { linearPools: string[]; }; - lido?: { - wstEthContract: string; - wstEthAprEndpoint: string; - }; stader?: { sFtmxContract: string; }; diff --git a/modules/network/network-config.ts b/modules/network/network-config.ts index 35f86c2b2..fd555b33e 100644 --- a/modules/network/network-config.ts +++ b/modules/network/network-config.ts @@ -9,6 +9,7 @@ import { zkevmNetworkConfig } from './zkevm'; import { avalancheNetworkConfig } from './avalanche'; import { baseNetworkConfig } from './base'; import { Chain } from '@prisma/client'; +import { sepoliaNetworkConfig } from './sepolia'; export const AllNetworkConfigs: { [chainId: string]: NetworkConfig } = { '250': fantomNetworkConfig, @@ -20,6 +21,7 @@ export const AllNetworkConfigs: { [chainId: string]: NetworkConfig } = { '1101': zkevmNetworkConfig, '43114': avalancheNetworkConfig, '8453': baseNetworkConfig, + '11155111': sepoliaNetworkConfig, }; export const AllNetworkConfigsKeyedOnChain: { [chain in Chain]: NetworkConfig } = { @@ -32,6 +34,7 @@ export const AllNetworkConfigsKeyedOnChain: { [chain in Chain]: NetworkConfig } ZKEVM: zkevmNetworkConfig, AVALANCHE: avalancheNetworkConfig, BASE: baseNetworkConfig, + SEPOLIA: sepoliaNetworkConfig, }; export const chainIdToChain: { [id: string]: Chain } = { @@ -44,9 +47,10 @@ export const chainIdToChain: { [id: string]: Chain } = { '8453': Chain.BASE, '42161': Chain.ARBITRUM, '43114': Chain.AVALANCHE, + '11155111': Chain.SEPOLIA, }; -export const BalancerChainIds = ['1', '137', '42161', '100', '1101', '43114', '8453']; +export const BalancerChainIds = ['1', '137', '42161', '100', '1101', '43114', '8453', '11155111']; export const BeethovenChainIds = ['250', '10']; export const chainToIdMap = Object.values(AllNetworkConfigs).reduce((acc, config) => { diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts new file mode 100644 index 000000000..421b587ed --- /dev/null +++ b/modules/network/sepolia.ts @@ -0,0 +1,245 @@ +import { BigNumber, ethers } from 'ethers'; +import { DeploymentEnv, NetworkConfig, NetworkData } from './network-config-types'; +import { tokenService } from '../token/token.service'; +import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; +import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; +import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; +import { GaugeAprService } from '../pool/lib/apr-data-sources/ve-bal-gauge-apr.service'; +import { GaugeStakingService } from '../pool/lib/staking/gauge-staking.service'; +import { BptPriceHandlerService } from '../token/lib/token-price-handlers/bpt-price-handler.service'; +import { LinearWrappedTokenPriceHandlerService } from '../token/lib/token-price-handlers/linear-wrapped-token-price-handler.service'; +import { SwapsPriceHandlerService } from '../token/lib/token-price-handlers/swaps-price-handler.service'; +import { UserSyncGaugeBalanceService } from '../user/lib/user-sync-gauge-balance.service'; +import { every } from '../../worker/intervals'; +import { GithubContentService } from '../content/github-content.service'; +import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; +import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; +import { coingeckoService } from '../coingecko/coingecko.service'; +import { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; +import { env } from '../../app/env'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; + +export const sepoliaNetworkData: NetworkData = { + chain: { + slug: 'sepolia', + id: 11155111, + nativeAssetAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + wrappedNativeAssetAddress: '0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9', + prismaId: 'SEPOLIA', + gqlId: 'SEPOLIA', + }, + subgraphs: { + startDate: '2021-08-23', + balancer: 'https://api.studio.thegraph.com/query/24660/balancer-sepolia-v2/version/latest', + beetsBar: 'https://', + blocks: 'https://', + gauge: 'https://api.studio.thegraph.com/query/24660/balancer-gauges-sepolia-beta/version/latest', + // veBalLocks: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gauges', + userBalances: 'https://', + }, + eth: { + address: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + addressFormatted: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + symbol: 'ETH', + name: 'Ether', + }, + weth: { + address: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', + addressFormatted: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + }, + coingecko: { + nativeAssetId: 'ethereum', + platformId: 'ethereum', + excludedTokenAddresses: [], + }, + rpcUrl: env.INFURA_API_KEY + ? `https://sepolia.infura.io/v3/${env.INFURA_API_KEY}` + : 'https://gateway.tenderly.co/public/sepolia', + rpcMaxBlockRange: 700, + protocolToken: 'bal', + bal: { + address: '0xb19382073c7A0aDdbb56Ac6AF1808Fa49e377B75', + }, + // veBal: { + // address: '0xc128a9954e6c874ea3d62ce62b468ba073093f25', + // delegationProxy: '0x81cfae226343b24ba12ec6521db2c79e7aeeb310', + // }, + balancer: { + vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v2DefaultSwapFeePercentage: '0.5', + v2DefaultYieldFeePercentage: '0.5', + vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', + v3DefaultSwapFeePercentage: '0.5', + v3DefaultYieldFeePercentage: '0.5', + }, + multicall: '0x80c7dd17b01855a6d2347444a0fcc36136a314de', + multicall3: '0xca11bde05977b3631167028862be2a173976ca11', + avgBlockSpeed: 1, + sor: { + main: { + url: 'https://uu6cfghhd5lqa7py3nojxkivd40zuugb.lambda-url.ca-central-1.on.aws/', + maxPools: 8, + forceRefresh: false, + gasPrice: BigNumber.from(10), + swapGas: BigNumber.from('1000000'), + poolIdsToExclude: [], + }, + canary: { + url: 'https://ksa66wlkjbvteijxmflqjehsay0jmekw.lambda-url.eu-central-1.on.aws/', + maxPools: 8, + forceRefresh: false, + gasPrice: BigNumber.from(10), + swapGas: BigNumber.from('1000000'), + poolIdsToExclude: [], + }, + }, + ybAprConfig: {}, + datastudio: { + main: { + user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', + sheetId: '11anHUEb9snGwvB-errb5HvO8TvoLTRJhkDdD80Gxw1Q', + databaseTabName: 'Database v2', + compositionTabName: 'Pool Composition v2', + emissionDataTabName: 'EmissionData', + }, + canary: { + user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', + sheetId: '1HnJOuRQXGy06tNgqjYMzQNIsaCSCC01Yxe_lZhXBDpY', + databaseTabName: 'Database v2', + compositionTabName: 'Pool Composition v2', + emissionDataTabName: 'EmissionData', + }, + }, + monitoring: { + main: { + alarmTopicArn: 'arn:aws:sns:ca-central-1:118697801881:api_alarms', + }, + canary: { + alarmTopicArn: 'arn:aws:sns:eu-central-1:118697801881:api_alarms', + }, + }, +}; + +export const sepoliaNetworkConfig: NetworkConfig = { + data: sepoliaNetworkData, + contentService: new GithubContentService(), + provider: new ethers.providers.JsonRpcProvider({ url: sepoliaNetworkData.rpcUrl, timeout: 60000 }), + poolAprServices: [ + new YbTokensAprService(sepoliaNetworkData.ybAprConfig, sepoliaNetworkData.chain.prismaId), + new PhantomStableAprService(sepoliaNetworkData.chain.prismaId), + new BoostedPoolAprService(), + new SwapFeeAprService(), + new GaugeAprService(tokenService, [sepoliaNetworkData.bal!.address]), + ], + poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, sepoliaNetworkData.bal!.address)], + tokenPriceHandlers: [ + new CoingeckoPriceHandlerService(coingeckoService), + new BptPriceHandlerService(), + new LinearWrappedTokenPriceHandlerService(), + new SwapsPriceHandlerService(), + ], + userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService( + sepoliaNetworkData.subgraphs.balancer, + sepoliaNetworkData.chain.id, + ), + }, + /* + For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. + This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. + + For every 1 days jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. + This is needed because the maximum alarm evaluation period is 1 day (period * evaluationPeriod). + */ + workerJobs: [ + { + name: 'update-token-prices', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(2, 'minutes'), + }, + { + name: 'update-liquidity-for-inactive-pools', + interval: every(1, 'days'), + alarmEvaluationPeriod: 1, + alarmDatapointsToAlarm: 1, + }, + { + name: 'update-liquidity-for-active-pools', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), + }, + { + name: 'update-pool-apr', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), + }, + { + name: 'load-on-chain-data-for-pools-with-active-updates', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(4, 'minutes') : every(1, 'minutes'), + }, + { + name: 'sync-new-pools-from-subgraph', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), + }, + { + name: 'sync-tokens-from-pool-tokens', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), + }, + { + name: 'update-liquidity-24h-ago-for-all-pools', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), + }, + { + name: 'cache-average-block-time', + interval: every(1, 'hours'), + }, + { + name: 'sync-staking-for-pools', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), + }, + { + name: 'sync-latest-snapshots-for-all-pools', + interval: every(90, 'minutes'), + }, + { + name: 'update-lifetime-values-for-all-pools', + interval: every(50, 'minutes'), + }, + { + name: 'sync-changed-pools', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(2, 'minutes') : every(30, 'seconds'), + alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + }, + { + name: 'user-sync-wallet-balances-for-all-pools', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(5, 'minutes') : every(20, 'seconds'), + alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + }, + { + name: 'user-sync-staked-balances', + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(5, 'minutes') : every(20, 'seconds'), + alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + }, + { + name: 'sync-coingecko-coinids', + interval: every(2, 'hours'), + }, + { + name: 'update-fee-volume-yield-all-pools', + interval: every(1, 'hours'), + }, + // { + // name: 'sync-vebal-balances', + // interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(9, 'minutes') : every(3, 'minutes'), + // }, + // { + // name: 'sync-vebal-totalSupply', + // interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), + // }, + // { + // name: 'feed-data-to-datastudio', + // interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(5, 'minutes') : every(5, 'minutes'), + // }, + ], +}; diff --git a/modules/pool/pool.prisma b/modules/pool/pool.prisma index d14e977c0..13ab76260 100644 --- a/modules/pool/pool.prisma +++ b/modules/pool/pool.prisma @@ -128,7 +128,7 @@ model PrismaPoolDynamicData { blockNumber Int updatedAt DateTime @updatedAt - protocolYieldFee String @default("0") + protocolYieldFee String? protocolSwapFee String @default("0") swapFee String swapEnabled Boolean diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index 638ebe5dd..6b3e01a1b 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -1,6 +1,6 @@ import { Chain, PrismaPoolStaking, PrismaPoolStakingType } from '@prisma/client'; import { prisma } from '../../prisma/prisma-client'; -import { GqlPoolJoinExit, GqlPoolSwap, GqlUserSnapshotDataRange } from '../../schema'; +import { GqlPoolJoinExit, GqlPoolSwap } from '../../schema'; import { PoolSwapService } from '../pool/lib/pool-swap.service'; import { tokenService } from '../token/token.service'; import { UserBalanceService } from './lib/user-balance.service'; diff --git a/prisma/base.prisma b/prisma/base.prisma index 5793c1606..7b4ef06cb 100644 --- a/prisma/base.prisma +++ b/prisma/base.prisma @@ -20,6 +20,7 @@ enum Chain { MAINNET OPTIMISM POLYGON + SEPOLIA ZKEVM } diff --git a/prisma/migrations/20240119135136_add_swapfee_and_sepolia/migration.sql b/prisma/migrations/20240119135136_add_swapfee_and_sepolia/migration.sql new file mode 100644 index 000000000..08909f873 --- /dev/null +++ b/prisma/migrations/20240119135136_add_swapfee_and_sepolia/migration.sql @@ -0,0 +1,5 @@ +-- AlterEnum +ALTER TYPE "Chain" ADD VALUE 'SEPOLIA'; + +-- AlterTable +ALTER TABLE "PrismaPoolDynamicData" ADD COLUMN "protocolSwapFee" TEXT NOT NULL DEFAULT '0'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0b6a6ed16..8a1c04992 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -22,6 +22,7 @@ enum Chain { MAINNET OPTIMISM POLYGON + SEPOLIA ZKEVM } @@ -174,7 +175,7 @@ model PrismaPoolDynamicData { blockNumber Int updatedAt DateTime @updatedAt - protocolYieldFee String @default("0") + protocolYieldFee String? protocolSwapFee String @default("0") swapFee String swapEnabled Boolean diff --git a/worker/scheduler.ts b/worker/scheduler.ts index b01095a72..fc1ff6095 100644 --- a/worker/scheduler.ts +++ b/worker/scheduler.ts @@ -5,6 +5,7 @@ import { createAlerts } from './create-alerts'; import { createMonitors } from './create-monitors'; import { sleep } from '../modules/common/promise'; import { scheduleJobs } from './job-queue'; +import { DeploymentEnv } from '../modules/network/network-config-types'; export async function startScheduler() { Sentry.init({ @@ -15,7 +16,14 @@ export async function startScheduler() { }); try { - const chainIds = env.SUPPORTED_NETWORKS ? env.SUPPORTED_NETWORKS.split(',') : Object.keys(AllNetworkConfigs); + const SEPOLIA_ID = '11155111'; + let chainIds: string[] = [SEPOLIA_ID]; + + if (env.DEPLOYMENT_ENV === 'canary' || env.DEPLOYMENT_ENV === 'main') { + // use all chains, remove sepolia + chainIds = Object.keys(AllNetworkConfigs).filter((chainId) => chainId !== SEPOLIA_ID); + } + for (const chainId of chainIds) { scheduleJobs(chainId); if (process.env.AWS_ALERTS === 'true') { From a04a6a2d7818945104413c46f37b684d154c5368 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 15:36:02 +0100 Subject: [PATCH 08/23] three chains for dev --- worker/scheduler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worker/scheduler.ts b/worker/scheduler.ts index fc1ff6095..c0bb73d2a 100644 --- a/worker/scheduler.ts +++ b/worker/scheduler.ts @@ -17,7 +17,7 @@ export async function startScheduler() { try { const SEPOLIA_ID = '11155111'; - let chainIds: string[] = [SEPOLIA_ID]; + let chainIds: string[] = [SEPOLIA_ID, '1', '10']; // sepolia, mainnet, optimism if (env.DEPLOYMENT_ENV === 'canary' || env.DEPLOYMENT_ENV === 'main') { // use all chains, remove sepolia From fd137dfb1c1dc90ef508a1ce88795cb4035e1d5d Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 15:36:54 +0100 Subject: [PATCH 09/23] sepolia blocks subgraph --- modules/network/sepolia.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts index 421b587ed..5847ed587 100644 --- a/modules/network/sepolia.ts +++ b/modules/network/sepolia.ts @@ -32,7 +32,7 @@ export const sepoliaNetworkData: NetworkData = { startDate: '2021-08-23', balancer: 'https://api.studio.thegraph.com/query/24660/balancer-sepolia-v2/version/latest', beetsBar: 'https://', - blocks: 'https://', + blocks: 'https://api.studio.thegraph.com/query/48427/bleu-sepolia-blocks/version/latest', gauge: 'https://api.studio.thegraph.com/query/24660/balancer-gauges-sepolia-beta/version/latest', // veBalLocks: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gauges', userBalances: 'https://', From 4e4cb03c38781fb980c4769d021a2402f2b04291 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 19 Jan 2024 15:38:24 +0100 Subject: [PATCH 10/23] change start date --- modules/network/sepolia.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts index 5847ed587..6ed5b07ad 100644 --- a/modules/network/sepolia.ts +++ b/modules/network/sepolia.ts @@ -29,7 +29,7 @@ export const sepoliaNetworkData: NetworkData = { gqlId: 'SEPOLIA', }, subgraphs: { - startDate: '2021-08-23', + startDate: '2023-05-03', balancer: 'https://api.studio.thegraph.com/query/24660/balancer-sepolia-v2/version/latest', beetsBar: 'https://', blocks: 'https://api.studio.thegraph.com/query/48427/bleu-sepolia-blocks/version/latest', From 12a3fceae60e729d8447d00b2db7facfd68e3151 Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 22 Jan 2024 15:55:02 +0100 Subject: [PATCH 11/23] namespace for config --- modules/network/arbitrum.ts | 16 ++++++++++------ modules/network/avalanche.ts | 16 ++++++++++------ modules/network/base.ts | 16 ++++++++++------ modules/network/fantom.ts | 16 ++++++++++------ modules/network/gnosis.ts | 16 ++++++++++------ modules/network/mainnet.ts | 19 ++++++++++++------- modules/network/network-config-types.ts | 19 ++++++++++++------- modules/network/optimism.ts | 16 ++++++++++------ modules/network/polygon.ts | 16 ++++++++++------ modules/network/sepolia.ts | 16 ++++++++++------ modules/network/zkevm.ts | 16 ++++++++++------ .../pool/lib/pool-on-chain-data.service.ts | 6 +++--- modules/pool/lib/pool-sync.service.ts | 2 +- modules/sor/balancer-sor.test.ts | 2 +- .../sor/sorV1Beets/balancer-sor.service.ts | 2 +- .../lib/user-sync-wallet-balance.service.ts | 2 +- modules/vebal/balancer-token-admin.service.ts | 2 +- 17 files changed, 122 insertions(+), 76 deletions(-) diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 2cc40b63c..3ab8838c6 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -68,12 +68,16 @@ export const arbitrumNetworkData: NetworkData = { delegationProxy: '0x81cfae226343b24ba12ec6521db2c79e7aeeb310', }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0x80c7dd17b01855a6d2347444a0fcc36136a314de', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index e8907b37f..472bb26d6 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -66,12 +66,16 @@ const avalancheNetworkData: NetworkData = { delegationProxy: '0x0c6052254551eae3ecac77b01dfcf1025418828f', }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/base.ts b/modules/network/base.ts index efe5a1250..166a9f48c 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -62,12 +62,16 @@ const baseNetworkData: NetworkData = { delegationProxy: '0xd87f44df0159dc78029ab9ca7d7e57e7249f5acd', }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, ybAprConfig: { defaultHandlers: { diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 718bd50b1..a7e504462 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -114,12 +114,16 @@ const fantomNetworkData: NetworkData = { poolAddress: '0xcde5a11a4acb4ee4c805352cec57e236bdbc3837', }, balancer: { - vaultV2Address: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', - v2DefaultSwapFeePercentage: '0.25', - v2DefaultYieldFeePercentage: '0.25', - vaultV3Address: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', - v3DefaultSwapFeePercentage: '0.25', - v3DefaultYieldFeePercentage: '0.25', + v2: { + vaultAddress: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0x66335d7ad8011f6aa3f48aadcb523b62b38ed961', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index e0f7a6f16..2aeb92d9e 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -64,12 +64,16 @@ const gnosisNetworkData: NetworkData = { delegationProxy: '0x7a2535f5fb47b8e44c02ef5d9990588313fe8f05', }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0xbb6fab6b627947dae0a75808250d8b2652952cb5', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index dbd2a0578..b977001df 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -82,13 +82,18 @@ const data: NetworkData = { config: '0xac89cc9d78bbad7eb3a02601b4d65daa1f908aa6', }, balancer: { - tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + tokenAdmin: '0xf302f9f50958c5593770fdf4d4812309ff77414f', + }, }, multicall: '0x5ba1e12693dc8f9c48aad8770482f4739beed696', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index fac23e02d..d8d7506d7 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -102,13 +102,18 @@ export interface NetworkData { config: string; }; balancer: { - vaultV2Address: string; - v2DefaultSwapFeePercentage: string; - v2DefaultYieldFeePercentage: string; - vaultV3Address: string; - v3DefaultSwapFeePercentage: string; - v3DefaultYieldFeePercentage: string; - tokenAdmin?: string; + v2: { + vaultAddress: string; + defaultSwapFeePercentage: string; + defaultYieldFeePercentage: string; + tokenAdmin?: string; + }; + v3: { + vaultAddress: string; + defaultSwapFeePercentage: string; + defaultYieldFeePercentage: string; + tokenAdmin?: string; + }; }; multicall: string; multicall3: string; diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 68c567cc2..184b83a87 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -73,12 +73,16 @@ const optimismNetworkData: NetworkData = { config: '0x32acb44fc929339b9f16f0449525cc590d2a23f3', }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0x2dc0e2aa608532da689e89e237df582b783e552c', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 9f97bb7e6..a15be06fb 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -68,12 +68,16 @@ const polygonNetworkData: NetworkData = { config: '0xfdc2e9e03f515804744a40d0f8d25c16e93fbe67', }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0x275617327c958bd06b5d6b871e7f491d76113dd8', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts index 6ed5b07ad..2f36679aa 100644 --- a/modules/network/sepolia.ts +++ b/modules/network/sepolia.ts @@ -65,12 +65,16 @@ export const sepoliaNetworkData: NetworkData = { // delegationProxy: '0x81cfae226343b24ba12ec6521db2c79e7aeeb310', // }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0x80c7dd17b01855a6d2347444a0fcc36136a314de', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 2732e83f2..8c82e27e9 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -66,12 +66,16 @@ const zkevmNetworkData: NetworkData = { delegationProxy: '0xc7e5ed1054a24ef31d827e6f86caa58b3bc168d7', }, balancer: { - vaultV2Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v2DefaultSwapFeePercentage: '0.5', - v2DefaultYieldFeePercentage: '0.5', - vaultV3Address: '0xba12222222228d8ba445958a75a0704d566bf2c8', - v3DefaultSwapFeePercentage: '0.5', - v3DefaultYieldFeePercentage: '0.5', + v2: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, + v3: { + vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + defaultSwapFeePercentage: '0.5', + defaultYieldFeePercentage: '0.5', + }, }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/pool/lib/pool-on-chain-data.service.ts b/modules/pool/lib/pool-on-chain-data.service.ts index 11e43a46d..4371ffbd5 100644 --- a/modules/pool/lib/pool-on-chain-data.service.ts +++ b/modules/pool/lib/pool-on-chain-data.service.ts @@ -31,9 +31,9 @@ export class PoolOnChainDataService { private get options() { return { chain: networkContext.chain, - vaultAddress: networkContext.data.balancer.vaultV2Address, - yieldProtocolFeePercentage: networkContext.data.balancer.v2DefaultYieldFeePercentage, - swapProtocolFeePercentage: networkContext.data.balancer.v2DefaultSwapFeePercentage, + vaultAddress: networkContext.data.balancer.v2.vaultAddress, + yieldProtocolFeePercentage: networkContext.data.balancer.v2.defaultSwapFeePercentage, + swapProtocolFeePercentage: networkContext.data.balancer.v2.defaultSwapFeePercentage, gyroConfig: networkContext.data.gyro?.config, }; } diff --git a/modules/pool/lib/pool-sync.service.ts b/modules/pool/lib/pool-sync.service.ts index 31615575a..43e94c5d7 100644 --- a/modules/pool/lib/pool-sync.service.ts +++ b/modules/pool/lib/pool-sync.service.ts @@ -20,7 +20,7 @@ export class PoolSyncService { } get vaultAddress() { - return networkContext.data.balancer.vaultV2Address; + return networkContext.data.balancer.v2.vaultAddress; } get rpcUrl() { diff --git a/modules/sor/balancer-sor.test.ts b/modules/sor/balancer-sor.test.ts index 0a7261f9e..3154ac27d 100644 --- a/modules/sor/balancer-sor.test.ts +++ b/modules/sor/balancer-sor.test.ts @@ -1,4 +1,4 @@ -import { BalancerSorService } from './balancer-sor.service'; +import { BalancerSorService } from './sorV1Beets/balancer-sor.service'; import { tokenService } from '../token/token.service'; import { poolService } from '../pool/pool.service'; diff --git a/modules/sor/sorV1Beets/balancer-sor.service.ts b/modules/sor/sorV1Beets/balancer-sor.service.ts index 7c2960993..8388cf743 100644 --- a/modules/sor/sorV1Beets/balancer-sor.service.ts +++ b/modules/sor/sorV1Beets/balancer-sor.service.ts @@ -320,7 +320,7 @@ export class BalancerSorService { private queryBatchSwap(swapType: SwapTypes, swaps: SwapV2[], assets: string[]): Promise { const vaultContract = new Contract( - networkContext.data.balancer.vaultV2Address, + networkContext.data.balancer.v2.vaultAddress, VaultAbi, networkContext.provider, ); diff --git a/modules/user/lib/user-sync-wallet-balance.service.ts b/modules/user/lib/user-sync-wallet-balance.service.ts index 1a5ec9fd0..9dfb59284 100644 --- a/modules/user/lib/user-sync-wallet-balance.service.ts +++ b/modules/user/lib/user-sync-wallet-balance.service.ts @@ -42,7 +42,7 @@ export class UserSyncWalletBalanceService { } get vaultAddress() { - return AllNetworkConfigs[this.chainId].data.balancer.vaultV2Address; + return AllNetworkConfigs[this.chainId].data.balancer.v2.vaultAddress; } get fbeetsAddress() { diff --git a/modules/vebal/balancer-token-admin.service.ts b/modules/vebal/balancer-token-admin.service.ts index 9fb51ad96..b058f2842 100644 --- a/modules/vebal/balancer-token-admin.service.ts +++ b/modules/vebal/balancer-token-admin.service.ts @@ -5,7 +5,7 @@ import { networkContext } from '../network/network-context.service'; export async function getInflationRate(): Promise { if (networkContext.isMainnet) { - const tokenAdmin = new Contract(networkContext.data.balancer.tokenAdmin!, abi, networkContext.provider); + const tokenAdmin = new Contract(networkContext.data.balancer.v2.tokenAdmin!, abi, networkContext.provider); const inflationRate = await tokenAdmin.getInflationRate(); return inflationRate; } else { From 7e14c276325603d7cf84613e86131f31c20964f0 Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 22 Jan 2024 18:32:10 +0100 Subject: [PATCH 12/23] slight change --- worker/scheduler.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worker/scheduler.ts b/worker/scheduler.ts index c0bb73d2a..bde8ff178 100644 --- a/worker/scheduler.ts +++ b/worker/scheduler.ts @@ -17,11 +17,14 @@ export async function startScheduler() { try { const SEPOLIA_ID = '11155111'; - let chainIds: string[] = [SEPOLIA_ID, '1', '10']; // sepolia, mainnet, optimism + let chainIds = []; if (env.DEPLOYMENT_ENV === 'canary' || env.DEPLOYMENT_ENV === 'main') { // use all chains, remove sepolia chainIds = Object.keys(AllNetworkConfigs).filter((chainId) => chainId !== SEPOLIA_ID); + } else { + // if not canary nor main, must be dev + chainIds = [SEPOLIA_ID, '1', '10']; // sepolia, mainnet, optimism } for (const chainId of chainIds) { From 57ed1e0b6f57ce471294c3ba27908918d8a0a4dd Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 22 Jan 2024 20:13:18 +0100 Subject: [PATCH 13/23] adding placeholder crons --- modules/pool/pool.service.ts | 25 +++++++++++++++++- worker/job-handlers.ts | 50 +++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 7cd8eb9ac..ef91a0fcf 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -39,7 +39,6 @@ import { ReliquarySnapshotService } from './lib/reliquary-snapshot.service'; import { ContentService } from '../content/content-types'; export class PoolService { - private cache = new Cache(); constructor( private readonly poolCreatorService: PoolCreatorService, private readonly poolOnChainDataService: PoolOnChainDataService, @@ -460,6 +459,30 @@ export class PoolService { where: { id_chain: { id: poolId, chain: this.chain } }, }); } + + public async syncChangedPoolsV3() { + throw new Error('Method not implemented.'); + } + + public async loadOnChainDataForPoolsWithActiveUpdatesV3() { + throw new Error('Method not implemented.'); + } + + public async syncNewPoolsFromSubgraphV3() { + throw new Error('Method not implemented.'); + } + + public async updateLiquidity24hAgoForAllPoolsV3() { + throw new Error('Method not implemented.'); + } + + public async syncLatestSnapshotsForAllPoolsV3() { + throw new Error('Method not implemented.'); + } + + public async updateLifetimeValuesForAllPoolsV3() { + throw new Error('Method not implemented.'); + } } export const poolService = new PoolService( diff --git a/worker/job-handlers.ts b/worker/job-handlers.ts index 82ee33dbf..06a54a168 100644 --- a/worker/job-handlers.ts +++ b/worker/job-handlers.ts @@ -103,6 +103,10 @@ export function configureWorkerRoutes(app: Express) { case 'sync-changed-pools': await runIfNotAlreadyRunning(job.name, chainId, () => poolService.syncChangedPools(), res, next); break; + + case 'sync-changed-pools-v3': + await runIfNotAlreadyRunning(job.name, chainId, () => poolService.syncChangedPoolsV3(), res, next); + break; case 'user-sync-wallet-balances-for-all-pools': await runIfNotAlreadyRunning( job.name, @@ -123,7 +127,6 @@ export function configureWorkerRoutes(app: Express) { break; case 'update-token-prices': await runIfNotAlreadyRunning(job.name, chainId, () => tokenService.updateTokenPrices(), res, next); - break; case 'update-liquidity-for-active-pools': await runIfNotAlreadyRunning( @@ -155,6 +158,15 @@ export function configureWorkerRoutes(app: Express) { next, ); break; + case 'load-on-chain-data-for-pools-with-active-updates-v3': + await runIfNotAlreadyRunning( + job.name, + chainId, + () => poolService.loadOnChainDataForPoolsWithActiveUpdatesV3(), + res, + next, + ); + break; case 'sync-new-pools-from-subgraph': await runIfNotAlreadyRunning( job.name, @@ -164,6 +176,15 @@ export function configureWorkerRoutes(app: Express) { next, ); break; + case 'sync-new-pools-from-subgraph-v3': + await runIfNotAlreadyRunning( + job.name, + chainId, + () => poolService.syncNewPoolsFromSubgraphV3(), + res, + next, + ); + break; case 'sync-sanity-pool-data': await runIfNotAlreadyRunning(job.name, chainId, () => poolService.syncPoolContentData(), res, next); break; @@ -179,6 +200,15 @@ export function configureWorkerRoutes(app: Express) { next, ); break; + case 'update-liquidity-24h-ago-for-all-pools-v3': + await runIfNotAlreadyRunning( + job.name, + chainId, + () => poolService.updateLiquidity24hAgoForAllPoolsV3(), + res, + next, + ); + break; case 'cache-average-block-time': await runIfNotAlreadyRunning( job.name, @@ -218,6 +248,15 @@ export function configureWorkerRoutes(app: Express) { next, ); break; + case 'sync-latest-snapshots-for-all-pools-v3': + await runIfNotAlreadyRunning( + job.name, + chainId, + () => poolService.syncLatestSnapshotsForAllPoolsV3(), + res, + next, + ); + break; case 'update-lifetime-values-for-all-pools': await runIfNotAlreadyRunning( job.name, @@ -227,6 +266,15 @@ export function configureWorkerRoutes(app: Express) { next, ); break; + case 'update-lifetime-values-for-all-pools-v3': + await runIfNotAlreadyRunning( + job.name, + chainId, + () => poolService.updateLifetimeValuesForAllPoolsV3(), + res, + next, + ); + break; case 'feed-data-to-datastudio': await runIfNotAlreadyRunning(job.name, chainId, () => datastudioService.feedPoolData(), res, next); break; From df91ccbfd9fddcbb096cbcd1fcc041d683a1fb3f Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 23 Jan 2024 11:43:43 +0100 Subject: [PATCH 14/23] add v3 vault address --- modules/network/sepolia.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts index 2f36679aa..45be46186 100644 --- a/modules/network/sepolia.ts +++ b/modules/network/sepolia.ts @@ -71,7 +71,7 @@ export const sepoliaNetworkData: NetworkData = { defaultYieldFeePercentage: '0.5', }, v3: { - vaultAddress: '0xba12222222228d8ba445958a75a0704d566bf2c8', + vaultAddress: '0x816e90DC85bF016455017a76Bc09CC0451Eeb308', defaultSwapFeePercentage: '0.5', defaultYieldFeePercentage: '0.5', }, From 0c7dcea1fd7475a28201585a7fe449712003d4db Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 23 Jan 2024 11:47:29 +0100 Subject: [PATCH 15/23] scale stern apr --- modules/network/optimism.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 2faa94d8f..bdfc07dfa 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -209,6 +209,7 @@ const optimismNetworkData: NetworkData = { sourceUrl: 'https://2ch9hbg8hh.execute-api.us-east-1.amazonaws.com/dev/api/vault/0x3eE6107d9C93955acBb3f39871D32B02F82B78AB:0xa', path: 'data.yields.apy', + scale: 1, isIbYield: true, }, ankrETH: { From b28d1067a66aadd6c29febd01768f3c1bf8534d6 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Tue, 23 Jan 2024 12:38:16 +0100 Subject: [PATCH 16/23] truMatic APR --- modules/network/polygon.ts | 7 +++++++ .../lib/apr-data-sources/yb-apr-handlers/sources/index.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index ae8f88d55..5157381df 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -214,6 +214,13 @@ const polygonNetworkData: NetworkData = { path: 'data.0.rewardRate', isIbYield: true, }, + truMATIC: { + tokenAddress: '0xf33687811f3ad0cd6b48dd4b39f9f977bd7165a2', + sourceUrl: 'https://api.trufin.io/staker/apy?staker=MATIC', + path: 'apy', + scale: 100, + isIbYield: true, + }, }, }, beefy: { diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts index 74bb6844d..692ef4b6b 100644 --- a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts @@ -1,6 +1,6 @@ +export * from './default-apr-handler'; export * from './aave-apr-handler'; export * from './sftmx-apr-handler'; -export * from './default-apr-handler'; export * from './euler-apr-handler'; export * from './gearbox-apr-handler'; export * from './idle-apr-handler'; From 44e470e602cb20694cf240f996a3fa36d4c37ec0 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:00:16 +0100 Subject: [PATCH 17/23] PoolDynamicData indexes --- modules/pool/pool.prisma | 5 +++++ .../20240123115918_dynamic_data_indexes/migration.sql | 11 +++++++++++ prisma/schema.prisma | 5 +++++ 3 files changed, 21 insertions(+) create mode 100644 prisma/migrations/20240123115918_dynamic_data_indexes/migration.sql diff --git a/modules/pool/pool.prisma b/modules/pool/pool.prisma index e9189664e..f7a974642 100644 --- a/modules/pool/pool.prisma +++ b/modules/pool/pool.prisma @@ -118,6 +118,11 @@ model PrismaPoolGyroData{ model PrismaPoolDynamicData { @@id([id, chain]) @@unique([poolId, chain]) + // Indexes used for sorting pools in the UI by different metrics + @@index(totalLiquidity) + @@index(totalShares) + @@index(volume24h) + @@index(apr) id String poolId String diff --git a/prisma/migrations/20240123115918_dynamic_data_indexes/migration.sql b/prisma/migrations/20240123115918_dynamic_data_indexes/migration.sql new file mode 100644 index 000000000..0fc74b6c1 --- /dev/null +++ b/prisma/migrations/20240123115918_dynamic_data_indexes/migration.sql @@ -0,0 +1,11 @@ +-- CreateIndex +CREATE INDEX "PrismaPoolDynamicData_totalLiquidity_idx" ON "PrismaPoolDynamicData"("totalLiquidity"); + +-- CreateIndex +CREATE INDEX "PrismaPoolDynamicData_totalShares_idx" ON "PrismaPoolDynamicData"("totalShares"); + +-- CreateIndex +CREATE INDEX "PrismaPoolDynamicData_volume24h_idx" ON "PrismaPoolDynamicData"("volume24h"); + +-- CreateIndex +CREATE INDEX "PrismaPoolDynamicData_apr_idx" ON "PrismaPoolDynamicData"("apr"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 02648160e..93660db29 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -164,6 +164,11 @@ model PrismaPoolGyroData{ model PrismaPoolDynamicData { @@id([id, chain]) @@unique([poolId, chain]) + // Indexes used for sorting pools in the UI by different metrics + @@index(totalLiquidity) + @@index(totalShares) + @@index(volume24h) + @@index(apr) id String poolId String From fe8e18547bbcf61d294f301fe9b176fc20d6e047 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 23 Jan 2024 16:25:11 +0100 Subject: [PATCH 18/23] add v3 abi, combined vault and vault extension --- modules/pool/abi/VaultV3.json | 3401 +++++++++++++++++++++++++++++++++ 1 file changed, 3401 insertions(+) create mode 100644 modules/pool/abi/VaultV3.json diff --git a/modules/pool/abi/VaultV3.json b/modules/pool/abi/VaultV3.json new file mode 100644 index 000000000..2e0ae17c0 --- /dev/null +++ b/modules/pool/abi/VaultV3.json @@ -0,0 +1,3401 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVaultExtension", + "name": "vaultExtension", + "type": "address" + }, + { + "internalType": "contract IAuthorizer", + "name": "authorizer", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "AllZeroInputs", + "type": "error" + }, + { + "inputs": [], + "name": "AmountGivenZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "AmountInAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "AmountOutBelowMin", + "type": "error" + }, + { + "inputs": [], + "name": "BalanceNotSettled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "BptAmountInAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "BptAmountOutBelowMin", + "type": "error" + }, + { + "inputs": [], + "name": "CallbackFailed", + "type": "error" + }, + { + "inputs": [], + "name": "CannotReceiveEth", + "type": "error" + }, + { + "inputs": [], + "name": "CannotSwapSameToken", + "type": "error" + }, + { + "inputs": [], + "name": "DoesNotSupportAddLiquidityCustom", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "HandlerOutOfBounds", + "type": "error" + }, + { + "inputs": [], + "name": "InputLengthMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidAddLiquidityKind", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidRemoveLiquidityKind", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidToken", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenConfiguration", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenType", + "type": "error" + }, + { + "inputs": [], + "name": "MaxTokens", + "type": "error" + }, + { + "inputs": [], + "name": "MinTokens", + "type": "error" + }, + { + "inputs": [], + "name": "MultipleNonZeroInputs", + "type": "error" + }, + { + "inputs": [], + "name": "NoHandler", + "type": "error" + }, + { + "inputs": [], + "name": "NotStaticCall", + "type": "error" + }, + { + "inputs": [], + "name": "NotVaultDelegateCall", + "type": "error" + }, + { + "inputs": [], + "name": "PauseBufferPeriodDurationTooLarge", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolAlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolAlreadyRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolInRecoveryMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotInRecoveryMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolPauseWindowExpired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolPaused", + "type": "error" + }, + { + "inputs": [], + "name": "ProtocolSwapFeePercentageTooHigh", + "type": "error" + }, + { + "inputs": [], + "name": "QueriesDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [], + "name": "RouterNotTrusted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintToInt", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "SenderIsNotPauseManager", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "SenderIsNotVault", + "type": "error" + }, + { + "inputs": [], + "name": "SwapFeePercentageTooHigh", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "TokenAlreadyRegistered", + "type": "error" + }, + { + "inputs": [], + "name": "TokenNotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "expectedToken", + "type": "address" + }, + { + "internalType": "address", + "name": "actualToken", + "type": "address" + } + ], + "name": "TokensMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "TotalSupplyTooLow", + "type": "error" + }, + { + "inputs": [], + "name": "UserDataNotSupported", + "type": "error" + }, + { + "inputs": [], + "name": "VaultNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPauseWindowDurationTooLarge", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPauseWindowExpired", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "handler", + "type": "address" + }, + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "WrongHandler", + "type": "error" + }, + { + "inputs": [], + "name": "WrongVaultExtensionDeployment", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroDivision", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IAuthorizer", + "name": "newAuthorizer", + "type": "address" + } + ], + "name": "AuthorizerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "liquidityProvider", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "int256[]", + "name": "deltas", + "type": "int256[]" + } + ], + "name": "PoolBalanceChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolInitialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "PoolPausedStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "recoveryMode", + "type": "bool" + } + ], + "name": "PoolRecoveryModeStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "enum TokenType", + "name": "tokenType", + "type": "uint8" + }, + { + "internalType": "contract IRateProvider", + "name": "rateProvider", + "type": "address" + }, + { + "internalType": "bool", + "name": "yieldFeeExempt", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct TokenConfig[]", + "name": "tokenConfig", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "pauseManager", + "type": "address" + }, + { + "components": [ + { + "internalType": "bool", + "name": "shouldCallBeforeInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterRemoveLiquidity", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct PoolCallbacks", + "name": "callbacks", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "supportsAddLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "supportsRemoveLiquidityCustom", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct LiquidityManagement", + "name": "liquidityManagement", + "type": "tuple" + } + ], + "name": "PoolRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProtocolFeeCollected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + } + ], + "name": "ProtocolSwapFeePercentageChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "swapFeeAmount", + "type": "uint256" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "VaultPausedStateChanged", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "MAX_BUFFER_PERIOD_DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_PAUSE_WINDOW_DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "enum AddLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct AddLiquidityParams", + "name": "params", + "type": "tuple" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getVaultExtension", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "invoke", + "outputs": [ + { + "internalType": "bytes", + "name": "result", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxBptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "enum RemoveLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct RemoveLiquidityParams", + "name": "params", + "type": "tuple" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + } + ], + "name": "removeLiquidityRecovery", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOutRaw", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "retrieve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "settle", + "outputs": [ + { + "internalType": "uint256", + "name": "paid", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountGivenRaw", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct SwapParams", + "name": "params", + "type": "tuple" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "uint256", + "name": "amountCalculated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "wire", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + + "inputs": [ + { + "internalType": "contract IVault", + "name": "mainVault", + "type": "address" + }, + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "AmountGivenZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "AmountInAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "AmountOutBelowMin", + "type": "error" + }, + { + "inputs": [], + "name": "BalanceNotSettled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "BptAmountInAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "BptAmountOutBelowMin", + "type": "error" + }, + { + "inputs": [], + "name": "CallbackFailed", + "type": "error" + }, + { + "inputs": [], + "name": "CannotReceiveEth", + "type": "error" + }, + { + "inputs": [], + "name": "CannotSwapSameToken", + "type": "error" + }, + { + "inputs": [], + "name": "CodecOverflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "HandlerOutOfBounds", + "type": "error" + }, + { + "inputs": [], + "name": "InputLengthMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidAddLiquidityKind", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidRemoveLiquidityKind", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidToken", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenConfiguration", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenType", + "type": "error" + }, + { + "inputs": [], + "name": "MaxTokens", + "type": "error" + }, + { + "inputs": [], + "name": "MinTokens", + "type": "error" + }, + { + "inputs": [], + "name": "NoHandler", + "type": "error" + }, + { + "inputs": [], + "name": "NotStaticCall", + "type": "error" + }, + { + "inputs": [], + "name": "NotVaultDelegateCall", + "type": "error" + }, + { + "inputs": [], + "name": "OutOfBounds", + "type": "error" + }, + { + "inputs": [], + "name": "PauseBufferPeriodDurationTooLarge", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolAlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolAlreadyRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolInRecoveryMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotInRecoveryMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolPauseWindowExpired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolPaused", + "type": "error" + }, + { + "inputs": [], + "name": "ProtocolSwapFeePercentageTooHigh", + "type": "error" + }, + { + "inputs": [], + "name": "QueriesDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [], + "name": "RouterNotTrusted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintToInt", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "SenderIsNotPauseManager", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "SenderIsNotVault", + "type": "error" + }, + { + "inputs": [], + "name": "SenderNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "SwapFeePercentageTooHigh", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "TokenAlreadyRegistered", + "type": "error" + }, + { + "inputs": [], + "name": "TokenNotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "expectedToken", + "type": "address" + }, + { + "internalType": "address", + "name": "actualToken", + "type": "address" + } + ], + "name": "TokensMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "TotalSupplyTooLow", + "type": "error" + }, + { + "inputs": [], + "name": "UserDataNotSupported", + "type": "error" + }, + { + "inputs": [], + "name": "VaultNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPauseWindowDurationTooLarge", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPauseWindowExpired", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "handler", + "type": "address" + }, + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "WrongHandler", + "type": "error" + }, + { + "inputs": [], + "name": "WrongVaultExtensionDeployment", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IAuthorizer", + "name": "newAuthorizer", + "type": "address" + } + ], + "name": "AuthorizerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "liquidityProvider", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "int256[]", + "name": "deltas", + "type": "int256[]" + } + ], + "name": "PoolBalanceChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolInitialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "PoolPausedStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "recoveryMode", + "type": "bool" + } + ], + "name": "PoolRecoveryModeStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "enum TokenType", + "name": "tokenType", + "type": "uint8" + }, + { + "internalType": "contract IRateProvider", + "name": "rateProvider", + "type": "address" + }, + { + "internalType": "bool", + "name": "yieldFeeExempt", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct TokenConfig[]", + "name": "tokenConfig", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "pauseManager", + "type": "address" + }, + { + "components": [ + { + "internalType": "bool", + "name": "shouldCallBeforeInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterRemoveLiquidity", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct PoolCallbacks", + "name": "callbacks", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "supportsAddLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "supportsRemoveLiquidityCustom", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct LiquidityManagement", + "name": "liquidityManagement", + "type": "tuple" + } + ], + "name": "PoolRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProtocolFeeCollected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + } + ], + "name": "ProtocolSwapFeePercentageChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + } + ], + "name": "SwapFeePercentageChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "VaultPausedStateChanged", + "type": "event" + }, + { + "inputs": [], + "name": "MAX_BUFFER_PERIOD_DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_PAUSE_WINDOW_DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "collectProtocolFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableQuery", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "disableRecoveryMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "enableRecoveryMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBufferPeriodDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBufferPeriodEndTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getHandler", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getHandlersCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMaximumPoolTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "getMinimumPoolTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "getNonzeroDeltaCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseWindowEndTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isPoolRegistered", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPoolInitialized", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPoolPaused", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPoolInRecoveryMode", + "type": "bool" + }, + { + "internalType": "bool", + "name": "hasDynamicSwapFee", + "type": "bool" + }, + { + "internalType": "uint64", + "name": "staticSwapFeePercentage", + "type": "uint64" + }, + { + "internalType": "uint24", + "name": "tokenDecimalDiffs", + "type": "uint24" + }, + { + "internalType": "uint32", + "name": "pauseWindowEndTime", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "shouldCallBeforeInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterRemoveLiquidity", + "type": "bool" + } + ], + "internalType": "struct PoolCallbacks", + "name": "callbacks", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "supportsAddLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "supportsRemoveLiquidityCustom", + "type": "bool" + } + ], + "internalType": "struct LiquidityManagement", + "name": "liquidityManagement", + "type": "tuple" + } + ], + "internalType": "struct PoolConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolPausedState", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getPoolTokenCountAndIndexOfToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolTokenInfo", + "outputs": [ + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "enum TokenType[]", + "name": "tokenTypes", + "type": "uint8[]" + }, + { + "internalType": "uint256[]", + "name": "balancesRaw", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "decimalScalingFactors", + "type": "uint256[]" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolTokenRates", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolTokens", + "outputs": [ + { + "internalType": "contract IERC20[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "getProtocolSwapFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolSwapFeePercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getStaticSwapFeePercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getTokenDelta", + "outputs": [ + { + "internalType": "int256", + "name": "", + "type": "int256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getTokenReserve", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVaultPausedState", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "exactAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolInRecoveryMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolRegistered", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isQueryDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isVaultPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "pausePool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pauseVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "bytes", + "name": "result", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "enum TokenType", + "name": "tokenType", + "type": "uint8" + }, + { + "internalType": "contract IRateProvider", + "name": "rateProvider", + "type": "address" + }, + { + "internalType": "bool", + "name": "yieldFeeExempt", + "type": "bool" + } + ], + "internalType": "struct TokenConfig[]", + "name": "tokenConfig", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "address", + "name": "pauseManager", + "type": "address" + }, + { + "components": [ + { + "internalType": "bool", + "name": "shouldCallBeforeInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterRemoveLiquidity", + "type": "bool" + } + ], + "internalType": "struct PoolCallbacks", + "name": "poolCallbacks", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "supportsAddLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "supportsRemoveLiquidityCustom", + "type": "bool" + } + ], + "internalType": "struct LiquidityManagement", + "name": "liquidityManagement", + "type": "tuple" + } + ], + "name": "registerPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IAuthorizer", + "name": "newAuthorizer", + "type": "address" + } + ], + "name": "setAuthorizer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newProtocolSwapFeePercentage", + "type": "uint256" + } + ], + "name": "setProtocolSwapFeePercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + } + ], + "name": "setStaticSwapFeePercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "unpausePool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpauseVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file From cac7024d1d5d769db4cb53321ce606320a2c4832 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 23 Jan 2024 16:38:34 +0100 Subject: [PATCH 19/23] mainnet crons to prod level --- modules/network/mainnet.ts | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index b862ed02f..b481fc636 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -407,27 +407,27 @@ export const mainnetNetworkConfig: NetworkConfig = { }, { name: 'update-liquidity-for-active-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(8, 'minutes') : every(4, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), }, { name: 'update-pool-apr', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(7, 'minutes') : every(5, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), }, { name: 'load-on-chain-data-for-pools-with-active-updates', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(9, 'minutes') : every(5, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(4, 'minutes') : every(1, 'minutes'), }, { name: 'sync-new-pools-from-subgraph', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(12, 'minutes') : every(8, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), }, { name: 'sync-tokens-from-pool-tokens', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(7, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, { name: 'update-liquidity-24h-ago-for-all-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(15, 'minutes') : every(8, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, { name: 'cache-average-block-time', @@ -435,7 +435,7 @@ export const mainnetNetworkConfig: NetworkConfig = { }, { name: 'sync-staking-for-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(15, 'minutes') : every(10, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, { name: 'sync-latest-snapshots-for-all-pools', @@ -443,21 +443,25 @@ export const mainnetNetworkConfig: NetworkConfig = { }, { name: 'update-lifetime-values-for-all-pools', - interval: every(45, 'minutes'), + interval: every(50, 'minutes'), }, { name: 'sync-changed-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(2, 'minutes') : every(1, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(2, 'minutes') : every(30, 'seconds'), alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, }, { name: 'user-sync-wallet-balances-for-all-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(29, 'minutes') : every(9, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(5, 'minutes') : every(20, 'seconds'), + alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, }, { name: 'user-sync-staked-balances', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(31, 'minutes') : every(11, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(5, 'minutes') : every(20, 'seconds'), + alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, }, { name: 'sync-coingecko-coinids', @@ -465,15 +469,15 @@ export const mainnetNetworkConfig: NetworkConfig = { }, { name: 'update-fee-volume-yield-all-pools', - interval: every(75, 'minutes'), + interval: every(1, 'hours'), }, { name: 'sync-vebal-balances', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(20, 'minutes') : every(14, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(9, 'minutes') : every(3, 'minutes'), }, { name: 'sync-vebal-totalSupply', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(20, 'minutes') : every(16, 'minutes'), + interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, { name: 'sync-vebal-voting-gauges', From 855f20380f1ff591157aa4ce3c66eba43ecd27ce Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 24 Jan 2024 15:04:31 +0100 Subject: [PATCH 20/23] fix subgraph --- modules/network/sepolia.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts index 45be46186..05a02c24b 100644 --- a/modules/network/sepolia.ts +++ b/modules/network/sepolia.ts @@ -33,7 +33,7 @@ export const sepoliaNetworkData: NetworkData = { balancer: 'https://api.studio.thegraph.com/query/24660/balancer-sepolia-v2/version/latest', beetsBar: 'https://', blocks: 'https://api.studio.thegraph.com/query/48427/bleu-sepolia-blocks/version/latest', - gauge: 'https://api.studio.thegraph.com/query/24660/balancer-gauges-sepolia-beta/version/latest', + gauge: 'https://api.studio.thegraph.com/proxy/24660/balancer-gauges-sepolia/version/latest', // veBalLocks: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gauges', userBalances: 'https://', }, From 98ddc253994eccf1b0828bc8bd14cd9cabee186d Mon Sep 17 00:00:00 2001 From: franzns <93920061+franzns@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:30:27 +0100 Subject: [PATCH 21/23] Dev fix (#74) * higher intervals for polygon * reduce some crons on dev for mainnet --- modules/network/mainnet.ts | 15 +++++++++++++-- modules/network/sepolia.ts | 38 ++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index f3bd2754e..e34694e85 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -482,9 +482,15 @@ export const mainnetNetworkConfig: NetworkConfig = { name: 'sync-vebal-totalSupply', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, + // this does not work on dev because we don't sync all chains on dev. Hence we only sync it rarely as it produces a lot of errors { name: 'sync-vebal-voting-gauges', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(20, 'minutes') : every(5, 'minutes'), + interval: + (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' + ? every(20, 'minutes') + : (env.DEPLOYMENT_ENV as DeploymentEnv) === 'main' + ? every(5, 'minutes') + : every(10, 'days'), }, { name: 'feed-data-to-datastudio', @@ -497,7 +503,12 @@ export const mainnetNetworkConfig: NetworkConfig = { // The following are multichain jobs and should only run once for all chains. { name: 'sync-global-coingecko-prices', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(2, 'minutes'), + interval: + (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' + ? every(10, 'minutes') + : (env.DEPLOYMENT_ENV as DeploymentEnv) === 'main' + ? every(2, 'minutes') + : every(10, 'days'), }, { name: 'global-purge-old-tokenprices', diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts index 05a02c24b..5154078df 100644 --- a/modules/network/sepolia.ts +++ b/modules/network/sepolia.ts @@ -137,7 +137,7 @@ export const sepoliaNetworkConfig: NetworkConfig = { ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, sepoliaNetworkData.bal!.address)], tokenPriceHandlers: [ - new CoingeckoPriceHandlerService(coingeckoService), + // new CoingeckoPriceHandlerService(coingeckoService), new BptPriceHandlerService(), new LinearWrappedTokenPriceHandlerService(), new SwapsPriceHandlerService(), @@ -159,7 +159,7 @@ export const sepoliaNetworkConfig: NetworkConfig = { workerJobs: [ { name: 'update-token-prices', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(2, 'minutes'), + interval: every(15, 'minutes'), }, { name: 'update-liquidity-for-inactive-pools', @@ -169,27 +169,27 @@ export const sepoliaNetworkConfig: NetworkConfig = { }, { name: 'update-liquidity-for-active-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), + interval: every(10, 'minutes'), }, { name: 'update-pool-apr', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), + interval: every(10, 'minutes'), }, { name: 'load-on-chain-data-for-pools-with-active-updates', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(4, 'minutes') : every(1, 'minutes'), + interval: every(10, 'minutes'), }, { name: 'sync-new-pools-from-subgraph', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), + interval: every(10, 'minutes'), }, { name: 'sync-tokens-from-pool-tokens', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), + interval: every(10, 'minutes'), }, { name: 'update-liquidity-24h-ago-for-all-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), + interval: every(10, 'minutes'), }, { name: 'cache-average-block-time', @@ -197,7 +197,7 @@ export const sepoliaNetworkConfig: NetworkConfig = { }, { name: 'sync-staking-for-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), + interval: every(10, 'minutes'), }, { name: 'sync-latest-snapshots-for-all-pools', @@ -209,26 +209,20 @@ export const sepoliaNetworkConfig: NetworkConfig = { }, { name: 'sync-changed-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(2, 'minutes') : every(30, 'seconds'), - alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, - alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + interval: every(5, 'minutes'), }, { name: 'user-sync-wallet-balances-for-all-pools', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(5, 'minutes') : every(20, 'seconds'), - alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, - alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, + interval: every(5, 'minutes'), }, { name: 'user-sync-staked-balances', - interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(5, 'minutes') : every(20, 'seconds'), - alarmEvaluationPeriod: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, - alarmDatapointsToAlarm: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? 3 : 1, - }, - { - name: 'sync-coingecko-coinids', - interval: every(2, 'hours'), + interval: every(5, 'minutes'), }, + // { + // name: 'sync-coingecko-coinids', + // interval: every(2, 'hours'), + // }, { name: 'update-fee-volume-yield-all-pools', interval: every(1, 'hours'), From c051fbb14a8841d3baf1b0b1d1c8998e03854538 Mon Sep 17 00:00:00 2001 From: franzns <93920061+franzns@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:22:02 +0100 Subject: [PATCH 22/23] only run OP and sepolia (#75) --- worker/scheduler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worker/scheduler.ts b/worker/scheduler.ts index bde8ff178..3c83f2bd0 100644 --- a/worker/scheduler.ts +++ b/worker/scheduler.ts @@ -24,7 +24,7 @@ export async function startScheduler() { chainIds = Object.keys(AllNetworkConfigs).filter((chainId) => chainId !== SEPOLIA_ID); } else { // if not canary nor main, must be dev - chainIds = [SEPOLIA_ID, '1', '10']; // sepolia, mainnet, optimism + chainIds = [SEPOLIA_ID, '10']; // sepolia, optimism } for (const chainId of chainIds) { From 440d548e0c88fb248bbcc8b2c755dbb0f0c7bf8e Mon Sep 17 00:00:00 2001 From: franzns <93920061+franzns@users.noreply.github.com> Date: Wed, 24 Jan 2024 18:01:09 +0100 Subject: [PATCH 23/23] Fix poolid null (#76) * filter null poolIds --- modules/user/lib/user-balance.service.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/user/lib/user-balance.service.ts b/modules/user/lib/user-balance.service.ts index 5167d30a0..e67483688 100644 --- a/modules/user/lib/user-balance.service.ts +++ b/modules/user/lib/user-balance.service.ts @@ -37,8 +37,12 @@ export class UserBalanceService { }, }); - const nonZeroUserWalletBalances = userWalletBalances.filter((balance) => balance.balanceNum > 0); - const nonZeroUserStakedBalances = userStakedBalances.filter((balance) => balance.balanceNum > 0); + const nonZeroUserWalletBalances = userWalletBalances.filter( + (balance) => balance.balanceNum > 0 && balance.poolId !== null, + ); + const nonZeroUserStakedBalances = userStakedBalances.filter( + (balance) => balance.balanceNum > 0 && balance.poolId !== null, + ); if (nonZeroUserWalletBalances.length === 0 && nonZeroUserStakedBalances.length === 0) { return [];