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

Commit

Permalink
fix(rari-fuse): Optimize balances to use Comptroller to pre-emptively…
Browse files Browse the repository at this point in the history
… determine participated markets (#550)
  • Loading branch information
immasandwich authored May 31, 2022
1 parent 1cd1cb0 commit 46d8593
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Inject, Injectable } from '@nestjs/common';
import { sumBy } from 'lodash';
import { identity, sumBy } from 'lodash';

import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { EthersMulticall as Multicall } from '~multicall';
Expand All @@ -13,6 +13,7 @@ type GetTokenBalancesParams<T> = {
appId: string;
groupId: string;
address: string;
filter?: (contractPosition: ContractPosition<T>) => boolean;
resolveBalances: (opts: {
address: string;
network: Network;
Expand All @@ -30,6 +31,7 @@ export class ContractPositionBalanceHelper {
appId,
groupId,
address,
filter = identity,
resolveBalances,
}: GetTokenBalancesParams<T>) {
const multicall = this.appToolkit.getMulticall(network);
Expand All @@ -39,8 +41,9 @@ export class ContractPositionBalanceHelper {
groupIds: [groupId],
});

const filteredPositions = contractPositions.filter(filter);
const balances = await Promise.all(
contractPositions.map(async contractPosition => {
filteredPositions.map(async contractPosition => {
const tokens = await resolveBalances({ multicall, network, address, contractPosition });
const balanceUSD = sumBy(tokens, t => t.balanceUSD);
const balance: ContractPositionBalance<T> = { ...contractPosition, tokens, balanceUSD };
Expand Down
25 changes: 16 additions & 9 deletions src/app-toolkit/helpers/balance/token-balance.helper.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { Inject, Injectable } from '@nestjs/common';
import BigNumberJS from 'bignumber.js';
import { isArray, pick } from 'lodash';
import { identity, isArray, pick } from 'lodash';

import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import { EthersMulticall } from '~multicall/multicall.ethers';
import { ContractType } from '~position/contract.interface';
import { StatsItem, WithMetaType } from '~position/display.interface';
import { DefaultDataProps, StatsItem, WithMetaType } from '~position/display.interface';
import { AppTokenPositionBalance, BaseTokenBalance } from '~position/position-balance.interface';
import { AppTokenPosition, ContractPosition, MetaType, Token } from '~position/position.interface';
import { BaseToken } from '~position/token.interface';
import { Network } from '~types/network.interface';

import { buildPercentageDisplayItem } from '../presentation/display-item.present';

type GetTokenBalancesParams = {
type GetTokenBalancesParams<T> = {
network: Network;
appId: string;
groupId: string;
address: string;
resolveBalance?: (opts: { multicall: EthersMulticall; address: string; token: AppTokenPosition }) => Promise<string>;
filter?: (contractPosition: AppTokenPosition<T>) => boolean;
resolveBalance?: (opts: {
multicall: EthersMulticall;
address: string;
token: AppTokenPosition<T>;
}) => Promise<string>;
};

type Options = {
Expand Down Expand Up @@ -99,25 +104,27 @@ export const drillBalance = <T extends Token>(
export class TokenBalanceHelper {
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {}

async getTokenBalances({
async getTokenBalances<T = DefaultDataProps>({
network,
appId,
groupId,
address,
filter = identity,
resolveBalance = async ({ multicall, address, token }) => {
return await multicall
.wrap(this.appToolkit.globalContracts.erc20({ network, address: token.address }))
.balanceOf(address)
.then(v => v.toString());
},
}: GetTokenBalancesParams) {
}: GetTokenBalancesParams<T>) {
const multicall = this.appToolkit.getMulticall(network);
const appTokens = await this.appToolkit.getAppTokenPositions({ appId, network, groupIds: [groupId] });
const appTokens = await this.appToolkit.getAppTokenPositions<T>({ appId, network, groupIds: [groupId] });

const filteredTokens = appTokens.filter(filter);
const balances = await Promise.all(
appTokens.map(async token => {
filteredTokens.map(async token => {
const balanceRaw = await resolveBalance({ multicall, address, token });
const tokenBalance = drillBalance(token, balanceRaw);
const tokenBalance = drillBalance(token as AppTokenPosition, balanceRaw);
return tokenBalance;
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { drillBalance } from '~app-toolkit';
import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { CompoundContractFactory } from '~apps/compound';
import { CompoundBorrowContractPositionDataProps } from '~apps/compound/helper/compound.borrow.contract-position-helper';
import { PositionBalanceFetcher } from '~position/position-balance-fetcher.interface';
import { ContractPositionBalance } from '~position/position-balance.interface';
import { isBorrowed } from '~position/position.utils';
import { Network } from '~types/network.interface';

import { RariFuseContractFactory } from '../contracts';
import { RARI_FUSE_DEFINITION } from '../rari-fuse.definition';

@Register.ContractPositionBalanceFetcher({
Expand All @@ -24,24 +26,35 @@ export class EthereumRariFuseBorrowContractPositionBalanceFetcher
private readonly appToolkit: IAppToolkit,
@Inject(CompoundContractFactory)
private readonly compoundContractFactory: CompoundContractFactory,
@Inject(RariFuseContractFactory)
private readonly rariFuseContractFactory: RariFuseContractFactory,
) {}

async getBalances(address: string) {
return this.appToolkit.helpers.contractPositionBalanceHelper.getContractPositionBalances({
address,
appId: RARI_FUSE_DEFINITION.id,
groupId: RARI_FUSE_DEFINITION.groups.borrow.id,
network: Network.ETHEREUM_MAINNET,
resolveBalances: async ({ address, contractPosition, multicall }) => {
const borrowedToken = contractPosition.tokens.find(isBorrowed)!;
const contract = this.compoundContractFactory.compoundCToken(contractPosition);
const balanceRaw = await multicall
.wrap(contract)
.borrowBalanceCurrent(address)
.catch(() => '0');
const network = Network.ETHEREUM_MAINNET;
const fuseLensAddress = '0x8da38681826f4abbe089643d2b3fe4c6e4730493';
const fuseLens = this.rariFuseContractFactory.rariFusePoolLens({ address: fuseLensAddress, network });
const poolsBySupplier = await fuseLens.getPoolsBySupplierWithData(address);
const participatedComptrollers = poolsBySupplier[1].map(p => p.comptroller.toLowerCase());

return [drillBalance(borrowedToken, balanceRaw.toString(), { isDebt: true })];
return this.appToolkit.helpers.contractPositionBalanceHelper.getContractPositionBalances<CompoundBorrowContractPositionDataProps>(
{
address,
appId: RARI_FUSE_DEFINITION.id,
groupId: RARI_FUSE_DEFINITION.groups.borrow.id,
network: Network.ETHEREUM_MAINNET,
filter: v => participatedComptrollers.includes(v.dataProps.comptrollerAddress),
resolveBalances: async ({ address, contractPosition, multicall }) => {
const borrowedToken = contractPosition.tokens.find(isBorrowed)!;
const contract = this.compoundContractFactory.compoundCToken(contractPosition);
const balanceRaw = await multicall
.wrap(contract)
.borrowBalanceCurrent(address)
.catch(() => '0');

return [drillBalance(borrowedToken, balanceRaw.toString(), { isDebt: true })];
},
},
});
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Inject } from '@nestjs/common';

import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { CompoundSupplyTokenDataProps } from '~apps/compound/helper/compound.supply.token-helper';
import { PositionBalanceFetcher } from '~position/position-balance-fetcher.interface';
import { AppTokenPositionBalance } from '~position/position-balance.interface';
import { Network } from '~types/network.interface';

import { RariFuseContractFactory } from '../contracts';
import { RARI_FUSE_DEFINITION } from '../rari-fuse.definition';

@Register.TokenPositionBalanceFetcher({
appId: RARI_FUSE_DEFINITION.id,
groupId: RARI_FUSE_DEFINITION.groups.supply.id,
network: Network.ETHEREUM_MAINNET,
})
export class EthereumRariFuseSupplyTokenBalanceFetcher implements PositionBalanceFetcher<AppTokenPositionBalance> {
constructor(
@Inject(APP_TOOLKIT)
private readonly appToolkit: IAppToolkit,
@Inject(RariFuseContractFactory)
private readonly rariFuseContractFactory: RariFuseContractFactory,
) {}

async getBalances(address: string) {
const network = Network.ETHEREUM_MAINNET;
const fuseLensAddress = '0x8da38681826f4abbe089643d2b3fe4c6e4730493';
const fuseLens = this.rariFuseContractFactory.rariFusePoolLens({ address: fuseLensAddress, network });
const poolsBySupplier = await fuseLens.getPoolsBySupplierWithData(address);
const participatedComptrollers = poolsBySupplier[1].map(p => p.comptroller.toLowerCase());

return this.appToolkit.helpers.tokenBalanceHelper.getTokenBalances<CompoundSupplyTokenDataProps>({
address,
appId: RARI_FUSE_DEFINITION.id,
groupId: RARI_FUSE_DEFINITION.groups.supply.id,
network: Network.ETHEREUM_MAINNET,
filter: v => participatedComptrollers.includes(v.dataProps.comptrollerAddress),
});
}
}
2 changes: 2 additions & 0 deletions src/apps/rari-fuse/rari-fuse.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { RariFuseContractFactory } from './contracts';
import { EthereumRariFuseBalancePresenter } from './ethereum/rari-fuse.balance-presenter';
import { EthereumRariFuseBorrowContractPositionBalanceFetcher } from './ethereum/rari-fuse.borrow.contract-position-balance-fetcher';
import { EthereumRariFuseBorrowContractPositionFetcher } from './ethereum/rari-fuse.borrow.contract-position-fetcher';
import { EthereumRariFuseSupplyTokenBalanceFetcher } from './ethereum/rari-fuse.supply.token-balance-fetcher';
import { EthereumRariFuseSupplyTokenFetcher } from './ethereum/rari-fuse.supply.token-fetcher';
import { RariFuseAppDefinition, RARI_FUSE_DEFINITION } from './rari-fuse.definition';

Expand All @@ -20,6 +21,7 @@ import { RariFuseAppDefinition, RARI_FUSE_DEFINITION } from './rari-fuse.definit
EthereumRariFuseBorrowContractPositionFetcher,
EthereumRariFuseBorrowContractPositionBalanceFetcher,
EthereumRariFuseSupplyTokenFetcher,
EthereumRariFuseSupplyTokenBalanceFetcher,
],
})
export class RariFuseAppModule extends AbstractApp() {}

0 comments on commit 46d8593

Please sign in to comment.