From a9c218eb2b718db946e15f8175f464c567396b80 Mon Sep 17 00:00:00 2001 From: immasandwich Date: Tue, 17 May 2022 13:15:25 -0400 Subject: [PATCH] feat(curve): Add child liquidity gauges to Optimism (#451) --- .../curve.farm.contract-position-fetcher.ts | 4 +- .../curve.farm.contract-position-fetcher.ts | 4 +- .../curve.farm.contract-position-fetcher.ts | 4 +- .../curve.farm.contract-position-fetcher.ts | 6 +- .../curve/optimism/curve.balance-fetcher.ts | 83 +++++++++---------- .../curve.farm.contract-position-fetcher.ts | 81 +++++++++--------- .../curve.farm.contract-position-fetcher.ts | 4 +- 7 files changed, 95 insertions(+), 91 deletions(-) diff --git a/src/apps/curve/arbitrum/curve.farm.contract-position-fetcher.ts b/src/apps/curve/arbitrum/curve.farm.contract-position-fetcher.ts index 2db0752d2..8256d3dfd 100644 --- a/src/apps/curve/arbitrum/curve.farm.contract-position-fetcher.ts +++ b/src/apps/curve/arbitrum/curve.farm.contract-position-fetcher.ts @@ -38,7 +38,7 @@ export class ArbitrumCurveFarmContractPositionFetcher implements PositionFetcher private readonly childGaugeRewardTokenStrategy: CurveChildLiquidityGaugeRewardTokenStrategy, ) {} - async getRewardOnlyGaugePositions() { + async getRewardsOnlyGaugePositions() { const definitions = [CURVE_V1_POOL_DEFINITIONS, CURVE_V2_POOL_DEFINITIONS].flat().filter(v => !!v.gaugeAddress); return this.appToolkit.helpers.singleStakingFarmContractPositionHelper.getContractPositions({ @@ -85,7 +85,7 @@ export class ArbitrumCurveFarmContractPositionFetcher implements PositionFetcher async getPositions() { const [rewardOnlyGaugePositions, childLiquidityGaugePositions] = await Promise.all([ - this.getRewardOnlyGaugePositions(), + this.getRewardsOnlyGaugePositions(), this.getChildLiquidityGaugePositions(), ]); diff --git a/src/apps/curve/avalanche/curve.farm.contract-position-fetcher.ts b/src/apps/curve/avalanche/curve.farm.contract-position-fetcher.ts index 9e5102f08..693ed6849 100644 --- a/src/apps/curve/avalanche/curve.farm.contract-position-fetcher.ts +++ b/src/apps/curve/avalanche/curve.farm.contract-position-fetcher.ts @@ -38,7 +38,7 @@ export class AvalancheCurveFarmContractPositionFetcher implements PositionFetche private readonly childGaugeRewardTokenStrategy: CurveChildLiquidityGaugeRewardTokenStrategy, ) {} - async getRewardOnlyGaugePositions() { + async getRewardsOnlyGaugePositions() { const definitions = [CURVE_V1_POOL_DEFINITIONS, CURVE_V2_POOL_DEFINITIONS].flat().filter(v => !!v.gaugeAddress); return this.appToolkit.helpers.singleStakingFarmContractPositionHelper.getContractPositions({ @@ -84,7 +84,7 @@ export class AvalancheCurveFarmContractPositionFetcher implements PositionFetche async getPositions() { const [rewardOnlyGaugePositions, childLiquidityGaugePositions] = await Promise.all([ - this.getRewardOnlyGaugePositions(), + this.getRewardsOnlyGaugePositions(), this.getChildLiquidityGaugePositions(), ]); diff --git a/src/apps/curve/fantom/curve.farm.contract-position-fetcher.ts b/src/apps/curve/fantom/curve.farm.contract-position-fetcher.ts index 8650b3484..1a6d4888b 100644 --- a/src/apps/curve/fantom/curve.farm.contract-position-fetcher.ts +++ b/src/apps/curve/fantom/curve.farm.contract-position-fetcher.ts @@ -42,7 +42,7 @@ export class FantomCurveFarmContractPositionFetcher implements PositionFetcher !!v.gaugeAddress); @@ -90,7 +90,7 @@ export class FantomCurveFarmContractPositionFetcher implements PositionFetcher !!v.gaugeAddress); + async getRewardsOnlyGaugePositions() { + const definitions = [CURVE_V1_POOL_DEFINITIONS].flat().filter(v => !!v.gaugeAddress); return this.appToolkit.helpers.singleStakingFarmContractPositionHelper.getContractPositions({ network, @@ -84,7 +84,7 @@ export class GnosisCurveFarmContractPositionFetcher implements PositionFetcher({ - address, - appId: CURVE_DEFINITION.id, - groupId: CURVE_DEFINITION.groups.farm.id, - network: Network.OPTIMISM_MAINNET, - resolveContract: ({ address, network }) => - this.curveContractFactory.curveRewardsOnlyGauge({ address, network }), - resolveStakedTokenBalance: ({ contract, address, multicall }) => multicall.wrap(contract).balanceOf(address), - resolveRewardTokenBalances: ({ contract, address, multicall, contractPosition }) => { - const rewardTokens = contractPosition.tokens.filter(isClaimable); - const wrappedContract = multicall.wrap(contract); - return Promise.all(rewardTokens.map(v => wrappedContract.claimable_reward_write(address, v.address))); - }, - }), - // N-Gauge - this.appToolkit.helpers.singleStakingContractPositionBalanceHelper.getBalances({ - address, - network: Network.OPTIMISM_MAINNET, - appId: CURVE_DEFINITION.id, - groupId: CURVE_DEFINITION.groups.farm.id, - farmFilter: farm => farm.dataProps.implementation === 'n-gauge', - resolveContract: ({ address, network }) => this.curveContractFactory.curveNGauge({ address, network }), - resolveStakedTokenBalance: ({ contract, address, multicall }) => multicall.wrap(contract).balanceOf(address), - resolveRewardTokenBalances: async ({ contract, address, multicall, contractPosition }) => { - const rewardTokens = contractPosition.tokens.filter(isClaimable); - const wrappedContract = multicall.wrap(contract); - const primaryRewardBalance = await wrappedContract.claimable_tokens(address); - const rewardBalances = [primaryRewardBalance]; + private async getRewardsOnlyGaugeStakedBalances(address: string) { + return this.appToolkit.helpers.singleStakingContractPositionBalanceHelper.getBalances({ + address, + appId: CURVE_DEFINITION.id, + groupId: CURVE_DEFINITION.groups.farm.id, + network: Network.OPTIMISM_MAINNET, + farmFilter: v => v.dataProps.implementation === 'rewards-only-gauge', + resolveContract: ({ address, network }) => this.curveContractFactory.curveRewardsOnlyGauge({ address, network }), + resolveStakedTokenBalance: ({ contract, address, multicall }) => multicall.wrap(contract).balanceOf(address), + resolveRewardTokenBalances: ({ contract, address, multicall, contractPosition }) => { + const rewardTokens = contractPosition.tokens.filter(isClaimable); + const wrappedContract = multicall.wrap(contract); + return Promise.all(rewardTokens.map(v => wrappedContract.claimable_reward_write(address, v.address))); + }, + }); + } - if (rewardTokens.length > 1) { - const secondaryRewardBalance = await wrappedContract.claimable_reward(address, rewardTokens[1].address); - rewardBalances.push(secondaryRewardBalance); - } + private async getChildLiquidityGaugeStakedBalances(address: string) { + return this.appToolkit.helpers.singleStakingContractPositionBalanceHelper.getBalances({ + address, + appId: CURVE_DEFINITION.id, + groupId: CURVE_DEFINITION.groups.farm.id, + network: Network.OPTIMISM_MAINNET, + farmFilter: v => v.dataProps.implementation === 'child-liquidity-gauge', + resolveContract: ({ address, network }) => + this.curveContractFactory.curveChildLiquidityGauge({ address, network }), + resolveStakedTokenBalance: ({ contract, address, multicall }) => multicall.wrap(contract).balanceOf(address), + resolveRewardTokenBalances: async ({ contract, address, multicall, contractPosition }) => { + const rewardTokens = contractPosition.tokens.filter(isClaimable); + const otherRewardTokens = rewardTokens.filter(v => v.symbol !== 'CRV'); - return rewardBalances; - }, - }), - ]).then(v => v.flat()); + return Promise.all([ + multicall.wrap(contract).callStatic.claimable_tokens(address), + ...otherRewardTokens.map(v => multicall.wrap(contract).claimable_reward(address, v.address)), + ]); + }, + }); } async getBalances(address: string) { - const [poolTokenBalances, stakedBalances] = await Promise.all([ + const [poolTokenBalances, rewardOnlyGaugeStakedBalances, childLiquidityGaugeStakedBalances] = await Promise.all([ this.getPoolTokenBalances(address), - this.getStakedBalances(address), + this.getRewardsOnlyGaugeStakedBalances(address), + this.getChildLiquidityGaugeStakedBalances(address), ]); return presentBalanceFetcherResponse([ @@ -82,7 +79,7 @@ export class OptimismCurveBalanceFetcher implements BalanceFetcher { }, { label: 'Staked', - assets: stakedBalances, + assets: [...rewardOnlyGaugeStakedBalances, ...childLiquidityGaugeStakedBalances], }, ]); } diff --git a/src/apps/curve/optimism/curve.farm.contract-position-fetcher.ts b/src/apps/curve/optimism/curve.farm.contract-position-fetcher.ts index 567bf8d39..36811ec29 100644 --- a/src/apps/curve/optimism/curve.farm.contract-position-fetcher.ts +++ b/src/apps/curve/optimism/curve.farm.contract-position-fetcher.ts @@ -1,18 +1,18 @@ import { Inject } from '@nestjs/common'; import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface'; -import { ZERO_ADDRESS } from '~app-toolkit/constants/address'; import { Register } from '~app-toolkit/decorators'; import { PositionFetcher } from '~position/position-fetcher.interface'; import { ContractPosition } from '~position/position.interface'; import { Network } from '~types/network.interface'; -import { CurveContractFactory, CurveNGauge, CurveRewardsOnlyGauge } from '../contracts'; +import { CurveChildLiquidityGauge, CurveContractFactory, CurveRewardsOnlyGauge } from '../contracts'; import { CURVE_DEFINITION } from '../curve.definition'; -import { CurveFactoryGaugeAddressHelper } from '../helpers/curve.factory-gauge.address-helper'; +import { CurveChildLiquidityGaugeFactoryAddressHelper } from '../helpers/curve.child-liquidity-gauge-factory.address-helper'; +import { CurveChildLiquidityGaugeRewardTokenStrategy } from '../helpers/curve.child-liquidity-gauge.reward-token-strategy'; +import { CurveChildLiquidityGaugeRoiStrategy } from '../helpers/curve.child-liquidity-gauge.roi-strategy'; import { CurveGaugeV2RewardTokenStrategy } from '../helpers/curve.gauge-v2.reward-token-strategy'; import { CurveGaugeV2RoiStrategy } from '../helpers/curve.gauge-v2.roi-strategy'; -import { CurveGaugeIsActiveStrategy } from '../helpers/curve.gauge.is-active-strategy'; import { CURVE_V1_POOL_DEFINITIONS } from './curve.pool.definitions'; @@ -30,46 +30,23 @@ export class OptimismCurveFarmContractPositionFetcher implements PositionFetcher private readonly curveGaugeV2RoiStrategy: CurveGaugeV2RoiStrategy, @Inject(CurveGaugeV2RewardTokenStrategy) private readonly curveGaugeV2RewardTokenStrategy: CurveGaugeV2RewardTokenStrategy, - @Inject(CurveFactoryGaugeAddressHelper) - private readonly curveFactoryGaugeAddressHelper: CurveFactoryGaugeAddressHelper, - @Inject(CurveGaugeIsActiveStrategy) - private readonly curveGaugeIsActiveStrategy: CurveGaugeIsActiveStrategy, + @Inject(CurveChildLiquidityGaugeFactoryAddressHelper) + private readonly childGaugeAddressHelper: CurveChildLiquidityGaugeFactoryAddressHelper, + @Inject(CurveChildLiquidityGaugeRoiStrategy) + private readonly childGaugeRoiStrategy: CurveChildLiquidityGaugeRoiStrategy, + @Inject(CurveChildLiquidityGaugeRewardTokenStrategy) + private readonly childGaugeRewardTokenStrategy: CurveChildLiquidityGaugeRewardTokenStrategy, ) {} - private async getNGaugeFarms() { - return this.appToolkit.helpers.singleStakingFarmContractPositionHelper.getContractPositions({ - network, - appId, - groupId, - dependencies: [{ appId: CURVE_DEFINITION.id, groupIds: [CURVE_DEFINITION.groups.pool.id], network }], - resolveFarmAddresses: async () => { - return await this.curveFactoryGaugeAddressHelper.getGaugeAddresses({ - factoryAddress: '0x2db0e83599a91b508ac268a6197b8b14f5e72840', - network, - }); - }, - resolveImplementation: () => 'n-gauge', - resolveTotalValueLocked: ({ contract, multicall }) => multicall.wrap(contract).totalSupply(), - resolveFarmContract: ({ address, network }) => this.curveContractFactory.curveNGauge({ address, network }), - resolveStakedTokenAddress: ({ contract, multicall }) => multicall.wrap(contract).lp_token(), - resolveRewardTokenAddresses: async ({ contract, multicall }) => { - const bonusRewardTokenAddress = await multicall.wrap(contract).reward_tokens(0); - return [bonusRewardTokenAddress].filter(v => v !== ZERO_ADDRESS); - }, - resolveIsActive: this.curveGaugeIsActiveStrategy.build({ - resolveInflationRate: ({ contract, multicall }) => multicall.wrap(contract).inflation_rate(), - }), - resolveRois: async () => ({ dailyROI: 0, weeklyROI: 0, yearlyROI: 0 }), - }); - } - - async getSingleGaugeFarms() { + async getRewardsOnlyGaugePositions() { const definitions = [CURVE_V1_POOL_DEFINITIONS].flat().filter(v => !!v.gaugeAddress); + return this.appToolkit.helpers.singleStakingFarmContractPositionHelper.getContractPositions({ network, appId, groupId, dependencies: [{ appId: CURVE_DEFINITION.id, groupIds: [CURVE_DEFINITION.groups.pool.id], network }], + resolveImplementation: () => 'rewards-only-gauge', resolveFarmAddresses: () => definitions.map(v => v.gaugeAddress ?? null), resolveFarmContract: ({ address, network }) => this.curveContractFactory.curveRewardsOnlyGauge({ address, network }), @@ -82,7 +59,37 @@ export class OptimismCurveFarmContractPositionFetcher implements PositionFetcher }); } + async getChildLiquidityGaugePositions() { + return this.appToolkit.helpers.singleStakingFarmContractPositionHelper.getContractPositions( + { + network, + appId, + groupId, + dependencies: [{ appId: CURVE_DEFINITION.id, groupIds: [CURVE_DEFINITION.groups.pool.id], network }], + resolveImplementation: () => 'child-liquidity-gauge', + resolveFarmAddresses: () => + this.childGaugeAddressHelper.getGaugeAddresses({ + factoryAddress: '0xabc000d88f23bb45525e447528dbf656a9d55bf5', + network, + }), + resolveFarmContract: ({ address, network }) => + this.curveContractFactory.curveChildLiquidityGauge({ address, network }), + resolveStakedTokenAddress: ({ contract, multicall }) => multicall.wrap(contract).lp_token(), + resolveRewardTokenAddresses: this.childGaugeRewardTokenStrategy.build({ + crvTokenAddress: '0x0994206dfe8de6ec6920ff4d779b0d950605fb53', + }), + resolveRois: this.childGaugeRoiStrategy.build(), + resolveIsActive: () => true, + }, + ); + } + async getPositions() { - return Promise.all([this.getSingleGaugeFarms(), this.getNGaugeFarms()]).then(v => v.flat()); + const [rewardOnlyGaugePositions, childLiquidityGaugePositions] = await Promise.all([ + this.getRewardsOnlyGaugePositions(), + this.getChildLiquidityGaugePositions(), + ]); + + return [...rewardOnlyGaugePositions, ...childLiquidityGaugePositions]; } } diff --git a/src/apps/curve/polygon/curve.farm.contract-position-fetcher.ts b/src/apps/curve/polygon/curve.farm.contract-position-fetcher.ts index ff9ccb30f..330caa33c 100644 --- a/src/apps/curve/polygon/curve.farm.contract-position-fetcher.ts +++ b/src/apps/curve/polygon/curve.farm.contract-position-fetcher.ts @@ -38,7 +38,7 @@ export class PolygonCurveFarmContractPositionFetcher implements PositionFetcher< private readonly childGaugeRewardTokenStrategy: CurveChildLiquidityGaugeRewardTokenStrategy, ) {} - async getRewardOnlyGaugePositions() { + async getRewardsOnlyGaugePositions() { const definitions = [CURVE_V1_POOL_DEFINITIONS, CURVE_V2_POOL_DEFINITIONS].flat().filter(v => !!v.gaugeAddress); return this.appToolkit.helpers.singleStakingFarmContractPositionHelper.getContractPositions({ @@ -84,7 +84,7 @@ export class PolygonCurveFarmContractPositionFetcher implements PositionFetcher< async getPositions() { const [rewardOnlyGaugePositions, childLiquidityGaugePositions] = await Promise.all([ - this.getRewardOnlyGaugePositions(), + this.getRewardsOnlyGaugePositions(), this.getChildLiquidityGaugePositions(), ]);