Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
feat(revert-fi): Add compounding Uniswap v3 LP positions (#1112)
Browse files Browse the repository at this point in the history
  • Loading branch information
Clonescody committed Aug 12, 2022
1 parent 9f1c2c0 commit 2c83174
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 43 deletions.
60 changes: 50 additions & 10 deletions src/apps/revert-finance/arbitrum/revert-finance.balance-fetcher.ts
@@ -1,14 +1,18 @@
import { Inject } from '@nestjs/common';
import { getAddress } from 'ethers/lib/utils';

import { drillBalance } from '~app-toolkit';
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present';
import { UniswapV2ContractFactory } from '~apps/uniswap-v2';
import { UniswapV3LiquidityTokenHelper } from '~apps/uniswap-v2/helpers/uniswap-v3.liquidity.token-helper';
import { BalanceFetcher } from '~balance/balance-fetcher.interface';
import { ContractPositionBalance } from '~position/position-balance.interface';
import { AppTokenPositionBalance, ContractPositionBalance } from '~position/position-balance.interface';
import { Network } from '~types/network.interface';

import { accountBalancesQuery, CompoundorUserPosition } from '../graphql/accountBalancesQuery';
import { accountBalancesQuery, CompoundorAccountBalances } from '../graphql/accountBalancesQuery';
import { accountCompoundingTokensQuery, CompoundingAccountTokens } from '../graphql/accountCompoundingTokensQuery';
import { generateGraphUrlForNetwork } from '../graphql/graphUrlGenerator';
import { getCompoundorContractPosition } from '../helpers/contractPositionParser';
import { REVERT_FINANCE_DEFINITION } from '../revert-finance.definition';
Expand All @@ -17,34 +21,70 @@ const network = Network.ARBITRUM_MAINNET;

@Register.BalanceFetcher(REVERT_FINANCE_DEFINITION.id, network)
export class ArbitrumRevertFinanceBalanceFetcher implements BalanceFetcher {
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {}
constructor(
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit,
@Inject(UniswapV2ContractFactory) protected readonly uniswapV2ContractFactory: UniswapV2ContractFactory,
@Inject(UniswapV3LiquidityTokenHelper)
private readonly uniswapV3LiquidityTokenHelper: UniswapV3LiquidityTokenHelper,
) {}

async getAccumulatedCompoundorRewards(address: string) {
async getCompoundorAccountBalances(address: string) {
const graphHelper = this.appToolkit.helpers.theGraphHelper;
const data = await graphHelper.requestGraph<CompoundorUserPosition>({
const data = await graphHelper.requestGraph<CompoundorAccountBalances>({
endpoint: generateGraphUrlForNetwork(network),
query: accountBalancesQuery,
variables: { address: getAddress(address) },
});
if (!data) return [];
const baseTokens = await this.appToolkit.getBaseTokenPrices(network);
const rewards: Array<ContractPositionBalance> = [];
const accountBalances: Array<ContractPositionBalance> = [];
data.accountBalances.map(({ token, balance }) => {
const existingToken = baseTokens.find(item => item.address === token)!;
if (!token) return [];
accountBalances.push(getCompoundorContractPosition(network, existingToken, balance));
});
return accountBalances;
}

rewards.push(getCompoundorContractPosition(network, existingToken, balance));
async getCompoundingAccountTokens(address: string) {
const graphHelper = this.appToolkit.helpers.theGraphHelper;
const data = await graphHelper.requestGraph<CompoundingAccountTokens>({
endpoint: generateGraphUrlForNetwork(network),
query: accountCompoundingTokensQuery,
variables: { address: getAddress(address) },
});
return rewards;
if (!data) return [];
const multicall = this.appToolkit.getMulticall(network);
const compoundingBalances: Array<AppTokenPositionBalance> = [];
const baseTokens = await this.appToolkit.getBaseTokenPrices(network);
await Promise.all(
data.tokens.map(async ({ id }) => {
const uniV3Token = await this.uniswapV3LiquidityTokenHelper.getLiquidityToken({
positionId: id,
network,
context: { multicall, baseTokens },
});
if (!uniV3Token) return;
compoundingBalances.push(drillBalance(uniV3Token, '1'));
}),
);
return compoundingBalances;
}

async getBalances(address: string) {
const [accumulatedCompoundorRewards] = await Promise.all([this.getAccumulatedCompoundorRewards(address)]);
const [compoundorAccountBalances, compoundingAccountBalances] = await Promise.all([
this.getCompoundorAccountBalances(address),
this.getCompoundingAccountTokens(address),
]);

return presentBalanceFetcherResponse([
{
label: 'Compoundor rewards',
assets: accumulatedCompoundorRewards,
assets: compoundorAccountBalances,
},
{
label: 'Compounding positions',
assets: compoundingAccountBalances,
},
]);
}
Expand Down
60 changes: 50 additions & 10 deletions src/apps/revert-finance/ethereum/revert-finance.balance-fetcher.ts
@@ -1,14 +1,18 @@
import { Inject } from '@nestjs/common';
import { getAddress } from 'ethers/lib/utils';

import { drillBalance } from '~app-toolkit';
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present';
import { UniswapV2ContractFactory } from '~apps/uniswap-v2';
import { UniswapV3LiquidityTokenHelper } from '~apps/uniswap-v2/helpers/uniswap-v3.liquidity.token-helper';
import { BalanceFetcher } from '~balance/balance-fetcher.interface';
import { ContractPositionBalance } from '~position/position-balance.interface';
import { AppTokenPositionBalance, ContractPositionBalance } from '~position/position-balance.interface';
import { Network } from '~types/network.interface';

import { accountBalancesQuery, CompoundorUserPosition } from '../graphql/accountBalancesQuery';
import { accountBalancesQuery, CompoundorAccountBalances } from '../graphql/accountBalancesQuery';
import { accountCompoundingTokensQuery, CompoundingAccountTokens } from '../graphql/accountCompoundingTokensQuery';
import { generateGraphUrlForNetwork } from '../graphql/graphUrlGenerator';
import { getCompoundorContractPosition } from '../helpers/contractPositionParser';
import { REVERT_FINANCE_DEFINITION } from '../revert-finance.definition';
Expand All @@ -17,34 +21,70 @@ const network = Network.ETHEREUM_MAINNET;

@Register.BalanceFetcher(REVERT_FINANCE_DEFINITION.id, network)
export class EthereumRevertFinanceBalanceFetcher implements BalanceFetcher {
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {}
constructor(
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit,
@Inject(UniswapV2ContractFactory) protected readonly uniswapV2ContractFactory: UniswapV2ContractFactory,
@Inject(UniswapV3LiquidityTokenHelper)
private readonly uniswapV3LiquidityTokenHelper: UniswapV3LiquidityTokenHelper,
) {}

async getAccumulatedCompoundorRewards(address: string) {
async getCompoundorAccountBalances(address: string) {
const graphHelper = this.appToolkit.helpers.theGraphHelper;
const data = await graphHelper.requestGraph<CompoundorUserPosition>({
const data = await graphHelper.requestGraph<CompoundorAccountBalances>({
endpoint: generateGraphUrlForNetwork(network),
query: accountBalancesQuery,
variables: { address: getAddress(address) },
});
if (!data) return [];
const baseTokens = await this.appToolkit.getBaseTokenPrices(network);
const rewards: Array<ContractPositionBalance> = [];
const accountBalances: Array<ContractPositionBalance> = [];
data.accountBalances.map(({ token, balance }) => {
const existingToken = baseTokens.find(item => item.address === token)!;
if (!token) return [];
accountBalances.push(getCompoundorContractPosition(network, existingToken, balance));
});
return accountBalances;
}

rewards.push(getCompoundorContractPosition(network, existingToken, balance));
async getCompoundingAccountTokens(address: string) {
const graphHelper = this.appToolkit.helpers.theGraphHelper;
const data = await graphHelper.requestGraph<CompoundingAccountTokens>({
endpoint: generateGraphUrlForNetwork(network),
query: accountCompoundingTokensQuery,
variables: { address: getAddress(address) },
});
return rewards;
if (!data) return [];
const multicall = this.appToolkit.getMulticall(network);
const compoundingBalances: Array<AppTokenPositionBalance> = [];
const baseTokens = await this.appToolkit.getBaseTokenPrices(network);
await Promise.all(
data.tokens.map(async ({ id }) => {
const uniV3Token = await this.uniswapV3LiquidityTokenHelper.getLiquidityToken({
positionId: id,
network,
context: { multicall, baseTokens },
});
if (!uniV3Token) return;
compoundingBalances.push(drillBalance(uniV3Token, '1'));
}),
);
return compoundingBalances;
}

async getBalances(address: string) {
const [accumulatedCompoundorRewards] = await Promise.all([this.getAccumulatedCompoundorRewards(address)]);
const [compoundorAccountBalances, compoundingAccountBalances] = await Promise.all([
this.getCompoundorAccountBalances(address),
this.getCompoundingAccountTokens(address),
]);

return presentBalanceFetcherResponse([
{
label: 'Compoundor rewards',
assets: accumulatedCompoundorRewards,
assets: compoundorAccountBalances,
},
{
label: 'Compounding positions',
assets: compoundingAccountBalances,
},
]);
}
Expand Down
4 changes: 2 additions & 2 deletions src/apps/revert-finance/graphql/accountBalancesQuery.ts
Expand Up @@ -7,12 +7,12 @@ type AccountBalance = {
balance: string;
};

export type CompoundorUserPosition = {
export type CompoundorAccountBalances = {
accountBalances: Array<AccountBalance>;
};

export const accountBalancesQuery = gql`
query getUserPositions($address: String!) {
query getAccountBalances($address: String) {
accountBalances(where: { account: $address }) {
id
account
Expand Down
23 changes: 23 additions & 0 deletions src/apps/revert-finance/graphql/accountCompoundingTokensQuery.ts
@@ -0,0 +1,23 @@
import { gql } from 'graphql-request';

type AccountTokens = {
id: string;
account: string;
compoundCount: string;
compounded0: string;
};

export type CompoundingAccountTokens = {
tokens: Array<AccountTokens>;
};

export const accountCompoundingTokensQuery = gql`
query getAccountCompoundingTokens($address: String) {
tokens(where: { account: $address }) {
id
account
compoundCount
compounded0
}
}
`;
12 changes: 12 additions & 0 deletions src/apps/revert-finance/helpers/contractPositionParser.ts
Expand Up @@ -39,3 +39,15 @@ export const getCompoundorContractPosition = (
displayProps,
};
};

// export const getCompoundingContractPosition = (network: Network, uniV3Lp: AppTokenPosition): TokenBalance => ({
// ...uniV3Lp,
// network,
// type: ContractType.APP_TOKEN,
// appId: REVERT_FINANCE_DEFINITION.id,
// groupId: REVERT_FINANCE_DEFINITION.groups.compoundorRewards.id,
// tokens: [...uniV3Lp.tokens],
// balanceUSD: uniV3Lp.balanceUSD,
// dataProps: uniV3Lp.dataProps,
// displayProps: uniV3Lp.displayProps,
// });
62 changes: 51 additions & 11 deletions src/apps/revert-finance/optimism/revert-finance.balance-fetcher.ts
@@ -1,14 +1,18 @@
import { Inject } from '@nestjs/common';
import { getAddress } from 'ethers/lib/utils';

import { drillBalance } from '~app-toolkit';
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { presentBalanceFetcherResponse } from '~app-toolkit/helpers/presentation/balance-fetcher-response.present';
import { UniswapV2ContractFactory } from '~apps/uniswap-v2';
import { UniswapV3LiquidityTokenHelper } from '~apps/uniswap-v2/helpers/uniswap-v3.liquidity.token-helper';
import { BalanceFetcher } from '~balance/balance-fetcher.interface';
import { ContractPositionBalance } from '~position/position-balance.interface';
import { AppTokenPositionBalance, ContractPositionBalance } from '~position/position-balance.interface';
import { Network } from '~types/network.interface';

import { accountBalancesQuery, CompoundorUserPosition } from '../graphql/accountBalancesQuery';
import { accountBalancesQuery, CompoundorAccountBalances } from '../graphql/accountBalancesQuery';
import { accountCompoundingTokensQuery, CompoundingAccountTokens } from '../graphql/accountCompoundingTokensQuery';
import { generateGraphUrlForNetwork } from '../graphql/graphUrlGenerator';
import { getCompoundorContractPosition } from '../helpers/contractPositionParser';
import { REVERT_FINANCE_DEFINITION } from '../revert-finance.definition';
Expand All @@ -17,34 +21,70 @@ const network = Network.OPTIMISM_MAINNET;

@Register.BalanceFetcher(REVERT_FINANCE_DEFINITION.id, network)
export class OptimismRevertFinanceBalanceFetcher implements BalanceFetcher {
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {}
constructor(
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit,
@Inject(UniswapV2ContractFactory) protected readonly uniswapV2ContractFactory: UniswapV2ContractFactory,
@Inject(UniswapV3LiquidityTokenHelper)
private readonly uniswapV3LiquidityTokenHelper: UniswapV3LiquidityTokenHelper,
) {}

async getAccumulatedCompoundorRewards(address: string) {
async getCompoundorAccountBalances(address: string) {
const graphHelper = this.appToolkit.helpers.theGraphHelper;
const data = await graphHelper.requestGraph<CompoundorUserPosition>({
const data = await graphHelper.requestGraph<CompoundorAccountBalances>({
endpoint: generateGraphUrlForNetwork(network),
query: accountBalancesQuery,
variables: { address: getAddress(address) },
});
if (!data) return [];
const baseTokens = await this.appToolkit.getBaseTokenPrices(network);
const rewards: Array<ContractPositionBalance> = [];
const accountBalances: Array<ContractPositionBalance> = [];
data.accountBalances.map(({ token, balance }) => {
const existingToken = baseTokens.find(item => item.address === token)!;
if (!token) return [];
if (!token) return;
accountBalances.push(getCompoundorContractPosition(network, existingToken, balance));
});
return accountBalances;
}

rewards.push(getCompoundorContractPosition(network, existingToken, balance));
async getCompoundingAccountTokens(address: string) {
const graphHelper = this.appToolkit.helpers.theGraphHelper;
const data = await graphHelper.requestGraph<CompoundingAccountTokens>({
endpoint: generateGraphUrlForNetwork(network),
query: accountCompoundingTokensQuery,
variables: { address: getAddress(address) },
});
return rewards;
if (!data) return [];
const multicall = this.appToolkit.getMulticall(network);
const compoundingBalances: Array<AppTokenPositionBalance> = [];
const baseTokens = await this.appToolkit.getBaseTokenPrices(network);
await Promise.all(
data.tokens.map(async ({ id }) => {
const uniV3Token = await this.uniswapV3LiquidityTokenHelper.getLiquidityToken({
positionId: id,
network,
context: { multicall, baseTokens },
});
if (!uniV3Token) return;
compoundingBalances.push(drillBalance(uniV3Token, '1'));
}),
);
return compoundingBalances;
}

async getBalances(address: string) {
const [accumulatedCompoundorRewards] = await Promise.all([this.getAccumulatedCompoundorRewards(address)]);
const [compoundorAccountBalances, compoundingAccountBalances] = await Promise.all([
this.getCompoundorAccountBalances(address),
this.getCompoundingAccountTokens(address),
]);

return presentBalanceFetcherResponse([
{
label: 'Compoundor rewards',
assets: accumulatedCompoundorRewards,
assets: compoundorAccountBalances,
},
{
label: 'Compounding positions',
assets: compoundingAccountBalances,
},
]);
}
Expand Down

0 comments on commit 2c83174

Please sign in to comment.