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

Commit

Permalink
feat(saddle): Migrate to templates, add Curve template for simple sta…
Browse files Browse the repository at this point in the history
…tic definitions (#1813)

* feat(saddle): Migrate to templates, add Curve template for simple static definitions

* Gr

* feat(saddle): Smol fixes
  • Loading branch information
immasandwich authored Nov 28, 2022
1 parent 7fc135c commit 7e97ef8
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 288 deletions.
6 changes: 3 additions & 3 deletions src/apps/curve/common/curve.crypto-pool.token-fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { CurveContractFactory, CurveCryptoRegistry } from '../contracts';

import {
CurvePoolTokenFetcher,
CurvePoolDynamicTokenFetcher,
ResolveCoinAddressesParams,
ResolveFeesParams,
ResolvePoolCountParams,
ResolveReservesParams,
ResolveSwapAddressParams,
ResolveTokenAddressParams,
} from './curve.pool.token-fetcher';
} from './curve.pool-dynamic.token-fetcher';
import { CurveVolumeDataLoader } from './curve.volume.data-loader';

export abstract class CurveCryptoPoolTokenFetcher extends CurvePoolTokenFetcher<CurveCryptoRegistry> {
export abstract class CurveCryptoPoolTokenFetcher extends CurvePoolDynamicTokenFetcher<CurveCryptoRegistry> {
constructor(
@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit,
@Inject(CurveContractFactory) protected readonly contractFactory: CurveContractFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import { isMulticallUnderlyingError } from '~multicall/multicall.ethers';
import { CurveContractFactory, CurveCryptoFactory } from '../contracts';

import {
CurvePoolTokenFetcher,
CurvePoolDynamicTokenFetcher,
ResolveCoinAddressesParams,
ResolveFeesParams,
ResolvePoolCountParams,
ResolveReservesParams,
ResolveSwapAddressParams,
ResolveTokenAddressParams,
} from './curve.pool.token-fetcher';
} from './curve.pool-dynamic.token-fetcher';
import { CurveVolumeDataLoader } from './curve.volume.data-loader';

export abstract class CurveFactoryCryptoPoolTokenFetcher extends CurvePoolTokenFetcher<CurveCryptoFactory> {
export abstract class CurveFactoryCryptoPoolTokenFetcher extends CurvePoolDynamicTokenFetcher<CurveCryptoFactory> {
constructor(
@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit,
@Inject(CurveContractFactory) protected readonly contractFactory: CurveContractFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { CurveContractFactory, CurveStableFactory } from '../contracts';

import {
CurvePoolTokenFetcher,
CurvePoolDynamicTokenFetcher,
ResolveCoinAddressesParams,
ResolveFeesParams,
ResolvePoolCountParams,
ResolveReservesParams,
ResolveSwapAddressParams,
ResolveTokenAddressParams,
} from './curve.pool.token-fetcher';
} from './curve.pool-dynamic.token-fetcher';
import { CurveVolumeDataLoader } from './curve.volume.data-loader';

export abstract class CurveFactoryStablePoolTokenFetcher extends CurvePoolTokenFetcher<CurveStableFactory> {
export abstract class CurveFactoryStablePoolTokenFetcher extends CurvePoolDynamicTokenFetcher<CurveStableFactory> {
constructor(
@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit,
@Inject(CurveContractFactory) protected readonly contractFactory: CurveContractFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export type ResolveFeesParams<T extends Contract> = {
multicall: IMulticallWrapper;
};

export abstract class CurvePoolTokenFetcher<T extends Contract> extends AppTokenTemplatePositionFetcher<
export abstract class CurvePoolDynamicTokenFetcher<T extends Contract> extends AppTokenTemplatePositionFetcher<
Erc20,
CurvePoolTokenDataProps,
CurvePoolDefinition
Expand Down
160 changes: 160 additions & 0 deletions src/apps/curve/common/curve.pool-static.token-fetcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { Inject } from '@nestjs/common';
import { BigNumberish, Contract } from 'ethers';
import { compact, range } from 'lodash';

import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { ETH_ADDR_ALIAS, ZERO_ADDRESS } from '~app-toolkit/constants/address';
import {
buildDollarDisplayItem,
buildPercentageDisplayItem,
} from '~app-toolkit/helpers/presentation/display-item.present';
import { getLabelFromToken } from '~app-toolkit/helpers/presentation/image.present';
import { ContractFactory, Erc20 } from '~contract/contracts';
import { IMulticallWrapper } from '~multicall';
import { isMulticallUnderlyingError } from '~multicall/multicall.ethers';
import { AppTokenTemplatePositionFetcher } from '~position/template/app-token.template.position-fetcher';
import {
GetAddressesParams,
DefaultAppTokenDefinition,
GetUnderlyingTokensParams,
GetPricePerShareParams,
GetDataPropsParams,
GetDisplayPropsParams,
} from '~position/template/app-token.template.types';

export type CurvePoolTokenDataProps = {
swapAddress: string;
liquidity: number;
reserves: number[];
apy: number;
volume: number;
fee: number;
};

export type CurvePoolDefinition = {
address: string;
swapAddress: string;
isLegacy?: boolean;
};

export type ResolvePoolCoinAddressParams<T extends Contract> = {
contract: T;
multicall: IMulticallWrapper;
index: number;
};

export type ResolvePoolReserveParams<T extends Contract> = {
contract: T;
multicall: IMulticallWrapper;
index: number;
};

export type ResolvePoolFeeParams<T extends Contract> = {
contract: T;
multicall: IMulticallWrapper;
};

export abstract class CurvePoolStaticTokenFetcher<T extends Contract> extends AppTokenTemplatePositionFetcher<
Erc20,
CurvePoolTokenDataProps,
CurvePoolDefinition
> {
abstract poolDefinitions: CurvePoolDefinition[];

abstract resolvePoolContract(definition: CurvePoolDefinition): T;
abstract resolvePoolCoinAddress(opts: ResolvePoolCoinAddressParams<T>): Promise<string>;
abstract resolvePoolReserve(opts: ResolvePoolReserveParams<T>): Promise<BigNumberish>;
abstract resolvePoolFee(opts: ResolvePoolFeeParams<T>): Promise<BigNumberish>;

constructor(
@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit,
@Inject(ContractFactory) protected readonly contractFactory: ContractFactory,
) {
super(appToolkit);
}

getContract(address: string): Erc20 {
return this.contractFactory.erc20({ address, network: this.network });
}

async getDefinitions() {
return this.poolDefinitions;
}

async getAddresses({ definitions }: GetAddressesParams<DefaultAppTokenDefinition>) {
return definitions.map(v => v.address);
}

async getUnderlyingTokenAddresses({ multicall, definition }: GetUnderlyingTokensParams<Erc20, CurvePoolDefinition>) {
const contract = multicall.wrap(this.resolvePoolContract(definition));

const coinAddressesRaw = await Promise.all(
range(0, 4).map(index =>
this.resolvePoolCoinAddress({ multicall, contract, index }).catch(err => {
if (isMulticallUnderlyingError(err)) return null;
throw err;
}),
),
);

return compact(coinAddressesRaw)
.filter(v => v !== ZERO_ADDRESS)
.map(v => v.toLowerCase())
.map(v => v.replace(ETH_ADDR_ALIAS, ZERO_ADDRESS));
}

async getPricePerShare({
multicall,
definition,
appToken,
}: GetPricePerShareParams<Erc20, CurvePoolTokenDataProps, CurvePoolDefinition>) {
const contract = multicall.wrap(this.resolvePoolContract(definition));
const coinsRange = range(0, appToken.tokens.length);
const reservesRaw = await Promise.all(
coinsRange.map(index => this.resolvePoolReserve({ multicall, contract, index })),
);

const reserves = reservesRaw.map((v, i) => Number(v) / 10 ** appToken.tokens[i].decimals);
const pricePerShare = reserves.map(v => v / appToken.supply);
return pricePerShare;
}

async getDataProps(params: GetDataPropsParams<Erc20, CurvePoolTokenDataProps, CurvePoolDefinition>) {
const defaultDataProps = await super.getDataProps(params);

const { multicall, definition } = params;
const contract = multicall.wrap(this.resolvePoolContract(definition));
const swapAddress = definition.swapAddress;

const fees = await this.resolvePoolFee({ contract, multicall });
const fee = Number(fees[0]) / 10 ** 8;
const volume = 0; // not supported
const apy = 0; // not supported

return { ...defaultDataProps, fee, volume, apy, swapAddress };
}

async getLabel({ appToken }: GetDisplayPropsParams<Erc20, CurvePoolTokenDataProps, CurvePoolDefinition>) {
return appToken.tokens.map(v => getLabelFromToken(v)).join(' / ');
}

async getSecondaryLabel({ appToken }: GetDisplayPropsParams<Erc20, CurvePoolTokenDataProps, CurvePoolDefinition>) {
const reservesUSD = appToken.tokens.map((t, i) => appToken.dataProps.reserves[i] * t.price);
const liquidity = reservesUSD.reduce((total, r) => total + r, 0);
const reservePercentages = reservesUSD.map(reserveUSD => reserveUSD / liquidity);
const ratio = reservePercentages.map(p => `${Math.floor(p * 100)}%`).join(' / ');

return ratio;
}

async getStatsItems({ appToken }: GetDisplayPropsParams<Erc20, CurvePoolTokenDataProps, CurvePoolDefinition>) {
const { liquidity, volume, apy, fee } = appToken.dataProps;

return [
{ label: 'Liquidity', value: buildDollarDisplayItem(liquidity) },
{ label: 'Volume', value: buildDollarDisplayItem(volume) },
{ label: 'APY', value: buildPercentageDisplayItem(apy) },
{ label: 'Fee', value: buildPercentageDisplayItem(fee) },
];
}
}
6 changes: 3 additions & 3 deletions src/apps/curve/common/curve.stable-pool.token-fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { CurveContractFactory, CurveStableRegistry } from '../contracts';

import {
CurvePoolTokenFetcher,
CurvePoolDynamicTokenFetcher,
ResolveCoinAddressesParams,
ResolveFeesParams,
ResolvePoolCountParams,
ResolveReservesParams,
ResolveSwapAddressParams,
ResolveTokenAddressParams,
} from './curve.pool.token-fetcher';
} from './curve.pool-dynamic.token-fetcher';
import { CurveVolumeDataLoader } from './curve.volume.data-loader';

export abstract class CurveStablePoolTokenFetcher extends CurvePoolTokenFetcher<CurveStableRegistry> {
export abstract class CurveStablePoolTokenFetcher extends CurvePoolDynamicTokenFetcher<CurveStableRegistry> {
constructor(
@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit,
@Inject(CurveContractFactory) protected readonly contractFactory: CurveContractFactory,
Expand Down
91 changes: 0 additions & 91 deletions src/apps/saddle/ethereum/saddle.balance-fetcher.ts

This file was deleted.

Loading

0 comments on commit 7e97ef8

Please sign in to comment.