From 1aff35726a2c688724c5a33f5313277b488b8fa2 Mon Sep 17 00:00:00 2001 From: immasandwich Date: Wed, 31 Aug 2022 16:01:04 -0400 Subject: [PATCH] feat(llama-airforce): Add uauraBAL and migrate to templates (#1317) --- ...rdrop.contract-position-balance-fetcher.ts | 53 ------- ...force.airdrop.contract-position-fetcher.ts | 65 ++++++--- .../llama-airforce.vault.token-fetcher.ts | 138 ++++++++++-------- .../llama-airforce/llama-airforce.module.ts | 2 - 4 files changed, 123 insertions(+), 135 deletions(-) delete mode 100644 src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-balance-fetcher.ts diff --git a/src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-balance-fetcher.ts b/src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-balance-fetcher.ts deleted file mode 100644 index 110f47500..000000000 --- a/src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-balance-fetcher.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Inject } from '@nestjs/common'; -import BigNumber from 'bignumber.js'; - -import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface'; -import { Register } from '~app-toolkit/decorators'; -import { drillBalance } from '~app-toolkit/helpers/balance/token-balance.helper'; -import { PositionBalanceFetcher } from '~position/position-balance-fetcher.interface'; -import { ContractPositionBalance } from '~position/position-balance.interface'; -import { isClaimable } from '~position/position.utils'; -import { Network } from '~types/network.interface'; - -import { LlamaAirforceContractFactory } from '../contracts'; -import { LLAMA_AIRFORCE_DEFINITION } from '../llama-airforce.definition'; - -import { EthereumLlamaAirforceMerkleCache } from './llama-airforce.merkle-cache'; - -const appId = LLAMA_AIRFORCE_DEFINITION.id; -const groupId = LLAMA_AIRFORCE_DEFINITION.groups.airdrop.id; -const network = Network.ETHEREUM_MAINNET; - -@Register.ContractPositionBalanceFetcher({ appId, groupId, network }) -export class EthereumLlamaAirforceAirdropContractPositionBalanceFetcher - implements PositionBalanceFetcher -{ - constructor( - @Inject(APP_TOOLKIT) - private readonly appToolkit: IAppToolkit, - @Inject(EthereumLlamaAirforceMerkleCache) - private readonly merkleCache: EthereumLlamaAirforceMerkleCache, - @Inject(LlamaAirforceContractFactory) private readonly contractFactory: LlamaAirforceContractFactory, - ) {} - - async getBalances(address: string) { - return this.appToolkit.helpers.contractPositionBalanceHelper.getContractPositionBalances({ - address, - appId, - groupId, - network, - resolveBalances: async ({ contractPosition, multicall }) => { - const contract = this.contractFactory.llamaAirforceMerkleDistributor(contractPosition); - const rewardToken = contractPosition.tokens.find(isClaimable)!; - const rewardsData = await this.merkleCache.getClaim(rewardToken.address, address); - if (!rewardsData) return [drillBalance(rewardToken, '0')]; - - const { index, amount } = rewardsData; - const isClaimed = await multicall.wrap(contract).isClaimed(index); - - const balanceRaw = new BigNumber(isClaimed ? '0' : amount); - return [drillBalance(rewardToken, balanceRaw.toFixed(0))]; - }, - }); - } -} diff --git a/src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-fetcher.ts b/src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-fetcher.ts index 600ad8c6e..24dddec54 100644 --- a/src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-fetcher.ts +++ b/src/apps/llama-airforce/ethereum/llama-airforce.airdrop.contract-position-fetcher.ts @@ -2,32 +2,61 @@ import { Inject } from '@nestjs/common'; import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; import { Register } from '~app-toolkit/decorators'; -import { PositionFetcher } from '~position/position-fetcher.interface'; -import { ContractPosition } from '~position/position.interface'; +import { isClaimable } from '~position/position.utils'; +import { GetTokenBalancesParams } from '~position/template/contract-position.template.types'; +import { MerkleTemplateContractPositionFetcher } from '~position/template/merkle.template.contract-position-fetcher'; import { Network } from '~types/network.interface'; +import { LlamaAirforceContractFactory, LlamaAirforceMerkleDistributor } from '../contracts'; import { LLAMA_AIRFORCE_DEFINITION } from '../llama-airforce.definition'; +import { EthereumLlamaAirforceMerkleCache } from './llama-airforce.merkle-cache'; + const appId = LLAMA_AIRFORCE_DEFINITION.id; const groupId = LLAMA_AIRFORCE_DEFINITION.groups.airdrop.id; const network = Network.ETHEREUM_MAINNET; @Register.ContractPositionFetcher({ appId, groupId, network, options: { excludeFromTvl: true } }) -export class EthereumLlamaAirforceAirdropContractPositionFetcher implements PositionFetcher { - constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {} - - async getPositions() { - return this.appToolkit.helpers.merkleContractPositionHelper.getContractPositions({ - address: '0xa83043df401346a67eddeb074679b4570b956183', // Merkle Claim - appId, - groupId, - network, - dependencies: [{ appId, groupIds: [LLAMA_AIRFORCE_DEFINITION.groups.vault.id], network }], - rewardTokenAddresses: [ - '0x83507cc8c8b67ed48badd1f59f684d5d02884c81', // uCRV - '0xf964b0e3ffdea659c44a5a52bc0b82a24b89ce0e', // uFXS - '0x8659fc767cad6005de79af65dafe4249c57927af', // uCVX - ], - }); +export class EthereumLlamaAirforceAirdropContractPositionFetcher extends MerkleTemplateContractPositionFetcher { + appId = appId; + groupId = groupId; + network = network; + groupLabel = 'Airdrop'; + merkleAddress = '0xa83043df401346a67eddeb074679b4570b956183'; + + constructor( + @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, + @Inject(LlamaAirforceContractFactory) protected readonly contractFactory: LlamaAirforceContractFactory, + @Inject(EthereumLlamaAirforceMerkleCache) private readonly merkleCache: EthereumLlamaAirforceMerkleCache, + ) { + super(appToolkit); + } + + getContract(address: string): LlamaAirforceMerkleDistributor { + return this.contractFactory.llamaAirforceMerkleDistributor({ address, network: this.network }); + } + + async getRewardTokenAddresses() { + return [ + '0x83507cc8c8b67ed48badd1f59f684d5d02884c81', // uCRV + '0xf964b0e3ffdea659c44a5a52bc0b82a24b89ce0e', // uFXS + '0x8659fc767cad6005de79af65dafe4249c57927af', // uCVX + ]; + } + + async getTokenBalancesPerPosition({ + address, + contractPosition, + contract, + }: GetTokenBalancesParams) { + const rewardToken = contractPosition.tokens.find(isClaimable)!; + const rewardsData = await this.merkleCache.getClaim(rewardToken.address, address); + if (!rewardsData) return [0]; + + const { index, amount } = rewardsData; + const isClaimed = await contract.isClaimed(index); + if (isClaimed) return [0]; + + return [amount]; } } diff --git a/src/apps/llama-airforce/ethereum/llama-airforce.vault.token-fetcher.ts b/src/apps/llama-airforce/ethereum/llama-airforce.vault.token-fetcher.ts index 628c6cf3d..987512c48 100644 --- a/src/apps/llama-airforce/ethereum/llama-airforce.vault.token-fetcher.ts +++ b/src/apps/llama-airforce/ethereum/llama-airforce.vault.token-fetcher.ts @@ -3,82 +3,96 @@ import { Inject } from '@nestjs/common'; import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface'; import { Register } from '~app-toolkit/decorators'; import { getLabelFromToken } from '~app-toolkit/helpers/presentation/image.present'; -import { CURVE_DEFINITION } from '~apps/curve'; -import { PIREX_DEFINITION } from '~apps/pirex'; -import { PositionFetcher } from '~position/position-fetcher.interface'; -import { AppTokenPosition } from '~position/position.interface'; +import { AppTokenTemplatePositionFetcher } from '~position/template/app-token.template.position-fetcher'; +import { + GetDataPropsParams, + GetDisplayPropsParams, + GetPricePerShareParams, + GetUnderlyingTokensParams, +} from '~position/template/app-token.template.types'; import { Network } from '~types'; -import { LlamaAirforceContractFactory, LlamaAirforceUnionVault, LlamaAirforceUnionVaultPirex } from '../contracts'; +import { LlamaAirforceContractFactory, LlamaAirforceUnionVault } from '../contracts'; import { LLAMA_AIRFORCE_DEFINITION } from '../llama-airforce.definition'; +export type LlamaAirforceVaultTokenDataProps = { + reserve: number; + liquidity: number; +}; + const appId = LLAMA_AIRFORCE_DEFINITION.id; const groupId = LLAMA_AIRFORCE_DEFINITION.groups.vault.id; const network = Network.ETHEREUM_MAINNET; @Register.TokenPositionFetcher({ appId, groupId, network }) -export class EthereumLlamaAirforceVaultTokenFetcher implements PositionFetcher { +export class EthereumLlamaAirforceVaultTokenFetcher extends AppTokenTemplatePositionFetcher< + LlamaAirforceUnionVault, + LlamaAirforceVaultTokenDataProps +> { + appId = appId; + groupId = groupId; + network = network; + groupLabel = 'Vaults'; + constructor( - @Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit, - @Inject(LlamaAirforceContractFactory) private readonly llamaAirforceContractFactory: LlamaAirforceContractFactory, - ) {} + @Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit, + @Inject(LlamaAirforceContractFactory) protected readonly contractFactory: LlamaAirforceContractFactory, + ) { + super(appToolkit); + } + + getContract(address: string): LlamaAirforceUnionVault { + return this.contractFactory.llamaAirforceUnionVault({ address, network: this.network }); + } + + getAddresses() { + return [ + '0x83507cc8c8b67ed48badd1f59f684d5d02884c81', // uCRV + '0xf964b0e3ffdea659c44a5a52bc0b82a24b89ce0e', // uFXS + '0x8659fc767cad6005de79af65dafe4249c57927af', // uCVX + '0xd6fc1ecd9965ba9cac895654979564a291c74c29', // uauraBAL + ]; + } + + async getUnderlyingTokenAddresses({ + address, + contract, + multicall, + }: GetUnderlyingTokensParams) { + if (address === '0x8659fc767cad6005de79af65dafe4249c57927af') { + const pirexContract = this.contractFactory.llamaAirforceUnionVaultPirex({ address, network: this.network }); + return multicall.wrap(pirexContract).asset(); + } + + return contract.underlying(); + } + + async getPricePerShare({ contract, appToken, multicall }: GetPricePerShareParams) { + if (appToken.address === '0x8659fc767cad6005de79af65dafe4249c57927af') { + const pirexContract = this.contractFactory.llamaAirforceUnionVaultPirex({ + address: appToken.address, + network: this.network, + }); + + const reserveRaw = await multicall.wrap(pirexContract).totalAssets(); + const reserve = Number(reserveRaw) / 10 ** appToken.tokens[0].decimals; + return reserve / appToken.supply; + } - async getUnionVaults() { - return await this.appToolkit.helpers.vaultTokenHelper.getTokens({ - appId, - groupId, - network, - dependencies: [ - { appId: CURVE_DEFINITION.id, groupIds: [CURVE_DEFINITION.groups.pool.id], network }, - { appId: PIREX_DEFINITION.id, groupIds: [PIREX_DEFINITION.groups.vault.id], network }, - ], - resolveContract: ({ address, network }) => - this.llamaAirforceContractFactory.llamaAirforceUnionVault({ address, network }), - resolveVaultAddresses: async () => [ - '0x83507cc8c8b67ed48badd1f59f684d5d02884c81', // uCRV - '0xf964b0e3ffdea659c44a5a52bc0b82a24b89ce0e', // uFXS - '0x8659fc767cad6005de79af65dafe4249c57927af', // uCVX - ], - resolveUnderlyingTokenAddress: async ({ contract, multicall }) => multicall.wrap(contract).underlying(), - resolvePricePerShare: async ({ reserve, supply }) => reserve / supply, - resolveReserve: async ({ multicall, contract, underlyingToken }) => - multicall - .wrap(contract) - .totalUnderlying() - .then(v => Number(v) / 10 ** underlyingToken.decimals), - resolvePrimaryLabel: ({ underlyingToken }) => `${getLabelFromToken(underlyingToken)} Pounder`, - }); + const reserveRaw = await contract.totalUnderlying(); + const reserve = Number(reserveRaw) / 10 ** appToken.tokens[0].decimals; + return reserve / appToken.supply; } - async getUnionPirexVaults() { - return await this.appToolkit.helpers.vaultTokenHelper.getTokens({ - appId, - groupId, - network, - dependencies: [ - { appId: CURVE_DEFINITION.id, groupIds: [CURVE_DEFINITION.groups.pool.id], network }, - { appId: PIREX_DEFINITION.id, groupIds: [PIREX_DEFINITION.groups.vault.id], network }, - ], - resolveContract: ({ address, network }) => - this.llamaAirforceContractFactory.llamaAirforceUnionVaultPirex({ address, network }), - resolveVaultAddresses: async () => [ - '0x83507cc8c8b67ed48badd1f59f684d5d02884c81', // uCRV - '0xf964b0e3ffdea659c44a5a52bc0b82a24b89ce0e', // uFXS - '0x8659fc767cad6005de79af65dafe4249c57927af', // uCVX - ], - resolveUnderlyingTokenAddress: async ({ contract, multicall }) => multicall.wrap(contract).asset(), - resolvePricePerShare: async ({ reserve, supply }) => reserve / supply, - resolveReserve: async ({ multicall, contract, underlyingToken }) => - multicall - .wrap(contract) - .totalAssets() - .then(v => Number(v) / 10 ** underlyingToken.decimals), - resolvePrimaryLabel: ({ underlyingToken }) => `${getLabelFromToken(underlyingToken)} Pounder`, - }); + async getDataProps({ + appToken, + }: GetDataPropsParams): Promise { + const reserve = appToken.pricePerShare[0] * appToken.supply; + const liquidity = reserve * appToken.price; + return { reserve, liquidity }; } - async getPositions() { - const [unionVaults, unionPirexVaults] = await Promise.all([this.getUnionVaults(), this.getUnionPirexVaults()]); - return [...unionVaults, ...unionPirexVaults]; + async getLabel({ appToken }: GetDisplayPropsParams) { + return `${getLabelFromToken(appToken.tokens[0])} Pounder`; } } diff --git a/src/apps/llama-airforce/llama-airforce.module.ts b/src/apps/llama-airforce/llama-airforce.module.ts index fcbd96a49..2413beb11 100644 --- a/src/apps/llama-airforce/llama-airforce.module.ts +++ b/src/apps/llama-airforce/llama-airforce.module.ts @@ -2,7 +2,6 @@ import { Register } from '~app-toolkit/decorators'; import { AbstractApp } from '~app/app.dynamic-module'; import { LlamaAirforceContractFactory } from './contracts'; -import { EthereumLlamaAirforceAirdropContractPositionBalanceFetcher } from './ethereum/llama-airforce.airdrop.contract-position-balance-fetcher'; import { EthereumLlamaAirforceAirdropContractPositionFetcher } from './ethereum/llama-airforce.airdrop.contract-position-fetcher'; import { EthereumLlamaAirforceMerkleCache } from './ethereum/llama-airforce.merkle-cache'; import { EthereumLlamaAirforceVaultTokenFetcher } from './ethereum/llama-airforce.vault.token-fetcher'; @@ -16,7 +15,6 @@ import { LlamaAirforceAppDefinition, LLAMA_AIRFORCE_DEFINITION } from './llama-a // Ethereum EthereumLlamaAirforceMerkleCache, EthereumLlamaAirforceAirdropContractPositionFetcher, - EthereumLlamaAirforceAirdropContractPositionBalanceFetcher, EthereumLlamaAirforceVaultTokenFetcher, ], })