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

Commit

Permalink
feat(exactly): 🩹 Fix rates (x100), add deposit rates, update metadata (
Browse files Browse the repository at this point in the history
…#2033)

* chore(exactly): 💬 update app name and description

* chore(exactly): ⬆️ upgrade previewer

* refactor(exactly): ⚡️ get borrow rate from definition

* fix(exactly): 🩹 lowercase underlying address

* feat(exactly): ✨ add block number and timestamp to definitions

* refactor(exactly): 🎨 single import for types and values

* fix(exactly): 🐛 multiply rates by 100

* feat(exactly): ✨ return deposit rates

Co-authored-by: itofarina <[email protected]>

Co-authored-by: itofarina <[email protected]>
  • Loading branch information
cruzdanilo and itofarina authored Jan 5, 2023
1 parent 7602d32 commit 004354c
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 82 deletions.
34 changes: 22 additions & 12 deletions src/apps/exactly/common/exactly.definitions-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
import { Inject, Injectable } from '@nestjs/common';
import { constants } from 'ethers';
import { Injectable } from '@nestjs/common';
import { type BigNumber, constants } from 'ethers';

import type { IMulticallWrapper } from '~multicall/multicall.interface';
import type { DefaultAppTokenDefinition } from '~position/template/app-token.template.types';
import { Network } from '~types/network.interface';

import { ExactlyContractFactory } from '../contracts';
import type { Previewer } from '../contracts';
import { type Previewer, Previewer__factory } from '../contracts/ethers';

export const PREVIEWER_ADDRESSES = {
[Network.ETHEREUM_MAINNET]: '0x0aa3529ae5fdbceb69cf8ab2b9e2d3af85860469',
[Network.ETHEREUM_MAINNET]: '0x37ac9c4a26db589ee35215c7053009ee645585bb',
} as Partial<Record<Network, string>>;

export type ExactlyMarketDefinition = DefaultAppTokenDefinition & Previewer.MarketAccountStructOutput;
export type ExactlyMarketDefinition = DefaultAppTokenDefinition &
Previewer.MarketAccountStructOutput & { blockNumber: number; timestamp: number };
export type GetMarketDefinitionsParams = { network: Network; multicall: IMulticallWrapper; account?: string };

@Injectable()
export class ExactlyDefinitionsResolver {
constructor(@Inject(ExactlyContractFactory) protected readonly contractFactory: ExactlyContractFactory) {}

async getDefinitions({ multicall, network, account }: GetMarketDefinitionsParams) {
const address = PREVIEWER_ADDRESSES[network];
if (!address) throw new Error(`missing previewer on ${network}`);
const exactly = await multicall
.wrap(this.contractFactory.previewer({ address, network }))
.exactly(account ?? constants.AddressZero);
return exactly.map(m => ({ address: m.market.toLowerCase(), ...m } as ExactlyMarketDefinition));
const previewer = Previewer__factory.createInterface();
const { address: multicallAddress, interface: multicallInterface } = multicall.contract;
const [block, [{ data: exactly }, { data: ts }]] = await multicall.wrap(multicall.contract).callStatic.aggregate(
[
{ target: address, callData: previewer.encodeFunctionData('exactly', [account ?? constants.AddressZero]) },
{ target: multicallAddress, callData: multicallInterface.encodeFunctionData('getCurrentBlockTimestamp') },
],
true,
);
const blockNumber = block.toNumber();
const timestamp = (
multicall.contract.interface.decodeFunctionResult('getCurrentBlockTimestamp', ts)[0] as BigNumber
).toNumber();
return (previewer.decodeFunctionResult('exactly', exactly)[0] as Previewer.MarketAccountStructOutput[]).map(
m => ({ address: m.market.toLowerCase(), blockNumber, timestamp, ...m } as ExactlyMarketDefinition),
);
}

async getDefinition(params: GetMarketDefinitionsParams & { market: string }) {
Expand Down
18 changes: 8 additions & 10 deletions src/apps/exactly/common/exactly.fixed-position-fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { Inject } from '@nestjs/common';
import type { BigNumber } from 'ethers';

import { APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import type { IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { APP_TOOLKIT, type IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import type { GetDataPropsParams, GetTokenPropsParams } from '~position/template/app-token.template.types';

import { ExactlyContractFactory } from '../contracts';
import type { Market } from '../contracts';
import { ExactlyContractFactory, type Market } from '../contracts';
import { EXACTLY_DEFINITION } from '../exactly.definition';

import { ExactlyDefinitionsResolver } from './exactly.definitions-resolver';
import type { ExactlyMarketDefinition } from './exactly.definitions-resolver';
import { ExactlyTokenFetcher } from './exactly.token-fetcher';
import type { ExactlyMarketProps } from './exactly.token-fetcher';
import { ExactlyDefinitionsResolver, type ExactlyMarketDefinition } from './exactly.definitions-resolver';
import { type ExactlyMarketProps, ExactlyTokenFetcher } from './exactly.token-fetcher';

export type ExactlyFixedMarketProps = ExactlyMarketProps & { maturity: number };

Expand Down Expand Up @@ -40,12 +36,14 @@ export abstract class ExactlyFixedPositionFetcher<
};

getApr(params: GetDataPropsParams<Market, ExactlyMarketProps, ExactlyMarketDefinition>) {
return Number(this.getBestRate(params).rate) / 1e18;
return Number(this.getBestRate(params).rate) / 1e16;
}

getApy(params: GetDataPropsParams<Market, ExactlyMarketProps, ExactlyMarketDefinition>) {
const { maturity, rate } = this.getBestRate(params);
const timeLeft = maturity.toNumber() - Math.round(Date.now() / 1_000);
return Promise.resolve((1 + ((Number(rate) / 1e18) * timeLeft) / 31_536_000) ** (31_536_000 / timeLeft) - 1);
return Promise.resolve(
((1 + ((Number(rate) / 1e18) * timeLeft) / 31_536_000) ** (31_536_000 / timeLeft) - 1) * 100,
);
}
}
16 changes: 6 additions & 10 deletions src/apps/exactly/common/exactly.token-fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Inject } from '@nestjs/common';
import { constants } from 'ethers';
import type { BigNumber } from 'ethers';
import { constants, type BigNumber } from 'ethers';

import { APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import type { IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { APP_TOOLKIT, type IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { getLabelFromToken } from '~app-toolkit/helpers/presentation/image.present';
import { BalanceDisplayMode } from '~position/display.interface';
import { AppTokenTemplatePositionFetcher } from '~position/template/app-token.template.position-fetcher';
Expand All @@ -18,12 +16,10 @@ import type {
GetDisplayPropsParams,
} from '~position/template/app-token.template.types';

import { ExactlyContractFactory } from '../contracts';
import type { Market } from '../contracts';
import { ExactlyContractFactory, type Market } from '../contracts';
import { EXACTLY_DEFINITION } from '../exactly.definition';

import { ExactlyDefinitionsResolver } from './exactly.definitions-resolver';
import type { ExactlyMarketDefinition } from './exactly.definitions-resolver';
import { ExactlyDefinitionsResolver, type ExactlyMarketDefinition } from './exactly.definitions-resolver';

export type ExactlyMarketProps = DefaultAppTokenDataProps & { apr: number };

Expand Down Expand Up @@ -53,7 +49,7 @@ export abstract class ExactlyTokenFetcher<
}

getUnderlyingTokenDefinitions({ definition }: GetUnderlyingTokensParams<Market, ExactlyMarketDefinition>) {
return Promise.resolve([{ address: definition.asset, network: this.network }]);
return Promise.resolve([{ address: definition.asset.toLowerCase(), network: this.network }]);
}

getSymbol({ definition }: GetTokenPropsParams<Market, V, ExactlyMarketDefinition>) {
Expand Down Expand Up @@ -84,7 +80,7 @@ export abstract class ExactlyTokenFetcher<
}

async getApy(params: GetDataPropsParams<Market, V, ExactlyMarketDefinition>) {
return Promise.resolve((1 + (await this.getApr(params)) / 31_536_000) ** 31_536_000 - 1);
return ((1 + (await this.getApr(params)) / (100 * 31_536_000)) ** 31_536_000 - 1) * 100;
}

async getDataProps(params: GetDataPropsParams<Market, V, ExactlyMarketDefinition>) {
Expand Down
31 changes: 28 additions & 3 deletions src/apps/exactly/contracts/abis/previewer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
{ "internalType": "string", "name": "symbol", "type": "string" },
{ "internalType": "uint8", "name": "decimals", "type": "uint8" },
{ "internalType": "address", "name": "asset", "type": "address" },
{ "internalType": "string", "name": "assetName", "type": "string" },
{ "internalType": "string", "name": "assetSymbol", "type": "string" },
{
"components": [
Expand Down Expand Up @@ -66,6 +67,8 @@
"name": "fixedPools",
"type": "tuple[]"
},
{ "internalType": "uint256", "name": "floatingBorrowRate", "type": "uint256" },
{ "internalType": "uint256", "name": "floatingUtilization", "type": "uint256" },
{ "internalType": "uint256", "name": "floatingBackupBorrowed", "type": "uint256" },
{ "internalType": "uint256", "name": "floatingAvailableAssets", "type": "uint256" },
{ "internalType": "uint256", "name": "totalFloatingBorrowAssets", "type": "uint256" },
Expand Down Expand Up @@ -217,7 +220,18 @@
{ "internalType": "address", "name": "borrower", "type": "address" }
],
"name": "previewRepayAtMaturity",
"outputs": [{ "internalType": "uint256", "name": "repayAssets", "type": "uint256" }],
"outputs": [
{
"components": [
{ "internalType": "uint256", "name": "maturity", "type": "uint256" },
{ "internalType": "uint256", "name": "assets", "type": "uint256" },
{ "internalType": "uint256", "name": "utilization", "type": "uint256" }
],
"internalType": "struct Previewer.FixedPreview",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
Expand All @@ -226,10 +240,21 @@
{ "internalType": "contract Market", "name": "market", "type": "address" },
{ "internalType": "uint256", "name": "maturity", "type": "uint256" },
{ "internalType": "uint256", "name": "positionAssets", "type": "uint256" },
{ "internalType": "address", "name": "", "type": "address" }
{ "internalType": "address", "name": "owner", "type": "address" }
],
"name": "previewWithdrawAtMaturity",
"outputs": [{ "internalType": "uint256", "name": "withdrawAssets", "type": "uint256" }],
"outputs": [
{
"components": [
{ "internalType": "uint256", "name": "maturity", "type": "uint256" },
{ "internalType": "uint256", "name": "assets", "type": "uint256" },
{ "internalType": "uint256", "name": "utilization", "type": "uint256" }
],
"internalType": "struct Previewer.FixedPreview",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
}
Expand Down
31 changes: 20 additions & 11 deletions src/apps/exactly/contracts/ethers/Previewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,16 @@ export declare namespace Previewer {
symbol: PromiseOrValue<string>;
decimals: PromiseOrValue<BigNumberish>;
asset: PromiseOrValue<string>;
assetName: PromiseOrValue<string>;
assetSymbol: PromiseOrValue<string>;
interestRateModel: Previewer.InterestRateModelStruct;
usdPrice: PromiseOrValue<BigNumberish>;
penaltyRate: PromiseOrValue<BigNumberish>;
adjustFactor: PromiseOrValue<BigNumberish>;
maxFuturePools: PromiseOrValue<BigNumberish>;
fixedPools: Previewer.FixedPoolStruct[];
floatingBorrowRate: PromiseOrValue<BigNumberish>;
floatingUtilization: PromiseOrValue<BigNumberish>;
floatingBackupBorrowed: PromiseOrValue<BigNumberish>;
floatingAvailableAssets: PromiseOrValue<BigNumberish>;
totalFloatingBorrowAssets: PromiseOrValue<BigNumberish>;
Expand All @@ -121,6 +124,7 @@ export declare namespace Previewer {
number,
string,
string,
string,
Previewer.InterestRateModelStructOutput,
BigNumber,
BigNumber,
Expand All @@ -133,6 +137,8 @@ export declare namespace Previewer {
BigNumber,
BigNumber,
BigNumber,
BigNumber,
BigNumber,
boolean,
BigNumber,
BigNumber,
Expand All @@ -146,13 +152,16 @@ export declare namespace Previewer {
symbol: string;
decimals: number;
asset: string;
assetName: string;
assetSymbol: string;
interestRateModel: Previewer.InterestRateModelStructOutput;
usdPrice: BigNumber;
penaltyRate: BigNumber;
adjustFactor: BigNumber;
maxFuturePools: number;
fixedPools: Previewer.FixedPoolStructOutput[];
floatingBorrowRate: BigNumber;
floatingUtilization: BigNumber;
floatingBackupBorrowed: BigNumber;
floatingAvailableAssets: BigNumber;
totalFloatingBorrowAssets: BigNumber;
Expand Down Expand Up @@ -347,15 +356,15 @@ export interface Previewer extends BaseContract {
positionAssets: PromiseOrValue<BigNumberish>,
borrower: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<[BigNumber] & { repayAssets: BigNumber }>;
): Promise<[Previewer.FixedPreviewStructOutput]>;

previewWithdrawAtMaturity(
market: PromiseOrValue<string>,
maturity: PromiseOrValue<BigNumberish>,
positionAssets: PromiseOrValue<BigNumberish>,
arg3: PromiseOrValue<string>,
owner: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<[BigNumber] & { withdrawAssets: BigNumber }>;
): Promise<[Previewer.FixedPreviewStructOutput]>;
};

auditor(overrides?: CallOverrides): Promise<string>;
Expand Down Expand Up @@ -396,15 +405,15 @@ export interface Previewer extends BaseContract {
positionAssets: PromiseOrValue<BigNumberish>,
borrower: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<BigNumber>;
): Promise<Previewer.FixedPreviewStructOutput>;

previewWithdrawAtMaturity(
market: PromiseOrValue<string>,
maturity: PromiseOrValue<BigNumberish>,
positionAssets: PromiseOrValue<BigNumberish>,
arg3: PromiseOrValue<string>,
owner: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<BigNumber>;
): Promise<Previewer.FixedPreviewStructOutput>;

callStatic: {
auditor(overrides?: CallOverrides): Promise<string>;
Expand Down Expand Up @@ -445,15 +454,15 @@ export interface Previewer extends BaseContract {
positionAssets: PromiseOrValue<BigNumberish>,
borrower: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<BigNumber>;
): Promise<Previewer.FixedPreviewStructOutput>;

previewWithdrawAtMaturity(
market: PromiseOrValue<string>,
maturity: PromiseOrValue<BigNumberish>,
positionAssets: PromiseOrValue<BigNumberish>,
arg3: PromiseOrValue<string>,
owner: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<BigNumber>;
): Promise<Previewer.FixedPreviewStructOutput>;
};

filters: {};
Expand Down Expand Up @@ -503,7 +512,7 @@ export interface Previewer extends BaseContract {
market: PromiseOrValue<string>,
maturity: PromiseOrValue<BigNumberish>,
positionAssets: PromiseOrValue<BigNumberish>,
arg3: PromiseOrValue<string>,
owner: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<BigNumber>;
};
Expand Down Expand Up @@ -553,7 +562,7 @@ export interface Previewer extends BaseContract {
market: PromiseOrValue<string>,
maturity: PromiseOrValue<BigNumberish>,
positionAssets: PromiseOrValue<BigNumberish>,
arg3: PromiseOrValue<string>,
owner: PromiseOrValue<string>,
overrides?: CallOverrides,
): Promise<PopulatedTransaction>;
};
Expand Down
Loading

0 comments on commit 004354c

Please sign in to comment.