diff --git a/src/apps/lyra-avalon/arbitrum/lyra-avalon.pool.token-fetcher.ts b/src/apps/lyra-avalon/arbitrum/lyra-avalon.pool.token-fetcher.ts index c3b942ae7..d35849571 100644 --- a/src/apps/lyra-avalon/arbitrum/lyra-avalon.pool.token-fetcher.ts +++ b/src/apps/lyra-avalon/arbitrum/lyra-avalon.pool.token-fetcher.ts @@ -1,89 +1,11 @@ -import { Inject } from '@nestjs/common'; -import { gql } from 'graphql-request'; - -import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator'; -import { gqlFetch } from '~app-toolkit/helpers/the-graph.helper'; -import { AppTokenTemplatePositionFetcher } from '~position/template/app-token.template.position-fetcher'; -import { - DefaultAppTokenDefinition, - DefaultAppTokenDataProps, - GetAddressesParams, - GetPricePerShareParams, -} from '~position/template/app-token.template.types'; - -import { LyraAvalonContractFactory, LyraLiquidityToken } from '../contracts'; -// TODO: find better way to determine available markets -type QueryResponse = { - markets: { - id: string; - baseAddress: string; - quoteAddress: string; - liquidityPool: { - id: string; - }; - }[]; -}; -const QUERY = gql` - { - markets(where: { isRemoved: false }) { - id - baseAddress - quoteAddress - liquidityPool { - id - } - } - } -`; +import { LyraAvalonPoolTokenFetcher } from '../common/lyra-avalon.pool.token-fetcher'; @PositionTemplate() -export class ArbitrumLyraAvalonPoolTokenFetcher extends AppTokenTemplatePositionFetcher { - groupLabel = 'Pools'; - - constructor( - @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, - @Inject(LyraAvalonContractFactory) protected readonly contractFactory: LyraAvalonContractFactory, - ) { - super(appToolkit); - } - - getContract(address: string): LyraLiquidityToken { - return this.contractFactory.lyraLiquidityToken({ address, network: this.network }); - } - - async getAddresses({ multicall }: GetAddressesParams) { - const registryContract = this.contractFactory.lyraRegistry({ - address: '0x6c87e4364fd44b0d425adfd0328e56b89b201329', - network: this.network, - }); - - const marketsResponse = await gqlFetch({ - endpoint: 'https://api.lyra.finance/subgraph/arbitrum/v2/api', - query: QUERY, - }); - - const markets = await Promise.all( - marketsResponse.markets.map(market => multicall.wrap(registryContract).marketAddresses(market.id)), - ); - - return markets.map(market => market.liquidityToken); - } - - async getUnderlyingTokenDefinitions() { - return [{ address: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', network: this.network }]; - } - - async getPricePerShare({ - contract, - multicall, - }: GetPricePerShareParams) { - const pool = await contract.liquidityPool(); - const poolContract = this.contractFactory.lyraLiquidityPool({ address: pool, network: this.network }); - const ratioRaw = await multicall.wrap(poolContract).getTokenPrice(); - const ratio = Number(ratioRaw) / 10 ** 18; +export class ArbitrumLyraAvalonPoolTokenFetcher extends LyraAvalonPoolTokenFetcher { + subgraphUrl = 'https://api.lyra.finance/subgraph/arbitrum/v2/api'; - return [ratio]; - } + registryContractAddress = '0x6c87e4364fd44b0d425adfd0328e56b89b201329'; + underlyingContractAddress = '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8'; } diff --git a/src/apps/lyra-avalon/common/lyra-avalon.pool.token-fetcher.ts b/src/apps/lyra-avalon/common/lyra-avalon.pool.token-fetcher.ts new file mode 100644 index 000000000..c73435ac0 --- /dev/null +++ b/src/apps/lyra-avalon/common/lyra-avalon.pool.token-fetcher.ts @@ -0,0 +1,91 @@ +import { Inject } from '@nestjs/common'; +import { gql } from 'graphql-request'; + +import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; +import { gqlFetch } from '~app-toolkit/helpers/the-graph.helper'; +import { AppTokenTemplatePositionFetcher } from '~position/template/app-token.template.position-fetcher'; +import { + DefaultAppTokenDefinition, + DefaultAppTokenDataProps, + GetAddressesParams, + GetPricePerShareParams, +} from '~position/template/app-token.template.types'; + +import { LyraAvalonContractFactory, LyraLiquidityToken } from '../contracts'; + +// TODO: find better way to determine available markets +type QueryResponse = { + markets: { + id: string; + baseAddress: string; + quoteAddress: string; + liquidityPool: { + id: string; + }; + }[]; +}; +const QUERY = gql` + { + markets(where: { isRemoved: false }) { + id + baseAddress + quoteAddress + liquidityPool { + id + } + } + } +`; + +export abstract class LyraAvalonPoolTokenFetcher extends AppTokenTemplatePositionFetcher { + groupLabel = 'Pools'; + + abstract subgraphUrl: string; + abstract registryContractAddress: string; + abstract underlyingContractAddress: string; + + constructor( + @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, + @Inject(LyraAvalonContractFactory) protected readonly contractFactory: LyraAvalonContractFactory, + ) { + super(appToolkit); + } + + getContract(address: string): LyraLiquidityToken { + return this.contractFactory.lyraLiquidityToken({ address, network: this.network }); + } + + async getAddresses({ multicall }: GetAddressesParams) { + const registryContract = this.contractFactory.lyraRegistry({ + address: this.registryContractAddress, + network: this.network, + }); + + const marketsResponse = await gqlFetch({ + endpoint: this.subgraphUrl, + query: QUERY, + }); + + const markets = await Promise.all( + marketsResponse.markets.map(market => multicall.wrap(registryContract).marketAddresses(market.id)), + ); + + return markets.map(market => market.liquidityToken); + } + + async getUnderlyingTokenDefinitions() { + return [{ address: this.underlyingContractAddress, network: this.network }]; + } + + async getPricePerShare({ + contract, + multicall, + }: GetPricePerShareParams) { + const pool = await contract.liquidityPool(); + const poolContract = this.contractFactory.lyraLiquidityPool({ address: pool, network: this.network }); + const ratioRaw = await multicall.wrap(poolContract).getTokenPrice(); + const ratio = Number(ratioRaw) / 10 ** 18; + + return [ratio]; + } +} diff --git a/src/apps/lyra-avalon/common/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts b/src/apps/lyra-avalon/common/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts new file mode 100644 index 000000000..677cf797c --- /dev/null +++ b/src/apps/lyra-avalon/common/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts @@ -0,0 +1,54 @@ +import { Inject } from '@nestjs/common'; + +import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface'; +import { getLabelFromToken } from '~app-toolkit/helpers/presentation/image.present'; +import { MetaType } from '~position/position.interface'; +import { ContractPositionTemplatePositionFetcher } from '~position/template/contract-position.template.position-fetcher'; +import { + DefaultContractPositionDefinition, + GetDisplayPropsParams, + GetTokenBalancesParams, + GetTokenDefinitionsParams, +} from '~position/template/contract-position.template.types'; + +import { LyraAvalonContractFactory, LyraStkLyra } from '../contracts'; + +export abstract class LyraAvalonStkLyraClaimableContractPositionFetcher extends ContractPositionTemplatePositionFetcher { + groupLabel = 'stkLYRA Rewards'; + + abstract stkLyraContractAddress: string; + + constructor( + @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, + @Inject(LyraAvalonContractFactory) protected readonly contractFactory: LyraAvalonContractFactory, + ) { + super(appToolkit); + } + + getContract(address: string): LyraStkLyra { + return this.contractFactory.lyraStkLyra({ address, network: this.network }); + } + + async getDefinitions(): Promise { + return [{ address: this.stkLyraContractAddress }]; + } + + async getTokenDefinitions({ contract }: GetTokenDefinitionsParams) { + return [ + { + metaType: MetaType.CLAIMABLE, + address: await contract.STAKED_TOKEN(), + network: this.network, + }, + ]; + } + + async getLabel({ contractPosition }: GetDisplayPropsParams) { + return `Claimable ${getLabelFromToken(contractPosition.tokens[0])}`; + } + + async getTokenBalancesPerPosition({ address, contract }: GetTokenBalancesParams) { + const rewardBalance = await contract.getTotalRewardsBalance(address); + return [rewardBalance]; + } +} diff --git a/src/apps/lyra-avalon/ethereum/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts b/src/apps/lyra-avalon/ethereum/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts new file mode 100644 index 000000000..16490c269 --- /dev/null +++ b/src/apps/lyra-avalon/ethereum/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts @@ -0,0 +1,10 @@ +import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator'; + +import { LyraAvalonStkLyraClaimableContractPositionFetcher } from '../common/lyra-avalon.stk-lyra-claimable.contract-position-fetcher'; + +@PositionTemplate() +export class EthereumLyraAvalonStkLyraClaimableContractPositionFetcher extends LyraAvalonStkLyraClaimableContractPositionFetcher { + groupLabel = 'stkLYRA Rewards'; + + stkLyraContractAddress = '0xcb9f85730f57732fc899fb158164b9ed60c77d49'; +} diff --git a/src/apps/lyra-avalon/lyra-avalon.module.ts b/src/apps/lyra-avalon/lyra-avalon.module.ts index 646830db6..4f2c1d032 100644 --- a/src/apps/lyra-avalon/lyra-avalon.module.ts +++ b/src/apps/lyra-avalon/lyra-avalon.module.ts @@ -7,11 +7,13 @@ import { ArbitrumLyraAvalonPoolTokenFetcher } from './arbitrum/lyra-avalon.pool. import { ArbitrumLyraAvalonStkLyraTokenFetcher } from './arbitrum/lyra-avalon.stk-lyra.token-fetcher'; import { LyraAvalonContractFactory } from './contracts'; import { EthereumLyraAvalonStakingContractPositionFetcher } from './ethereum/lyra-avalon.staking.contract-position-fetcher'; +import { EthereumLyraAvalonStkLyraClaimableContractPositionFetcher } from './ethereum/lyra-avalon.stk-lyra-claimable.contract-position-fetcher'; import { EthereumLyraAvalonStkLyraTokenFetcher } from './ethereum/lyra-avalon.stk-lyra.token-fetcher'; import { OptimismLyraAvalonOptionsContractPositionFetcher } from './optimism/lyra-avalon.options.contract-position-fetcher'; import { OptimismLyraAvalonPoolTokenFetcher } from './optimism/lyra-avalon.pool.token-fetcher'; import { OptimismLyraAvalonStakingContractPositionFetcher } from './optimism/lyra-avalon.staking.contract-position-fetcher'; import { OptimismLyraAvalonStkLyraClaimableContractPositionFetcher } from './optimism/lyra-avalon.stk-lyra-claimable.contract-position-fetcher'; +import { OptimismLyraAvalonStkLyraOldTokenFetcher } from './optimism/lyra-avalon.stk-lyra-old.token-fetcher'; import { OptimismLyraAvalonStkLyraTokenFetcher } from './optimism/lyra-avalon.stk-lyra.token-fetcher'; @Module({ @@ -21,15 +23,17 @@ import { OptimismLyraAvalonStkLyraTokenFetcher } from './optimism/lyra-avalon.st ArbitrumLyraAvalonOptionsContractPositionFetcher, ArbitrumLyraAvalonStkLyraTokenFetcher, ArbitrumLyraAvalonPoolTokenFetcher, + // Ethereum + EthereumLyraAvalonStkLyraTokenFetcher, + EthereumLyraAvalonStakingContractPositionFetcher, + EthereumLyraAvalonStkLyraClaimableContractPositionFetcher, // Optimism OptimismLyraAvalonOptionsContractPositionFetcher, OptimismLyraAvalonPoolTokenFetcher, OptimismLyraAvalonStakingContractPositionFetcher, + OptimismLyraAvalonStkLyraOldTokenFetcher, OptimismLyraAvalonStkLyraTokenFetcher, OptimismLyraAvalonStkLyraClaimableContractPositionFetcher, - // Ethereum - EthereumLyraAvalonStkLyraTokenFetcher, - EthereumLyraAvalonStakingContractPositionFetcher, ], }) export class LyraAvalonAppModule extends AbstractApp() {} diff --git a/src/apps/lyra-avalon/optimism/lyra-avalon.pool.token-fetcher.ts b/src/apps/lyra-avalon/optimism/lyra-avalon.pool.token-fetcher.ts index adb3cf5e3..64a259157 100644 --- a/src/apps/lyra-avalon/optimism/lyra-avalon.pool.token-fetcher.ts +++ b/src/apps/lyra-avalon/optimism/lyra-avalon.pool.token-fetcher.ts @@ -1,103 +1,10 @@ -import { Inject } from '@nestjs/common'; -import Axios from 'axios'; -import { gql } from 'graphql-request'; - -import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator'; -import { gqlFetch } from '~app-toolkit/helpers/the-graph.helper'; -import { AppTokenTemplatePositionFetcher } from '~position/template/app-token.template.position-fetcher'; -import { - DefaultAppTokenDefinition, - DefaultAppTokenDataProps, - GetAddressesParams, - GetPricePerShareParams, -} from '~position/template/app-token.template.types'; - -import { LyraAvalonContractFactory, LyraLiquidityToken } from '../contracts'; - -type LyraMainnetAddresses = Record< - string, - { - contractName: string; - source: string; - address: string; - txn: string; - blockNumber: number; - } ->; -// TODO: find better way to determine available markets -type QueryResponse = { - markets: { - id: string; - baseAddress: string; - quoteAddress: string; - liquidityPool: { - id: string; - }; - }[]; -}; -const QUERY = gql` - { - markets(where: { isRemoved: false }) { - id - baseAddress - quoteAddress - liquidityPool { - id - } - } - } -`; +import { LyraAvalonPoolTokenFetcher } from '../common/lyra-avalon.pool.token-fetcher'; @PositionTemplate() -export class OptimismLyraAvalonPoolTokenFetcher extends AppTokenTemplatePositionFetcher { - groupLabel = 'Pools'; - - constructor( - @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, - @Inject(LyraAvalonContractFactory) protected readonly contractFactory: LyraAvalonContractFactory, - ) { - super(appToolkit); - } - - getContract(address: string): LyraLiquidityToken { - return this.contractFactory.lyraLiquidityToken({ address, network: this.network }); - } - - async getAddresses({ multicall }: GetAddressesParams) { - const dataUrl = 'https://raw.githubusercontent.com/lyra-finance/subgraph/master/addresses/mainnet-ovm/lyra.json'; - const { data: addresses } = await Axios.get(dataUrl); - const registryContract = this.contractFactory.lyraRegistry({ - address: addresses.LyraRegistry.address, - network: this.network, - }); - - const marketsResponse = await gqlFetch({ - endpoint: 'https://api.lyra.finance/subgraph/optimism/v1/api', - query: QUERY, - }); - - const markets = await Promise.all( - marketsResponse.markets.map(market => multicall.wrap(registryContract).marketAddresses(market.id)), - ); - - return markets.map(market => market.liquidityToken); - } - - async getUnderlyingTokenDefinitions() { - return [{ address: '0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9', network: this.network }]; - } - - async getPricePerShare({ - appToken, - contract, - multicall, - }: GetPricePerShareParams) { - const pool = await contract.liquidityPool(); - const poolContract = this.contractFactory.lyraLiquidityPool({ address: pool, network: this.network }); - const ratioRaw = await multicall.wrap(poolContract).getTokenPrice(); - const ratio = Number(ratioRaw) / 10 ** appToken.tokens[0].decimals; - return [ratio]; - } +export class OptimismLyraAvalonPoolTokenFetcher extends LyraAvalonPoolTokenFetcher { + subgraphUrl = 'https://api.lyra.finance/subgraph/optimism/v2/api'; + registryContractAddress = '0x0fed189bcd4a680e05b153dc7c3dc87004e162fb'; + underlyingContractAddress = '0x7f5c764cbc14f9669b88837ca1490cca17c31607'; } diff --git a/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts b/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts index 50b49a91b..62be393fb 100644 --- a/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts +++ b/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra-claimable.contract-position-fetcher.ts @@ -1,54 +1,10 @@ -import { Inject } from '@nestjs/common'; - -import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface'; import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator'; -import { getLabelFromToken } from '~app-toolkit/helpers/presentation/image.present'; -import { MetaType } from '~position/position.interface'; -import { ContractPositionTemplatePositionFetcher } from '~position/template/contract-position.template.position-fetcher'; -import { - DefaultContractPositionDefinition, - GetDisplayPropsParams, - GetTokenBalancesParams, - GetTokenDefinitionsParams, -} from '~position/template/contract-position.template.types'; -import { LyraAvalonContractFactory, LyraStkLyra } from '../contracts'; +import { LyraAvalonStkLyraClaimableContractPositionFetcher } from '../common/lyra-avalon.stk-lyra-claimable.contract-position-fetcher'; @PositionTemplate() -export class OptimismLyraAvalonStkLyraClaimableContractPositionFetcher extends ContractPositionTemplatePositionFetcher { +export class OptimismLyraAvalonStkLyraClaimableContractPositionFetcher extends LyraAvalonStkLyraClaimableContractPositionFetcher { groupLabel = 'stkLYRA Rewards'; - constructor( - @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, - @Inject(LyraAvalonContractFactory) protected readonly contractFactory: LyraAvalonContractFactory, - ) { - super(appToolkit); - } - - getContract(address: string): LyraStkLyra { - return this.contractFactory.lyraStkLyra({ address, network: this.network }); - } - - async getDefinitions(): Promise { - return [{ address: '0xde48b1b5853cc63b1d05e507414d3e02831722f8' }]; - } - - async getTokenDefinitions(_params: GetTokenDefinitionsParams) { - return [ - { - metaType: MetaType.CLAIMABLE, - address: '0x50c5725949a6f0c72e6c4a641f24049a917db0cb', - network: this.network, - }, - ]; - } - - async getLabel({ contractPosition }: GetDisplayPropsParams) { - return `Claimable ${getLabelFromToken(contractPosition.tokens[0])}`; - } - - async getTokenBalancesPerPosition({ address, contract }: GetTokenBalancesParams) { - const rewardBalance = await contract.getTotalRewardsBalance(address); - return [rewardBalance]; - } + stkLyraContractAddress = '0xde48b1b5853cc63b1d05e507414d3e02831722f8'; } diff --git a/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra-old.token-fetcher.ts b/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra-old.token-fetcher.ts new file mode 100644 index 000000000..594688023 --- /dev/null +++ b/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra-old.token-fetcher.ts @@ -0,0 +1,35 @@ +import { Inject } from '@nestjs/common'; + +import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface'; +import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator'; +import { AppTokenTemplatePositionFetcher } from '~position/template/app-token.template.position-fetcher'; + +import { LyraAvalonContractFactory, LyraStkLyra } from '../contracts'; + +@PositionTemplate() +export class OptimismLyraAvalonStkLyraOldTokenFetcher extends AppTokenTemplatePositionFetcher { + groupLabel = 'stkLYRA (old)'; + + constructor( + @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, + @Inject(LyraAvalonContractFactory) protected readonly contractFactory: LyraAvalonContractFactory, + ) { + super(appToolkit); + } + + getContract(address: string): LyraStkLyra { + return this.contractFactory.lyraStkLyra({ address, network: this.network }); + } + + async getAddresses() { + return ['0xde48b1b5853cc63b1d05e507414d3e02831722f8']; + } + + async getUnderlyingTokenDefinitions() { + return [{ address: '0x50c5725949a6f0c72e6c4a641f24049a917db0cb', network: this.network }]; + } + + async getPricePerShare() { + return [1]; + } +} diff --git a/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra.token-fetcher.ts b/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra.token-fetcher.ts index 07577e7b9..9a34818d1 100644 --- a/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra.token-fetcher.ts +++ b/src/apps/lyra-avalon/optimism/lyra-avalon.stk-lyra.token-fetcher.ts @@ -22,7 +22,7 @@ export class OptimismLyraAvalonStkLyraTokenFetcher extends AppTokenTemplatePosit } async getAddresses() { - return ['0xde48b1b5853cc63b1d05e507414d3e02831722f8']; + return ['0x0f5d45a7023612e9e244fe84fac5fcf3740d1492']; } async getUnderlyingTokenDefinitions() {